我最近意识到OpenGL不仅对x
和y
执行透视除法,而且对z
也执行透视除法。
在我的理解中,x /= w;
和y /= w;
就足够了。当然,我们需要不同的投影矩阵。
那么,为什么OpenGL z /= w;
呢?使 z 缓冲区在短距离上更精确,但在长距离上不那么精确?
在数学上,划分所有组件是正确的方法。这样,就可以线性地插值屏幕空间中的z
(不会对位置数据进行透视校正插值,因为它应该在屏幕空间中进行插值)。当然,场景空间中的线性插值意味着在眼睛或物体空间中观察,它似乎是非线性的。它只是意味着对于不平行于图像平面的对象,在屏幕上向左移动一个像素确实意味着沿 + 或 -z 移动可变量,具体取决于距离 - 因此,感知实际上也会扭曲 z 轴。
副作用是Z缓冲区精度在近平面上最高,这对于大多数场景来说实际上是一件好事。
使用"未分割"Z进行深度测试称为W缓冲区。但这意味着线性插值不能再使用。但是,对于现代GPU,这不是一个太大的问题。
变换的作用是将对象从世界空间移动到投影空间(实际上它将是投影空间之前的摄像机空间,但它不在范围内)。
从视觉上看,每隔一个空间都是一个从-1到1的立方体,而投影空间是一个金字塔截面,近平面在Z0,远平面在Z1(或Z-1取决于右手或左手系统)。所以 z 也会变形(除非你有正交投影)。Z 从 0 变为 1,因为近平面后面的对象进入渲染管线没有任何意义。
您提到了自己,并在评论中提到了Z缓冲区精度。它的精度不会改变,但是,在投影变换之后,远平面附近的对象之间的对象 Z 增量将更少,而靠近近平面的对象之间的对象 Z 增量将更多(用不太花哨的话说:靠近近平面的物体之间的 Z 轴上的距离将增加,而远平面附近物体之间的 Z 轴上的距离将减小)。
这就是为什么减少近平面和远平面距离有时会修复 Z 战斗:如果两个平面之间的距离较小,则远处物体之间的距离将减少。