第二章 线性

我们学习3D计算机图形学的第一件任务,是理解怎样用坐标系来表示点,以及怎样对这些点实施有用的几何变换。学习线性代数时你可能已经见过类似的内容,但是,在计算机图形学中,我们常常同时使用许多不同的坐标系统,并且同样地,我们需要特别关注这些不同的坐标系统各自起到的作用。最终,我们处理这些基本内容的方式或许也会和线性代数有些不同。

在本章中,我们从向量和线性变换开始。向量用来表示三维运动,而线性变换用来操作向量,例如旋转和缩放。在随后的几章中,我们会了解到仿射(affine)变换,它增加了平移的功能。在第6章之前我们都不会进入到实际的编程中。我们会先仔细理解相应的原理,这样在随后开始编程时,实现我们想要的功能就会更容易。

2.1 几何体类型

假想一些真实世界中的几何点。这样的点在三维空间中可以用三个实数来表示,

[xyz]\left[ \begin{array}{c} x \\ y \\ z \end{array}\right]

我们称之为坐标系向量(coordinate vector)。这些数用于表示某点的位置,它与某个默认坐标系统(coordinate system)相关,该坐标系统有默认的原点和方向。如果我们需要改变默认坐标系统,我们就会需要用不同的数字,不同的坐标系向量,来描述同样一个点。所以,为了指明一个点的实际位置,我们同时需要一个坐标系统和一个坐标系向量。这样我们就必须非常小心区分以下概念:坐标系统,坐标系向量和几何点。

我们从四种类型的数据开始,每种类型有它自己的表示符号(图2.1)。

  • 点(point):用带有波浪线的字母 p~\tilde{p} 表示,这是一个几何点,而不是数值对象。

  • 向量(vector):用上方带有箭头的字母 v\vec{\mathbf{v}} 表示。这也是一个非数值对象。我们在第3章会更详细的解释向量和点的区别。它们最主要的区别是点代表位置,而向量代表点与点之间的位移。

  • 坐标系向量(coordinate vector):由粗体字母 c\mathbf{c} 表示,坐标系向量是一个由实数组成的数值对象。

  • 坐标系统(coordinate system):(它由一组向量组成,因此也不是数值对象)表示为 ft\vec{\mathbf{f}}^t ,由粗体字母、箭头和上标 t 表示。(我们用粗体来表示垂直方向上的集合,上标 t 将它转换为一个水平方向的集合,而箭头告诉我们它是一个向量的集合而非数值的。)实际上,有两种坐标系统,向量基(basis)用来描述向量,坐标系(frame)用来描述点。我们使用同一个符号,利用上下文来区分它们。

在下面以及随后的章节中,我们会定义所有的对象类型,以及可以对它们进行的操作。当思考如何操作几何体时,我们会极大的依靠符号来完成数值的(坐标系向量)和非数值的(向量和坐标系统)对象计算。我们只有预先建立好所有必须的惯例,到了第5章才能够放下非数值对象,而使用其数值部分在计算机代码中完成计算。

2.2 向量,坐标系向量和向量基

首先,我们要清晰的区分向量和坐标系向量。在本书中,向量总是抽象的几何实体用以表示世界中两个点之间的位移。例如“向东一英里”。坐标系向量是在我们有一个默认坐标系统时,用于表示向量的一组实数。

正式来说,一个向量空间V是一系列满足特定规则的$\vec{v}$元素。特别是,需要定义一个加法运算,将两个向量映射到第三个上。也还需要定义一个乘法,将实数标量乘以一个向量来得到另一个向量。

要得到一个有效的向量空间,还需要遵守一些其他的规则,我们不会在此很详细的展开描述。 例如,加法运算需要符合结合律和交换律。 再例如,标量乘法必须符合分配率

α(v+w)=αv+αw\alpha(\vec{v}+\vec{w}) = \alpha\vec{v} + \alpha\vec{w}

等等[40]。

有很多对象类型都符合向量空间的结构。 但是在本书中,我们仅将注意力放在某一类向量空间上:它由实际的几何体点之间发生的实际运动所构成。特别是,我们不会将向量看做三个数的集合。

