跳到主要内容

04 - 模型变换

齐次坐标(Homogeneous Coordinate)

给点和向量的描述升一维(ww),以2D为例:

  • 二维中的点:(x,y,1)T(x,y,1)^\mathsf{T}
  • 二维中的向量:(x,y,0)T(x,y,0)^\mathsf{T}

这里理解一下为什么点的w=1w=1,向量的w=0w=0

在三维中w=1w=1处的标准二维平面,实际的二维点此时表示为(x,y,1)(x,y,1)。而对于那些不在w=1w=1平面的点,则可以通过除以ww,将它们投影到w=1w=1平面上。这样,齐次坐标(x,y,w)(x,y,w)就能够映射到实际的二维点(x/w,y/w)(x/w,y/w)

对于任何给定的二维点(x,y)(x,y),在三维齐次空间中存在无限数量的对应点(kx,ky,k),k0(kx,ky,k),\,k\neq0。这些点形成一条穿过三维齐次空间原点的直线。

w=0w=0时,上面的除法未定义,而向量恰好没有在空间中平移的概念(都一样),因此可以用来描述向量。

并且根据w的特性,可以快速判别两个点/向量的关系:

  • 向量+向量=向量 (0+0=0)
  • 点-点=向量(1-1=0)
  • 点+向量=点(1+0=1)
  • 点+点=中点(1+1=2 表示点(x/2,y/2,1)T(x/2,y/2,1)^\mathsf{T}

线性变换(Linear)

形如{x=ax+byy=cx+dy\nonumber\left\{\begin{matrix}x'=ax+by\\y'=cx+dy\end{matrix}\right.的变换,即[xy]=[abcd][xy]\begin{bmatrix} x'\\ y' \end{bmatrix}= \begin{bmatrix} a & b\\ c & d \end{bmatrix} \begin{bmatrix} x\\ y \end{bmatrix}。包括下面的缩放,反射,错切和旋转。

缩放(Scale)

二维

首先是沿主轴方向的缩放:

然后是沿任意方向的缩放,该矩阵将在由单位向量n^\mathbf{\hat{n}}指定的任意方向上按照kk的因子缩放:

S(n^,k)=[1+(k1)nx2(k1)nxny(k1)nxny1+(k1)ny2]\nonumber \mathbf{S}(\mathbf{\hat{n}},k)= \begin{bmatrix} 1+(k-1)n_x^2 & (k-1)n_xn_y \\ (k-1)n_xn_y & 1+(k-1)n_y^2 \\ \end{bmatrix}

如果需要引入齐次坐标,简单升维即可:

三维

首先是沿主轴方向的缩放,引入齐次坐标:

然后是沿任意方向的缩放:

S(n^,k)=[1+(k1)nx2(k1)nxny(k1)nxnz(k1)nxny1+(k1)ny2(k1)nynz(k1)nxnz(k1)nynz1+(k1)nz2]\nonumber \mathbf{S}(\mathbf{\hat{n}},k)= \begin{bmatrix} 1+(k-1)n_x^2 & (k-1)n_xn_y & (k-1)n_xn_z \\ (k-1)n_xn_y & 1+(k-1)n_y^2 & (k-1)n_yn_z \\ (k-1)n_xn_z & (k-1)n_yn_z & 1+(k-1)n_z^2 \\ \end{bmatrix}

反射(Reflection)

二维

反射,也被称为镜像(Mirroring),是一种围绕直线(二维)或平面(三维)中”翻转“对象的变换。

在二维中,可以通过应用-1的比例因子来完成反射。设n^\mathbf{\hat{n}}是二维单位矢量,围绕穿过原点并垂直于n^\mathbf{\hat{n}}的反射矩阵如下:

R(n^)=S(n^,1)=[1+(11)nx2(11)nxny(11)nxny1+(11)ny2]=[12nx22nxny2nxny12ny2]\nonumber \begin{aligned} \mathbf{R(\hat{n})} &= \mathbf{S(\hat{n},-1)} \\ &= \begin{bmatrix} 1+(-1-1)n_x^2 & (-1-1)n_xn_y \\ (-1-1)n_xn_y & 1+(-1-1)n_y^2 \\ \end{bmatrix} \\ &= \begin{bmatrix} 1-2n_x^2 & -2n_xn_y \\ -2n_xn_y & 1-2n_y^2 \\ \end{bmatrix} \end{aligned}

例如如果向按+y方向反射(即按+x方向缩放-1),它的n^=[1,0]\mathbf{\hat{n}}=[1,0]

三维

同理,三维中,

R(n^)=S(n^,1)=[1+(11)nx2(11)nxny(11)nxnz(11)nxny1+(11)ny2(11)nynz(11)nxnz(11)nynz1+(11)nz2]=[12nx22nxny2nxnz2nxny12ny22nynz2nxnz2nynz12nz2]\nonumber \begin{aligned} \mathbf{R(\hat{n})} &= \mathbf{S(\hat{n},-1)} \\ &= \begin{bmatrix} 1+(-1-1)n_x^2 & (-1-1)n_xn_y & (-1-1)n_xn_z \\ (-1-1)n_xn_y & 1+(-1-1)n_y^2 & (-1-1)n_yn_z \\ (-1-1)n_xn_z & (-1-1)n_yn_z & 1+(-1-1)n_z^2 \end{bmatrix} \\ &= \begin{bmatrix} 1-2n_x^2 & -2n_xn_y & -2n_xn_z \\ -2n_xn_y & 1-2n_y^2 & -2n_yn_z \\ -2n_xn_z & -2n_yn_z & 1-2n_z^2 \end{bmatrix} \end{aligned}

错切(Shear)

二维

错切是一种”倾斜“坐标空间的变形,它将不均匀地拉伸坐标空间,不保留角度,但保留了面积/体积。其基本思路是将一个坐标的倍数添加到另一个坐标上。

y方向上的同理。

三维

Hxy(s,t)\mathbf{H}_{xy}(s,t)表示x坐标和y坐标按照另一个坐标z移动,即(x' = x + sz, y' = y + tz):

Hxy(s,t)=[10s01t001]Hxz(s,t)=[1s00100t1]Hyz(s,t)=[100s10t01]\nonumber \begin{aligned} \mathbf{H}_{xy}(s,t)= \begin{bmatrix} 1 & 0 & s \\ 0 & 1& t\\ 0 & 0 & 1 \end{bmatrix} \\ \mathbf{H}_{xz}(s,t)= \begin{bmatrix} 1 & s & 0 \\ 0 & 1 & 0\\ 0 & t & 1 \end{bmatrix} \\ \mathbf{H}_{yz}(s,t)= \begin{bmatrix} 1 & 0 & 0 \\ s & 1 & 0\\ t & 0 & 1 \end{bmatrix} \end{aligned}

旋转(Rotate)

二维

在二维中,只能进行绕某点旋转的变换。以绕原点,逆时针旋转为默认,矩阵如下:

引入齐次坐标系:

三维

矩阵

考虑如何分别绕三个坐标轴旋转,首先是绕x轴旋转

前面的文章说过,矩阵其实是向量的数组,因此我们可以用三个轴的方向向量来表示一个旋转矩阵。按照上图描述,基本旋转矩阵为:

Rx(θ)=[pqr]=[1000cosθsinθ0sinθcosθ]\nonumber \mathbf{R}_x(\theta)= \begin{bmatrix} | & | & | \\ \mathbf{p'} & \mathbf{q'} & \mathbf{r'}\\ | & | & | \end{bmatrix}= \begin{bmatrix} 1 & 0 & 0 \\ 0 & \rm{cos}\theta & -\rm{sin}\theta \\ 0 & \rm{sin}\theta & \rm{cos}\theta \end{bmatrix}

用齐次坐标描述:

类似的,绕y轴旋转为:

绕z轴旋转为:

如果想要绕任意方向进行旋转,可以使用罗德里格斯旋转公式:

其中,n为旋转轴,用向量表示;α\alpha为旋转角度。默认旋转轴是过原点的,如果不过就先平移到原点旋转,再平移回去。

欧拉角

三维旋转也能通过使用欧拉角/四元数来表示,这里先看欧拉角。

如上图所示,只需将3个绕轴旋转的矩阵结合起来就行了,这三个角在欧拉角中被称为偏航角(Yaw),翻滚角(Roll),俯仰角(Pitch)。

通常情况下,只会选择一个固定的顺序进行旋转,而这会导致**万向锁(Gimbal Lock)**发生。例如以ZYX顺序进行旋转,首先绕z旋转θz\theta_z,然后绕y旋转90°,最后绕x旋转θx\theta_x,也就是

Rzyx(θz, π/2, θx)=Rx(θx)Ry(π/2)Rz(θz)=[001sin(θx+θz)cos(θx+θz)0cos(θx+θz)sin(θx+θz)0]=Ry(π/2)Rz(θx+θz)\begin{align} \nonumber R_{zyx}(\theta_z,\ \pi/2,\ \theta_x) &= R_x(\theta_x)R_y(\pi/2)R_z(\theta_z) \\ &= \nonumber \begin{bmatrix} 0 & 0 & 1 \\ \mathrm{sin}(\theta_x+\theta_z) & \mathrm{cos}(\theta_x+\theta_z) & 0 \\ -\mathrm{cos}(\theta_x+\theta_z) & \mathrm{sin}(\theta_x+\theta_z) & 0 \end{bmatrix} \\ &= \nonumber R_y(\pi/2)R_z(\theta_x+\theta_z) \end{align}

可以发现此时旋转只由θx+θz\theta_x+\theta_z​决定,而不是三个旋转角,丢失了一个旋转自由度。

万向锁没有简单的解决方案,如果在使用欧拉角的过程中发生了万向锁,那么它们之间的插值可能会变得很怪异或摇摆不定,也就是产生“抖动”。

四元数

有关四元数的基础知识在这里

定义相关元素如下:

  • p=[0,v]p=[0,\,\mathbf{v}]表示3D中的一个点
  • q=[cos(θ/2),sin(θ/2)n^]q=[\cos(\theta/2),\,\sin(\theta/2)\mathbf{\hat{n}}],其中θ\theta是要旋转的角度,n^\mathbf{\hat{n}}是单位矢量旋转轴。这是通过轴-角系统的视角从而定义成这样的。

那么,ppn^\mathbf{\hat{n}}旋转θ\theta°后的pp'可由以下乘法运算得出:

p=qpq1\nonumber p'=qpq^{-1}

当然,旋转是可以叠加的,例如将pp先旋转aa,再旋转bb,那么就相当于直接将pp旋转baba

p=b(apa1)b1=(ba)p(a1b1)=(ba)p(ba)1\begin{align} \nonumber p' &= b(apa^{-1})b^{-1} \\ \nonumber &= (ba)p(a^{-1}b^{-1}) \\ \nonumber &= (ba)p(ba)^{-1} \end{align}

仿射变换(Affine)

线性变换+平移变换。

平移变换(Translation)

二维

矩阵形式如下:

[xy]=[1001][xy]+[txty]\nonumber \begin{bmatrix} x'\\ y' \end{bmatrix}= \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} x\\ y \end{bmatrix}+ \begin{bmatrix} t_x\\ t_y \end{bmatrix}

显然,这种变换写不成线性变换的形式,因为它后边还有加法。我们不想让平移变换成为特例,于是引入齐次坐标,这样,平移就能写成”线性变换“的形式:

[xyw]=[10tx01ty001][xy1]=[x+txy+ty1]\nonumber \begin{bmatrix} x'\\ y'\\ w' \end{bmatrix}= \begin{bmatrix} 1 & 0 & t_x\\ 0 & 1 & t_y\\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix}= \begin{bmatrix} x+t_x\\ y+t_y\\ 1 \end{bmatrix}

这样,就能方便进行组合变换运算了。

三维

引入齐次坐标系:

可逆变换(Invertible)

除了投影之外的所有原始变换都是可逆的。

组合变换

顾名思义,就是将上边一堆原始变换组合起来。

例如:

可以先绕原点旋转45°,然后平移过去 (注意变换的次序是重要的,颠倒过来再组合可能不是同一种变换了):

并且注意到,用列向量描述的前提下,矩阵是从右往左乘的

为了计算简便,可以提前把这些变换矩阵给乘到一起。

参考资料