OpenGL中frustum投影矩阵的推导

OpenGL中,有一个函数叫frustum,字面的意思是截锥体,也就是一个去掉头部的锥体,如下图所示,

看了一下《计算机图形学》(英文名Computer Graphics with OpenGL)的透视投影推导过程,比较全面,各种情况都有描述。不过最近又参考了网上的一些资料,发现这里【1】的推导过程比较单纯直接。我们看一下,

注意到上面这个图,观察者的位置相对于(0,0,0)这个点是在右边的,也就目光是沿Z轴方向(所以距离 眼睛越近,显得越大嘛),OpenGL的camera也就是(0,0,0)点,沿-Z方向。

把xe映射到xp,ye映射到yp是这样的,

    式(1)

通过Mprojection矩阵,把eye坐标投影到NDC空间(Normalized Device Coordinates, 归一化设备坐标系),

注意下上面的ndc和clip坐标系之间,只差了一个系数 wclip,他们都是3维齐次坐标【2】。下面这个方程中,c就是clip,变换矩阵的第4行设置为(0, 0, -1, 0),为什么呢?因为这一行实际上只处理系数wc,看前面我们知道xp与yp分别和(-Ze)成反比,所以这里我们也期望,wc和(-ze)成反比,且最后能归一化wc/(-ze)=1。

接下来的一步,就是完成xp,yp到xn,yn的归一化映射:[l, r] ⇒ [-1, 1] and [b, t] ⇒ [-1, 1],首先来看映射[l, r] ⇒ [-1, 1],如下图

这是一个非常简单的线性映射,写成方程式就是,

其中\beta就是xp=0时在xn轴上的截距,根据映射,当xp=r时,xn=1,代入到该式中,就可以得到,

然后变换一下格式,

现在把\beta代回最上面那个式子,就得到了,

 式(2)

同样的道理,可以得到

         式(3)

把式(2),式(3)代回到式(1),就得到这样一个结果,

这两个结果,结合我们前面得到的wc=-ze,整个矩阵就可以等价地写成下面的形式,

现在只有矩阵的第3行是未知的,我们这样处理,

因为在eye的空间,we=1(w是一个和透视距离有关的量,0表示无穷远点,参考【2】),所以,

,和上面的道理类似,映射  (ze, zn)满足范围为近点=(-n, -1),远点= (-f, 1), 

求解该线性方程组,得到,

这样,得到

 式(4)

最后得到的矩阵就可以写成

这个矩阵,也正是我们frustum函数变换所采用的矩阵。

这里也顺便提一下Z-finghting。根据式(4),Zn和Ze的关系为

因此,当[-n, -f]的距离比较大的时候,因为有理数取值都有误差,在远点就容易形成z-finghting,也就是当两个实体在远点有交接时,因为误差产生的距离抖动,无法准确得到交接线从而产生类似下图的结果,

本文结束。

参考

【1】http://www.songho.ca/opengl/gl_projectionmatrix.html

【2】https://blog.csdn.net/tanmx219/article/details/81394995

【3】https://en.wikipedia.org/wiki/Z-fighting

posted @ 2018-08-04 10:47  SpaceVision  阅读(112)  评论(0编辑  收藏  举报