opoengl 投影矩阵的推导

原文:http://blog.csdn.net/wangdingqiaoit/article/details/39010077



OpenGL学习脚印: 投影矩阵的推导

写在前面

               本节内容翻译和整理自http://www.songho.ca songho的博客《OpenGL Projection Matrix》内容,以供自己和初学者熟悉投影矩阵推导过程。

通过本节,你可以了解到:

  •  投影矩阵计算的阶段
  •  透视投影和正交投影的矩阵推导
本节的要点就在于:   阅读时,自己拿笔推导一遍。

1.概览

计算机屏幕是2维的,OpenGL渲染的3D场景必须以2D形式的图像投影到屏幕上。GL_PROJECTION 矩阵就是用来设置投影变换的。首先,它将所有顶点从眼坐标(照相机坐标)转换到裁剪坐标系下。然后,这些裁剪坐标通过透视除法,即除以裁剪坐标中w分量,转换到归一化设备坐标系(NDC)

                                                                                                                               
                                                                                                      一个由视锥裁剪的三角形

因此,我们要记住,裁剪(视锥剔除frustum culling)NDC转换都集成到了GL_PROJECTION 矩阵。接下来的部分描述了怎么样通过left, right, bottom, top, near and far 这6个界限参数来构造投影矩阵。

注意:

   视锥剔除是在裁剪坐标系中进行的,并且恰好在透视除法之前进行。裁剪坐标xc, yc 和 zc 通过与wc比较来进行测试。 如果某个坐标值比Wc小或者比Wc大,那么这个顶点将被丢弃。然后,OpenGL会重新在裁剪进行的地方构造多边形的边缘。

补充内容:

实际上,眼坐标系下坐标在乘以投影矩阵后,裁剪测试和透视除法都是由GPU来执行的。而后面这两个过程处理的裁剪坐标系数据都是由投影矩阵变换的。

1. 裁剪测试也即视锥剔除

-Wc < Xc,Yc,Zc < Wc

2. NDC透视除法

Xn = Xc / Wc  Yn = Yc / Wc   Zn = Zc / Wc

这里需要注意的是,我们在构造16个参数的投影矩阵的同时,不仅要考虑到裁剪,还要考虑到透视除法的过程。这样,最终的NDC坐标才会满足:

-1 < Xn,Yn,Zn < 1

2.透视投影

在透视投影中,在眼坐标下截头椎体(a truncated pyramid frustum)内的3D点被映射到NDC下一个立方体中;x坐标从[l,r]映射到[-1,1],y坐标从[b,t]映射到[-1,1],z坐标从[n,f]映射到[-1,1]。

注意:

     眼坐标系使用右手坐标系,而NDC使用左手坐标系。这就是说,眼坐标系下,在原点处的照相机朝着-Z轴看去,但是在NDC中它朝着+Z轴看去。因为glFrustum() 仅接受正的nearfar距离,我们在构造GL_PROJECTION 矩阵时,需要取其相反数。眼坐标系和NDC坐标系如下图所示:



OpenGL,眼坐标下3D点被投影到近裁剪面(即投影平面)。下图展示了眼坐标系下点(xe, ye, ze) 如何投影到近裁剪面上的 (xp, yp, zp) 的。(左侧是视锥的俯视图,右侧是视锥的侧视图,拿出右手构成右手坐标系,然后比划比划就出来了)


根据三角形的相似性,由俯视图可得出:

由侧视图可以得出:

补充: xp 和yp其实是一个中间值,我们要找的是(Xc, Yc, Zc)和 (Xn, Yn, Zn)之间的关系,但是可以利用:

这一关系做过渡,后面利用xp和yp,映射到NDC中xn和yn的线性关系就利用到了 xp 和yp。这一点很重要。


注意,这里 xp 和yp 都依赖于ze,他们与 -ze成反比。换句话说,他们都被 -ze相除。这个事构造GL_PROJECTION    矩阵最初的线索。在眼坐标通过乘以 GL_PROJECTION    来转换时,裁剪坐标系仍然是一个齐次坐标系。通过对裁剪坐标进行透视除法得到最终的NDC坐标。下图解释了这个过程:


因此我们可以把裁剪坐标系下的w分量设为-ze,那么GL_PROJECTION矩阵第4行变为(0, 0, -1, 0),如下图(求出了投影矩阵第4行):


下现在我们把xp和yp,映射到NDC中xn和yn,他们之间是线性关系: [l, r] ⇒ [-1, 1]和[b, t] ⇒ [-1, 1].

线性关系如下图所示:

则可以推导出:

细节部分有删节,这个推导过程使用的就是简单的y=kx+b线性关系推导,同理利用[b, t] ⇒ [-1, 1]可推得:

将上面的 xp 和yp带入求得:

注意这里Xn和Yn已经是NDC中的坐标了,通过这两个坐标可以求出GL_PROJECTION 的前两行来,书写如下(求出了投影矩阵第1,2,4行):

现在怎么求出第3行呢?

找出zn与找出xnyn不同,因为 ze总是被投影近裁剪面-n上。但是我们需要唯一的Z值进行裁剪和深度测试。另外,我们还能够unproject即反向变换(inverse transform)。因为Z值不依赖于x或者y,因此我们借用w分量来找出 zn 和 ze之间的关系。

因此我们可以这样指定第3行:

在眼坐标下We等于1,因此上式变为:

我们使用(ze, zn)的关系(-n, -1)和 (-f, 1)来求解出系数A,B;

细节部分有删节,使用消元法即可求出:

