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

转载 2015年07月07日 21:10:14

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的话,则可以简化为:


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

相关文章推荐

OpenGL学习脚印: 投影矩阵和视口变换矩阵(math-projection and viewport matrix)

写在前面 前面几节分别介绍了模型变换,视变换,本节继续学习OpenGL坐标变换过程中的投影变换。这里主要是从数学角度推导投影矩阵。对数学不感兴趣的,可以稍微了解下,或者跳过本节内容。本文主要...

投影矩阵的推导(OpenGl)

概述 计算机显示器是一个2D平面。OpenGL渲染的3D场景必须以2D图像方式投影到计算机屏幕上。GL_PROJECTION矩阵用于该投影变换。首先,它将所有定点数据从观察坐标转换到裁减坐标。接...

OpenGL投影矩阵的推导过程

OpenGL学习脚印: 投影矩阵的推导 写在前面                本节内容翻译和整理自http://www.songho.ca ...

投影矩阵的推导(Direct3D)

本文乃译文,原文地址为:         http://www.codeguru.com/cpp/misc/misc/math/article.php/c10123__1/Deriving-Proj...

[3D基础]投影矩阵的推导

原文链接:http://www.cnblogs.com/effulgent/archive/2008/01/24/1051991.html        转眼我做游戏行业已经八个月了,游戏行业入门...

投影矩阵的推导(Deriving Projection Matrices)

投影矩阵的推导(DerivingProjection Matrices)   本文乃译文,原文地址为: http://www.codeguru.com/cpp/misc/misc/math/artic...

投影矩阵的推导(Deriving Projection Matrices)

本文乃译文,原文地址为:         http://www.codeguru.com/cpp/misc/misc/math/article.php/c10123__1/Deriving-Pr...

[译] - 投影矩阵的推导

很值得一读

通过投影矩阵推导最小二乘法

最小二乘用于参数拟合,说它是统计中最重要的公式都不为过,其线性推导如下。 对于一个公式,其中A为已知数据组成的列空间,x为待估计参数,b是x的线性组合。然而,在很多情况下,由于误差或其它原因,使得b不...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)