除了上文的线性坐标变换之外,很多情况下还会有平移、绕原点之外点的旋转、透视投影等变换,这些属于仿射变换。在开始进入仿射变换之前,先看齐次坐标的概念。
齐次坐标
尝试使用3D的矩阵来表示点的平移,把点$v$平移$\Delta v$。这需要对$v$和$\Delta v$的各个分量分别求和: $$ v'=v+\Delta v = \begin{bmatrix} (x+\Delta x) & (y+\Delta y) & (z+\Delta z) \end{bmatrix} $$ 矩阵的乘法涉及对元素的相乘和相加,但并没有办法把$\Delta v$的分量放置在$3\times 3$矩阵里,使其与矢量$v$相乘后产生如$(x+\Delta x)$的和。 为解决这一问题,引入齐次坐标的概念。使用齐次坐标时,原本$n$维矢量使用$n+1$维矢量来表示,增加的分量记为$w$。平面内的齐次坐标
平面中齐次坐标的形式为$(x,y,w)$ ,想象在3D中$w=1$处的2D平面,实际的2D点$(x,y)$用齐次坐标表示为$(x,y,1)$,对于那些不在$w=1$平面上的点,则将它们投影到$w=1$平面上。所以齐次坐标$(x,y,w)$映射的2D点为$(x/w,y/w)$,如下图所示:
因此,给定一个2D点$(x,y)$,齐次空间中会有无数个点与之对应。所有的点都可以写作$(kx,ky,k),k\neq0$。这些点构成一条穿过齐次原点的直线。
当$w=0$时,除法无意义,所以不存在实际的2D点。可以将2D齐次点$(x,y,0)$解释为位于无穷远处的点,它描述的是一个方向而不是一个位置。
空间中的齐次坐标
4D坐标的基本思想相同。3D点可以被认为是在4D中$w=1$“平面”上。4D点的形式是$(x,y,z,w)$,将4D点“投影”刚才的“平面”上,得到相应的实际3D点$(x/w,y/w,z/w)$。$w=0$时4D点用于描述一个方向而不是一个位置。
仿射变换
仿射变换是指线性变换后接着平移,因此仿射变换是线性变换的超集。 对于3D空间,$3\times3$变换矩阵用于表示线性变换,不包含平移,因为矩阵乘法的性质,零向量总是变换成零向量,因此任何能用矩阵乘法表达的变换都不包含平移。而$4\times4$矩阵可提供一种数学上的“技巧”,使平移变换也可以像线性变换一样使用矩阵乘法来表示。 假设$w$总是为1,标准3D矢量$[x,y,z]$对应的4D矢量为$[x,y,z,1]$,任意$3\times3$变换矩阵在4D中表示为: $$ \begin{bmatrix} m_{11} & m_{12} & m_{13} \\ m_{21} & m_{22} & m_{23} \\ m_{31} & m_{32} & m_{33} \\ \end{bmatrix} \Rightarrow \begin{bmatrix} m_{11} & m_{12} & m_{13} & 0\\ m_{21} & m_{22} & m_{23} & 0\\ m_{31} & m_{32} & m_{33} & 0\\ 0& 0 & 0 & 1 \end{bmatrix} $$ 则任意一个形如$[x,y,z,1]$的矢量乘以上边的$4\times4$矩阵,其结果会和标准的$3\times3$矩阵相同,只是用$w=1$的4D矢量表示。 $$ \begin{bmatrix} x & y & z \end{bmatrix} \begin{bmatrix} m_{11} & m_{12} & m_{13} \\ m_{21} & m_{22} & m_{23} \\ m_{31} & m_{32} & m_{33} \\ \end{bmatrix} = \begin{bmatrix} xm_{11}+ym_{21}+zm_{31} & xm_{12}+ym_{22}+zm_{32} & xm_{13}+ym_{23}+zm_{33} \end{bmatrix} $$ $$ \begin{bmatrix} x & y & z & 1 \end{bmatrix} \begin{bmatrix} m_{11} & m_{12} & m_{13} & 0\\ m_{21} & m_{22} & m_{23} & 0\\ m_{31} & m_{32} & m_{33} & 0\\ 0& 0 & 0 & 1 \end{bmatrix} = \begin{bmatrix} xm_{11}+ym_{21}+zm_{31} & xm_{12}+ym_{22}+zm_{32} & xm_{13}+ym_{23}+zm_{33} & 1 \end{bmatrix} $$ 3D中的所有线性变换矩阵也都可以通过$4\times4$矩阵的形式表示。平移
本文一开始提出的问题得以解决: $$ \begin{bmatrix} x & y & z & 1 \end{bmatrix} \begin{bmatrix} 1 & 0 &0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 1 & 0\\ \Delta x & \Delta y & \Delta z & 1 \end{bmatrix} = \begin{bmatrix} x+\Delta x & y+\Delta y & z+\Delta z & 1 \end{bmatrix} $$旋转(绕指定点)
绕原点以外的点旋转(及其它的不满足线性变换条件的变换)可以分解为三步: 1. 将旋转(或其它变换)的中心点移到原点 2. 进行线性变换 3. 变换后将原点移回旋转中心(或其它变换的中心) 使用这一思路来推导绕点$P$旋转的变换矩阵。 矩阵$T$表示将$P$平移变换至原点的矩阵,则有: $$ T=\begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 1 & 0\\ -P_x & -P_y & -P_z & 1 \end{bmatrix} = \begin{bmatrix} I & 0 \\ -P & 1 \end{bmatrix} $$ 上式中$I$表示3阶的单位矩阵,后边均用这种表示方法。 易知将原点移回$P$的矩阵为$T$的逆矩阵: $$ T^{-1}=\begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 1 & 0\\ P_x & P_y & P_z & 1 \end{bmatrix} = \begin{bmatrix} I & 0 \\ P & 1 \end{bmatrix} $$ 旋转变换矩阵用$R_{3\times 3}$表示: $$ R_{3\times 3} = \begin{bmatrix} r_{11} & r_{12} & r_{13} \\ r_{21} & r_{22} & r_{23} \\ r_{31} & r_{32} & r_{33} \\ \end{bmatrix} $$ 对应的4D表示为: $$ R_{4\times 4}= \begin{bmatrix} r_{11} & r_{12} & r_{13} & 0\\ r_{21} & r_{22} & r_{23} & 0\\ r_{31} & r_{32} & r_{33} & 0\\ 0 & 0 & 0 & 1 \end{bmatrix} = \begin{bmatrix} R_{3\times 3} & 0 \\ 0 & 1 \\ \end{bmatrix} $$ 绕任意点$P$旋转的矩阵为: $$ \begin{align} M &= TR_{4\times 4}T^{-1}\\ &= \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 1 & 0\\ -P_x & -P_y & -P_z & 1 \end{bmatrix} \begin{bmatrix} r_{11} & r_{12} & r_{13} & 0\\ r_{21} & r_{22} & r_{23} & 0\\ r_{31} & r_{32} & r_{33} & 0\\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 1 & 0\\ P_x & P_y & P_z & 1 \end{bmatrix}\\ &= \begin{bmatrix} I & 0 \\ -P & 1 \end{bmatrix} \begin{bmatrix} R_{3\times 3} & 0 \\ 0 & 1 \\ \end{bmatrix} \begin{bmatrix} I & 0 \\ P & 1 \end{bmatrix}\\ &=\begin{bmatrix} R_{3\times 3} & 0 \\ -P R_{3\times 3} +P& 1 \end{bmatrix} \end{align} $$ 可以看出,仿射变换中增加的平移部分仅仅改变了$4\times4$矩阵的最后一行,并没有影响到上边所包含的线性变换的$3\times3$的部分。 其余的仿射变换,如绕不通过原点的轴旋转,沿不穿过原点的平面缩放,沿不穿过原点的平面镜像,向不穿过原点的平面正交投影等均是类似的情况。透视投影
之前的讨论中齐次坐标齐次项始终有$w=1$,将$3\times3$矩阵变化为$4\times4$矩阵并非齐次坐标的所有用处。 透视投影是一种比较复杂的变换。首先来考虑一个比较简单的情况,下图中,待投影的点为$P$,投影平面为平行于$xy$平面的$z=d$平面,投影中心为原点。投影得到的点为$P'$。 根据相似三角形原理很容易得出$P'$点的坐标: $$ P' = \begin{bmatrix} P'_x & P'_y & P'_z \end{bmatrix} = \begin{bmatrix} dP_x/P_z & dP_y/P_z & d \end{bmatrix} $$ 为了得到透视投影的变换矩阵,需要将$P'$的坐标转化到4D表示: $$ P'= \begin{bmatrix} dP_x/P_z & dP_y/P_z & d & 1 \end{bmatrix} = \begin{bmatrix} P_x & P_y & P_z & P_z/d \end{bmatrix} $$ 此时,需要找到一个$4\times4$的矩阵,使其满足条件$PR=P'$: $$ \begin{bmatrix} P_x & P_y & P_z & 1 \end{bmatrix} \begin{bmatrix} 1&0&0&0 \\ 0&1&0&0 \\ 0&0&1&1/d\\ 0&0&0&0 \end{bmatrix} = \begin{bmatrix} P_x & P_y & P_z & P_z/d \end{bmatrix} $$ 因此找到了向$z=d$平面透视投影的矩阵$R$: $$ R=\begin{bmatrix} 1&0&0&0 \\ 0&1&0&0 \\ 0&0&1&1/d\\ 0&0&0&0 \end{bmatrix} $$ 此矩阵用来计算出齐次坐标$w$的值,然后再将4D的齐次坐标变换为3D坐标,即完成了透视投影的变换。但是在实际应用中,投影中心或投影平面有不同的定义时,投影矩阵会有很多种变化情况。REFERENCE
游戏引擎架构
3D数学基础:图形与游戏开发
http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c10123/Deriving-Projection-Matrices.htm