概述
第四章 变换(Transforms)
”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(变换运算)是指对实体如点,向量或颜色执行的一种操作,并使用某种方式对他们进行转换。对于计算机图形学专业人员,掌握变换运算是极其重要的。掌握了变换运算,你就可以改变物体,光源以及相机的位置,形状和动画。另外,还可以保证所有的计算都是在同一个坐标系进行的,并且可以使用不同的方法把物体投影到一个平面上。这些只是使用变换运算能处理的很小一部分操作,但是足以说明变换运算在实时图形学,或者说在任何一种计算机图形学中的重要性。
*Linear transform(线性变换)是一种用于执行向量加法和向量-标量乘法的变换运算。具体表示为,
例如, f(x)=5x 表示一种对向量的每个分量元素乘以5的变换运算。这种类型的变换是线性的,因为任何两个向量先分别乘以5再相加,与把这两个向量先相加再乘以5的结果是一样的。这种运算显然满足标量乘法的条件。这种功能的运算称为缩放变换(scaling transform),因为改变了一种物体的规模(大小)。另一种线性变换为旋转变换(rotation transform),相对于原点对向量执行旋转操作。除了缩放和旋转变换,事实上对于所有含有3个元素的向量的线性变换,都可以使用一个 3×3 大小的矩阵表示。
然而,这种大小的矩阵通常是不够大的。对于一个包含3个元素的向量 x ,函数 f(x)=x+(7,3,2) 不是线性变换。在两个独立的向量上分别执行该函数运算会导致生成的结果中对 (7,3,2) 的每个值相加两次。把一个固定的向量加到另一个向量中会执行一次平移运算,比如使用相同的数量移动所有向量的位置。这是一种有用的变换运算,而且我们将会把多种变换结合起来,比如把一个物体先缩放为原始大小的一半,然后再移动到一个不同的位置。到目前为止所使用的这些简单函数形式,要把它们合并起来是很困难的。
使用一个affine transform(仿射变换)可以把线性变换和平移运算进行合并,该变换通常存储为一个 4×4 的矩阵。仿射变换是一种先执行线性变换再进行平移操作的变换运算。为了表示统一表示含有4个元素的向量,比如点和方向,我们使用homogeneous notation(齐次表示法)。方向向量通常表示为 v=(vx vy vz 0)T ,点向量表示为 v=(vx vy vz 1)T 。在整个章节中,我们将会大量使用附录A所讲述的术语。因此,不妨现在就回顾一下附录的内容,尤其是A.4节关于homogeneous notation部分的内容。
所有的平移,旋转,缩放,反射和切变矩阵都是仿射矩阵。仿射矩阵的主要特点是,平行线在变换之后依然保持平行,但是不保证线的长度和角度在变换后保持一致。一个仿射矩阵还可以是多个单独的仿射矩阵的串联系列。
本章将从最重要的基本仿射变换开始讲解。这些变换确实是非常基础的,而且本节可以作为简单变换的一种“参考手册”。然后描述一些更专业的矩阵,接着是关于四元数(quaternion)的讨论和说明。之后就是讲解vertex blending和morphing,这是两种非常简单的变换运算,但是是表示meshes动画的更强大的方法。最后,将会讨论投影矩阵(projection matrix)。表格4.1中总结了大部分变换矩阵,以及相应的表示记号,函数和属性。
Notation | Name | Characteristics |
---|---|---|
T(t) | 平移矩阵 | 移动一个点,仿射矩阵 |
Rx(ρ) | 旋转矩阵 | 绕着
x
轴旋转 |
R | 旋转矩阵 | 任意的旋转矩阵。正交和仿射矩阵 |
S(s) | 缩放矩阵 | 根据 s 沿着 x,y,z 轴进行缩放。仿射矩阵 |
Hij(s) | 切变矩阵 | 根据分量
j
,由切变因子 |
E(h,p,r) | 欧拉变换 | 通过欧拉角度head(yaw),pitch,roll给定一个方向矩阵。正交和仿射矩阵 |
Po(s) | 正交投影 | 平行投影到某个平面或视域体上。仿射矩阵 |
Pp(s) | 透视投影 | 透视投影到某个平面或视域体上 |
slerp(q^,r^,t) | 四元数插值变换 | 根据四元数 q^ 和 r^ ,以及参数 t 创建一个插值后的四元数。 |
表格4.1 总结了本章所讨论的大部分变换运算。
变换运算是操控几何物体的一种基本工具。在大多数的图形应用编程接口(APIs)中都包括了基本的矩阵运算,实现了本章所讨论的大量的变换运算。但是,了解这些函数调用背后实际的矩阵运算和交互作用是非常值得的。了解函数调用背后的矩阵运算只是一个开始,只有真正理解矩阵本身的特性才能更进行更深入的学习。比如,如果理解了矩阵的性质,在处理一个正交矩阵时你就能明确的知道正交矩阵的逆等于转置,这样就可以更快计算出矩阵的逆。理解了类型于这样的原理,可以写出加速性能的代码。
4.1 Basic Transforms
本节讲述了最基本的变换运算,比如平移,旋转,缩放,切变,变换串联,刚体变换,法线变换 (normal transform,不是指正常的意思),以及逆变换的计算。对于有经验的读者,本节可以作为简单变换的参考手册,对于新手来说,可以作为变换运算的导论。这一节的内容是学习本章的其余部分,以及本书的其他章节必不可以的部分。首先,我们开始讨论最简单的一种变换—平移变换。
4.1.1 Translation
从一个位置变化到另一个位置可以使用一个平移矩阵
图4.1中显示了平移变换的效果示例。其中,简单地显示了点 p=(px,py,pz,1) 与矩阵 T(t) 相乘产生一个新的点 p′=(px+tx,py+ty,pz+tz,1) ,很明显这是一种平移变换。需要注意的是,向量 v=(vx,vy,vz,0) 与矩阵 T 相乘是不会有影响的,因为一个方向向量是无法进行平移的。与之相反的是,其余的仿射变换可以对点和向量都产生影响。平移矩阵 T 的逆矩阵为 T−1(t)=T(−t) ,即对向量 t 取反即可。
图4.1 使用变换矩阵
T(5,2,0)
对左图中的正方形执行变换操作,变换结果如图所示,沿着向右的方向移动5个单位距离并向上方向移动2个单位距离。
4.1.2 Rotation
旋转变换是指围绕一个穿过原点的给定坐标轴对一个向量(表示点或方向)旋转给定的角度。与平移矩阵一样,旋转变换也是一种rigid-body transform(刚体变换),即在变换后点与点之间的距离保持不变,使用的左右手坐标系也不变(即不会出现左右手交换的情况)。这两种变换运算在计算机图形学中设置物体的位置和朝向是很有用的。Orientation matrix是一种与相机视角或物体关联的旋转矩阵,定义了相机或物体在坐标空间中的朝向,即向上和向前的方向。常用的旋转矩阵为
Rx(ϕ)
,
Ry(ϕ)
,
Rz(ϕ)
,分别表示围绕
x
,
对于每一个
3×3
的旋转矩阵
R
,围绕任意轴旋转
ϕ
弧度,矩阵的迹(定义见附录A)与轴无关且始终保持不变,可以使用如下公式计算:
注:如果删除一个 4×4 矩阵的最正面一行和最右边一列,就可以得到一个 3×3 的矩阵。
旋转矩阵的变换效果可以参考(原书62页的)图4.4。旋转矩阵
Ri(ϕ)
实际上除了描述围绕
i
轴旋转
所有旋转矩阵的行列式都为1,并且都为正交矩阵,使用附录A中关于正交矩阵的定义可以很容易验证该性质。任意数量的矩阵串联后依然具有正交矩阵的性质。并且逆矩阵还有另外一种计算方法: R−1i(ϕ)=R _i(-phi),即围绕同一个轴以及反方向进行旋转。另外,由于旋转矩阵为正交矩阵,因此行列式始终为1。
EXAMPLE: ROTATION AROUND A POINT(围绕一个点旋转)。假设我们要围绕
z
轴对物体旋转
ϕ
弧度,旋转的中心是某个特定点
p
。那么这种变换是什么样的呢?图4.2中描述了这种情况的变换操作。由于围绕一点进行旋转时,点本身不会受到旋转操作的影响,因此变换的第一步是对物体进行平移,使得
p
与原点相吻合,平移操作表示为
T(−p)
。之后就是真正的旋转操作:
Rz(ϕ)
。最后,需要使用
T(p)
再把物体平移到原始的位置。最终的变换矩阵
X
表示如下:
图4.2 围绕一个特定点
p
旋转的示例。
4.1.3 Scaling
缩放矩阵
S(s)=S(sx,sy,sz)
表示使用缩放因子
sx
,
sy
和
sz
对实体分别沿着
x−
,
y−
,和
z−
方向进行缩放。也就是说使用缩放矩阵可以放大或缩小物体。
si
的值(其中
i∈{x,y,z}
) 越大,在该方向上实体被放大的就越多。把
s
的任意一个分量设为
1
,就可以避免在对应方向上的缩放变化。矩阵
图4.4中演示了缩放矩阵的变换效果。如果 sx=sy=sz ,则称缩放操作为uniform(等比例缩放),否则称为nonuniform(非等比例缩放)。有时候还会使用术语isotropic()和anisotropic()表示,而不是uniform和nonuniform。对应的逆矩阵为 S−1(s)=S(1/sx,1/sy,1/sz) 。
在使用齐次坐标表示的情况下,创建等比例缩放矩阵的另外一种有效的方法是调整位于索引
(3,3)
位置的矩阵元素,即最右下角的元素。该元素值会影响齐次坐标的
w
分量,因此可以对每一个经过矩阵变换的坐标进行缩放。例如,使用缩放因子
与使用 S 表示等比例缩放不同的是,矩阵 S′ 必须总是在齐次表示下执行运算。这种运算可能是很低效的,因为其中涉及到齐次过程中除法计算;如果位于右下角(索引为 (3,3) 的位置)的元素值为1,则不需要执行除法。当然,如果系统在执行除法计算时不进行等于1的测试,就没有额外的计算成本。
对 s 中的一个或三个分量值取反则会得到一个reflection matrix(反射矩阵),也称为mirror matrix(镜像矩阵)。如果只有两个缩放因子为 −1 ,则旋转 π 弧度。在使用反射矩阵时通常需要进行一些特别的处理。例如,一个顶点为逆时针顺序的三角形通过反射矩阵变换后顶点会变成顺时针顺序。这种顺序变化会导致错误的光照和背面消除的情况发生。要检查一个给定的矩阵是否会执行某种方法的反射变换,只需要计算该矩阵左上边 3×3 区域元素的行列式。如果行列式的值为负,该矩阵就是反射矩阵。
注:根据反射矩阵的部分定义,分量值为负的情况下,必须为-1。
EXAMPLE: SCALING IN A CERTAIN DIRECTION(在某个特定方向上进行缩放)。缩放矩阵 S 只能沿着 x− , y− 和 z− 轴进行缩放。如果要在其他方向上执行缩放操作,需要一个复合变换矩阵。假设要沿着一组标准正交向量(正向朝右) fx , fx 和 fx 执行缩放操作。首先,构建矩阵 F 如下:
具体的实现思想是,把这三个轴确定的坐标第变换到与标准轴相吻合的位置,然后使用标准缩放矩阵执行缩放变换,再把缩放结果变换回原始的位置。首先与
F
的转置矩阵,即逆矩阵相乘。然后执行真正的缩放操作,接下来变换回原始位置。整个变换运算如公式4.11所示:
4.1.4 Shearing
另一类的变换运算是一组切变矩阵。比如,这些矩阵可以用于在游戏中扭曲整个场景从而创建一种迷幻的效果,或者通过抖动(jittering,见第9章9.3.1节)创建模糊的镜像。总共有6种基本的切变矩阵,分别表示为 Hxy(s) , Hxz(s) , Hyx(s) , Hyz(s) , Hzx(s) 和 Hzy(s) 。其中,第一个下标用于表示将会被切变矩阵改变的坐标,而第二个下标表示执行切换操作的坐标。公式4.12显示了一个切变矩阵 Hxz(s) 的示例。注意到下标可以用于查找参数 s在该矩阵中的位置;其中 x (数值索引为0)指明了第0行, z (数值索引为2)指明了第2列,也就是 s$ 所在的位置。
把该矩阵与点
p
相乘的结果是产生一个新的点:
(px+spz py pz)T
。图4.3中以图形的方式显示了单位正文形使用该矩阵变换的结果。切变矩阵
Hij(s)
(相对于第
j
个坐标对第
图4.3 使用切变矩阵
Hxz(s)
对单位正方形执行切变的结果。该变换不会影响
y
和
另外,有些计算机图形学书籍[348,349]中使用一个略微不同的切变矩阵:
但是,这里的两个下标用于表示那些通过第3个坐标执行切变的坐标。这两种不同的表示方法之间的联系是 H′ij(s,t)=Hik(s)Hjk(t) ,其中 k 用于获取第3个坐标的索引值。使用右边的矩阵所面临的主要问题是使用体验以及API的支持问题。
最后需要注意的是,由于任何切变矩阵的行列式
4.1.5 Concatenation of Transforms
由于矩阵乘法运算的不可交换性,矩阵计算的顺序是至关重要的。因此变换矩阵的串联是与计算顺序相关的。
作为顺序相关性的示例,考虑以下情况。有两个矩阵
S
和
R
,其中
S(2,0.5,1)表示
使用缩放因子2对
x
分量进行缩放,而
图4.4 演示了矩阵乘法运算的顺序相关性。在上图中,先使用缩放矩阵
S(s)
,其中
s=(2,0.5,1)
,执行缩放再使用旋转矩阵
Rz(π/6)
执行旋转操作。组合矩阵为
S(s)Rz(π/6)
。在下图中,则是执行相反的矩阵乘法操作,产生的组合矩阵为
Rz(π/6)S(s)
。从图中可以明显的看出这两个结果完全不同。一般的,对于任意的矩阵
M
和
N
,都有
MN≠NM
。
把一系列矩阵连接成单个矩阵很显然是为了提高运算效率。例如,假设一个物体包含几千个顶点,你需要对该物体进行缩放,旋转,以及平移。现在,可以把这三个矩阵连接成单个的矩阵,而不是把物体中所有的顶点与这三个矩阵的每一个进行相乘。然后把连接后的单个矩阵应用到所有顶点上即可。这种组合矩阵为 C=TRS 。注意一下这里所使用的乘法顺序:第一个应用于顶点的是缩放矩阵 S ,因此位于组合乘法的最右边。这种乘法顺序表示$mathbf{TRSp}=(mathbf{T}(mathbf{R}(mathbf{Sp})))。
注:在计算机图形学中有时还会见到另一种记号方式,矩阵的最下面一行为平移向量。使用这种表示的情况下,矩阵乘法的顺序完全相反,即执行的顺序是依次从左往右的方式。以这种记号表示的向量和矩阵称为行优先的形式,因为向量以行向量表示。在本书中,我们使用列优先的形式。
值得注意的是,虽然矩阵串联是与乘法顺序相关的,但是可以根据需要把矩阵分组。比如,在使用 TRSp 的情况下,你想要一次计算刚体运动变换矩阵 TR 。可以把这两个矩阵有效的结合起来, (TR)(Sp) ,并使用生成的中间结果替换。因此,矩阵串联是满足结合律的。
4.1.6 The Rigid-Body Transform
当一个人抓住一个固态物体,比如说从桌面上拿起一支笔,并移动到另一个位置,比如放到上衣的口袋里,在些过程中只有物体的方向和位置发生了变化,而物体的形状通常是不会受到影响的。这种仅通过平移和旋转矩阵串联组成的变换操作称为rigid-body transform(刚体变换),并且这种变换还具有的性质是变换时长度,角度和左右手坐标系保持不变。
任意的刚体矩阵 X 可以表示为一个平移矩阵 T(t) 和一个旋转矩阵 R 的串联。因此, X 可以写成公式4.14所示的矩阵:
X 的逆矩阵计算方法为 X−1=(T(t)R)−1=R−1T(t)−1=RTT(−t) 因此逆矩阵的计算,只需要把矩阵 R 左上角区域的 3×3 矩阵进行转置,并改变矩阵 T 的平移值的符号。然后以相反的顺序对这两个新矩阵执行乘法运算,就可以得到逆矩阵。计算 X 的逆矩阵的另一种方法是使用以下的记号表示矩阵 R (使 R 显示为 3×3 的矩阵)和矩阵 X :
其中, 0 是一个元素值全为 0 的
4.1.7 Normal Transform
单个矩阵可以用于对点,线,多边形以及其他的几何形状执行一致的变换。同样的矩阵还可以用于沿着这些直线或在多边形表面上对正切向量(tangent vectors)执行变换操作。但是,该矩阵无法用于对一个重要的几何属性,表面的法向量(还有顶点的光照法线)执行变换。图4.5中使用同一个矩阵对法向量执行变换的结果。
图4.5 左图中是原始的几何形状,一个多边形及该侧面对应的法线。中间的图中显示了在模型沿着
x
-轴缩放0.5倍时,使用同样的矩阵对法线执行变换的结果。右图中显示了法线在使用正确的变换矩阵时得到的结果。
对于法向量的变换,正确的方法是使用变换矩阵的伴随矩阵[156]的转置,而不是与变换矩阵本身相乘。在附录A.3.1节描述了伴随矩阵的计算方法。在这里,伴随矩阵保证总是存在的。而变换后的法向量并不保证总是单位长度,因此通常需要进行规范化。
执行法向量变换操作的传统方法是计算逆矩阵的转置[1277]。这种方法正常情况是可行的。但是,并不需要计算完整的逆矩阵,而且有时候并不存在逆矩阵。逆矩阵是由伴随矩阵除以原始矩阵的行列式得到的。如果行列式为0,该矩阵则为奇异矩阵,不存在逆矩阵。
即使是计算一个完整的
通常情况下,即便是该伴随矩阵的计算也是不需要的。假设变换矩阵完全由一组平移变换,旋转变换和等比例缩放操作(不会拉伸或挤压)的串联矩阵组成。而平移变换不会影响法线,等比例缩放因子只是简单地改变法向量的长度。剩下的就是一系列的旋转变换,这些旋转变换通常会产生某种顺序的单纯变换,不会再有其他的影响。旋转矩阵又被定义为逆矩阵等于矩阵的转置。那么就可以使用逆矩阵的转置对法向量执行变换,通过两次转置矩阵(或两次逆矩阵)变换则可以抵消变换。综上所述,在这些情况下,也可以使用原始的变换矩阵直接对法线执行变换。
最后,不需要总是对变换后的法向量重新进行规范化。如果只是把平移矩阵和旋转矩阵串联在一起,在使用该串联矩阵对法向量执行变换时并不会改变法向量的长度,因此不需要重新进行规范化。如果还串联了等比例缩放矩阵,则可以使用整体的缩放因子(引自4.2.3节)直接对变换后的法向量执行规范化。例如,如果已知所使用的一系列缩放矩阵把物体放大5.2倍,使用该矩阵直接进行变换的法向量,通过除以5.2执行规范化。或者,创建一个将会产生规范化结果的法向量变换矩阵,只需要把原始矩阵左上角的 3×3 分量部分除以该缩放因子。
需要注意的是,如果表面的法向量在变换后是由表面所在的三角形推导计算的(比如,使用三角形两条边的叉乘得到),在这种系统中法向量的变换不再是一个问题了。切向量与法向量具有不同的性质,而且总是通过原始矩阵直接执行变换。
4.1.8 Computation of Inverses
在很多情况下都需要使用逆矩阵,比如在两个坐标系之间来回变换。根据与某个变换相关的可用信息,可以使用下面三种方法之一计算矩阵的逆矩阵。
- 如果矩阵是一个单一的变换或一序列包含给定参数的简单变换,那么该矩阵的逆矩阵可以简单的通过“对参数取反”以及矩阵顺序逆向计算得到。比如,如果 M=T(t)R(ϕ) ,则有 M−1=R(−ϕ)T(−t) 。
- 如果已经矩阵为正交矩阵,则有 M−1=MT ,即矩阵的转置为矩阵的逆。任意的旋转序列依然是一个旋转矩阵,因此还是正交矩阵。
- 如果没有任何特殊的矩阵性质,则使用伴随矩阵方法(附录A的公式A.32),克莱姆法则,LU分解,或者高斯消元法计算逆矩阵(见附录A.3.1节)。一般情况下,最好使用克莱姆法则和高斯消元法,因此这两种方法具有较少的分支操作;在现代GPU架构中最好避免使用“if”测试语句。关于如何使用伴随矩阵对法向量执行逆变换,详见4.1.7节。
在优化时也需要考虑计算逆矩阵的目的。比如,如果逆矩阵是用于执行计算向量的变换,通过只需要计算矩阵左上角 3×3 部分的逆矩阵(详见上一节)。
最后
以上就是勤奋书本为你收集整理的Real-Time Rendering-第四章 Transforms第四章 变换(Transforms)的全部内容,希望文章能够帮你解决Real-Time Rendering-第四章 Transforms第四章 变换(Transforms)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复