透视鸿沟:为什么要使用w组件?

Kar*_*rus 1 opengl graphics glsl

在OpenGL中,我已经读过顶点应该由(x,y,z,w)表示,其中w = z.这是为了实现透视分割,其中(x,y,z)除以w以便由于透视效果确定它们的屏幕位置.如果它们刚刚除以原始z值,那么z到处都是1.

我的问题是:为什么你需要将z分量除以w?为什么不能将x和y分量除以z,这样屏幕坐标应用了透视效果,然后只使用原始未修改的z分量进行深度测试?通过这种方式,您根本不必使用w组件....

显然我错过了什么!

der*_*ass 9

3D计算机图形通常用齐次坐标投影矢量空间处理.这背后的数学比"仅仅除以w"更多.

使用4D齐次矢量和4×4矩阵具有很好的优点,即各种仿射变换(这尤其包括也依赖于w的平移)和投影变换可以通过简单的矩阵乘法来表示.

在OpenGL中,我已经读过顶点应该由(x,y,z,w)表示,其中w = z.

事实并非如此.顶点应该用(x,y,z,w)表示,其中w只是w.在典型情况下,输入w实际上是1,因此它通常不存储在顶点数据中,而是在着色器等中按需添加.

您的典型投影矩阵将设置w_clip = -z_eye.但这是另一回事.这意味着您只需沿着-z眼睛空间的方向投射.你也可以放在w_clip=2 *x_eye -3*y_eye + 4 * z_eye那里,你的投影轴将有方向(2,-3,4,0).

我的问题是:为什么你需要将z分量除以w?为什么不能将x和y分量除以z,这样屏幕坐标应用了透视效果,然后只使用原始未修改的z分量进行深度测试?

从概念上讲,空间沿着所有3个维度扭曲,而不仅仅是x和y.此外,在开始时,GPU 对于深度缓冲器仅具有16位或24位整数精度.在这种情况下,你肯定希望在相机附近有一个更密集的表示,而在远处则是一个稀疏的表示.

如今,通过可编程顶点着色器和浮点深度缓冲格式,您基本上只需将z_eye值存储在深度缓冲区中,并将其用于深度测试.然而,这通常被称为W缓冲,因为使用了(剪辑空间)w分量.

如果你将z除以另一个概念问题:你将无法使用正交投影,你总是会强迫某种观点.现在有人可能认为z除法不必自动发生,但可以在顶点着色器中需要时应用它.但这也行不通.您不能在顶点着色器中应用透视分割,因为这会在相机前面投射位于相机后面的点.由于顶点着色器不适用于整个基元,如果至少有一个顶点位于摄像机后面而另一个顶点位于摄像机前面,则会完全搞乱任何基元.为了处理这种情况,必须在除法之前应用剪辑 - 因此名称剪辑空间.

通过这种方式,您根本不必使用w组件.

那也不是真的.w组件进一步沿管道使用.这对于透视校正属性插值至关重要.