当前位置: 代码迷 >> 综合 >> 《Real-Time Rendering 4th Edition》读书笔记--简单粗糙翻译 第四章 变换 Transforms
  详细解决方案

《Real-Time Rendering 4th Edition》读书笔记--简单粗糙翻译 第四章 变换 Transforms

热度:83   发布时间:2024-01-26 14:50:38.0

写在前面的话:因为英语不好,所以看得慢,所以还不如索性按自己的理解简单粗糙翻译一遍,就当是自己的读书笔记了。不对之处甚多,以后理解深刻了,英语好了再回来修改。相信花在本书上的时间和精力是值得的。

———————————————————————————————

“What if angry vectors veer Round your sleeping head, and form. There’s never need to fear ,Violence of the poor world’s abstract storm.”—Robert Penn Warren

“若疯狂的矢量的运算,纠缠着你昏昏欲睡的大脑,掀起抽象世界的风暴,不要畏惧!干就完了!"   —王大伟

 

变换(Transform)是一种操作,针对的是点,向量或颜色值,以某种方式进行转换。对于计算机图形操作者而言,掌握变换极其重要。利用好这种操作,你可以对物体进行光照,对摄像机进行定位,重塑或者触发动画。你还可以把所有计算转换到同一坐标系下,可以用不同的方式把物体投影到一个平面上。

        线性变换满足向量加法和标量乘法:

        举个例子,f(x)= 5x,是将一个向量的每个元素都乘以5。为了证明这个是线性操作,4.1和4.2的两个条件都需要满足。4.2被称为是缩放变换(Scaling transform),因为它可以改变一个物体的大小(尺寸)。旋转变换(Rotation transform)也是一个线性变换,旋转变换会将一个向量绕着原点进行旋转。缩放变换和旋转变换,以及所有针对三元素向量的线性变换,都可以用一个3x3的矩阵表示。

        然而,3x3通常不够大。例如,f(x) = x + (7,3,2)不是一个线性变换,其中x是一个三元素向量,因为按照公式4.1来算,等号左边比等号右边多加了一个(7,3,2)。将一个固定的向量和另外一个向量相加的操作,称为平移。这是一个很重要的操作。通常我们会组合各种变换,例如,先缩小一个物体的一半,然后移动它到另外一个位置。如果使用3x3的矩阵形式来表达的话,不利于我们组合各种变换。

        利于一种仿射变换(Affine transform),通常用4x4的矩阵来存储,可以将线性变换和平移组装到一块。仿射变换通常是先进行线性变换,然后再进行平移变换。用齐次坐标来表示四元素向量,点和方向向量可以用同一种表达式。方向向量可以用表示,点可以用表示。所有的平移矩阵,旋转矩阵,缩放矩阵,反射矩阵和剪切矩阵都是仿射矩阵。

        本章从最基础的基本仿射变换开始。表4.1总结了大部分这些变换、符号、函数和属性。其中,正交矩阵的转置矩阵就是其逆矩阵。

表4.1 本章中讨论的大部分变换的总结

       变换可以说是操作几何图形的基本工具。大多数图形API是允许用户设置任意矩阵的,以及一些含有很多矩阵操作的库。然而,还是很值得去理解这些库和API后面的矩阵操作。知道一个API功能的使用只是个开始,了解后面矩阵操作才会使得你走的更远。例如,知道正交矩阵的逆矩阵就是它的转置矩阵,会让你的代码更简单更快速。

4.1 基本变换

        本节主要介绍一些最为基本的变换,例如平移,旋转,缩放, 切变(Shearing)刚体变换( rigid-body transform)法线变换(normal transform),求逆计算等。我们从最简单的平移变换开始。
 

4.1.1 平移

        平移矩阵T作用于将一个物体从一个位置移动到另外一个位置。这个矩阵根据向量 平移一个物体。 T表示如公式4.3.
 下图4.1是一个平移矩阵的实例。可以看到,将点 相乘,会生成一个新点 ,这就是平移。注意向量 和T相乘是没有用的,因为方向向量是不会被平移的。但是,点和方向向量都会受到仿射变换其他部分的影响。平移矩阵的逆矩阵
 
图4.1 左图中的方块通过平移矩阵T(5,2,0)变换后,x轴方向平移了5个单位,y轴方向平移了2个单位。
 
        需要注意的一点,计算机图形行业经常会看到矩阵的平移向量保存在最下面一行。比如DirectX就这么使用。因为这些向量和矩阵都是以行优先存储的,在本书中,我们以列优先存储。这些都是单纯表现形式不同而已, 矩阵在内存中,16个数字中的最后4个都是3个平移数值再加上一个1。
 

4.1.2 旋转

        旋转变换是指用一个指定的角度绕着一个穿过原点的轴来旋转一个向量(位置或方向)。和平移变换一样,是属于刚体变换,它保存了点间距离,不会导致左右两边交换。这两种变换在计算机图形领域的定位物体和定向物体上非常有用。 方向矩阵( orientation matrix )是作用于摄像机视口或作用于物体的旋转矩阵,用来定义它们在空间的方向,例如,朝上或朝前。
 
        在2D中我们很容易计算出旋转矩阵,假设我们有一个向量,V = (Vx,Vy),我们可以写V = (Vx,Vy) = (rcosθ,rsinθ)。如果逆时针旋转这个向量 φ 度,可以得到u = (r cos(θ + φ), r sin(θ + φ))。如下:

        在3D领域中,通常用Rx(φ), Ry(φ), and Rz(φ)来表示旋转矩阵,分别表示沿着x,y,z轴进行旋转。如下公式4.5-4.7:

如果将上述4x4矩阵的最下行和最右lie删掉,变成一个3x3的矩阵, 可见这个3x3矩阵的对角线之和和旋转轴无关,是一个常数,

旋转矩阵的效果见于图4.4。旋转矩阵有两个特征,一是它绕着i轴(x,y,z)旋转,二是i轴上所有点保持不变。注意,旋转矩阵也可以用来表示绕任意轴的旋转矩阵,可以利用上面三个旋转矩阵组合得到绕任意轴的旋转矩阵,这些将在4.2.1和4.2.4中进一步讲到。

        所有的旋转矩阵的行列式都为1,并且是正交矩阵。这就使得任意数量的旋转变换都可以级联在一起。可以通过来表示旋转矩阵的逆矩阵,绕着同一个轴进行反方向旋转。

        例子:绕点旋转。假设围绕z轴旋转,旋转的中心点为P,如图4.2所示。因为围绕P旋转,所以P不动。变换第一步是平移物体,利用平移矩阵T(-p)将p平移到原点处,然后旋转物体,利用旋转矩阵进行旋转操作,最后利用平移矩阵T(P)将物体移回到原始位置。最终结果为

