这个比较基础了,不过基础最重要,往往应该理解透彻,并且反复复习。
我们知道在3D画面渲染过程中对于模型的计算的一部分被称为Transforming and Lighting(T\&L)阶段,其中Lighting表示光照,而Transforming就是指的坐标变换,这两部分的计算也是3D场景中计算最重要基础的一步。
空间坐标变换主要的工作就是将处于局部坐标系的模型转换到用户屏幕所在的屏幕坐标系内。
而这个过程的计算上主要是来自线性代数中的知识,我们知道在线性代数中,线性的变换是可以用矩阵来表示的,而通过将向量[x,y,z,w]同变换矩阵相乘即可完成相应的变换,这正是我们实现空间坐标变换的数学基础,在3D图形学中,空间坐标变换一般分为三个步骤——世界变换、视角变换、投影变换,而完成这些变换就是由矩阵运算来完成的。
世界变换
我们知道所有模型都是独立创建的,他们拥有自己独立的一个局部坐标系来描述模型内部各个面片顶点之间位置的关系,当我们将这些模型放在一起来组建游戏场景的时候,逻辑上他们就处在了同一个坐标系内来描述模型与模型之间位置与角度的关系,这个坐标系我们所说的世界坐标系,而将模型中的每一个顶点从局部坐标系转换到世界坐标系的过程,我们称之为世界变换。
世界变换是通过将模型中每一个顶点乘以世界变换矩阵来完成的,通常情况下这个世界变换矩阵是通过一系列变换矩阵的结合形成的一个包含了所有变换内容的矩阵来完成计算的,包括平移、旋转、缩放等等变换。
在3D图形学里的矩阵变换同2D图形学里一样,只是多了一维坐标,一般的变换矩阵如下图所示:
单独平移矩阵和缩放矩阵如下图所示,也比较好理解,其中Tx,Ty,Tz分别表示在各个坐标轴上平移的距离,Sx,Sy,Sz分别表示在各个坐标方向上缩放的倍数。
旋转矩阵在理解上需要一点点推导,以2维空间下围绕原点旋转为例,大家可以画一个草图来帮助推导,设点(x,y)与原点的连线同X轴的角度为b,以此方向继续旋转a度,至点(x’,y’),我们可知旋转轨迹所在圆的半径R=x/cosb,R=y/sinb。而x’=R*cos(a+b),y’=R*sin(a+b),根据合角公式拆开,再将前面的式子带入,可得x’=xcosa-ysina;y’=xsina+ycosa。
3维空间下以此相推可分别得出围绕X轴方向旋转、围绕Y轴方向旋转、围绕Z轴方向旋转的变换矩阵:
另外3维空间下围绕任意轴旋转的旋转变换矩阵是通过平移矩阵和围绕各个轴旋转的矩阵复合而得出的。
在世界坐标系里的任何一个模型的状态都可以通过若干中变换矩阵的组合来表明它的唯一状态,通过矩阵相乘来得到最终的变换矩阵,需要注意的是因为所有的变换矩阵都是相对坐标系的原点完成的,所以变换矩阵相乘时候的顺序关系很重要,相互颠倒会产生完全不同的变换矩阵。
视角变换
通过世界变换,我们将所有的模型都转换到一个统一的世界坐标系中,但是在游戏中我们的观察点不可能总是世界坐标系的原点,面向着Z轴的正方向。摄像机和模型是同样可以游离于场景中的任何地点,面向任意角度的,所以这就需要通过视角变换来实现。
一个视角变换通常是由一次平移变换和三次旋转变换来完成的,平移矩阵负责将相机从默认的世界坐标系的原点平移到正确的位置,三次旋转分别负责围绕三个坐标轴的旋转,将相机调整至正确的朝向。
说的很抽象,但实际上可以理解为将转换到世界坐标下的各个模型再转换到以摄像机为原点的摄像机坐标系下,当然在游戏中是不需要手动生成这个矩阵的,我们只需要提供相机的位置,朝向等等参数,API会帮我们生成正确的视角矩阵。
投影变换
投影变换的工作就是将摄影空间中的三维物体投影到二维的平面上,逻辑上也就是用户的屏幕区域。这种三维到二维的变换过程就是投影变换,即从取景空间到投影空间的变换。
投影变换分为两种基本的投影变换:正交投影和透视投影
正交投影中,投影向量和观察平面垂直,物体坐标沿观察坐标系的Z轴平行投影到观察平面上,观察点和观察平面间的距离不会影响物体的投影大小。工程设计中的顶视图、前视图和侧视图就是典型的正交投影,正交投影没有透视关系,可以利用正交投影来完成D3D渲染2D游戏画面。
而透视投影实现的是一个缩放、透视的投影。透视投影的特点是:距离摄像机越远的物体在投影平面上的成像越小。更像人眼所能看到的现实世界中的透视关系。
下面我们来根据透视投影的几何关系来推导一下透视投影下的投影矩阵的生成:
在游戏中,当以透视的方法从摄像机来观察场景的时候,会在场景内形成一个金字塔形状的可见区域,又因为远近两个裁剪面的存在,所以实际上可见区域是一个截体,透视投影矩阵的作用是将这个取景截体转换成一个立方体(将近摄像机端拉伸),分别将X和Y坐标映射到投影平面的正确的位置上,同时保持深度信息不变,因为截体的近端比远端小,所以靠近摄像机的对象将被放大,而远离摄像机的对象,则会相对保持原样。
到齐次裁剪空间的映射是通过一个4×4的投影矩阵实现的。在这个投影矩阵中,除了其他的变换功能外,还要保证变换后的点w坐标等于摄像机空间中的点的z坐标的负值,这样,将变换后的点的坐标分量除以w坐标后,就可以生成裁剪空间中相应的三维点。
我们设图中可视区中一点P(Px,Py,Pz),将P点同摄像机相连同投影面交于一点(x,y,z),这个点就是投影变换后P所应该在的点,远近裁剪面到摄像机的距离分别是d和Zf。根据相似三角形,我们可以知道x=d*Px/Pz;y=d*Py/Pz,设投影平面的四个边框的横纵坐标位置分别是r,l,t,b(右左上下)。为了满足取景截体到齐次空间的映射,我们还需要需要将投影后的x,y坐标映射到[-1,1]区间,而通常的,将z坐标映射到[0,1]区间,映射后的坐标为x’,y’,z’。根据两个平面内坐标同平面的线性比例关系,我们继续推导:
Z轴的线性关系相对简单,但是因为在光栅化过程中为避免透视失真而进行的乘以z倒数的插值操作(显卡的工作,为什么要这样的具体原理还理解不够透彻,以后补齐),所以这里要建立关于1/z的映射,这样就可以对投影深度值进行线性插值了:
将所得的x’,y’,z’同Px,Py,Pz所对应的关系进一步整理,就可以得到最终的正确的投影矩阵了。这个投影矩阵也是D3D中所用的投影矩阵,虽然我们通常都是提供相机的fov,朝向,位置等参数利用API生成, 但是理解原理是非常重要的,关于正交投影的投影矩阵大家也可以利用类似的步骤推导出来。
写的非常粗糙,只描述了一些关键步骤,权作笔记,画图和公式可真是耽误了我好多好多时间啊,真累人……