概述
电脑显示器是2D平面,一个3D物体通过OpenGL渲染投影到2D显示器平面形成图像,GL_PROJECTION是OpenGL用于投影转换的矩阵。首先,转换3D物体的顶点数据从相机空间到裁剪空间,然后,通过除以W(齐次坐标)从裁剪空间再转换到标准设备空间(NDC)。
因此,我们需要意识到裁剪计算和NDC转换都是整合到了GL_PROJECTION矩阵里了。接下来的内容将探讨怎么构建投影矩阵,使用6个代表边界值的参数分别是:left,right,bottom,top,near , far(下面简写为l、r、b、t、n、f)。有一点注意一下,裁剪计算是在转换成NDC坐标之前发生的,即在除以(齐次坐标)之前。通过裁剪坐标
,
,
和
(这里的c下标表示裁剪空间)做对比,如果裁剪坐标小于
或大于
将被裁减掉(
),然后OpenGL会重新构建网格边缘。

透视投影
在透视投影里,一个3D点在一个平头视锥体里面(相机空间)是要被映射到一个正方体(NDC空间)里的,x坐标的区间从[l,r]映射到[-1,1],y坐标的区间从[b,t]映射到[-1,1],z坐标的区间从[-n,-f]映射到[-1,1]。

注意一点,相机空间是使用右手坐标系统,但是NDC坐标空间使用左手坐标系统,这就是相机在原点沿着-Z方向看,但是在NDC空间是反过来的。因为glFrustum()仅仅接收正的near和far值,在构造GL_PROJECTION矩阵时我们需要给他们变成负值。
在OpenGL里,一个3D点在相机空间是被投影到near平面(projection plane 即下图的-n平面)。下面的图片展示一个点(


从上往下看视锥体,相机空间的x坐标点
同理,从侧边看视锥体可得:
注意到,


因此,我们可以设置裁剪空间的w坐标等于

下一步,我们通过线性关系映射(p下标表示投影空间未有裁剪的)和
(p下标表示投影空间未有裁剪的)到NDC坐标空间的
(n下标表示NDC空间)和
(n下标表示NDC空间),即:[l,r] => [-1,1] [b,t] => [-1,1]




然后使用上面的


注意到,我们故意把等式构造成除以
从上面的等式总结,我们可以找到GL_PROJECTION矩阵第一行和第二行的构造方法

现在GL_PROJECTION矩阵只剩下第三行没构造好,构造

在相机空间,

为了求出系数A和B,根据上面等式得出

由等式(1)推出:

把B等式代入等式(2):

把A等式代入等式(1):

得到A和B的等式可导出


当视锥体是个对称视锥体时,r = -l , t = -b 所以可以简化矩阵公式:

最后,再审视一下上面等式(3)表达的

正交投影
构造正交投影矩阵 GL_PROJECT比构造透视投影矩阵简单多了,只需要在相机空间里线性的映射到NDC空间。我们只需要缩放长方体变成正方体,然后移到原点位置,让我们看看GL_PROJECTION的各元素之间的线性关系吧。







因为正交投影矩阵是不需要用w计算z值的(z值也是线性关系直接求出来,透视投影需要用w来间接计算

当视锥体是对称长方体,即r = -l、t = -b,有:

坐标转换:模型坐标 -> 世界坐标 -> 相机坐标 -> 裁剪坐标 -> NDC坐标
原文链接
网友评论