GLSL 着色器:遮挡顺序和剔除
GLSL shader: occlusion order and culling
我有一个 GLSL 着色器,它在给定一组贝塞尔曲线(点的 3d 坐标)的情况下绘制 3D 曲线。绘图本身是按照我的意愿完成的,除了遮挡不能正常工作,即在某些视点下,应该在最前面的曲线似乎仍然被遮挡,而反向:应该是曲线的一部分被遮挡依然可见
为了说明,这里有几个截图示例:
1 - 彩色曲线更靠近相机,因此在此处正确渲染。
2 - 彩色曲线应该在灰色曲线的后面,但它呈现在顶部。
我是 GLSL 的新手,可能不知道这种效果的正确术语,但我认为它是遮挡剔除(更新:它实际上表明深度缓冲区存在问题,术语混乱!)。我的问题是:使用 GLSL 着色器时如何处理遮挡?我是否必须在着色器程序或其他地方处理它们?
关于我的代码,它有点长(加上我使用 OpenGL 包装器库),但主要步骤是:
- 在顶点着色器中,我计算
gl_Position = ModelViewProjectionMatrix * Vertex;
并将颜色信息进一步传递给几何着色器。
- 在几何着色器中,我采用 4 个控制点 (
lines_adjacency
) 及其相应的颜色,并生成一个遵循贝塞尔曲线的三角形带(我在贝塞尔曲线段之间使用了一些基本的颜色插值)。
- 片段着色器也很简单:
gl_FragColor = VertexIn.mColor;
.
关于OpenGL设置,我启用了GL_DEPTH_TEST
,但是好像没有我需要的东西。此外,如果我在场景中放置任何其他非着色器几何体(例如四边形),则无论视点如何,曲线总是渲染在它的顶部。
任何有关如何解决它以及它发生的原因的见解和提示都将受到赞赏。
更新解决方案
因此,据我了解,最初的问题不是找到剔除算法,而是我没有正确处理 z 值的计算(请参阅已接受的答案)。我还了解到,如果设置了正确的深度缓冲区,OpenGL 会自行正确处理遮挡,因此我不需要重新发明轮子。
我搜索了我的 GLSL 程序,发现在将顶点坐标转换为屏幕坐标 (vec2( vertex.xy / vertex.w ) * Viewport;
) 时,我基本上将几何着色器中的 z 值设置为零。我通过分别计算 z 值 (vertex.z/vertex.w
) 并将它们分配给发射点 (gl_Position = vec4( screenCoords[i], zValues[i], 1.0 );
) 来修复它。那解决了我的问题。
关于深度缓冲区设置,我不必明确指定它们,因为我使用的库默认情况下会根据需要正确设置它们。
如果您不使用深度缓冲区,那么最近渲染的对象将始终在顶部。
您应该使用 glEnable(GL_DEPTH_TEST)
启用它,根据您的喜好设置该功能 (glDepthFunc(GL_LEQUAL)
),并确保在每一帧清除它以及其他所有内容 (glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
)。
然后确保您的顶点着色器正确设置了最终顶点的 Z 值。看起来最简单的方法是在 CPU 侧设置 ModelViewProjectionMatrix
的 "Model" 部分,使其在传递到着色器之前具有深度值。
只要您使用的是正交投影矩阵,渲染就不会受到影响(除了使绘制顺序正确之外)。
我有一个 GLSL 着色器,它在给定一组贝塞尔曲线(点的 3d 坐标)的情况下绘制 3D 曲线。绘图本身是按照我的意愿完成的,除了遮挡不能正常工作,即在某些视点下,应该在最前面的曲线似乎仍然被遮挡,而反向:应该是曲线的一部分被遮挡依然可见
为了说明,这里有几个截图示例:
1 - 彩色曲线更靠近相机,因此在此处正确渲染。
2 - 彩色曲线应该在灰色曲线的后面,但它呈现在顶部。
我是 GLSL 的新手,可能不知道这种效果的正确术语,但我认为它是遮挡剔除(更新:它实际上表明深度缓冲区存在问题,术语混乱!)。我的问题是:使用 GLSL 着色器时如何处理遮挡?我是否必须在着色器程序或其他地方处理它们?
关于我的代码,它有点长(加上我使用 OpenGL 包装器库),但主要步骤是:
- 在顶点着色器中,我计算
gl_Position = ModelViewProjectionMatrix * Vertex;
并将颜色信息进一步传递给几何着色器。 - 在几何着色器中,我采用 4 个控制点 (
lines_adjacency
) 及其相应的颜色,并生成一个遵循贝塞尔曲线的三角形带(我在贝塞尔曲线段之间使用了一些基本的颜色插值)。 - 片段着色器也很简单:
gl_FragColor = VertexIn.mColor;
.
关于OpenGL设置,我启用了GL_DEPTH_TEST
,但是好像没有我需要的东西。此外,如果我在场景中放置任何其他非着色器几何体(例如四边形),则无论视点如何,曲线总是渲染在它的顶部。
任何有关如何解决它以及它发生的原因的见解和提示都将受到赞赏。
更新解决方案
因此,据我了解,最初的问题不是找到剔除算法,而是我没有正确处理 z 值的计算(请参阅已接受的答案)。我还了解到,如果设置了正确的深度缓冲区,OpenGL 会自行正确处理遮挡,因此我不需要重新发明轮子。
我搜索了我的 GLSL 程序,发现在将顶点坐标转换为屏幕坐标 (vec2( vertex.xy / vertex.w ) * Viewport;
) 时,我基本上将几何着色器中的 z 值设置为零。我通过分别计算 z 值 (vertex.z/vertex.w
) 并将它们分配给发射点 (gl_Position = vec4( screenCoords[i], zValues[i], 1.0 );
) 来修复它。那解决了我的问题。
关于深度缓冲区设置,我不必明确指定它们,因为我使用的库默认情况下会根据需要正确设置它们。
如果您不使用深度缓冲区,那么最近渲染的对象将始终在顶部。
您应该使用 glEnable(GL_DEPTH_TEST)
启用它,根据您的喜好设置该功能 (glDepthFunc(GL_LEQUAL)
),并确保在每一帧清除它以及其他所有内容 (glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
)。
然后确保您的顶点着色器正确设置了最终顶点的 Z 值。看起来最简单的方法是在 CPU 侧设置 ModelViewProjectionMatrix
的 "Model" 部分,使其在传递到着色器之前具有深度值。
只要您使用的是正交投影矩阵,渲染就不会受到影响(除了使绘制顺序正确之外)。