第四章 转换
“要是愤怒的航船改变了方向
围绕到你睡着的额头,和身体?
永远不用担心
那悲惨世界中抽象的风暴的暴力。”
--罗伯特·潘·沃伦
转换是一种操作,以某种方式对实体(如点、向量或者颜色等)进行转化。对于计算机图形从业者,掌握转化极其重要。通过转化,你可以对对象、光和相机等进行重定位、重塑以及生成动画。你还可以确保计算都是在同一个坐标系中进行,但使用不同的方式将物体投影到平面。这些只是可以通过转换完成的操作的很小一部分,但已足够用来说明在实时图形中(或者,从某种意义上说,在任何种类的计算机图形中)转换这一角色的重要性。
线性转换是保留操作之一,用来执行向量相加和标量相乘。
公式(4.1):
f(x) + f(y) = f(x + y),
kf(x) = f(kx).
如,f(x) = 5x是一个转换,将向量的每个元素乘以5。这种类型的转换是线性的,因为两个和5相乘后的向量相加后,所得的值和先相加再乘5相同。标量乘法条件被明确地实现。该函数叫作缩放转换,因为它改变了对象的比例(大小)。旋转变换是另一种线性转换,它相对于原点对向量执行旋转。缩放和旋转变换(实际上是向量的三个元素的线性转换)可以用3*3的矩阵表示。
不过,3*3的矩阵通常不够大。用于三元素向量x的函数如f(x) =x+ (7,3,2),不是线性的。对两个向量分别执行该函数,则每个向量的值增加(7,3,2),而最终结果就增加了两次。固定向量和另外的向量相加,执行了一个平移,如,它将所有的位置移动了相同的数量。这是一种有用的转换类型。我们会组合多种转换,如,先将对象缩小一半,然后再把它移动到不同的位置。到目前为止所用的这些简单格式的函数使得组合转换比较困难。
组合线性转换和平移可以使用一个仿射转换完成,它通常存储为一个4*4的矩阵。一个仿射转换执行一个线性转换,然后平移。为表示4元素的向量,我们使用同质符号;我们用相同的方式表示点和方向(小写粗体字符)。一个方向向量表示为v = (vx vy vz 0)T,点表示为v = (vx vy vz 1)T。本章,我们将广泛使用附录A中讲解的术语(同质符号在节A.4)。
所有的平移、旋转、缩放、反射和剪切矩阵都是仿射的。仿射矩阵的主要特性是它保留了线的平行((指对象间的相对关系保持不变,平行线还是平行线,且直线上点的位置顺序不变)),而长度和向量间的夹角可能会发生变化。仿射转换也可以是其它仿射转换的任意序列的串联。
本章将从最本质、最基础的仿射转换讲起。这些仿射转换确实非常基础,本节可被当作简单转换的“参考手册”。之后会讲解更加特殊的矩阵,接着是四元组(一个强大的转换工具)。再之后是顶点混合和变形(两种简单但更强大的表示网格动画的方式)。最后,讲解投影矩阵。这些转换中的绝大部分,其符号、功能和属性总结于表4.1中。
表 4.1 本章讨论的大部分转换的总结
转换是操作几何图形的基本工具。大多数图形API提供了本章讨论的许多转换对应的矩阵操作。不过,仍然值得去理解这些函数调用背后的实际的矩阵及其交互。知道矩阵在函数调用之后做些什么是一个开始,理解矩阵本身的属性将让你走得更远。比如,它可以让你知道,在处理一个正交矩阵(其逆矩阵也是其转置矩阵)时,如何进行更快的矩阵逆运算。这些知识可以产生更快的代码。
4.1 基本转换
本节介绍最基本的转换,如平移、旋转、缩放、剪切、转换串联、刚体转换、法线转换和逆运算等。有经验的读者可以把本节当作简易转换的参考手册;新手可以用来入门。它们是本书剩余章节必需的背景知识。我们从最简单的转换--平移--开始。
4.1.1 平移
图 4.1 左侧的方块被使用平移矩阵T(5,2,0)进行转换。转换结果是,方块向右移动了5个单位,向上移动了2个单位。
从一个位置到另一个位置的改变用一个平移矩阵T表示。该矩阵使用一个向量t = (tx,ty,tz)平移一个实体。T如公式4.2所示:
平移转换效果的一个例子如图4.1所示。用简单点的话说,用T(t)操作点p = (px,Py,Pz, 1),将得到一个新的点p' = (px + tx,py + ty,pz + tz, 1)。这显然是一个平移。注意,如果用T对一个向量v = (vx,vy, vz,0)进行操作,则v不会受到影响,因为方向向量无法平移。 相比之下,点和向量都会被其它的仿射转换所影响。转换矩阵的逆是T-1(t) = T(-t), 即,向量t取负。
4.1.2 旋转
旋转转换将一个向量(位置或方向)绕着一个穿过原点的轴旋转指定的角度。如同平移矩阵,它是一个刚体矩阵,如,它保留了两点间的距离和次序(它不会引起左右边交换)。这两种类型的转换在计算机图形中对对象的重定位和朝向有明显的作用。一个朝向矩阵(和机视角于定义了朝向的对象相关;对象的朝向有向上和向前的方向等)是一个旋转矩阵。常用的旋转矩阵是Rx(Φ),Ry(Φ),Rz(Φ),它们将绕着xyz轴吧实体转换Φ弧度。它们的公式如4.3-4.5所示:
对每个绕着坐标轴旋转Φ弧度的3*3的旋转矩阵R,它的迹(参考附录《矩阵的迹》)是一个常量且独立于坐标轴,可以用下面的公式计算[742]:
公式(4.6):
tr(R) = 1 + 2 cosΦ
旋转矩阵的效果可以参考图4.4。旋转矩阵Ri(Φ),除了绕着i轴将对象旋转Φ弧度之外,还有一个特性,就是不会改变旋转轴i上的所有点。注意,R也用来表示一个绕着坐标轴的旋转矩阵。上面给出的轴旋转矩阵可以用于一系列的转换以执行任意轴的旋转。这一过程在节4.2.1中讨论。而用一个单独的旋转矩阵执行绕任意轴的旋转,在节4.2.4中介绍。
所有旋转矩阵,其行列式的值都是1,并且都是正交矩阵。这可以很容易地使用附录A中的正交矩阵的定义进行验证。这也适用于这类转换矩阵任何数目的串联。还有另一种获得逆矩阵的方法:Ri-1(Φ) = Ri(-Φ),如,绕同一个轴反方向旋转。
示例:绕点旋转
假设我们想要绕着z轴方向将一个对象旋转Φ弧度,旋转的中心点为p。那么,转换矩阵是什么呢?这一场景描绘于图4.2。既然绕点旋转具有特性,点本身不会受旋转影响,那么我们就从平移转换开始。首先让p和原点重合,这通过T(-p)来完成。然后,进行实际的旋转:Rz(-Φ)。最后,再将对象平移会原始位置,使用T(p)。最终的转换矩阵X,则可表示为:
公式 4.7
X = T(p)Rz(Φ)T(-p)
图 4.2 绕指定点p旋转的例子