前几日看了B站的games101课程,突然就对图形学产生了一丝浓厚的兴趣,在认真听完闫老师对透视矩阵的讲解之后,我只觉得手痒难耐,跟着LearnOpengl的课程,并且准备不使用glm内置的投影矩阵函数,而是自己实现一个。但就是这个地方产生了许多困扰我困惑,直到今天才彻底理清投影矩阵的推导全过程。
这是games101中闫老师最终给出投影 矩阵公式
如果你直接将这个矩阵应用在opengl上,那么恭喜你,你会收获到void,什么都么有。
那么是这个矩阵错了吗?NO!这个矩阵没有一点问题,它非常的正确,并且相较于《3D游戏与计算机图形学中的数学方法》一书中关于透视矩阵的纯代数的推导方式,我更喜欢闫老师的图形结合的推导方式,这也是本文的主要推导方式。
Ok,让我们正式开始推导吧!
1.首先,我们先确定坐标系,坐标系分为左手坐标系和右手坐标系(在某些书上这被称为偏手性),
如果确定一个坐标系是左手还是右手呢?
只需要将你右手的拇指对准y轴,中指对准x轴,如果z轴刚好在食指指向的方向,那么这个坐标系是右手坐标系,如果z轴刚好和食指指向的方向相反,那么这个坐标系就是左手坐标系。
现在,我们选择右手坐标系为我们的变换前的坐标系
2.现在,让我们来确定第二个重要的概念,观察方向!
什么是观察方向,想象你是一个在固定在Z轴上的摄像机,你面向的方向就是你的观察方向。
观察方向有两个,一个是Z轴方向,一个是负Z轴方向。
我们现在选择看向负Z轴方向。
不要认为这两个属性不重要,四种组合方式,一旦你选择了一种错误的组合方式,那么你就只能在你的opengl窗口中收获虚无
现在想象我们从天上鸟瞰整个场景
原点为摄像机所在位置(视图变化导致的),黑线框住的区域为摄像机的可使范围,粉线表示的是近平面,天蓝线表示的是远平面,里面的物体为摄像机的可视物体。
现在,假设摄像机可视范围内有一点P,连接P点与原点,与近平面相交得到交点P`。
这里定义一下n和f,闫老师课内对n和f的定义为近平面与远平面的Z值,所以n,f∈[-∞,+∞],但在本文中,n与f定义为摄像机到近远平面的距离,所以n,f∈[0,+∞]。
所以因为摄像机看向的是负Z方向,所以近平面: ,远平面: 。
所以,线段OP与近平面交点 。
首先由相似三角形,我们可以得到等式: ,恒等变换后: ,同理可得:
P`以向量形式表示为: ,转换到齐次坐标:,等价变换为:
我们将P→P`的过程想象为变换,那么一定存在一个矩阵A,使得AP=P`,不妨列出等式:
,由矩阵乘法的性质,我们可以很容易得到第一行第二行和第四行。
A=。
那么第三行怎么求呢?games101中闫老师对此给出了两个重要定义,即近平面上任意点通过矩阵A变换之后,坐标不变。以及远平面的中心点在经过矩阵A的变换之后,坐标保持不变。
那么我们以此可以列出两个等式:
=
=
因为近平面上任意点经过矩阵A变换后都保持不变,如果a1,a2≠0,那么变换后P`的Z值除近平面中心点外其他所有点都会发生改变,这与我们的初始定义不符,所以a1,a2=0。
由此可得:
解出方程:,
解出矩阵A=
此时,若将视角内所有点乘上矩阵A,则会出现这样的情况:
视锥内的一个正方体会被改变形状,其靠近近平面的面更大,靠近远平面的面更小。近平面大小不变,且远平面缩小到和近平面大小一致。
这个时候若将近平面远平面围成的区域看作一个正方体,那么我们可以开始第二步的正交变换了。
首先我们需要将这个由近平面和远平面构成的立方体中心移动到原地。
平移矩阵很简单,但在此之前,我们需要定义一些属性:r=近平面右边x值,l=近平面的左边x值,t=近平面的上边y值,b=近平面的下边y值。
平移矩阵T=
注意矩阵第三行第四个为非负值,因为近平面和远平面构成的立方体本身就处于Z的负轴上,如果,那么矩阵T不可能把立方体中心平移至原点。
然后我们需要一个缩放矩阵,假设为立方体中的一个点,那么,我们需要将都缩放至这个区间。
缩放矩阵S=
好了,通过ATS三个矩阵的连续变换,我们能得到一个在右手坐标系下,n,f表示近远平面到摄像机距离的正确的投影矩阵。
但是,通过查证一些资料,我得知了opengl的NDC,标准设备坐标系其实是左手系,也就是近平面与远平面需要对调一下,但这也不难理解,只需要将向量的z值变成它的相反数就好了,所以最终的投影矩阵:
由此可以得出结论,不同的坐标系下,采用不同的观察方向,以及n与f的定义都会影响到最终的投影矩阵。