当前位置:网站首页>∑GL-透视投影矩阵的推导

∑GL-透视投影矩阵的推导

2022-04-23 16:39:00 itzyjr


计算机显示器是二维表面。由OpenGL渲染的3D场景必须作为2D图像投影到计算机屏幕上。投影矩阵用于此投影变换。首先,它将所有顶点数据从眼睛坐标转换为剪裁坐标。然后,通过与剪裁坐标的w分量相除,这些剪裁坐标也被转换为归一化设备坐标(NDC)。

剪裁坐标:眼睛坐标现在与投影矩阵相乘,成为剪裁坐标。该投影矩阵定义了视锥体——顶点数据投影到屏幕上的方式(透视或正交)。之所以称为剪裁坐标,是因为变换后的顶点(x,y,z)是通过与±wclip进行比较来剪裁的。

视锥体剔除(裁剪)操作是在剪裁坐标中执行的,正好在除以wclip之前。通过与wclip的比较,测试了剪裁坐标xclip、yclip和zclip。因为除以wclip后成为归一化的NDC坐标,所以要满足-1<=xclip/wclip<=1,所以xclip∈[-wclip,wclip];同理yclip∈[-wclip,wclip],zclip∈[-wclip,wclip]。如果任何剪裁坐标小于-wclip或大于wclip,则顶点将被丢弃(剪裁掉)。

因此,我们必须记住,裁剪(视锥体剔除)和NDC变换都集成到投影矩阵中。以下介绍如何从6个参数构建投影矩阵:left、right、bottom、top、near和far边界值。

然后,OpenGL将重建发生剪裁的多边形的边(如下图中的两条红线)。
下图中的灰色区域即是保留而未被丢弃的点,满足:xc,yc,zc∈(-wc,wc)

下图展示了透视视锥体和归一化设备坐标(NDC):

在透视投影中,视锥体的锥台(眼睛坐标)中的3D点被映射到立方体(NDC);x坐标从[l,r]到[-1,1],y坐标从[b,t]到[-1,1],z坐标从[-n,-f]到[-1,1]。

void glFrustum(
// 指定左右垂直剪裁平面的坐标。
GLdouble left, GLdouble right,
// 指定底部和顶部水平剪裁平面的坐标。
GLdouble bottom, GLdouble top,
// 指定到近深度剪裁平面和远深度剪裁平面的距离。两个距离都必须为正。
GLdouble nearVal, GLdouble farVal
);

请注意,眼睛坐标是在右手坐标系中定义的,但NDC使用左手坐标系。也就是说,原点处的相机在眼睛空间中沿-Z轴观看,但在NDC中沿+Z轴观看。由于glFrustum()只接受near和far的正值,因此我们需要在构造投影矩阵时对它们求反。

在OpenGL中,眼睛空间中的一个3D点被投影到近平面(投影平面)上。下图显示了眼睛空间中的一个点(xe,ye,ze)如何投影到近平面上的(xp,yp,zp)。

从视锥体的[俯视图],即眼睛空间的x坐标,xe被映射到xp,xp是通过使用相似三角形的比率来计算的:

从视锥体的侧面来看,yp也以类似的方式计算:

注意xp和yp都依赖于ze;它们与-ze成反比。换句话说,它们都被-ze除。这是构造投影矩阵的第一条线索。通过乘以投影矩阵变换眼睛坐标后,剪裁坐标仍然是齐次坐标。它最终成为标准化设备坐标(NDC),除以剪裁坐标的w分量。(更多细节,见OpenGL_Transformation)

因此,我们可以将剪裁坐标的w分量设置为-ze。投影矩阵的第4行变成(0,0,-1,0)。

接下来,我们用线性关系将xp和yp映射到NDC的xn和yn;[l,r]⇒ [-1,1]和[b,t]⇒ [-1,1]。

然后,我们将xp和yp代入上述方程。

注意,对于透视除法(xc/wc,yc/wc),我们使每个方程的两项都可以被-ze整除。我们在前面将wc设置为-ze,括号内的术语变成了剪裁坐标的xc和yc

从这些方程中,我们可以找到投影矩阵的第1行和第2行。

现在,我们只需要解第3行投影矩阵。发现zn与其他的有点不同,因为眼睛空间中的ze总是投射到近平面上的-n。但是我们需要唯一的z值来进行裁剪和深度测试。此外,我们应该能够取消投影(逆变换)。因为我们知道z不依赖于x或y值,所以我们借用w分量来寻找zn和ze之间的关系。因此,我们可以这样指定投影矩阵的第3行。

在眼睛空间中,we等于1。因此,方程变为:

为了求系数A和B,我们使用(ze,zn)关系:(-n,-1)和(-f,1),并将它们放入上述方程中,解出A、B。

此时,ze与zn的关系变为:

最后,我们找到了投影矩阵的所有条目。完整的投影矩阵是:
在这里插入图片描述
该投影矩阵适用于一般视锥体。如果视体是对称的,即r=-l, t=-b,则可以简化为:
在这里插入图片描述
在我们继续之前,请再次看看ze和zn之间的关系,等式(3)。你注意到这是一个有理函数,ze和zn之间是非线性关系(如下图)。这意味着在近平面的精度非常高,但在远平面的精度非常低。如果射程[-n,-f]越来越大,则会导致深度精度问题(z-fighting);远平面附近ze的微小变化不影响zn值。n和f之间的距离应尽可能短,以最小化深度缓冲精度问题。

使用FOV指定的透视投影:


h = 2 × near × tan(θ/2)
w = h × aspect;
对应上述透视投影矩阵中:
r = w/2;t = h/2
所以:
n/r = (2×n)/w
= (2×n)/(h × aspect)
= (2×n)/(2 × n × tan(θ/2) × aspect)
= cot(θ/2)/aspect
同理求得,n/t = cot(θ/2)
则得到透视投影矩阵为:

版权声明
本文为[itzyjr]所创,转载请带上原文链接,感谢
https://blog.csdn.net/itzyjr/article/details/124337143