
第3章 透视投影
透视投影是投影几何里面的概念,是一种将三维物体投影在二维平面的方法。
整个图形系统3D的概念,以及从3D到2D的投影,都是基于透视投影和正交投影的(光线追踪除外)。从开发者的角度看,用户最终获得的图像,和创建3D场景时输入的顶点坐标、模型视图变换矩阵、投影矩阵紧密相关。所以理解投影背后的设计原理,有助于开发者理解给定输入顶点坐标和投影矩阵,将会获得怎样的输出。理解输入和输出,对3D应用的开发者而言,是非常必要的。另外,如果要进行GPU设计,或者软件模拟GPU的行为,也需要深入理解投影背后的设计。本章介绍3D编程中最常用的透视投影,后续章节会介绍正交投影。
虽然本章都是公式推导,但是数学难度并不高。对读者数学上的要求有两点:①高中的立体几何知识;②矩阵运算的基本知识(甚至都不需要了解矩阵的逆)。本章使用的矩阵运算,一定程度上可以映射到高中的多元一次函数方程组的求解问题。从这个角度看,理解本章的内容,有高中的数学基础就可以了。
前面提到,3D流水线抽象出了多种坐标空间。透视投影实现的是从眼睛坐标到NDC坐标的变换,而眼睛坐标依赖于输入的物体坐标、模型视图矩阵等。所以要分析透视投影,还要考虑模型视图等的影响。模型视图矩阵让问题的分析变得复杂,测试起来也很不方便。针对本章分析透视投影矩阵,一种简化方法是,将模型视图变换设置为单位矩阵,这样的话,物体坐标、世界坐标、眼睛坐标就重合了。但是透视投影的几何模型不受这个简化的影响。
本章讨论的透视投影模型,就是在没有模型变换和视图变换的前提下,如何将眼睛坐标系的点,变换到归一化的NDC坐标系。没有模型变换,物体坐标系就是世界坐标系,这一点比较直接。没有视图变换的意思是,使用系统默认的视图变换。视图代表了用户的眼睛(或摄像头)观察3D场景的位置和方向。在GL或者Vulkan里面,眼睛默认在世界坐标系的原点。但是GL/Vulkan都可以通过观察函数(一般都叫lookAt)来修改眼睛的位置和观察方向。使用默认的眼睛位置和观察方向(有些应用程序,例如Chromium的合成器,Android的SurfaceFlinger都没有额外设置观察函数),带来的一个好处是,视图变换就是没有位移旋转的变换,也就是单位矩阵。因而视图变换后形成的眼睛坐标系和世界坐标重合了。
这个从眼睛坐标系变换到NDC坐标系的变换,需要具有将3D内容以合适的方式呈现在2D平面上的能力。所谓合适的方式,是指:
(1)保持立体感,立体感的本质就是远的物体显得较小,近的物体显得较大。
(2)和人眼距离一样的物体,投影后物体间的相对位置不变。
透视投影,就正好满足了这两个条件。
那么,如何求解得到这个透视投影的变换矩阵?
求解一个矩阵,要先理解这个矩阵的输入和输出是什么。透视投影的输入是眼睛坐标(如前述,因为眼睛坐标和物体坐标重合,所以也就是物体坐标)。输出呢?有两种比较直接的选择,一种是输出窗口(本书讨论窗口和视口重合的情况)坐标,这样的坐标是非归一化的。这个选择的缺点是,投影矩阵和窗口系统耦合到了一起。也就是窗口变换了(放大、缩小甚至移动),投影矩阵要重新计算。如果选择输出归一化的坐标呢?那就需要一次额外的窗口变换来将归一化的坐标映射到窗口坐标。GL和Vulkan都选择了归一化的窗口坐标方式。这个归一化的窗口坐标系叫作NDC坐标系(normalized device coordinates)。
现在问题变成了:给出眼睛坐标,如何求解出相应的NDC坐标?这里的眼睛坐标位于眼睛坐标系(等同于物体坐标系,世界坐标系),NDC坐标位于NDC坐标系(归一化的坐标系)。
但是通过分析发现,透视投影,也就是从眼睛坐标系到NDC坐标系的变换,不是一次矩阵运算就能解决的(所谓一次矩阵运算,里面涉及的矩阵可以是多个矩阵的乘积),其中有一个过程甚至引入了非线性部分。这个非线性部分,让整个透视投影变得没那么直观,让3D流水线变得更加复杂。
另外,公开的文献在分析透视投影的时候,或者直接给出结论,或者将几何模型和数学算法上的优化混合到了一起,这也让透视投影变得难以理解。
针对透视投影理解上的难点,本章将透视投影的几何模型和数学算法上的优化分开,因而得到了两个模型:透视投影的几何模型、透视投影的透视除法模型。前一个几何模型完全使用初等几何知识推导,重在理解物体和空间的几何关系,因此比较直观。后一个透视除法模型则侧重于数学算法优化。这两个模型降低了学习曲线,能够帮助读者理解透视投影的本质。
本章内容安排如下。
(1)左右手坐标系。介绍左右手坐标系的区别。
(2)3D坐标和坐标系。介绍了3D坐标的特点及所在的坐标系、坐标系之间的变换。
(3)3D流水线的基本概念。
(4)小孔成像。介绍了小孔成像的原理,并根据小孔成像推导出透视投影的模型。
(5)透视投影的几何模型。
(6)透视投影的透视除法模型。
本章要讨论非常多的坐标,对这些坐标约定如下。
物体坐标:xo,yo,zo。齐次坐标形式:xo,yo,zo,1。
世界坐标:xworld,yworld,zworld。齐次坐标形式:xworld,yworld,zworld,1。
眼睛坐标:xe,ye,ze。齐次坐标形式:xe,ye,ze,1。
裁剪坐标:xc,yc,zc。齐次坐标形式:xc,yc,zc,wc。
归一化的NDC坐标:xn,yn,zn。齐次坐标形式:xn,yn,zn,1。
窗口(视口)坐标:xw,yw。