一个坐标系统,或者向量基,是一小组向量,通过向量运算可以利用它来产生整个向量集合。(更正式一点,我们说一组向量b1bn\vec{b}1\cdots\vec{b}_n是线性相关的,如果存在非零的标量α1αn\alpha_1\cdots\alpha_n使得iaibi=0\sum{i}a_i\vec{b}_i = 0。如果一组向量不是线性相关的,那我们可以称它为非线性相关。如果b1bn\vec{b}_1\cdots\vec{b}_n 非线性相关,并且可以通过加法和标量乘法产生出完整的向量空间VV,那么集合bi\vec{b}_i称作VV的向量基,并且我们说nn表示该基/空间的维度。)对于空间中的任意运动,它的维度为3.我们也会把每一个向量基称为轴向(axis),我们会称第一个轴向为xx,第二个轴向为yy,第三个轴向为zz

我们可以使用一组向量基来生成空间中的任意向量。可以用一组唯一的坐标系向量cic_i表示如下。

v=icibi\vec{v}=\sum_ic_i\vec{b}_i

也可以使用向量代数符号将其写作

上述公式最右侧的表达式使用了线性代数中标准的矩阵乘法。其中,每个$c_i\vec{b}_i$表示一个实数标量与抽象向量相乘。我们可以使用速记符号将其写作

v=btc\vec{v}=\vec{\mathbf{b}}^t \mathbf{c}

其中v\vec{v}是向量,bt\vec{\mathbf{b}^t}是一行向量基,而c\mathbf{c}是(列)坐标系向量。

2.3 线性变换与3x3矩阵

一个线性变换L\mathcal{L}即是从VVVV的变换,它满足以下两个属性:

我们使用符号vL(v)\vec{v}\Rightarrow\mathcal{L}(\vec{v})来表示向量v\vec{v}通过L\mathcal{L}变换为L(v)\mathcal{L}(\vec{v})

线性变换恰恰可以用矩阵来表示。这是因为,线性变换可以通过它对向量基产生的影响来表示。下面是它的原理:

上述的两个线性属性隐含了以下关系

vL(v)=L(icibi)=iciL(bi)\vec{v}\Rightarrow\mathcal{L}(\vec{v})=\mathcal{L} \left( \sum_{i}c_i\vec{b}_i \right)=\sum_{i}c_i\mathcal{L}(\vec{b}_i)

我们可以将公式(2.1)以线性代数符号的形式写作

[b1b2b3][c1c2c3][L(b1)L(b2)L(b3)][c1c2c3]\left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \quad \vec{b}_3 \end{array} \right] \left[ \begin{array}{c} c_1 \\ c_2 \\ c_3 \end{array} \right] \Rightarrow \left[ \begin{array}{ccc} \mathcal{L}(\vec{b}_1) \quad \mathcal{L}(\vec{b}_2) \quad \mathcal{L}(\vec{b}_3) \end{array} \right] \left[ \begin{array}{c} c_1 \\ c_2 \\ c_3 \end{array} \right]

L(bi)\mathcal{L}(\vec{b}i)三个维度的向量中,每个单独的新向量自身也是VV中的元素,并且每个向量都最终都可以写作原始向量基的某种线性组合。例如,有了恰当的Mj,1M_{j,1}它可以写作

L(b1)=[b1b2b3][M1.1M2.1M3.1]\mathcal{L}(\vec{b}_1)= \left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \quad \vec{b}_3 \end{array} \right] \left[ \begin{array}{c} M_{1.1} \\ M_{2.1} \\ M_{3.1} \end{array} \right]

对向量基中所有的基向量进行同样的变换,我们就得到了

其中MM由 9 个恰当的实数组成。

将这些内容组合起来,我们可以看出,对于向量进行线性变换的操作可以表示为:

[b1b2b3][c1c2c3] \left[ \begin{array}{ccc} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 \end{array} \right] \left[ \begin{array}{c} c_1 \\ c_2 \\ c_3 \end{array} \right]

[b1b2b3][M1.1M1.2M1.3M2.1M2.2M2.3M3.1M3.2M3.3][c1c2c3] \Rightarrow \left[ \begin{array}{ccc} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 \end{array} \right] \left[ \begin{matrix} M_{1.1} & M_{1.2} & M_{1.3} \\ M_{2.1} & M_{2.2} & M_{2.3} \\ M_{3.1} & M_{3.2} & M_{3.3} \end{matrix} \right] \left[ \begin{array}{c} c_1 \\ c_2 \\ c_3 \end{array} \right]

总而言之,我们可以使用矩阵将一个向量变换为另一个

btcbtMc\vec{\mathbf{b}}^t\mathbf{c}\Rightarrow\vec{\mathbf{b}}^tM\mathbf{c}