注意上式的矩阵顺序。
 
图4.2 围着P点进行旋转。
 

4.1.3 缩放

        缩放矩阵将一个物体以Sx,Sy,Sz的比例分别对x轴,y轴,z轴进行缩放。这意味着缩放矩阵可以放大或缩小物体。缩放因为Si,,越大,对应轴向的缩放比例越大。如果缩放因子为1,那么该方向不会进行缩放。4.10为缩放矩阵:

图4.4 展示了缩放矩阵的作用。如果Sx=Sy=Sz,称为统一变换(uniform),否则称为非统一变换(nonuniform)。有时候也称为各向同性(isotropic)和各向异性(anisotropic)。逆矩阵

        当使用齐次坐标系时,还有一种方式表示统一缩放矩阵,就是利用矩阵位于(3,3)(右下角)的值。这个值会影响齐次坐标系中W值,进而通过W值影响到点的每个轴向的变换,对统一缩放矩阵的方向无效。如下两种方式表示:

        和S矩阵相比,S'必须是齐次操作。这可能会比较低效,因为齐次操作中引入了除法,如果右下角的值为1,则不需要进行除法。当然,有些系统是不会去判断是否值为1,因为这样可减少额外的消耗。

        如果S中一个元素或者三个元素为负数时,则称为反射矩阵(reflection),或者称为镜像矩阵(mirror)。如果只有两个元素值为-1,则会物体被旋转π。注意,一个旋转矩阵乘以一个反射矩阵,结果仍然是一个反射矩阵。例如:

        反射矩阵通常需要进行特殊处理。例如,反射矩阵处理一个逆时针三角形后,会变成一个顺时针三角形。这个顺序的变化可能会导致错误的光照和隐面消除。为了检测出是否为一个反射矩阵,可以先算出左上3x3的行列式。如果行列式为负,则该矩阵是反射矩阵。如4.12所示,0·0 -(-1)·(-1) = -1。

        例子:沿着一个特定方向进行缩放。标准缩放矩阵只针对x,y,z轴进行了缩放,如果需要做一个 特定方向上的缩放,需要进行复合变换。假设需要沿着正交坐标系进行缩放,则第一步是先构建出F矩阵,如下

        有了F矩阵,则变换就是先把标准坐标系下的坐标转换到新坐标系下,然后进行缩放变换,最后把坐标转移回来。公式如下

4.1.4 切变

        有一种变换叫切变变换,例如,在游戏中利用切变变换可以扭曲整个游戏场景以制造一种迷幻效果,或者扭曲物体的外观。有6个基本切变矩阵,分别为

。第一个下标表示的是切变矩阵改变的坐标,第二个下标表示的是切变变换使用的坐标。如公式4.15所示,表示的是切变矩阵,很明显可以从下标中找到参数s,x表示的是第0行,z表示的是第2列,则S位于第0行和第二列的交叉处。

        将和点P相乘得到新点P'。图4.3展示了一个方块切变变换后的效果。(i 不等于j)的逆矩阵为其反方向的切变矩阵,

 

图4.3 单位方可的切变效果。y轴和z轴没有变化,x轴的值变成了原值加上s乘以z值(x = x + s * z),正方形发生了倾斜。这种变换不会改变面积,图中虚线面积是一样的。
 
        如公式4.16所示,有两个下标表示表示被第三个坐标切变。两种切变有关系: ,其中用作第三个坐标的索引。需要注意的是切变矩阵的行列式始终等于1,它不会改变体积,正如图4.3所示。
 

4.1.5 变换结合

        由于矩阵乘法中的不可交换性,矩阵的顺序很重要,在变换串联的时候也是基于顺序的。

        假设有两个矩阵,S(2,0.5,1)和Rz(π/6)。S表示将x坐标乘以2,y坐标乘以0.5,z坐标不变,R表示沿着z轴(右手坐标系中,垂直平面指向外面的轴)逆时针旋转 π/6。如图4.4所示,两种顺序进行串联得到的结果不同。

图4.4 矩阵相乘顺序不同的例子。上面表示的是,先进行旋转然后再缩放。下面表示的是,先进行缩放,然后再进行旋转。可见结果不同,有矩阵的不可交换性

        串联矩阵的作用在于提高效率,举个例子,一个游戏场景中有几百万个顶点,在场景中的全部物体都需要进行缩放,旋转,然后平移。如果将每个顶点分别和这三个变换矩阵进行变换,不如将三个变换矩阵串联成一个矩阵,然后用来和顶点做变换处理。则串联后的矩阵为。注意,这里的顺序。首先进行的是缩放变换,所以S出现在最右侧。所以有,其中P表示的是需要变换的顶点。基本上TRS是图形系统中最为常见的顺序。

        值得注意的是,因为矩阵是顺序串联在一起的,所以可以对其进行分组计算。例如在进行刚体运算的时候,可以将TR进行结合,所以有TRSp=(TR)(Sp)。可见矩阵串联满足结合定律。

4.1.6 刚体变换

        当一个人抓住一个实物,例如桌子上的一支笔,从一个地方移动到另外一个地方,例如衬衫的口袋里,只有实物的方向和位置发生了变化,实物的形状没有任何变化。这样的变换,只是结合了旋转和平移,被称为刚体变换。它的特性是保持了物体本身的长度、角度和对称性。

        用T(t)表示平移矩阵,R表示旋转矩阵,X表示刚体矩阵,那么有

        X的逆矩阵有。也就是说计算X的逆矩阵,只需要转置R左上的3x3矩阵,平移矩阵T改变符号,然后将两个新矩阵按与原相乘的相反顺序相乘。还有一种计算X的逆矩阵,首先用下面的公式4.18表达X。

其中表示旋转矩阵的第一列,表示旋转矩阵的第一行。注意表示的是一个3x1的列向量,每个元素值都为0。所以X的逆可以表达为

        例子:摄像机的方向。图形学中一个常见的操作是旋转摄像机的朝向,使之对准一个方向。这里使用函数gluLookupAt()(来自OpenGL Utility库,简称 GLU)。尽管这个函数如今不怎么使用了,但是这个需求还是很常见。假设摄像机位于c,需要摄像机对准I,并给定了世界空间向上的向量u',如图4.5所示。需要计算一个基坐标系{r,u,v}。首先计算出视觉方向,从摄像机指向目标对象的归一化向量。摄像机朝向所对应的朝右方向有。u'通常不能表示摄像机朝上向量,最终的向上向量还是通过计算,v和r叉积得到,由于v和r都已归一化,则u也是归一化的,并相互垂直。接下来构造摄像机的变换矩阵M,首先将摄像机的位置归零,然后改变基坐标系,将r对应为(1,0,0),u对应为(0,1,0),v对应为(0,0,1)。

