我成功地编写了一个带有点精灵的标准基本变换反馈粒子系统。没有闪烁,粒子从一个缓冲区更新到下一个缓冲区,然后渲染,然后输出缓冲区在下一次迭代时成为输入缓冲区。所有 GPU 端的标准变换反馈。精彩的!一个大问题:它只有在我不使用 gl_PointCoord 时才有效。为我的点精灵使用纯色效果很好。但我需要 gl_PointCoord 来做任何有意义的事情。我所有的着色器,无论他们是否使用 gl_PointCoord,编译和链接都很好。但是,在运行时,如果着色器使用 gl_PointCoord(无论 gl_PointCoord 实际上是否在执行路径中),程序就会崩溃。我明确地 glEnable(GL_POINT_SPRITE)。这没有任何影响。省略 gl_PointCoord,设置 glPointSize(100.0f),使用 vec4(1.0,1.0,1.0, 1.)粒子系统渲染得就像大的白色块状正方形(如预期的那样)。但是在成功编译和链接后,以任何方式使用 gl_PointCoord(作为标准纹理查找坐标或程序颜色或其他任何东西)都会在运行时使我的着色器崩溃。我只是不明白为什么。它通过了glShaderSource、glCompileShader、glAttachShader、glLinkProgram。我将我的着色器编译为#version 430 和 440,我什至尝试了 300 es。所有编译,链接,我检查了编译和链接的状态。都好。我正在使用高端的微软 Surface Book Pro,Visual Studio 2015。NVIDIA GeForce GPU。我还确保我所有的驱动程序都是最新的。不幸的是,对于点精灵,我没有来自顶点着色器的广告牌顶点用于插入片段着色器作为纹理坐标。gl_FragCoord 也不起作用(正如我对点精灵的期望)。有谁知道如何解决这个问题或使用另一种技术来处理点精灵的纹理坐标?
glBeginTransformFeedback(GL_POINTS);//如果我的片段着色器使用gl_PointCoord,它在这里很难崩溃。
回复时,请理解我在 GLSL 和 HLSL 中编写着色器、顶点着色器、像素着色器、曲面细分控制、曲面细分评估和几何着色器方面非常有经验。但我并不声称知道一切。我可能忘记了一些简单的事情;我只是不知道那可能是什么。我想这可能是我没有启用的状态。就变换反馈而言,我还通过 glTransformFeedbackVaryings 正确设置了可变属性。C++:
void Render(void* pData)
{
auto pOwner = static_cast<CPointSpriteSystem*>(pData);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glEnable(GL_POINT_SPRITE);
glEnable(GL_POINT_SMOOTH);
//glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);
m_Shader.Activate();
auto num_particles = pOwner->m_NumPointSprites;
FeedbackIndex = 0;
while (true)
{
m_Shader.SetSubroutine(GL_VERTEX_SHADER, "RenderPass",
vssubroutines[FeedbackIndex],
vsprevSubLoc[FeedbackIndex],
vsupdateSub[FeedbackIndex]);
m_Shader.SetSubroutine(GL_FRAGMENT_SHADER, "RenderPixelPass",
pssubroutines[0],
psprevSubLoc[0],
psrenderSub[0]);
if (!FeedbackIndex)
{
glEnable(GL_RASTERIZER_DISCARD);
glBindVertexArray(m_vao[bufferIndex]);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_Feedback[bufferIndex]);
glBeginTransformFeedback(GL_POINTS);//if feedback fragment shader uses gl_PointCoord, will always hard-crash here
glDrawArrays(GL_POINTS, 0, num_particles);
glEndTransformFeedback();
glFlush();
}
else
{
m_Shader.SetSubroutine(GL_FRAGMENT_SHADER, "RenderPixelPass",
pssubroutines[(int)pOwner->m_ParticleType],
psprevSubLoc[(int)pOwner->m_ParticleType],
psrenderSub[(int)pOwner->m_ParticleType]);
glPointSize(100.0f);
glDisable(GL_RASTERIZER_DISCARD);
glDrawTransformFeedback(GL_POINTS, m_Feedback[bufferIndex]);
bufferIndex = 1 - bufferIndex;
break;
}
FeedbackIndex = 1 - FeedbackIndex;
}
}
VS 反馈:
#version 310 es
subroutine void RenderPassType();
subroutine uniform RenderPassType RenderPass;
layout(location=0) in vec3 VertexPosition;
layout(location=1) in vec3 VertexVelocity;
layout(location=2) in float VertexStartTime;
layout(location=3) in vec3 VertexInitialVelocity;
out vec3 Position;
out vec3 Velocity;
out float StartTime;
out float Transp;
uniform float g_fCurSeconds;
uniform float g_fElapsedSeconds;
uniform float Time;
uniform float H;
uniform vec3 Accel;
#ifdef USE_VIEW_BLOCK
layout(std140) uniform view_block{
mat4 g_mView,
g_mInvView,
g_mPrevView,
g_mPrevInvView,
g_mProj,
g_mInvProj;
};
uniform mat4 g_mWorld;
#endif
subroutine(RenderPassType) void UpdateSphere(){
Position=VertexPosition+VertexVelocity*g_fElapsedSeconds;
Velocity=VertexVelocity;
StartTime=VertexStartTime;
}
subroutine(RenderPassType) void Render(){
gl_Position=g_mProj*g_mInvView*vec4(VertexPosition,1.0);
}
void main(){
RenderPass();"
}
PS反馈:
#version 310 es //version 430 and 440 same results
subroutine void RenderPixelType();
subroutine uniform RenderPixelType RenderPixelPass;
uniform sampler2D tex0;
layout(location=0) out vec4 g_FragColor;
subroutine(RenderPixelType) void Basic(){
g_FragColor=vec4(1.0,1.0,1.0,1.0);
}
subroutine(RenderPixelType) void ProceduralSphere(){
#if 1
vec2 coord=gl_PointCoord;//at runtime: BOOM!
coord=coord*2.0-1.0;
float len=length(coord);
if(len>1.0) discard;
g_FragColor=vec4(1.0-len,1.0-len,1.0-len,1.0);
#else
g_FragColor=vec4(1.0,1.0,1.0,1.0);//always works
#endif
}
subroutine(RenderPixelType) void StandardImage(){
g_FragColor=texture2D(tex0,gl_PointCoord); //boom!!
g_FragColor=vec4(1.0,1.0,1.0,1.0);
}
void main(){
RenderPixelPass();
}