(见图2.2)。

如果我们对一组向量基中的每个向量进行变换,我们会得到新的基。这可以表示为

[b1b2b3][b1b2b3][M1.1M1.2M1.3M2.1M2.2M2.3M3.1M3.2M3.3] \left[ \begin{array}{ccc} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 \end{array} \right] \Rightarrow \left[ \begin{array}{ccc} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 \end{array} \right] \left[ \begin{matrix} M_{1.1} & M_{1.2} & M_{1.3} \\ M_{2.1} & M_{2.2} & M_{2.3} \\ M_{3.1} & M_{3.2} & M_{3.3} \end{matrix} \right]

或者,简写为

btbtM\vec{\mathbf{b}}^t \Rightarrow \vec{\mathbf{b}}^tM

(见图2.3)。

图2.2:经过线性变换的向量v=btcbtMc\vec{v}=\vec{\mathbf{b}}^t\mathbf{c}\Rightarrow\vec{\mathbf{b}}^tM\mathbf{c}。矩阵M与线性变换的具体内容相关。

图2.3:经过线性变换的向量基btbtM\vec{\mathbf{b}}^t\Rightarrow\vec{\mathbf{b}}^tM

以及当然,矩阵也可以和坐标系向量相乘,

cMc\mathbf{c}\Rightarrow M\mathbf{c}

2.3.1 单位矩阵与逆矩阵

单位变换(identity map)不改变任何向量。它的对应矩阵是单位矩阵(identity matrix)

I=[100010001] I = \left[ \begin{matrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{matrix} \right]

矩阵MM的逆M1M^{-1}是唯一的,具有属性MM1=M1M=IMM^{-1}=M^{-1}M=I。它表示对向量进行逆向变换。如果一个线性变换恰好会使得多个输入向量变换为同样的输出向量,则该变换不可逆,而它的相关矩阵也没有逆。在计算机图形学中,当选择一个3D到3D的线性变换来在空间中移动对象(包括缩放),很少会有需要用到不可逆变换。因此,除非有特殊说明,在本书中用到的所有矩阵都是可逆的。

2.3.2 矩阵用于变换向量基

除了用来描述变换(\Rightarrow),矩阵也可以用来描述一组基或向量间的相等关系(==)。尤其是,在等式(2.2)中,我们可以看到以下形式的表达式

这表达了向量基at\vec{\mathbf{a}}^tbt\vec{\mathbf{b}}^t之间的相等关系。

假设一个向量在一个特定的向量基内用一个特定的坐标系向量表示: v=btc\vec{v}=\vec{\mathbf{b}}^t\mathbf{c}。那么给定等式(2.3),则有

v=btc=atM1c \vec{v} = \vec{\mathbf{b}}^t\mathbf{c} = \vec{\mathbf{a}}^tM^{-1}\mathbf{c}

这并非是一个变换(否则会用到\Rightarrow符号),而是一个等式(使用了==符号)。我们简单的用两个向量基写出了同一个向量。坐标系向量c\mathbf{c}b\vec{\mathbf{b}}下描述了向量v\vec{v},而坐标系向量M1cM^{-1}\mathbf{c}a\vec{\mathbf{a}}下描述了同一个向量v\vec{v}

2.4 其他结构

3D空间中的向量也可以进行点乘操作

vw\vec{v}\cdot\vec{w}

它接收两个输入向量,返回一个实数值。点乘使得我们能够定义一个向量平方的长度(也叫做 squared norm)

v2:=vv|\vec{v}|^2:=\vec{v}\cdot \vec{v}

点乘结果与两向量间的夹角θ[0π]\theta\in[0\cdots\pi]关系为

cos(θ)=vwvw\cos(\theta)=\dfrac{\vec{v}\cdot\vec{w}}{\left \| \vec{v} \right \| \left \| \vec{w} \right \| }

vw=0\vec{v}\cdot\vec{w}=0时,我们说两向量垂直。

当一组向量基的向量都为单位长度,且两两相互垂直时,我们说它是一组正交向量基。

在一组正交基bt\vec{\mathbf{b}}^t中,很容易计算两个向量(btc)(btd)(\vec{\mathbf{b}}^t\mathbf{c})\cdot(\vec{\mathbf{b}}^t\mathbf{d})的点乘。我们有

其中第二行我们使用了点乘是双线性操作符的性质,而第三行依据了向量基的正交性。

当一组二维向量基的第二个向量基可以通过将第一个向量基逆时针旋转 90 度得到时,我们说这组二维正交基是右手性(right handed)的(在这里向量基的顺序非常重要)。

当三个向量基(有序的)按照图 2.4 的方式排列时,我们说该组三维向量基是右手性的,与图 2.5 相反。摊开右手,用手指指向第一个向量基,将手指向第二个向量基方向弯曲,此时你的大拇指将会指向第三个向量基方向。

在三维中,我们还有叉乘操作,输入两个向量,输出一个向量,定义为

v×w:=vwsin(θ)n \vec{v}\times\vec{w}:=\|\vec{v}\|\|\vec{w}\|\sin(\theta)\vec{n}

其中n\vec{n}是与由v\vec{v}w\vec{w}组成的平面垂直的单位向量,因此[v,w,n][\vec{v},\vec{w},\vec{n}]组成了一个右手坐标系。

在一个右手正交向量基bt\vec{\mathbf{b}}^t中,计算两个向量(btc)×(btd)(\vec{\mathbf{b}}^t\mathbf{c})\times(\vec{\mathbf{b}}^t\mathbf{d})的叉乘是很容易的。特别是,它在向量基bt\vec{\mathbf{b}}^t下的坐标系向量可以如下计算

[c2d3c3d2c3d1c1d3c1d2c2d1] \left[ \begin{array}{c} c_2d_3-c_3d_2 \\ c_3d_1-c_1d_3 \\ c_1d_2-c_2d_1 \end{array} \right]

2.5 旋转

我们最经常遇到的线性变换是旋转。旋转在保持向量间点乘关系不变的同时,将一组右手性向量基映射到另一组右手性向量基上。因此特别的,对一组右手性的正交向量基进行旋转总是会得到另一组正交向量基。在 3D 中,旋转总是由一个固定的旋转轴,和绕着该轴旋转的角度组成。

我们从描述 2D 中的旋转开始。以一个向量入手。

v=[b1b2][xy] \vec{v} = \left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \end{array} \right] \left[ \begin{array}{c} x \\ y \end{array} \right]