图4.5 已经摄像机位于点c,目标位于点I,世界空间向上向量为u',求摄像机指向i的变换矩阵。
        
        注意,4.20中需要将平移矩阵T放在最右侧,因为先进行平移。
 

4.1.7 法线变换

        矩阵可用于点、线、三角形及其他几何体的变换,同样矩阵也可以用于三角形的切线的变换。但是又一点需要记住,矩阵不能用来变换表面(或顶点)的法线。图4.6展示了如果用矩阵变换法线的后果。

图4.6 左图是原始几何图形,一个三角形及其法线,中间图表示的是原始三角形沿着x轴缩放0.5倍,法线经过相同变换后的结果,右图表示的是正确的法线结果。 
 
        计算法线变换,不使用三角形等使用的变换矩阵,取而代之的是其逆转置矩阵由于法线在经过变换后长度不一定为1,需要进行归一化处理。这种方法正常是有效的,但是有时候是不需要取逆的。逆矩阵是用伴随矩阵除以原始矩阵的行列式得到的,有时候行列式为0,即不存在逆矩阵。
 
        计算一个4x4矩阵的伴随矩阵是昂贵的,且通常是不需要的,因为平移是不会影响到法线,此外,大部分模型变换都是仿射的,并没有改变齐次坐标系下的w值,不会进行投影变换。在这些情况下,法线变换的计算通常是是计算矩阵左上的3x3伴随矩阵。
 
         甚至有时候左上角的伴随矩阵也不需要计算,变换矩阵由平移矩阵、旋转矩阵和统一缩放矩阵(无拉伸或挤压的)。平移是不会影响法线的。统一缩放矩阵只影响法线的长度,剩下的只有旋转矩阵。转置矩阵是正交矩阵,其转置矩阵就是其逆矩阵,所以逆转置矩阵就是其本身。这种情况下,法线转换可直接用原始矩阵。
 
        有时候归一化操作是不需要的。只有在平移和旋转在一起操作时,法线长度经过变换后会改变。如果使用了统一缩放,则直接用统一缩放因子处理就好。例如,一个物体被放大5.2倍,那么直接只需要把变换后的法线除以5.2即可归一化,或者将变换矩阵的左上的3x3矩阵除以5.2,即生成了一个已归一化的法线矩阵。  
        注意, 法线变换并不是作用于对三角形的面法线,面法线经过三角形的三条边叉乘得到,始终垂直于表面。切向量也不同于法向量,切向量是直接通过原始矩阵计算得到的。
 

4.1.8 求逆运算

        在许多情况下,例如,在坐标系切换的时候,根据变换的有用信息,可使用下面三个方式求矩阵的逆矩阵:
 
        · 如果矩阵是单个变换矩阵或一系列简单变换矩阵的组合,那么可以简单通过颠倒这些矩阵的顺序并依次求其逆矩阵的方式得到,例如,如果 , 那么 = 。这样简单且能保留变换的精度,这对渲染大世界的时候很有用。
        · 如果已知矩阵是正交矩阵,则有 ,也就是说其转置矩阵就是其逆矩阵。任何旋转矩阵的组合在一起还是旋转矩阵,也就是正交矩阵。
 
        · 如果已知变换没什么有用信息,那么只能通过伴随矩阵、  Cramer法则,LU分解或者高斯消元来计算逆矩阵。通常使用的是克莱默法则和伴随矩阵,因为他们的分支比较少,通常需要尽量避免if分支。
        在优化的时候通常要考虑到求逆计算。 如果需要对变换矩阵求逆,通常只需要计算矩阵左上的3x3矩阵
 

4.2 特殊的矩阵变换和操作

        本节将会介绍对实时图形渲染极其重要的几种矩阵变换。首先是欧拉变换(Euler transform ),含参数提取,一种很直观地描述方向的方式。然后是从一个矩阵中提取出一组基本变换。最后是找到一个绕任意轴旋转的方法。
 

4.2.1 欧拉变换

       欧拉变换是一种很直观的方式去构建物体的具体朝向。它的名字来自伟大的瑞典数学家莱昂哈德·欧拉(Leonhard Euler)。

        首先需要建立一些默认的视图方向。最为常见的是沿着负z轴,并头部沿着y轴向上,如图4.7所示。欧拉变换由三个旋转矩阵相乘得到,图4.7给出了这三个矩阵的名称。用公式E表示如下:

        上述矩阵的表达式有24种。这里给出的是最为常用的。因为E是一组旋转矩阵的串联,所以E是正交的,因此它的逆矩阵可以表示为,当然也可以直接使用E的转置矩阵。

图4.7 展示了欧拉变换及如何改变head,pitch和roll。默认的视图方向是,沿着负z轴向前,沿着y轴向上。

        欧拉角用h,p,r分别表示旋转顺序及它们各自沿着自己轴线的旋转角度。有时候这些角度都被称为rolls,例如head是y-roll,pitch是x-roll。而head有时候被称为yaw,例如在飞行模拟中。

        这种变换是很直观,因为很容易被外行理解。例如,改变head角度和观察者摇头很像,而改变pitch角度就像是点头,改变roll角度就像倾斜头部。所以我们不用x,y,z轴,改而用head,pitch和roll来表示。注意,欧拉变换可以确定任何物体的方向。不仅可以使用世界空间中的全局轴,也可以使用局部坐标系中的轴。

        注意一些欧拉角认为z轴是初始向上方向,这只是表达符号上的不同,尽管很容易混淆。在计算机图形学中存在一种分歧:z轴向上或y轴向上。大部分制造领域中,例如3D打印,认为z轴在世界空间中是向上的,而在航空、海洋领域认为-z表示向上。建筑学和地理信息系统(GIS)则认为z轴向上,因为建筑平面图和地图是2D,x轴和y轴。媒体相关的建模系统中认为y轴是世界坐标中向上的方向,这和我们在计算机图形学中一直认为的摄像机的向上方向是y轴的这一说法相吻合。这两种说法的区别仅在于旋转90度(或者反射90度),但是如果不知道容易出问题。在本书中,除非特别说明,使用的是y轴向上。

        需要指出的是摄像机的观察空间的向上方向和世界空间的向上方向不同。摄像机Roll的时候,观察视角会发生倾斜,这个时候它在世界空间的向上方向和世界空间定义的向上方向不同。再举个例子,世界空间是y轴向上的,然后用摄像机朝下去拍摄俯视图,这需要摄像机pitch旋转90度,所以这时候摄像机在世界空间中的向上方向为(0,0,-1)。这个方向上摄像机没有y分量,取而代之-z成为了向上方向。但是在观察空间,根据定义,y轴向上仍然是正确的。

        虽然在一些小角度上的改变或在观察方向上,欧拉角很有用,但是欧拉角有着严重的限制。很难组合使用两组欧拉角。例如,两组欧拉角间的插值并不是简单对每个角度进行插值。实际上,两组不同欧垃角有可能指向的同一个方向,所以插值根本就没有旋转物体。这也是引出欧拉角的取代方案(例如四元数)的原因。欧拉角会引起一种现象叫万向节死锁,下一节4.2.2将会讲到。

