# 第三章 仿射

## 3.1 点与坐标系

将点与向量作为两种不同的类型来思考很有帮助。点是在几何体世界中的某个固定的位置，而向量则描述两点间的运动。我们会使用两种不同符号来区分点和向量。向量$$\vec{v}$$顶部有一个箭头，而点$$\tilde{p}$$顶部则有波浪线。

如果我们将向量看作两点间的运动，那么向量运算（加，以及与标量的乘法）就有了明显的意义。如果我们将两向量相加，我们表示的是两个运动的连接。如果我们将向量与标量相乘，我们是将该运动以一定系数增大或减小。零向量是一个特殊的表示没有运动的向量。

这些运算对点来说并没有太多意义。将两个点相加应该得到什么结果（例如，将哈佛广场与肯德尔广场相加）？将点与标量乘应该意味着什么？用 7 乘以南极点应该意味着什么？存在着一个与其他点不同的零点吗？

有一种两点间的运算确实具有某些层面的意义：减法。当我们将一个点与另一个点相减时，我们应该得到从第二个点到第一个点的向量，

$$\tilde{p}-\tilde{q}=\vec{v}$$

相反，如果我们从一个点开始，沿着某一向量运动，我们应该得到另一个点

$$\tilde{p}+\vec{v}=\tilde{p}$$

对点进行线性变换是有意义的。例如，我们可以将一点绕着某一固定原点旋转。对于点，位移也是有意义的操作（位移的概念对向量没有意义）。为了表示位移，我们需要使用*仿射变换（affine transform）*&#x8FD9;一概念。为了实现它，我们需要 4x4 的矩阵。4x4 矩阵不仅仅有助于在这里处理仿射变换，随后我们描述摄影机投影运算时也很有用（见第10章）。

#### 3.1.1 坐标系

在仿射空间中，我们这样描述一个点，从某一原点$$\tilde{o}$$开始，再将它与向量的线性组合相加。该向量由一组向量基和坐标系向量$$\vec{c\_i}$$表示\
$$\tilde{p}=\tilde{o}+\sum\_ic\_i\vec{b}\_i=  	\left\[ \begin{matrix} 	\vec{b}\_1 & \vec{b}\_2 & \vec{b}\_3 & \tilde{o} 	\end{matrix} \right] 	\left\[ \begin{matrix} 	c\_1 \ c\_2 \ c\_3 \ 1 	\end{matrix} \right] 	= \vec{\mathbf{f}}^t\mathbf{c}$$，

其中$$1\tilde{o}$$定义为$$\tilde{o}$$。

横向的行

$$\left\[  	\begin{matrix} 	\vec{b}\_1 & \vec{b}\_2 & \vec{b}\_3 & \tilde{o} 	\end{matrix} \right]  	= \vec{\mathbf{f}}^t$$

称为一个*仿射坐标系（affine frame）*；它与向量基相似，但由三个向量和一个点组成。

用坐标系来指定一个点时，我们使用一组 4 项的坐标系向量，其中最后一项总是为 1。用坐标系来表示一个向量时，我们使用最后一项为 0 的坐标系向量（也就是说，它是向量基的组合）。使用含有 4 个项的坐标系向量来表示几何体（以及 4x4 矩阵）也会在第 10 章我们研究针孔相机模型的时候派上用场。

## 3.2 仿射变换与4乘4矩阵

与线性变换的情况相同，我们会在坐标系向量与坐标系之间放置一个合适的矩阵，以此来定义作用于点的仿射变换的概念。

我们来定义一个4乘4矩阵形式的仿射矩阵（affine matrix）

$$\left\[ \begin{matrix} 	a & b & c & d \ 	e & f & g & h \ 	i & j & k & l \ 	0 & 0 & 0 & 1 	\end{matrix} \right]$$

用以下方式对点$$\tilde{p}=\vec{\mathbf{f}}^t\mathbf{c}$$进行仿射变换：

$$\left\[ \begin{matrix} 	\vec{b}\_1 & \vec{b}\_2 & \vec{b}\_3 & \tilde{o} 	\end{matrix} \right]  	\left\[ \begin{matrix} 	c\_1 \ c\_2 \ c\_3 \ 1 	\end{matrix} \right]$$

$$\Rightarrow 	\left\[ \begin{matrix} 	\vec{b}\_1 & \vec{b}\_2 & \vec{b}\_3 & \tilde{o} 	\end{matrix} \right] 	\left\[ \begin{matrix} 	a & b & c & d \ 	e & f & g & h \ 	i & j & k & l \ 	0 & 0 & 0 & 1 	\end{matrix} \right] 	\left\[ \begin{matrix} 	c\_1 \ c\_2 \ c\_3 \ 1 	\end{matrix} \right]$$

或者简写为

