【发布时间】:2014-07-31 06:42:35
【问题描述】:
说明
我在 OpenGL 中遇到了 Z-Fighting 的主要问题,我花了很长时间寻找解决这个问题的方法。我发现的一些我理解但不喜欢的:
- 将多边形彼此分开(如 OpenGL 中的 glPolygonOffset)
- 根据 Z 坐标划分场景并使用单独的干净 z 缓冲区绘制场景的各个部分。
我不明白的:
- 使用投影矩阵 https://software.intel.com/en-us/articles/alternatives-to-using-z-bias-to-fix-z-fighting-issues
- 使用“对数深度缓冲区” http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html
我已经在我的程序中实现了第二个,只需将它放入一个球的顶点着色器中(它与地面发生 z-fight):
float C = 1.0;
float far = 2000.0;
gl_Position = u_projView * a_position;
gl_Position.z = 2.0*log(gl_Position.w*C + 1.0)/log(far*C + 1.0) - 1.0;
gl_Position.z *= gl_Position.w;
它成功了!
实际问题
- 谁能解释我在顶点着色器中更改顶点的 Z 坐标是如何在不将顶点明显移动到我的情况下解决问题的? (场景在人眼看来是一样的)。它是如何改变 z 深度值的分布的?我猜我缺少一些关于渲染管道的知识。
- 谁能解释一下我们如何使用投影矩阵来解决这个问题?它是如何工作的?
- 还有其他类似有效的方法来解决 z-fighting 问题吗?
谢谢!
【问题讨论】:
-
我认为你的场景真的有很大范围的 z 值需要渲染?范围有多大?
-
我可能应该详细说明:改变
z的值的唯一方法是改变屏幕上显示的内容(除了深度战斗)是在 之前或之前完成eye-space,因为这是从w派生而来的透视投影 (-eye.z)。在本例中不是在眼睛空间中完成,而是在剪辑空间(在眼睛空间之后)完成,所以z的值不会改变x或y。输出图像为 2D,如果x和y均未发生变化,您将不会看到屏幕上的几何形状有任何差异。 -
@MikeWazowsky:你链接的文章已经非常详细地解释了你实现的方法。它还解释了为什么在一般情况下仅以您所做的方式更改顶点着色器 not 起作用。您还需要调整每个片段的计算深度值,否则您可能会遇到在屏幕空间中显得相对较大的图元可能与附近的其他几何图形错误地相交的情况。
-
@MikeWazowsky:投影矩阵的方法是在渲染场景时使用多个投影矩阵(一个用于近处物体,另一个用于远处物体)。这是一个相当的技巧,只适用于某些类型的场景。您提供的链接中也对此进行了说明。
-
when z fighting appears, push the z near plane you will.简单的佛学知识。
标签: opengl graphics rendering glsl shader