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

时间:2015-07-28 20:41:49

标签: opengl graphics glsl

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

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

显然我错过了什么!

1 个答案:

答案 0 :(得分:9)

3D计算机图形通常使用homogeneous coordinatesprojective vector space处理。这背后的数学有点超过"只是除以w"。

使用4D齐次向量和4x4矩阵具有很好的优势,即各种仿射变换(尤其包括平移,也依赖于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 buffering,因为使用了(剪辑空间)w组件。

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

  

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

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