$$\vec{\mathbf{f}}^t\mathbf{c} 	\Rightarrow\vec{\mathbf{f}}^tA\mathbf{c}$$。

我们可以验证上面公式的第二行描述了一个合法的点，根据乘法

$$\left\[ \begin{matrix} 	x^{\prime} \ y^{\prime} \ z^{\prime} \ 1 	\end{matrix} \right] = 	\left\[ \begin{matrix} 	a & b & c & d \ 	e & f & g & h \ 	i & j & k & l \ 	0 & 0 & 0 & 1 	\end{matrix} \right] 	\left\[ \begin{matrix} 	x \ y \ z \ 1 	\end{matrix} \right]$$

我们得到了一个 4 项的向量，其中第 4 项为 1 。此外，我们可以看到

$$\left\[ \begin{matrix} 	\vec{b}\_1^\prime & \vec{b}\_2^\prime & \vec{b}\_3^\prime & \tilde{o}^\prime 	\end{matrix} \right] 	= 	\left\[ \begin{matrix} 	\vec{b}\_1 & \vec{b}\_2 & \vec{b}\_3 & \tilde{o} 	\end{matrix} \right] 	\left\[ \begin{matrix} 	a & b & c & d \ 	e & f & g & h \ 	i & j & k & l \ 	0 & 0 & 0 & 1 	\end{matrix} \right]$$，

其中$$0\tilde{o}$$定义为$$\vec{0}$$，我们得到了一个由3个向量和一个点组成的坐标系。

同样需要注意，如果矩阵的最后一行不是$$\[0,0,0,1]$$，那它通常会给我们一个非法的结果。

与线性变换相似，我们可以对坐标系进行仿射变换

$$\left\[ \begin{matrix} 	\vec{b}\_1 & \vec{b}\_2 & \vec{b}\_3 & \tilde{o} 	\end{matrix} \right] 	\Rightarrow 	\left\[ \begin{matrix} 	\vec{b}\_1 & \vec{b}\_2 & \vec{b}\_3 & \tilde{o} 	\end{matrix} \right] 	\left\[ \begin{matrix} 	a & b & c & d \ 	e & f & g & h \ 	i & j & k & l \ 	0 & 0 & 0 & 1 	\end{matrix} \right] 	\left\[ \begin{matrix} 	c\_1 \ c\_2 \ c\_3 \ 1 	\end{matrix} \right]$$，

或者简写为

$$\vec{\mathbf{f}}^t 	\Rightarrow\vec{\mathbf{f}}^tA$$。

## 3.3 对点进行线性变换

假设我们有一个表示一个线性变换的 3x3 矩阵。我们可以将它嵌入到 4x4 矩阵的左上角，并使用这个更大的矩阵来对点（或坐标系）进行变换：

$$\left\[ \begin{matrix} 	\vec{b}\_1 & \vec{b}\_2 & \vec{b}\_3 & \tilde{o} 	\end{matrix} \right]  	\left\[ \begin{matrix} 	c\_1 \ c\_2 \ c\_3 \ 1 	\end{matrix} \right]$$

$$\Rightarrow 	\left\[ \begin{matrix} 	\vec{b}\_1 & \vec{b}\_2 & \vec{b}\_3 & \tilde{o} 	\end{matrix} \right] 	\left\[ \begin{matrix} 	a & b & c & 0 \ 	e & f & g & 0 \ 	i & j & k & 0 \ 	0 & 0 & 0 & 1 	\end{matrix} \right] 	\left\[ \begin{matrix} 	c\_1 \ c\_2 \ c\_3 \ 1 	\end{matrix} \right]$$

这一变换与线性变换对$$c\_i$$有同样的效果。如果我们将点$$\tilde{p}$$看作从原点$$\tilde{o}$$偏移了向量$$\vec{v}$$，我们可以看出这一变换与对该向量进行线性变换具有同样的效果。所以，例如，如果该 3x3 矩阵是一个旋转矩阵，则这一线性变换会将该点绕着原点旋转（图3.1）。我们将会在第 4 章中看到，当对点进行线性变换时坐标系原点的位置会起到很重要的作用。

我们使用以下简写方式来描述只进行线性变换的 4x4 矩阵：

$$L =  	\left\[ \begin{matrix} 	l & 0 \ 	0 & 1 \ 	\end{matrix} \right]$$，

其中$$L$$是一个 4x4 矩阵，$$l$$是一个 3x3 矩阵，右上角的 0 是一个由 0 组成的 3x1 矩阵，左下角的 0 是一个由 0 组成的 1x3 矩阵，而右下角的 1 是一个标量。

