3D数学-透视投影
好记性不如烂笔头啊,还是记录一下!
概述
投影变换完成的是如何将三维模型显示到二维视口上,这是一个三维到二维的过程。你可以将投影变换看作是调整照相机的焦距,它模拟了为照相机选择镜头的过程。投影变换是所有变换中最复杂的一个。
近大远小
近大远小是众所周知的光学现象。之所以出现这种现象,是因为离人眼近的物体在视网膜上的投影大,而离眼睛远的物体在视网膜上的投影小。如下图所示,红色箭头和蓝色箭头的高度相同,但是蓝色箭头离眼睛近,因此它在视网膜上的投影,要大于红色箭头的投影。
然而物体看上去的大小,除了与它离眼睛的远近有关,还和物体本身的尺寸有关。视角(angle of view 或者 field of view 视域)
可以取代上述两者,直接比较物体看上去的大小。在计算机图形学中,为了让三维物体显示在屏幕上有立体感,有必要模拟人眼近大远小
这一个特性,利用透视投影矩阵可以方便地完成这项任务。
视锥体
视锥体是一个三维体,他的位置和摄像机相关,视锥体的形状决定了模型如何从camera space
投影到屏幕上。透视投影使用棱锥作为视锥体,摄像机位于棱锥的椎顶。该棱锥被前后两个平面截断,形成一个棱台,叫做View Frustum
,只有位于Frustum
内部的模型才是可见的。我们也通常称这个为裁剪空间
,在这个裁剪空间中有两个平面比较特殊,我们分辨称为近裁剪平面(near clip plane)
和远裁剪平面(far clip plane)
。
投影矩阵的本质
投影矩阵有两个目的:
- 首先是为投影做准备。这是个迷惑点。虽然投影矩阵的名称包含了投影二字,但是它并没有进行真正的投影工作,而是在为投影做准备。真正得投影发生在后面得
齐次除法(homogeneous division)
过程中。经过投影矩阵的变换后,顶点的w分量会具有特殊的意义。 - 其次是对
,
,
分量进行缩放。如果用视锥体的6个裁剪平面来进行裁剪会比较麻烦,而经过投影矩阵的缩放后,久可以直接使用
分量作为一个范围值。如果
,
,
分量都位于这个范围内,就说明该顶点位于裁剪空间内,如下图所示:
投影矩阵推导
如图所示:
是相机空间中的一个坐标点
表示该坐标点在
近裁剪平面(near clip plane)
上的投影坐标
表示经过透视投影后在
规范化设备坐标系(Normalized Device Coordinates)
中的坐标
表示
近裁剪平面(near clip plane)
的左边,即
表示
近裁剪平面(near clip plane)
的右边,即
表示
近裁剪平面(near clip plane)
的上边,即
表示
近裁剪平面(near clip plane)
的下边,即
有以下关系式:
可解出得:
同理:
现在需要将映射到
,
得范围是
,
得范围是
,可以利用简单线性插值的方法获得以下关系式:
同理可得到以下方程组:
可解出得:
最后看看,当视锥体内的顶点投影到
近裁剪平面(near clip plane)
的时候,实际上的值已经没有意义了,因为所有
近裁剪平面(near clip plane)
上的点,他们的值都是
-n
,看起来我们甚至可以抛弃这个值,可以么?当然不行!不要忘记还有深度测试。
到
这条直线上的点都会投影到
这个点,那么如果直线上有多个点投影到同一个点时,如何确定最终保留哪一个呢?当然时距离观察者最近的这个了,也就是深度值(
)最小的,所以
可以直接保存为
的值。由于在光栅化的过程中,要进行
坐标的倒数的插值(参考《3D数学-透视校正插值》),因此映射函数应为
的函数,同时允许深度投影是线性插值,则可以获得以下映射函数的表达式:
在映射前,的范围是
。在映射后,
的范围是
。需要找到
,
的映射关系(
该映射应该将z坐标反向,因为齐次裁剪空间为左手坐标系
), 将数据代入上面的一次式,可得下面的方程组:
解出可得:
可以得到坐标映射到
的映射函数为:
整理可得:
可以发现以上等式中都除以,则3D点
对应的齐次坐标为:
则,
,
分别为:
以上函数组为点的线性函数组,因此可以用一个
的矩阵
来表示
点的计算公式:
就是最终的透视变换矩阵。相机空间中的顶点,如果在视锥体中,则变换后就在
规范化设备坐标系(Normalized Device Coordinates)
中。如果在视锥体外,变换后就在规范化设备坐标系(Normalized Device Coordinates)
外,而规范化设备坐标系(Normalized Device Coordinates)
本身的规则性对于多边形的裁剪很有利。
投影矩阵的另一种形式
视角(angle of view 或者 field of view 视域)
是视锥体再平面或者
平面的开角角度,也可以用来描述透视投影矩阵。具体哪个平面都可以,
OpenGL
和D3D
都使用平面,
Aspect
是投影平面的宽高比,如图所示:
![avatar][image5]
可以得到一下关系式:
所以还可以写成:
z-fighting
还有一点需要额外注意,上述变换矩阵的过程中,和
,
和
是线性的,但是
和
是非线性的:
越接近
,
越接近1,
越接近
,
越接近-1。也就是说,
越大,离相机越远,反之离相机越近。
随
的变化关系如下图所示:
通过观察左侧图,我们发现:当相机坐标系中的点越接近近裁剪平面(near clip plane)
时,上发生的微小变化都会导致
的剧烈变化;而当点越接近
远裁剪平面(far clip plane)
时,对
上发生的变化不敏感。在做渲染时,
方向的绝对深度并没有意义,我们只需要知道各点的相对深度,确定遮挡关系,保证靠近相机的点挡住它后面离相机远的点即可。因此,越接近
近裁剪平面(near clip plane)
的点,它的深度渲染就越准确,而越接近远裁剪平面(far clip plane)
的点,它的深度渲染就越不准确。
此外,对比上面的左右两幅图,我们发现:当远裁剪平面(far clip plane)
和近裁剪平面(near clip plane)
距离较大时,接近远裁剪平面(far clip plane)
的点的对
的变化十分不敏感,这样导致的问题称为
z-fighting
。因此,在条件允许的情况下,应该尽量减小两个裁剪平面
之间的距离。
附一张方向的映射关系图:
饮水思源
参考文献:
《3D游戏与图形学中的数学方法》
《透视投影详解》
《Perspective Projection Matrix 透视投影矩阵的推导》
《图形学扫盲--(2)透视投影(Perspective Projection)》
版权声明:原创技术文章,撰写不易,转载请注明出处!