通常,当在OpenGL中渲染共面或接近共面的多边形时,每个多边形的纹理会以不确定的方式混合在一起。我的理解是,这是由于z缓冲区使用浮点值而导致的精度有限。但是,这种情况似乎是一个例外。我注意到,当两个多边形以完全相同的顶点位置进行渲染时,不会发生z冲突。最后渲染的多边形出现在另一个共面多边形的顶部。

为什么会发生这种情况?是否总是会发生这种现象?是否可以在所有OpenGL实现中保证这种行为?

#1 楼

OpenGL规范中有关于不变性保证的明确规则。为了便于讨论,这些规则可以归结为以下内容。

鉴于特定的一系列顶点处理着色器(VS,细分和GS),有一些输入值,统一,等导致计算该过程中图元的最终gl_Position值。如果所有这些值都是二进制相同的(包括顶点格式导致任何VS输入的方式),那么可以确保gl_Position具有二进制相同的值。而且,如果两个相同类型的图元具有二进制相同的位置,则需要光栅化程序来生成二进制相同的片段位置。

,因此无需进行z角操作。

现在,那是限制性的,因为它仅适用于相同的着色器。您可以使用不同的着色器,只要:


所有涉及的着色器在表达式上获得二进制相同的值,导致计算gl_Position
所有涉及的着色器都使用完全相同的表达式(我的意思是确切的;无论数学如何说,a + b都不是与b + a相同的表达式)来计算gl_Position

gl_Position以及导致其生成的任何着色器间输入/输出变量所有着色器中的invariant限定符都可以对计算进行限定。这告诉编译器不要在导致计算此类值的表达式中优化某些内容。


#2 楼

那是因为GPU是确定性的。对于相同的输入(顶点位置),每个像素深度输出应产生完全相同的输出。

Z战斗通常发生在顶点位置不同但仍在同一平面上的多边形中,因此插值舍入误差显示为差异,因此发生Z战斗。

评论


$ \ begingroup $
因此,例如在游戏编程中渲染纹理叠加层时,在不同的实现和GPU上依靠此行为会很安全吗?
$ \ endgroup $
–Quantum64
19年6月26日在9:43

$ \ begingroup $
我要说的是GPU的内部原理,我看过一些具有出色插值精度的移动SOC GPU。我不确定,但是我不认为openGL会遇到这种精度,因为它可以在GPU芯片内部的定点整数单位的浮点单位中执行。
$ \ endgroup $
–PaulHK
19年6月26日在9:47

$ \ begingroup $
该评论令人怀疑我是否应该在游戏中使用它。我的替代方法是为要应用叠加层的纹理生成Alpha蒙版,但我想避免这种情况,以尽可能节省纹理图集上的空间。我只关心台式机GPU,这对它们安全吗?
$ \ endgroup $
–Quantum64
19-6-26在9:53



$ \ begingroup $
@ Quantum64不,这不仅取决于GPU的内部,OpenGL标准实际上为不变性做出了某些保证,这就是其中之一。对于相同的输入,相同的计算将返回相同的结果。这适用于流水线转换和内插,就像适用于任何确定性程序一样。
$ \ endgroup $
–克里斯蒂安·劳(Christian Rau)
19-6-26在12:26



$ \ begingroup $
...如果您在顶点着色器中进行了不同的顶点转换操作(例如,MVP乘法与单独的P * MV乘法),可能会导致差异。确保使用相同的计算。即使这样,理论上也可能会有不同的结果(尽管实际上没有),但即使声明顶点位置不变,也可以解决。因此,是的,多次绘制网格以进行纹理分层之类的事情是一个完全合理且常见的用例,如果正确处理,则可以以100%符合标准且可靠的方式完成。
$ \ endgroup $
–克里斯蒂安·劳(Christian Rau)
19-6-26在12:27