![对一个点进行线性变换。由对从原点出发到该点的向量进行线性变换来完成。](https://3079340014-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MR9b16cwt_hvqTAbEF_%2F-MRAg5ixzu3P_wdnWL4l%2F-MRBBlEsCwb_ks9l9NbY%2FFigure_3-1.jpg?alt=media\&token=e37dc570-ee30-4364-aed0-59b0bbb59148)

## 3.4 位移

对点的位移操作非常有用。这一变换不是线性的（见练习2.4）。仿射变换主要的新功能就在于，它能够表示位移。特别是，如果我们进行以下变换

$$\left\[ \begin{matrix} 	\vec{b}\_1 & \vec{b}\_2 & \vec{b}\_3 & \tilde{o} 	\end{matrix} \right]  	\left\[ \begin{matrix} 	c\_1 \ c\_2 \ c\_3 \ 1 	\end{matrix} \right]$$

$$\Rightarrow 	\left\[ \begin{matrix} 	\vec{b}\_1 & \vec{b}\_2 & \vec{b}\_3 & \tilde{o} 	\end{matrix} \right] 	\left\[ \begin{matrix} 	1 & 0 & 0 & t\_x \ 	0 & 1 & 0 & t\_y \ 	0 & 0 & 1 & t\_z \ 	0 & 0 & 0 & 1 	\end{matrix} \right] 	\left\[ \begin{matrix} 	c\_1 \ c\_2 \ c\_3 \ 1 	\end{matrix} \right]$$，

我们可以看出它对坐标系向量造成的影响为

$$c\_1 \Rightarrow c\_1 + t\_x \ 	c\_2 \Rightarrow c\_2 + t\_y \ 	c\_3 \Rightarrow c\_3 + t\_z$$

对于位移，我们使用以下方式简写

$$T =  	\left\[ \begin{matrix} 	i & t \ 	0 & 1 \ 	\end{matrix} \right]$$，

其中$$T$$是一个 4x4 矩阵，$$i$$是一个 3x3 单位矩阵，右上角的$$t$$是一个表示位移的 3x1 矩阵，左下角的 0 是一个由 0 组成的 1x3 矩阵，而右下角的 1 是一个标量。

注意，如果$$\mathbf{c}$$的第 4 项为 0，那么它表示向量而不是一个点，那么它就不会受到位移的影响。

## 3.5 综合所有要素

任意仿射矩阵都可以被分解为一个线性部分和一个位移部分：

$$\left\[ \begin{matrix} 	a & b & c & d \ 	e & f & g & h \ 	i & j & k & l \ 	0 & 0 & 0 & 1 	\end{matrix} \right] 	= 	\left\[ \begin{matrix} 	1 & 0 & 0 & d \ 	0 & 1 & 0 & h \ 	0 & 0 & 1 & l \ 	0 & 0 & 0 & 1 	\end{matrix} \right] 	\left\[ \begin{matrix} 	a & b & c & 0 \ 	e & f & g & 0 \ 	i & j & k & 0 \ 	0 & 0 & 0 & 1 	\end{matrix} \right]$$，

或者简写为

$$\begin{eqnarray}  \left\[ \begin{matrix} 	l & t \ 	0 & 1 \ 	\end{matrix} \right] 	 &=& 	\left\[ \begin{matrix} 	i & t \ 	0 & 1 \ 	\end{matrix} \right] 	\left\[ \begin{matrix} 	l & 0 \ 	0 & 1 \ 	\end{matrix} \right] \tag{3.1} \ A &=& TL \tag{3.2} \end{eqnarray}$$

注意矩阵相乘是不满足互易性的，$$TL$$相乘的顺序有意义，一个仿射矩阵也可以用另一个位移矩阵$$T^\prime$$被分解为$$A=LT^\prime$$，但我们不会使用这个形式。

如果$$L$$，即$$A$$的线性部分，其内容为旋转，我们将其写作$$A=TR \tag{3.3}$$

在这个情况中，我们将矩阵$$A$$称作一个*刚体矩阵（rigid body matrix）*，它所进行的变换称为*刚体变换（rigid body transformation）*，或 RBT。一个刚体变换保持了向量间的点乘关系，向量基的手性信息，以及点与点之间的距离关系。

## 3.6 法线

在计算机图形学中，我们常常使用表面的法线信息来决定表面上的一个点应当如何被着色。因此，我们需要了解当表面上的点发生由矩阵$$A$$所描述的仿射变换时，表面的法线会如何变化。

有人会猜测我们可以将法线坐标系简单的与$$A$$相乘。例如，当我们旋转几何体时，法线会以同样的方式旋转。但是使用矩阵$$A$$，事实上，并不总是正确。例如，如图 3.2 所示，我们沿着$$y$$轴方向挤压一个球体。在此情况中，实际上法线被沿着$$y$$方向拉伸而不是挤压。在这里，我们需要在所有情况下都能适用的正确变换。

让我们定义一个光滑表面上某一点的法线（normal）为一个向量，垂直于表面在该点处的切线平面。切线平面是由在该表面上接近（无穷小）的点相减得到的向量来定义的，由此，我们得到了

![](https://3079340014-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MR9b16cwt_hvqTAbEF_%2F-MRAg5ixzu3P_wdnWL4l%2F-MRBBp2mE3VxArBt7bxK%2FFigure_3-2.jpg?alt=media\&token=0a228d07-2e12-4dd7-aac1-70e9f71fa999)

**图3.2** 左：有色形状和黑色的法线。中：形状在$$y$$方向上被减小，并且(未被归一化的)法线在$$y$$方向被拉伸。右：法线被重新校正为对挤压后形状来说正确的单位法线。

$$\vec{n}\cdot(\tilde{p\_1}-\tilde{p\_0})=0$$

对于法线$$\vec{n}$$和两个在表面上非常近的点$$\tilde{p\_1}$$和$$\tilde{p\_0}$$。在某些固定的正交坐标系统当中，它可以被表示为

$$\left\[ \begin{matrix} 	nx & ny & nz & \* 	\end{matrix} \right] 	\left( \left\[ \begin{matrix} 	x1 \ y1 \ z1 \ 1 	\end{matrix} \right] 	- 	\left\[ \begin{matrix} 	x0 \ y0 \ z0 \ 1 	\end{matrix} \right] \right) 	=0 \tag{3.4}$$

我们在第4项使用"\*"，因为它会与 0 相乘因而无关紧要。

假设我们使用一个仿射矩阵$$A$$来对我们所有的点进行仿射变换。那么什么向量对于所有切线向量都保持垂直呢？我们将等式（3.4）重写为

$$\left( \left\[ \begin{matrix} 	nx & ny & nz & \* 	\end{matrix} \right] A^{-1} \right) 	\left( A 	\left( \left\[ \begin{matrix} 	x1 \ y1 \ z1 \ 1 	\end{matrix} \right] 	- 	\left\[ \begin{matrix} 	x0 \ y0 \ z0 \ 1 	\end{matrix} \right] \right) \right) 	=0$$，

如果我们定义$$\[x^\prime,y^\prime,z^\prime,1]^t=A\[x,y,z,1]^t$$为一个变换后点的坐标系向量，并且让$$\[nx^\prime,ny^\prime,nz^\prime,\*]=\[nx,ny,nz,1]A^{-1}$$，那么我们有

$$\left\[ \begin{matrix} 	nx^\prime & ny^\prime & nz^\prime & \* 	\end{matrix} \right] 	\left( \left\[ \begin{matrix} 	x1^\prime \ y1^\prime \ z1^\prime \ 1 	\end{matrix} \right] 	- 	\left\[ \begin{matrix} 	x0^\prime \ y0^\prime \ z0^\prime \ 1 	\end{matrix} \right] \right) 	=0$$，

由此我们可以看出$$\[nx^\prime,ny^\prime,nz^\prime]^t$$是几何形体变换后法线的坐标系向量（由缩放决定）。

注意，我们不关心"\*"处的取值，因此我们也不关心$$A^{-1}$$的第 4 列。同时，$$A$$是一个仿射矩阵，因此$$A^{-1}$$也是，由此得出余下 3 列的第 4 行全部为 0 可以安全的被忽略。因此，使用简写

$$A =  	\left\[ \begin{matrix} 	l & t \ 	0 & 1 	\end{matrix} \right]$$，

我们可以看出

$$\left\[ \begin{matrix} 	nx\prime & ny\prime & nz\prime  	\end{matrix} \right] 	= 	\left\[ \begin{matrix} 	nx & ny & nz  	\end{matrix} \right] 	l^{-1}$$，

并将整个表达式转置，我们就得到了

$$\left\[ \begin{matrix} 	nx^\prime \ ny^\prime \ nz^\prime  	\end{matrix} \right] 	= l^{-1} 	\left\[ \begin{matrix} 	nx \ ny \ nz  	\end{matrix} \right]$$，

其中$$l^{-1}$$是 3x3 矩阵的逆转置（与转置的逆相等）。注意如果$$l$$是一个旋转矩阵，该矩阵是正交的，因此它的逆转置实际上与$$l$$相同。在这个情况下，一个法线的坐标系向量与一个点的坐标系向量表现相同。对于其他的线性变换，它们却有不同的表现（图3.2）。也需要注意下，$$A$$的位移部分对法线没有影响。

## 练习

**3.1** 如果生成以下对于点的运算是定义明确的：对于实数$$\alpha\_i$$，只要$$1=\sum\_i\alpha\_i$$，有$$\alpha\_1\tilde{p}\_1+\alpha\_2\tilde{p}\_2$$。证明它可以解释为在 3.1 节开始部分描述过的对于点和向量的运算。