我们假定bt\vec{b}^t是一个2D右手性正交向量基。假设我们希望将向量v\vec{v}围绕原点逆时针旋转θ\theta角度:该向量旋转后的坐标系向量[x,y]t[x^\prime, y^\prime]^t可以如下计算

这个线性变换可以写作如下矩阵形式:

[b1b2][xy]\left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \end{array} \right] \left[ \begin{array}{c} x \\ y \end{array} \right]

[b1b2][cosθsinθsinθcosθ][xy] \Rightarrow \left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \end{array} \right] \left[ \begin{matrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \\ \end{matrix} \right] \left[ \begin{array}{c} x \\ y \end{array} \right]

同样,我们可以旋转整个向量基

[b1b2] \left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \end{array} \right]

[b1b2][cosθsinθsinθcosθ] \Rightarrow \left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \end{array} \right] \left[ \begin{matrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \\ \end{matrix} \right]

对于 3D 中的情况,也先假定我们使用一个右手性正交坐标系统。那么,一个向量围绕着 z 轴旋转θ\theta度就可以表示为

[b1b2b3][xyz] \left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \quad \vec{b}_3 \end{array} \right] \left[ \begin{array}{c} x \\ y \\ z \end{array} \right]

[b1b2b3][cs0sc0001][xyz] \Rightarrow \left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \quad \vec{b}_3 \end{array} \right] \left[ \begin{matrix} c & -s & 0 \\ s & c & 0 \\ 0 & 0 & 1 \end{matrix} \right] \left[ \begin{array}{c} x \\ y \\ z \end{array} \right]

其中,为了简便,我们使用符号c:=cosθc: =\cos\theta以及s:=sinθs: =\sin\theta。与预期相符,这一变换保持位于第三个轴上的向量不变。在任何 z 值为常量的平面中,该变换与我们刚刚描述的 2D 旋转相同。旋转方向可以用以下的方式来视觉化:用右手握住 z 轴,底部朝向z=0z=0平面;旋转的正方向即为手指弯曲的方向。

一个向量基围绕着x轴的旋转可以如下计算

[b1b2b3][xyz] \left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \quad \vec{b}_3 \end{array} \right] \left[ \begin{array}{c} x \\ y \\ z \end{array} \right]