4.2.2 从欧拉角中提取参数

        有时候,从一个正交矩阵中提取出欧拉参数(h,p,r)会非常有用。步骤如下:

        这里用3x3矩阵替代了4x4矩阵,因为3x3矩阵拥有旋转矩阵所有必要的信息。而4x4矩阵剩下部分除了右下角为1,其他部分全为0。

        公式4.22可表示为:

可以看到,pitch可以通过得到。将除以可以得到roll,除以可以得到head。

因此,欧拉角h(head)、p(pitch)、r(roll)可以通过矩阵E用函数得到:

        然而,有一个特殊的情况需要考虑到。如果,那么会出现万向节死锁,roll和head会绕着同一个轴旋转(尽管可能方向不同,这取决于p的旋转角度是还是。(万向节死锁,如果约定旋转的顺序是先y(head or yaw),然后x(pitch),最后z(roll),那么在y旋转后,将x旋转90度,会出现z和y在一条线上)。假设h = 0,则有

因为p不会影响到第一列,如果,则可以用,得到

        注意arcsin的定义,p的取值区间为,这意味着,如果p的取值在这外,则无法提取参数。h,p,r这三个参数并不是唯一,也就是说多组欧拉角可以得到同一结果。虽然上述方法会导致数据的不稳定,但这可减少性能消耗。

        从公式4.26也可以看出万向节死锁,如果,例如的时候,其中k是一个整数。在p这样的取值情况下,会丢失一个轴向自由度,因为矩阵仅依靠一个角度,或者

        尽管规定了欧拉角在模型系统中的顺序为x/y/z,但是还是可以按照其他顺序的。例如,在动画中通常用z/x/y这个顺序。没有完美的顺序可以避免万向节死锁,但是欧拉角还是最为常用的,例如动画师们经常在曲线编辑器中指定角度随着时间变化。

        例子:变换的一个限制。假设你有一个虚拟扳手,正在拧螺帽,为了把螺丝拧紧,需要绕着x轴旋转扳手。你的输入设备(例如鼠标,虚拟手套等)会在这时候给出一个旋转矩阵。这个旋转有可能是错误的,因为仅需要绕x轴旋转。为了限制这个输入变换,只需要简单的提取出欧拉角h,p,r。然后创建一个新的矩阵。这样绕x轴旋转就变得很简单了。

4.2.3 矩阵分解

        到目前为止,都是建立在假设已知所用变换矩阵,实际上往往并非如此。例如 ,只知道串联而成的变换矩阵,但并不知道各具体变换。从串联矩阵上分解出多个变换,称为矩阵分解。

        分解矩阵的原因有很多:

        · 提取出物体的缩放因子。

        · 找出一些特定系统的变换。(例如一些系统不允许使用任意的4x4矩阵)。

        · 确定模型是否只进行了刚体变换。

        · 插值动画的关键帧。

        · 从旋转矩阵中去掉切变。

        已经提出了两种分解,一种是刚体变换中提取出平移矩阵和旋转矩阵,另外一种是从正交矩阵中提取出欧拉角。

        可见,分解矩阵很简单,只需要拿到4x4矩阵最后一列的元素即可。还可以通过判断行列式是否为负来检测是否发生了反射。而分解除旋转、缩放、切变稍微要复杂点。

4.2.4 绕任意轴旋转

        假设现在需要物体绕一个任意轴旋转。旋转轴为r,已归一化,旋转角度为

        首先需要一个旋转矩阵M把物体转换到一个新的空间,在这个空间,转轴r变成了x轴。然后进行最终的旋转。最后利用逆矩阵变换回原来空间。这个过程如图4.8所示。

图4.8 绕任意轴r旋转。首先利用变换矩阵M找到正交基r,s,t。然后将这个正交基和标准基对齐,也就是r轴和x轴对齐,再进行旋转。最后利用M的逆矩阵转换回原本空间。

        为了计算出M,需要找出和r垂直并相互垂直的另外两个轴。只需要找出第二个轴s,第三个轴t就只需通过r和s叉乘得到了,。有一种比较稳妥的方法是找出r的最小分量(绝对值),然后将其设为0 。然后将剩余两个分量的其中一个取反。数学表达式如下:

这样保证了是垂直的,(r,s,t)就是正交基。然后利用这三个向量构建出一个旋转矩阵。   

这个矩阵将向量r对齐到了x轴,s对齐到了y轴,t对齐到了z轴。那么,绕r旋转度就变成在新坐标系中对x轴旋转。

Goldman提出了另外一种绕任意归一化轴r旋转角度的方法。其中的变换公式如下:

 

4.3 四元数

        尽管四元数( quaternions)在1843年就被Sir William Rowan Hamilton作为复数的扩展而发明出来,但直到1985年Shoemake才将其引入到计算机图形学中。四元数可以用来表示旋转和方向。它在很多方面是优于欧拉角和矩阵的。任何三维方向都可以表示为一个绕着特定轴旋转的单旋转。一旦有了这个特定轴和旋转角,那么转换成四元数或四元数转换成其他都变得很简单,而这对欧拉角无论哪种选择都是一个挑战。 四元数可以用于稳定和常数的方向插值,而这是欧拉角做不到的。

        复数分实部和虚部。每个部分都由两个实数表示,第二实数需要乘以。同样的,四元数有四个部分,前三个值和旋转轴紧密相关,旋转角度则对四个部分都有影响。 每个四元数由四个实数表示,每个实数对应一个不同的部分。由于四元数有四个分量,我们可以用向量的形式表示它,但是为了区分,我们加了一个帽子:

4.3.1 数学背景

        下面先聊下四元数的定义。

        定义。四元数可以用下列方式定义,都是等价的。

变量被称为四元数的实部,而称为虚部,i,j,k称为虚部单元。

        对于虚部,我可以使用所有正常的向量运算,像加,缩放,点乘,叉乘等等。两个四元数相乘,如下所示。需要注意,虚部单元的相乘是非交换的。

从上面的等式可以看出,用到了点乘和叉乘。

        根据四元数的定义,还可以给出四元数的加法(addition)、共轭复数(conjugate),范数(norm)和恒等式(identity)

        对范数,虚部被消除,只剩下实部。范数有时候也用表示。通过上面的这些公式可以推导出四元数的逆。满足。从范数的定义推导出一个公式如下:

再推导出

四元数和常数的乘法满足交换律:

,所以有

        下面介绍下规则:

单位四元数,也就是也可以写成:

其中三维向量有,因为

当且仅当。单位四元数是非常适合用于创建旋转和方向。

对于复数,一个2维单元向量可以写成。所以四元数可以表示为

        单位四元数的log函数和power函数如下:

4.3.2 四元数变换

        接下来研究下四元数的一个子集,单位四元数。 单位四元数最为重要的一点是它可以表示任何三维旋转。
        首先,将一个点或者一个向量的四个分量 组成一个四元数 。假设现在有单位四元素 ,则有:
将点p绕着 旋转 。注意,因为 是单位四元数,所以有 。见图4.9。
图4.9 单位四元数,绕旋转度。
 
        任何非零实数乘以 所表示的变换和 表示的变换一样,也就是说 和- 表示的旋转是一样的。也就是说将 取反,实部 取反,重新生成的四元数和原四元数表示的旋转是一样的。从一个矩阵得到的四元数可以是 也可以是-
        给定两个单位四元数 ,先应用 ,再用 ,则有:
在这 ,是一个串联了 的单位四元数。
 

矩阵变换

        因为经常需要将几个不同的变换组合在一起,并且大部分都是矩阵形式,公式4.34就是其中一种方法。一个四元数可以用公式4.45转换成矩阵

其中s是标量,。而对单位四元数可简化为:

一旦四元数构建成功,就不需要三角函数了,这样在实际应用中就有很高的效率。

        从正交矩阵转换到成单位四元数就稍微复杂点。从公式4.46可有:

如果知道了,就可以算出四元数剩下的三个元素,也就知道了四元数。可以算出迹(在线代中,一个nxn矩阵A的对角线上的元素和称为矩阵A的迹,用tr(A)表示):

对单位四元数有:

        为了保证稳定性,被除数需要避免太小。因此,设,则有:

如果知道谁最大,也就知道了谁最大。如果是最大的,公司4.49 就可以用来计算四元数。另外需要注意:

可以用4.51计算出谁最大。这样就可以避免使用除法计算出四元数。

球面线性插值

        球面线性插值是:利用两个单位四元数及参数计算插值。这对动画非常有用。但是对插值摄像机的方向没有用,因为摄像机的“向上”方向是会发生倾斜的,不注意很容易出错。

        这种操作的代数表现形式是一个复合四元数,如下:

        然后在一些软件内部实现中,用slerp表示球面线性插值:

其中。对参数,slerp计算出的插值四元数,组合在一起构建出了从的四维单位球的最短弧。这个弧位于给出平面和四维单位圆的交点所形成的圆上。如图4.10所示。计算出的旋转四元数以恒定速度绕固定轴旋转。这样一条速度恒定,加速度为0的曲线被称为测地线曲线。如果四元数给出的平面通过圆点,则交点形成的圆是最大圆(great circle),对应的弧为最大弧(great arc)。

图4.10 单位四元数在单位球上的点。slerp用于计算两个四元数的插值,插值路径在球面上形成一个弧。注意,从的插值和从再到的插值不是一回事,虽然最后到达同一个方向。

        slerp函数非常适合两个方向进行插值。在固定轴恒速的情况下表现很好,但如果用欧拉角来做会有问题。实际上,直接计算slerp需要用到三角函数,这是很耗性能。Malyshau提出在渲染管线中用四元数进行插值计算,这样可避免万向节死锁,在像素着色中使用,得到的误差可以接受。

        如果超过两个方向,有n个方向,并且希望从插值到再到,一直到。用slerp是一个简单直接的方法。但是当到达的时候,需要用到,紧接着到,又需要用到,这样会引起抖动,如图4.10所示。这点做线性插值的情况很像。

        一种更好的方法是利用样条曲线(spline)。在间引入四元数。就可以用做球面三次插值(Spherical cubic interpolation)。的计算如下:

三次球面插值公式如下:

可见, squad函数就是利用slerp进行三次球面插值。这些插值路径通过初试方向 ,而不会通过 ,而 可以用来表示初始方向 的切线方向。
 

从一个方向旋转到另外一个方向

        一种常见的操作是通过尽可能短的路径把一个方向s转换到另外一个方向t上。利用四元数大大简化了这一过程。首先,归一化s和t。然后计算出单位旋转轴u, 。然后 ,其中 是s和t的夹角。从s旋转到t的四元数可以表示为 。实际上,可以简化为 。利用半角公式和三角恒等式有:

这种方式生成四元数可以避免s和t几乎指向同一方向的时候计算不稳定,几乎为0。但是当s和t反向的时候还是会有问题。当排除这种特殊情况下,任何垂直于s的旋转轴都可以被用来旋转到t。

        有时需要用矩阵来表示从s旋转到t。通过公式4.46可有

其中一些中间计算如下:

可见所有的平方根和三角函数都消掉了。注意,4,57和4.30很像,但是4.57不需要三角函数。

        需要注意当s和t平行或者反向的时候,因为这种情况下。如果,可以返回单位矩阵。然而如果,可以围绕任意轴旋转。这个旋转轴可以通过对s和任何与s非平行的向量叉乘得到。

4.4 顶点混合

        想象一下,一个虚拟角色的手臂由两部分组成,前臂和上臂,如图4.11所示。该模型可以由刚体变换进行动画。 然而,这两部分之间的关节并不像一个真正的肘部 这是因为使用了两个不同的对象,关节由这两个不同对象的重叠部分组成 显然,最好只使用一个对象。然而,静态模型部件并不能解决关节变灵活的问题。
 
        为了 解决这个问题, 顶点混合( Vertex blending 是一个常用的方法。这个技术还有其他几种叫法,例如,线性混合蒙皮( linear-blend skinning ),包络( linear-blend skinning ),骨骼子空间变形( skeleton-subspace  deformation )。 虽然这里给出的算法的确切起源还不清楚,但定义骨骼和让皮肤对变化作出反应是计算机动画中的一个老概念 在其最简单的形式中,前臂和上臂像以前一样分别进行动画,但在关节处,这两个部分通过一个有弹性的“皮肤”连接起来 这样的 话,这个连接处的部位将会有一组顶点由前臂矩阵控制,另外一组顶点是由上臂矩阵控制。 这导致三角形的顶点可以有不同的矩阵转换,而不是每个三角形使用一个矩阵。如图4.11所示。
4.11   左图是 由前臂和上臂组成的手臂,肘部为重叠部分,分别使用独立的刚体变换来实现动画,肘部看起来不真实。右图组成手臂只有一个对象,并用顶点混合处理对象。右图的手臂说明了当一个简单皮肤直接连接两个部分来覆盖肘部会发生什么,并且有一些顶点使用了不同权重进行了混合( 2/3,1/3 ),这意味着上臂矩阵的权重是2/3,前臂的权重是1/3。还可从右图看出顶点混合的缺点,肘部内部折叠明显  如果使用 更多的骨骼和更精心选择的权重,则可以获得更好的结果。
       
        进一步,可以让一个顶点有多个不同矩阵处 理。 这是通过为动画对象提供骨骼骨架来完成的,每个骨骼的变化都会通过用户定义的权重影响每个顶点。 因为整个手臂可能是“有弹性的”,所有的顶点都可能受到超过一个以上的矩阵的影响,整个网格通常被称为皮肤(附在骨头上),如图4.12所示。 许多商业建模系统都有类似的骨骼建模功能。 尽管从他们的名字上看,好像是刚体,但不一定必须是刚体 例如,Mohr和Gleicher提出了增加额外关节的想法,以实现肌肉膨胀等效 果。 James和Twigg讨论了使用可以挤压和拉伸的骨头制作动画皮肤。
图4.12 一个顶点混合的真实例子。左上图表示的组成一个手臂的两个骨骼,并处于伸展位置。右上图展示的是手臂的网格模型,用颜色区分了两块骨骼。下图为渲染后的弯曲手臂。
        在数学上,可以用4.59表示,其中p是原始顶点, 为转换后的顶点,其位置随着时间变化。
有n根骨骼会影响到p在世界空间的位置。 是每个骨骼影响到p的权重。 把p从模型空间变换到世界空间。 一般来说,骨骼的控制关节位于其坐标系的原点 。例如, 前臂骨骼会降肘关节移动到原点,然后可以用旋转矩阵让前臂绕着关节做动画。 矩阵是第i个骨骼的世界变换,会随着时间变化而改变,通常是几个矩阵串联而成。
 
        Woodland深入讨论了一种维护和更新 矩阵动画函数的方法。  每块骨头根据自身的参照系将一个顶点转换为一个位置 然后将顶点进行插值得到最终结果。矩阵 在蒙皮的时候没有被详细说明,而是经常被认为是 的一部分。这里单独列出来,是因为它很重要,几乎总是矩阵串联过程中的一部分。
       顶点p通过不同骨骼的串联矩阵进行变换,然后用权重 进行混合,这就是顶点混合。权重非负,并且和为1。把顶点转换到对应位置后,再进行插值,这样, 最终 变换后的点u将会位于点集 的凸包内。法线也可以用公式4.59进行转换。 如果骨头被拉伸或压扁的严重, 的逆转置矩阵可能会用到。
 
        顶点混合非常适合GPU。网格中的一组顶点可以放置在一个静态缓冲区中,然后一次性发给GPU并重复使用。在每一帧中,只有骨骼矩阵发生变换,顶点着色才会重新计算Mesh 。通常这种方式,发送给CPU的数据会最小,GPU高效渲染网格。 如果模型的所有骨骼矩阵可以一起使用,那是最简单的 ,否则的话, 否则,模型就需要被分割且 复制 一些骨骼 。另外骨骼变换可以存储在顶点可访问的纹理中,以避免达到寄存器存储上限。通过使用四元数表示旋转,这样的话每个变换就可以存在两个纹理中。如果支持的话,UAV( unordered access view )也可以存储结果。
 
        权重也可以超过[0,1]范围,或者和不为1。但是,只有在使用其他混合算法(比如4.5节的morph变形算法)的时候,才有意义。
 
        顶点混合的一个缺陷在于会发生一些不必要的折叠、扭曲和自相交 。如图4.13所示。更好的解决方案是使用 对偶四元数 。这种蒙皮技术保持了原始变换的刚体性,避免了四肢出现像“糖果纸包装”似的的扭曲。以小于线性蒙皮混合计算量的1.5倍的计算量能获得非常好的效果,使得该技术迅速得到广泛应用。然而,对偶四元数蒙皮技术可能会 导致膨胀效应 Le 和 Hodgins提出一种改进方案: 中心旋转蒙皮 。这种方案是建立在假设局部变换是刚体变换,具有相似权重的 的顶点同样具有相似的变换。预先计算出每个顶点的旋转中心,同时使用 正交(刚体)约束来防止肘部塌陷和“ 糖果包装纸” 似的扭曲 运算时,该算法类似于线性蒙皮混合,GPU先在旋转中心执行线性蒙皮混合,然后再执行四元数混合。
图4.13  左边的图展示了线性混合蒙皮时关节发生的问题。而右边图使用的对偶四元数,可以解决这些问题。
 
 

4.5 变形        

        变形( Morphing 在一个3D模型播放动画时,由一个模型变成到另外一个模型,会非常有用。想象一下,在 时刻,展示的是模型A,等到 时刻则变成了另外一个模型B。而在 的这段时间里,模型一直发生类似插值的变换( mixed)。如图4.14所示是一个模型变形过程。
图4.14 顶点变形。每个顶点有两个坐标位置和一个法线。每一帧,都会在顶点着色中对其位置和法线进行插值。
 
        变形需要解决两个问题, 顶点对应问题和插值问题。对于两个模型,可能他们有不同的拓扑结构、不同的顶点数,不同的网格连接性,通常需要建立起这些顶点间的对应关系。这是一个难题,这个领域有很多研究。
 
        如果两个模型间已经建立起了一一对应关系,就可以基于每个顶点做插值计算了。 第一个模型上的每个顶点在第二个模型中只能对应一个顶点,反之亦然。这会使得插值变得简单。举个例子,对顶点直接使用线性插值。为了随时间变化的变形, ,首先计算 ,然后进行线性顶点混合:
其中 是同一个顶点在两个不同时刻的值。
         morph targets blend shapes是两个常用的方法。原理如图4.15所示。
图4.15 图中给出了两种口型,用一组不同的向量来计算插值, 在morph targets方法中,将这组向量作用在中性模型上,给予每个 向量的一个正权值,将会得到一个微笑的脸型,而负权重值对应一个相反的效果。
        从一个中性模型( neutral model)开始,在上图的例子里是一张脸,用 来表示。此外,我们还有一组不同的脸型(face pose)。假设有k个不同的脸型, 。设 ,即用每个变形后的脸型减去一开始的中性模型。
        这样,如果有了一个中性模型 和一组姿势(pose) ,那么新的变形模型可以用下面的公式算出:
如图4.15,如果 可得到一个微笑的脸, 会得到一个半微笑的脸,以此类推。也可以用负值或大于1的值。
 
       对这个简单例子,可以给眉形使用一个负值的权重会得到一个快乐的眉形。 由于位移是附加的,所以眉毛的姿势可以与微笑的嘴的姿势一起使用。
 
        morph targets是一个非常强大的技术,可以给动画师很多助力。Lewis等人提出了 姿势空间变形( pose-space deformation ,结合了顶点混合和morph targets。Senior使用预计算顶点纹理去存储和检索目标姿势之间的位移。
 
        图4.16展示了一个同时使用了蒙皮和变形的例子。
图4.16 图中展示的是在inFAMOUS Second Son中Delsin的脸,使用了blend shapes。图中所有的照片都使用了相同的休息姿势,然后通过使用不同的权重让脸部看起来不同。
 

4.6 几何缓存重播

        在过场动画中,通常需要高精度的动画,例如,一些无法用上述方法展示的动作。一 个天真的方法是保存每帧中所有的顶点数据,将它们保存在硬盘里,然后用于更新网格。然而,一个有30000个顶点的简单模型就需要50MB/s的数据存储。 Gneiting给出了几种可以降低存储10%左右的方法。
 
        首先,需要用到量子化( quantization 。例如,坐标位置和纹理坐标的每个坐标用16bit的整数存储,这个步骤是有损的,因为执行压缩后,不能完全恢复原始数据。为了进一步减少数据,对时间和空间进行预测,并对差异进行编码。对空间压缩,可以使用平行四边形预测( parallelogram prediction 。对一个三角形带( triangle strip ),下一个顶点的预测位置是在当前三角形所在平面内并以当前三角形的对应的边为对称线的对称点,和三角形形成了一个平行四边形。然后对新位置和老位置的差异进行编码。理想状态下。良好的预测会让大多数的差异都是0。类似于 MPEG压缩,预测也在时间维度里进行。也就是说,每n帧进行一次压缩。例如,一个顶点从n-1帧到n帧移动为一个delta向量,那么从n帧移动到n+1帧也是一个差不多的向量。 这些技术有效地减少了存储空间,让系统能够进行实时数据流传输。
 

4.7 投影

        在真正渲染场景之前,场景中的所有对象都需要投影到某个平面上或者某种简单体积上。之后进行裁剪和渲染。
 
        目前为止,本章都没有处理第四个坐标,w分量。也就是说,点和向量在变换后保留了它们的类型。但是,4x4矩阵的最下面一行总是(0,0,0, 1)。 透视投影矩阵不是这样,点和向量的操作需要用到最后一行,并且需要进行齐次处理。因为w通常部位1,所以需要除以w得到非齐次点。正交投影比较简单,它不受w的影响。
 
        在本节中,假设观察者沿着摄像机的z轴负方向观察,y轴向上,x轴向右,是一个右手坐标系。在一些文章和软件中,如DirectX,使用的是左手坐标系,观察者沿着z轴正方向观察。两种系统都有效,最终效果是一样的。
 

4.7.1 正交投影

        正交投影的一个特征是平行线经过投影后仍然是平行线。如果是用正交投影查看场景,无论场景中物体距离摄像机的距离如何变化,摄像机中的物体大小保存不变。下面的矩阵 是一个简单的正交矩阵,会使得x分量和y分量保存不变,而z分量置为0,所以正交投影到平面z = 0。
正交投影的效果如图4.17所示。很明显 没有逆,因为它的行列式。换句话说,它把物体从三维降为了二维。有一个问题是,它将点(不管z值得正负)都投影到了平面上。通常需要将z轴限定在一定范围内,在近平面n和远平面f之间。
图 4.17 简单正交投影的三种视图。可以认为是观察者沿着-z轴方向观察物体,保持x和y不变,将z置为0。平面z =0两侧的物体都被投影到平面上(z值的正负没有区分)。 
        
        正交投影的一个常见矩阵为 ,分别为左右上下近远六个面,这些平面形成了 轴对齐边框(AABB包围盒)。AABB包围盒的最小点为 ,最大点为 需要知道 ,因为是摄像机是沿着-z轴往前看的。
 
        在OpenGL中,轴对齐边框的最小点为(-1,-1,-1),最大点为(1, 1, 1)。在DirectX中,最小点为(-1, -1, 0),最大点为(1, 1,1)。这个包围盒被称为规范化可视空间( canonical view volume),这个坐标系被称为 规格化设备坐标(NPC,normalized device coordinates),转换过程如图4.18所示。 转换到规范化可视空间的目的是为了裁剪更加高效
图4.18 将一个轴对齐包围盒转换到规范化可视空间。首先让包围盒中心和原点重合,然后缩放包围盒的大小。
 
        完成转换后,然后利用新的立方体对物体的几何顶点进行裁剪,立方体内的几何体将会被映射到屏幕上绘制出来。正交投影变换如下:

如上式所示,可以是由变换矩阵和串联而成,其中,。矩阵是可逆的,。

        在计算机图形学中,投影后通常变成了左手坐标系,视口指向正z轴,向右为x轴,向上为y轴。因为在定义AABB的时候认为far值要比near值小,而正交投影通常都有一个镜像变换(mirroring transform)。AABB的坐标变化有,变为(-1,-1,-1),变为(1, 1, -1)。

可见公式4.64给了一个镜像变换,把右手坐标系变成了左手坐标系。      

    DirectX定义z值得范围为[0,1],而OpenGL定义为[-1, 1]。可以在正交投影后用一个简单的矩阵解决这个问题。

所以在DirectX中的正交投影矩阵为
 
因为DirectX里的矩阵通常用的是行形式,所以通常会用到矩阵的转置形式。
 

4.7.2 透视投影

        比正交投影更为复杂的是透视投影,在这里,平行线经过投影后将不再平行,相反,会在末端收敛成一个点, 透视投影更符合人对世界的感知,即离得远了感觉变小了
        首先,将物体投影到平面z=-d上,d > 0。
        假设摄像机位于原点,需要将点p投影到平面z=-d上,d>0,新形成的点为 。过程如图4.19所示。从图中的三角形可得出
相应的 。组合在一起有投影矩阵

图 4.19  推导透视投影矩阵的表达式。p点投影到z=-d,d>0平面上,对应的点为q。 投影是从摄像机位置的角度进行的,在本例中,位置是原点。

        透视投影矩阵如4.69所示,

最后一步是将整个向量除以w分量,本例中是 ,让最后一个值为1。
        很明显为什么透视投影用的是齐次坐标,几何上的解释是将点 投影到平面w=1上。
 
        和正交投影类似 透视投影也 会把视图转换到规范化可视空间, 实际上 它并不是投射到一个平面上(这是不可逆的),而是将视图 平截头体 转换到规范化可视空间( canonical view volume 。这里的平截头体从 开始到 结束, 。在z=n所在矩形内有最小点 和最大点 ,如图4.20所示。
图4.20 利用矩阵 将视图平截头体转换到单位立方体,称为规范化可视空间(canonical view volume )。
 
        参数 决定了摄像机的平截头体。 水平区域是由截锥的左右平面决定。垂直区域是由截锥的底面和顶面决定。  FOV( field of view )越大,相机看到的越多。如果 ,平截头体会不对称,用于立体视觉( stereo viewing )和虚拟现实。
        FOV 对提供场景感很重要。和计算机屏幕相比, 人眼就有一个物理FOV 。对于FOV有
表示FOV。 w为垂直于视线的物体的宽度,d为到物体的距离。例 ,一个25英寸的显示器大约是22英寸宽。在12英寸外,水平FOV为85度,20英寸处,为58度。30英寸处,为40度。同样的公式也可用于将摄像机镜头尺寸转换为FOV。比如35mm的摄像机(具有36mm宽的帧尺寸),对应标准50mm的镜头时, 度。
 
         用一个较窄的FOV相比于物理FOV(35mm的摄像机)将降低透视效果。而设置较阔的FOV会让物体看起来扭曲(比如广角摄像机镜头),尤其在屏幕边缘附近,会放大物体的比例。但是一个大FOV会让视野里的物体更大,更令人印象深刻,视野更大看到更多的东西。
        将平截头体转换到单位立方体所使用的透视变换矩阵为

点p转换后为点,w分量为,通常不为0也不等于1。为了拿到正确的投影点p,需要除以w分量,有

        在远平面之外的物体会被裁剪掉,不会被绘制在屏幕上。透视投影可以把远平面当做无穷远,使用公式4.73所示矩阵操作:

  

综上所述,经过透视投影后,然后进行裁剪和齐次除法(除以w),最后得到NDC(规格化设备坐标, normalized device coordinates)。

        为了得到OpenGL中的透视投影,首先需要乘以,原因和正交投影一样,这样会把公式4.71中的第三列的值取反。在镜像操作之后,近平面和远平面的值会变成正数,。但是在视图的视角方向上,它们仍然表示沿着世界的负z轴的距离。OpenGL的公式如下

        还有一个更简单的方法是用FOV(),屏幕宽高比(w和h是屏幕分辨率),。结果如下

其中,

        在一些APIs中,如DirectX,近平面为z=0(OpenGL为z=-1),远平面为z=1。此外,DirectX使用的是左手坐标系进行投影,这意味着DirectX是沿着z轴的正方向,近平面和远平面的值是正数。DirectX的公式如下:

        透视投影可用来计算深度值, 不随输入 值进行线性变化。通过公式4.74-4.76乘以点p,会得到如下结果
其中,x和y的值用省略号忽略了,常数d和f取决于所使用的的矩阵。如果使用4.74公式,则 ,为得到NDC中的深度值,需要除以w分量,结果有
其中对OpenGL有 。可以看到,输出的深度值 和输入 成反比。
         图4.21显示了改变近平面和原点之间距离会导致的效果。其实近远平面都会影响Zbuffer的精度。
图4.21  改变近平面和原点之间距离。 维持在100,近平面越靠近原点,靠近远平面的点使用的深度值(在NDC中)范围越小,这会使得zbuffer在远处的精度不精准
 
        有几种方法可以提高深度值的精度。常用的是 reversed z,用 表示深度。可以在图4.22中看到对比效果。
图4.22 上图展示了在DirectX中创建深度缓冲区的不同方法, 。左上:标准整数深度缓冲区,精度为4bit,可看到y轴上16个标记。右上:远平面被设置为无穷远,和左上对比的话,精度损失并不大。左下: 用3个指数位和3个尾数位表示浮点深度, 可以看到Y轴上的分布为非线性的,使得X轴上的分布更糟糕。右下:反向浮点深度, ,可以得到一个更好的分布。
        
         Lloyd建议使用深度值的对数来提高阴影贴图的精度 Lauritzen等人使用前一帧的Zbuffer去确定近平面和远平面。 对于屏幕空间深度,Kemen建议使用以下公式对每个顶点进行重新映射
 
其中,w是经过透视投影后w分量的值,z是顶点着色后的z值。常数 ,其中 是远平面。当这个变换只应用在顶点着色中, 深度值会变为线性插值,因为log函数单调函数, 只要分段线性插值和精确的非线性变换深度值之间的差异很小,遮挡剔除硬件( occlusion culling hardware )和深度压缩( depth compression )技术仍然有效。例如曲面细分的程度足够细的时候,或者在片元着色中进行这个操作。在顶点着色中逐顶点计算出 ,然后进行插值,然后在片元着色中修改每个片元的深度值为 ,其中 是e的插值。当GPU不支持浮点深度时而又在计算深度时需要用到大范围的时候,这个方法很有用。
 
         Cozzi建议 使用多个平截头体, 这样 能有效地提高精确度以达到任何期望的速度。 先将视椎体在深度方向上分成几个不重叠的小的平截头体,合在一起刚好是视椎体。子平截头体的渲染顺序是从后到前。首先,需要清理颜色缓冲区和深度缓冲区, 并将渲染的所有对象排列到它们对应的子平截头体中。 对于每个子 平截头体 ,设置其投影矩阵,清理深度缓冲区,然后渲染。
 
  相关解决方案