我们求出了A和B,那么ze和zn关系如下式:

最终的投影矩阵如下式:

这个公式对应的是一般的视锥,如果视锥是对称的,即r = -l ,t= -b,那么有:

z-fighting

在继续之前,我们来看看表示ze和zn关系的式3.这是一个有理函数,并且ze和zn之间不是线性关系。这意味着,在近裁剪面的精度很高,而远裁剪面则很小。如果[-n, -f]范围变得大写,就会引起深度精度问题,即z-fighting。在远裁剪面附近,ze的小变化根本不影响zn值。近裁剪面和远裁剪面之间的n和f举例,应该尽可能小,来减少深度缓存的精度问题。可参考下图来帮助理解。


3.正交投影

构造正交投影的矩阵简单很多。所有的是眼坐标下xe, ye 和ze,都被线性的映射到NDC中。我们需要做的就是讲长方体视景体缩放为规范视见体,然后移动到原点。如下图所示:

xe和xn之间映射关系为例,[l,r]=>[-1,1],则可以推导如下:

y,z也有类似推导,这里省略,最后得出投影矩阵为:

如果视锥是对称的话,即r = -l ,t= -b的话,则可以简化为:


到这里透视投影和正交投影矩阵推导完毕。



透视投影变换矩阵的推导过程如下: 假设有一个三维点 $(X,Y,Z)$,它在相机坐标系中的坐标为 $(X_c,Y_c,Z_c)$。相机坐标系的原点为相机位置,$Z_c$ 轴指向相机朝向的反方向,$X_c$ 和 $Y_c$ 轴分别与相机的右方向和下方向对齐。 为了把相机坐标系中的点映射到图像平面上,我们需要进行透视投影变换。首先,我们将相机坐标系中的点转换为齐次坐标 $(X_c,Y_c,Z_c,1)$。然后,我们将它乘以一个投影矩阵 $P$,得到一个新的齐次坐标 $(u,v,w,1)$: $$ \begin{bmatrix} u \\ v \\ w \\ 1 \\ \end{bmatrix} = P \cdot \begin{bmatrix} X_c \\ Y_c \\ Z_c \\ 1 \\ \end{bmatrix} $$ 其中,$u$ 和 $v$ 分别表示图像平面上的坐标,$w$ 用来进行透视除法,保证 $u$ 和 $v$ 的值在图像平面上。 投影矩阵 $P$ 可以分解为相机内参矩阵 $K$ 和相机外参矩阵 $[R|t]$ 的乘积: $$ P = K [R|t] $$ 其中,$K$ 是一个 $3 \times 3$ 的矩阵,包含了相机的内部参数,如焦距、主点等。$[R|t]$ 是一个 $3 \times 4$ 的矩阵,包含了相机的外部参数,如相机的旋转和平移。 为了推导 $P$ 的具体形式,我们可以先考虑一个简单的情况:相机坐标系的原点与图像平面重合,且相机的朝向与图像平面平行。这种情况下,投影矩阵可以表示为: $$ P = \begin{bmatrix} f & 0 & 0 & 0 \\ 0 & f & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} $$ 其中,$f$ 是焦距,表示相机到图像平面的距离。 当相机坐标系的原点和图像平面不重合时,我们可以使用相机外参矩阵 $[R|t]$ 来把相机坐标系的原点变换到图像平面上。具体来说,我们可以将相机坐标系的原点变换为 $(X_c',Y_c',Z_c')$,其中 $(X_c',Y_c',0)$ 是图像平面上的点。这个变换可以表示为: $$ \begin{bmatrix} X_c' \\ Y_c' \\ Z_c' \\ 1 \\ \end{bmatrix} = [R|t] \cdot \begin{bmatrix} 0 \\ 0 \\ 0 \\ 1 \\ \end{bmatrix} $$ 然后,我们可以把 $(X,Y,Z)$ 变换为 $(X',Y',Z')$,其中 $(X',Y')$ 是图像平面上的坐标。这个变换可以表示为: $$ \begin{bmatrix} X' \\ Y' \\ Z' \\ 1 \\ \end{bmatrix} = [R|t] \cdot \begin{bmatrix} X \\ Y \\ Z \\ 1 \\ \end{bmatrix} $$ 最后,我们可以将 $(X',Y',Z')$ 投影到图像平面上,得到一个新的齐次坐标 $(u,v,w,1)$。这个投影可以表示为: $$ \begin{bmatrix} u \\ v \\ w \\ 1 \\ \end{bmatrix} = K \cdot \begin{bmatrix} X'/Z' \\ Y'/Z' \\ 1 \\ \end{bmatrix} $$ 将以上三个变换组合起来,我们可以得到透视投影变换矩阵的形式: $$ P = K [R|t] = \begin{bmatrix} f_x & 0 & c_x & 0 \\ 0 & f_y & c_y & 0 \\ 0 & 0 & 1 & 0 \\ \end{bmatrix} \begin{bmatrix} r_{11} & r_{12} & r_{13} & t_1 \\ r_{21} & r_{22} & r_{23} & t_2 \\ r_{31} & r_{32} & r_{33} & t_3 \\ \end{bmatrix} $$ 其中,$f_x$ 和 $f_y$ 是 $K$ 矩阵的对角线元素,分别表示 $x$ 和 $y$ 方向上的焦距;$c_x$ 和 $c_y$ 是 $K$ 矩阵的中心点,表示图像平面上的主点;$r_{ij}$ 和 $t_i$ 是 $[R|t]$ 矩阵的元素,表示相机的旋转和平移。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值