[b1b2b3][1000cs0sc][xyz] \Rightarrow \left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \quad \vec{b}_3 \end{array} \right] \left[ \begin{matrix} 1 & 0 & 0 \\ 0 & c & -s \\ 0 & s & c \end{matrix} \right] \left[ \begin{array}{c} x \\ y \\ z \end{array} \right]

同样,旋转方向也可以通过以下方式视觉化:用右手握住 x 轴,底部朝向x=0x=0平面;旋转的正方向即为手指弯曲的方向(图2.4)。

围绕着y轴的旋转可以用以下矩阵完成

[c0s010s0c] \left[ \begin{matrix} c & 0 & s \\ 0 & 1 & 0 \\ -s & 0 & c \end{matrix} \right]

在某种意义上,通过这些轴向就可以完成 3D 中的任何旋转。首先,这些旋转的组合是另一个旋转。同时,可以看出通过指定 x,y 和 z 旋转我们可以达成任意的旋转。三个轴旋转的角度被称作xyz-欧拉角(xyz-Euler angles)。欧拉角可以通过一的平衡环来想象,有三个可动轴,可以通过三个参数决定要达成的旋转(图2.6)。

一种更直接的表示某一任意旋转的方式,是选取任意单位向量k\vec{k}作为旋转轴(axis of rotation)并直接沿该轴向旋转θ\theta角度。坐标系向量k\vec{k}由单位坐标系向量[kx,ky,kz]t[k_x,k_y,k_z]^t给出。那么,该旋转可以通过以下矩阵来表示

其中,为了简写,我们引入了标记v:=1cv:= 1-c。反过来考虑,任意旋转矩阵都可以写作这个形式。

我们注意到 3D 旋转表现出某种复杂的形式。两个围绕着不同轴的旋转不满足交换律。此外,将沿着两个不同轴向的旋转组合时,我们得到的是一个沿着第三个轴向的旋转!

在本书的随后章节,我们会引入四元数来表示旋转,用于在不同的旋转方位间产生平滑的过度动画。

2.6 缩放

对几何体进行建模时,我们需要对向量和向量基进行缩放。为了将任意向量以系数α\alpha缩放,我们可以使用

[b1b2b3][xyz] \left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \quad \vec{b}_3 \end{array} \right] \left[ \begin{array}{c} x \\ y \\ z \end{array} \right]

[b1b2b3][α000α000α][xyz] \Rightarrow \left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \quad \vec{b}_3 \end{array} \right] \left[ \begin{matrix} \alpha & 0 & 0 \\ 0 & \alpha & 0 \\ 0 & 0 & \alpha \end{matrix} \right] \left[ \begin{array}{c} x \\ y \\ z \end{array} \right]

想要沿着三个轴向进行不同的缩放,我们可以使用更通用的形式

[b1b2b3][xyz]\left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \quad \vec{b}_3 \end{array} \right] \left[ \begin{array}{c} x \\ y \\ z \end{array} \right]

[b1b2b3][α000β000γ][xyz] \Rightarrow \left[ \begin{array}{ccc} \vec{b}_1 \quad \vec{b}_2 \quad \vec{b}_3 \end{array} \right] \left[ \begin{matrix} \alpha & 0 & 0 \\ 0 & \beta & 0 \\ 0 & 0 & \gamma \end{matrix} \right] \left[ \begin{array}{c} x \\ y \\ z \end{array} \right]

这种类型的操作在建模中很有用,例如,当我们知道如何建立球体模型时,即可利用这种不均匀缩放建立椭圆体模型。

练习

2.1 在我们的符号体系当中,以下哪些是合法的表达式,如果合法,它的返回值类型是什么?

btM,cM,M1c,btNM1c\vec{\mathbf{b}}^tM, \mathbf{c}M, M^{-1}\mathbf{c}, \mathbf{b}^tNM^{-1}\mathbf{c}

2.2 对于给定at=btM\vec{\mathbf{a}}^t=\vec{\mathbf{b}}^tM,向量btNc\vec{\mathbf{b}}^tN\mathbf{c}在向量基at\vec{\mathbf{a}}^t下的坐标系向量是什么?

2.3 0\vec{0}是零向量,对于任意线性变换L\mathcal{L}L(0)\mathcal{L}(\vec{0})是什么?

2.4 T(v)\mathcal{T}(\vec{v})是一个将特定非零向量k\vec{k}v\vec{v}相加的变换:T(v)=v+k\mathcal{T}(\vec{v})=\vec{v}+\vec{k}。那么T\mathcal{T}是否为线性变换?

Last updated