# 一、旋转,平移,缩放# 1. 二维旋转直角坐标系 如下图,有一个长度为 l, 角度为 θ1 的向量逆时间旋转了 θ 度。设原先向量的横纵坐标为 x1 和 y1,旋转后的横纵左边为 x2 和 y2。
x 1 = c o s θ 1 l , y 1 = c o s θ 1 l x_1=cosθ_1l, y_1=cosθ_1l x 1 = cos θ 1 l , y 1 = cos θ 1 l
x 2 = c o s ( θ + θ 1 ) l = c o s θ c o s θ 1 l − s i n θ s i n θ 1 l = c o s θ x 1 − s i n θ y 1 x_2 = cos(θ+θ_1)l = cosθcosθ_1l-sinθsinθ_1l=cosθx_1-sinθy_1 x 2 = cos ( θ + θ 1 ) l = cos θ cos θ 1 l − s in θ s in θ 1 l = cos θ x 1 − s in θ y 1
y 2 = s i n ( θ + θ 1 ) l = s i n θ c o s θ 1 l + c o s θ s i n θ 1 l = s i n θ x 1 + c o s θ y 1 y_2=sin(θ+θ_1)l = sinθcosθ_1l + cosθsinθ_1l = sinθx_1 + cosθy_1 y 2 = s in ( θ + θ 1 ) l = s in θ cos θ 1 l + cos θ s in θ 1 l = s in θ x 1 + cos θ y 1
[ c o s θ − s i n θ s i n θ c o s θ ] [ x 1 y 1 ] = [ x 2 y 2 ] \left[ \begin{matrix} cosθ & -sinθ \\ sinθ & cosθ \\ \end{matrix} \right] \left[ \begin{matrix} x_1 \\ y_1 \\ \end{matrix} \right] = \left[ \begin{matrix} x_2 \\ y_2 \\ \end{matrix} \right] [ cos θ s in θ − s in θ cos θ ] [ x 1 y 1 ] = [ x 2 y 2 ]
由此可以推出在平面的转轴公式。
复平面 如果有两个模长为 1 的复数角度分别是 θ1 和 θ2,将这两个复数相乘
( c o s θ 1 + s i n θ 1 i ) ( c o s θ 2 + s i n θ 2 i ) = c o s θ 1 c o s θ 2 − s i n θ 1 s i n θ 2 + s i n θ 1 c o s θ 2 i + c o s θ 1 s i n θ 2 i (cosθ_1+sinθ_1i)(cosθ_2+sinθ_2i)=cosθ_1cosθ_2-sinθ_1sinθ_2+sinθ_1cosθ_2i+cosθ_1sinθ_2i ( cos θ 1 + s in θ 1 i ) ( cos θ 2 + s in θ 2 i ) = cos θ 1 cos θ 2 − s in θ 1 s in θ 2 + s in θ 1 cos θ 2 i + cos θ 1 s in θ 2 i
= c o s ( θ 1 + θ 2 ) + s i n ( θ 1 + θ 2 ) i =cos(θ_1+θ_2)+sin(θ_1+θ_2)i = cos ( θ 1 + θ 2 ) + s in ( θ 1 + θ 2 ) i
可以看到两个模长为 1 的复数相乘,相当于将两个复数的角度相加,也即角度为 θ1 的角逆时针旋转了 θ2 度,也可以说 θ2 的角逆时针旋转了 θ1 度。
极坐标 根据欧拉公式,将复数化成极坐标的形式。
c o s θ 1 + s i n θ 1 i = e i θ 1 c o s θ 2 + s i n θ 2 i = e i θ 2 cosθ_1+sinθ_1i=e^{iθ_1} cosθ_2+sinθ_2i=e^{iθ_2} cos θ 1 + s in θ 1 i = e i θ 1 cos θ 2 + s in θ 2 i = e i θ 2
e i θ 1 ∗ e i θ 2 = e i ( θ 1 + θ 2 ) e^{iθ_1}*e^{iθ_2} = e^{i(θ_1+θ_2)} e i θ 1 ∗ e i θ 2 = e i ( θ 1 + θ 2 )
# 2. 三维旋转 三维旋转分为,欧拉角,矩阵旋转和四元数。
# 一、欧拉角和矩阵旋转 欧拉证明了,3d 空间的任意旋转均可以通过绕着三个正交轴旋转得到,于是这种绕着三个正交轴旋转得到的旋转被称为欧拉角。
绕 x 轴旋转。设一个向量 v 为 (x1,y1,z1), 绕 x 轴旋转 θ 度。将这个向量 v 分解成平行于 x 轴的向量和垂直于 x 轴的向量。明显在绕着 x 轴旋转时候,平行于 x 轴的向量并没有发生改变,只要求出垂直于 x 轴的向量绕 x 轴旋转 θ 度后的向量再与平行于 x 轴的向量相加即可。
v = v ⊥ + v ∥ = ( 0 , y , z ) + ( x , 0 , 0 ) v=v_⊥+v_∥=(0,y,z)+(x,0,0) v = v ⊥ + v ∥ = ( 0 , y , z ) + ( x , 0 , 0 )
v ‘ = v ⊥ ‘ + v ∥ ‘ = v ⊥ ‘ + v ∥ v^`=v_⊥^`+v_∥^`=v_⊥^`+v_∥ v ‘ = v ⊥ ‘ + v ∥ ‘ = v ⊥ ‘ + v ∥
v ⊥ y = l c o s θ 1 , v ⊥ z = l s i n θ 1 , v ⊥ y ‘ = l c o s ( θ 1 + θ ) , v ⊥ z ‘ = l s i n ( θ 1 + θ ) v_{⊥y}=lcosθ_1,v_{⊥z}=lsinθ_1,v_{⊥y}^`=lcos(θ_1+θ),v_{⊥z}^`=lsin(θ_1+θ) v ⊥ y = l cos θ 1 , v ⊥ z = l s in θ 1 , v ⊥ y ‘ = l cos ( θ 1 + θ ) , v ⊥ z ‘ = l s in ( θ 1 + θ )
[ c o s θ − s i n θ s i n θ c o s θ ] [ v ⊥ y v ⊥ z ] = [ v ⊥ y ‘ v ⊥ z ‘ ] \left[ \begin{matrix} cosθ & -sinθ \\ sinθ & cosθ \\ \end{matrix} \right] \left[ \begin{matrix} v_{⊥y} \\ v_{⊥z} \\ \end{matrix} \right] = \left[\begin{matrix} v_{⊥y}^` \\ v_{⊥z}^` \\ \end{matrix} \right] [ cos θ s in θ − s in θ cos θ ] [ v ⊥ y v ⊥ z ] = [ v ⊥ y ‘ v ⊥ z ‘ ]
v ‘ = v ⊥ ‘ + v ∥ = [ 0 0 0 0 c o s θ − s i n θ 0 s i n θ c o s θ ] [ 0 v y v z ] + [ v x 0 0 ] = ( x , c o s θ y − s i n θ z , s i n θ y + c o s θ z ) v^`=v_⊥^`+v_∥= \left[ \begin{matrix} 0 & 0 & 0\\ 0 & cosθ & -sinθ \\ 0 & sinθ & cosθ \\ \end{matrix} \right] \left[ \begin{matrix} 0 \\ v_y \\ v_z \\ \end{matrix} \right]+ \left[ \begin{matrix} v_x \\ 0 \\ 0 \\ \end{matrix} \right]= (x,cosθ_y-sinθ_z,sinθy+cosθ_z) v ‘ = v ⊥ ‘ + v ∥ = 0 0 0 0 cos θ s in θ 0 − s in θ cos θ 0 v y v z + v x 0 0 = ( x , cos θ y − s in θ z , s in θ y + cos θ z )
( x , c o s θ y − s i n θ z , s i n θ y + c o s θ z ) = [ 1 0 0 ] x + [ 0 c o s θ s i n θ ] y + [ 0 − s i n θ c o s θ ] z = [ 1 0 0 0 c o s θ − s i n θ 0 s i n θ c o s θ ] [ x y z ] (x,cosθ_y-sinθ_z,sinθy+cosθ_z)= \left[ \begin{matrix} 1 \\ 0 \\ 0 \\ \end{matrix} \right]x+ \left[ \begin{matrix} 0 \\ cosθ \\ sinθ \\ \end{matrix} \right]y+ \left[ \begin{matrix} 0 \\ -sinθ \\ cosθ \\ \end{matrix} \right]z = \left[ \begin{matrix} 1 & 0 & 0\\ 0 & cosθ & -sinθ \\ 0 & sinθ & cosθ \\ \end{matrix} \right] \left[ \begin{matrix} x \\ y \\ z \\ \end{matrix} \right] ( x , cos θ y − s in θ z , s in θ y + cos θ z ) = 1 0 0 x + 0 cos θ s in θ y + 0 − s in θ cos θ z = 1 0 0 0 cos θ s in θ 0 − s in θ cos θ x y z
由此推出绕 x 轴旋转的旋转矩阵,此外也可以依次推出绕 y 轴旋转,绕 z 轴旋转的旋转矩阵
绕 x 轴旋转的旋转矩阵
\begin{matrix} 1 & 0 & 0\ 0 & cosθ & -sinθ \ 0 & sinθ & cosθ \ \end{matrix} \right]
[ c o s θ 0 s i n θ 0 1 0 − s i n θ 0 c o s θ ] \left[ \begin{matrix} cosθ & 0 & sinθ\\ 0 & 1 & 0 \\ -sinθ & 0 & cosθ \\ \end{matrix} \right] cos θ 0 − s in θ 0 1 0 s in θ 0 cos θ
绕 z 轴旋转的旋转矩阵 [ c o s θ − s i n θ 0 s i n θ c o s θ 0 0 0 1 ] \left[ \begin{matrix} cosθ & -sinθ & 0\\ sinθ & cosθ & 0\\ 0 & 0 & 1\\ \end{matrix} \right] cos θ s in θ 0 − s in θ cos θ 0 0 0 1
依次左乘旋转矩阵,比如依次左乘绕 x 轴旋转矩阵,绕 y 轴旋转矩阵,绕 z 轴旋转矩阵,A = ZYX, 这里的矩阵 A 就是一个复合矩阵,因为矩阵乘法有结合律,ZYXv=Av,左乘 A 相当于依次绕 xyz 轴旋转。另外这里的旋转矩阵均是基于初始坐标轴 (或者说世界坐标轴,反正这个坐标轴不会跟着变化) 进行旋转,这就会出现一个问题,如果绕着一个轴旋转 90 度,此时物体的自身的另外两个周会与最开始的两个轴分别重合。比如,绕着 y 轴旋转 90 度,此时物体目前的 x 轴会与初识的 z 轴重合,目前的 z 轴会与 - x 轴重合,这就导致了此时转动 z 轴就不是转动原来的 z 轴而是 x 轴。如果一个物体绕着 x 轴转动,然后再绕着 y 轴转动 90 度,最后再绕着 z 轴转动,会发现此时绕着 z 轴转动相当于之前绕着 x 轴转动,如果想绕着之前的 z 轴转动,得绕着 x 轴转动才行。这就产生一个问题,比如绕着 xyz 轴分别转动,只要中间的轴 y 轴转动达到 90 度,此时绕 z 轴旋转相当于之前绕 y 轴旋转时的绕 x 轴旋转,也即无法正常的绕着 z 轴时表现出绕着 z 轴 (这个是按自身的坐标轴) 的转的情况,或者说此时少了一种转动情况,也即少了一个自由度。这种情况叫做万向死锁。可以用矩阵的方式,探究这个情况。
假设有两种旋转,一种是绕着 x 轴旋转 θ 度然后绕着 y 轴旋转 90 度,一种是绕着 y 轴旋转 90 度,然后绕着 z 轴旋转 θ 度。
第一种旋转
A = X Y = [ 1 0 0 0 c o s θ − s i n θ 0 s i n θ c o s θ ] [ 0 0 1 0 1 0 − 1 0 0 ] = [ 0 0 1 s i n θ c o s θ 0 − c o s θ s i n θ 0 ] A=XY= \left[ \begin{matrix} 1 & 0 & 0\\ 0 & cosθ & -sinθ \\ 0 & sinθ & cosθ \\ \end{matrix} \right] \left[ \begin{matrix} 0 & 0 & 1\\ 0 & 1 & 0 \\ -1 & 0 & 0 \\ \end{matrix} \right]= \left[ \begin{matrix} 0 & 0 & 1\\ sinθ & cosθ & 0 \\ -cosθ & sinθ & 0 \\ \end{matrix} \right] A = X Y = 1 0 0 0 cos θ s in θ 0 − s in θ cos θ 0 0 − 1 0 1 0 1 0 0 = 0 s in θ − cos θ 0 cos θ s in θ 1 0 0
第二种旋转
B = Y Z = [ 0 0 1 0 1 0 − 1 0 0 ] [ c o s θ − s i n θ 0 s i n θ c o s θ 0 0 0 1 ] = [ 0 0 1 s i n θ c o s θ 0 − c o s θ s i n θ 0 ] (3) B=YZ= \left[ \begin{matrix} 0 & 0 & 1 \\ 0 & 1 & 0 \\ -1 & 0 & 0 \end{matrix} \right] \left[ \begin{matrix} cosθ & -sinθ & 0 \\ sinθ & cosθ & 0 \\ 0 & 0 & 1 \end{matrix} \right]= \left[ \begin{matrix} 0 & 0 & 1 \\ sinθ & cosθ & 0 \\ -cosθ & sinθ & 0 \end{matrix} \right] \tag{3} B = Y Z = 0 0 − 1 0 1 0 1 0 0 cos θ s in θ 0 − s in θ cos θ 0 0 0 1 = 0 s in θ − cos θ 0 cos θ s in θ 1 0 0 ( 3 )
可以发现 XY=YZ,换句话说就是,在绕 y 轴旋转 90 度后,此时绕 z 轴旋转相当于,在绕 y 轴旋转前绕 x 轴旋转。
既然出现万向死锁的原因是之后的旋转是基于最开始的坐标旋转的,那么如果每次旋转都改变坐标系,在根据目前的坐标系旋转,会不会能解决这个问题呢。
同样的绕 xyz 轴旋转,这次后面两次的旋转不再按照初始的坐标轴转,而是转完后重新建系。
首先绕 x 轴旋转
r y = X Y X − 1 r_y=XYX^{-1} r y = X Y X − 1
其实这时候将上面两个相乘就会发现问题,这时候继续绕 z 轴旋转。 r z = r y r x Z ( r y r z ) − 1 = X Y X − 1 X Z ( X Y X − 1 X ) − 1 = X Y Z Y − 1 X − 1 r_z=r_yr_xZ(r_yr_z)^{-1}=XYX^-1XZ(XYX^{-1}X)^{-1}=XYZY^{-1}X^{-1} r z = r y r x Z ( r y r z ) − 1 = X Y X − 1 XZ ( X Y X − 1 X ) − 1 = X Y Z Y − 1 X − 1
最后将这三个旋转依次相乘。 r z r y r x = X Y Z Y − 1 X − 1 X Y X − 1 X = X Y Z r_zr_yr_x=XYZY^{-1}X^{-1}XYX^{-1}X=XYZ r z r y r x = X Y Z Y − 1 X − 1 X Y X − 1 X = X Y Z
最终发现此时绕 xyz 轴旋转相当于绕 zyx 轴旋转,那么之前绕着初始坐标轴旋转出现的万向死锁问题,在旋转后重新建系也会出现。换句话说,万向死锁无解,此时旋转应该使用四元数。
总结一下欧拉角的缺点,存在万向死锁,且旋转一次需要用到四阶矩阵也即 16 个数,占用空间而且不好插值。唯一的好处可能就是简单易懂。
参考资料:
href="bonus_gimbal_lock.pdf (krasjet.github.io)
【熟肉】线性代数的本质 - 09 - 基变换_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1Ls411b7r2/
# 二、四元数 四元数由一个实部和三个虚部 (i,j,k) 组成 q=a+bi+cj+dk。虚部可以写成一个三维向量,q=[s,v], 其中 v 是虚部。ijk 有以下关系。
i 2 = j 2 = k 2 = i j k = − 1 i^2=j^2=k^2=ijk=-1 i 2 = j 2 = k 2 = ijk = − 1
关于四元数与旋转的公式推导可以参考 Krasjet 大佬的文章:quaternion.pdf (ruc.edu.cn) 。以下直接说结论。
向量 v 绕着旋转轴 u 旋转 θ 度,令 v=[0,v],q=[cos (θ/2),sin (θ/2) u],u 是单位向量,四元数的模长为 1,旋转后的向量为
v ‘ = q v q − 1 = q v q ∗ v^`=qvq^{-1}=qvq^* v ‘ = q v q − 1 = q v q ∗
四元数转为矩阵旋转:
v ‘ = [ 1 − 2 c 2 − 2 d 2 2 b c − 2 a d 2 a c + 2 b d 2 b c + 2 a d 1 − 2 b 2 − 2 d 2 2 c d − 2 a b 2 b d − 2 a c 2 a b + 2 c d 1 − 2 b 2 − 2 c 2 ] v v^`= \left[ \begin{matrix} 1-2c^2-2d^2 & 2bc-2ad & 2ac+2bd \\ 2bc+2ad & 1-2b^2-2d^2 & 2cd-2ab \\ 2bd-2ac & 2ab+2cd & 1-2b^2-2c^2 \\ \end{matrix} \right]v v ‘ = 1 − 2 c 2 − 2 d 2 2 b c + 2 a d 2 b d − 2 a c 2 b c − 2 a d 1 − 2 b 2 − 2 d 2 2 ab + 2 c d 2 a c + 2 b d 2 c d − 2 ab 1 − 2 b 2 − 2 c 2 v
旋转复合:
假设有两个不同的轴,旋转度数不同的四元数 q1,q2. 向量 v 先绕着 q1 所在的轴旋转然后再绕着 q2 所在的轴旋转。
v ‘ = q 2 q 1 v q 1 − 1 q 2 − 1 = q 2 q 1 v q 1 ∗ q 2 ∗ v^`=q_2q_1vq_1^{-1}q_2^{-1}=q_2q_1vq_1^*q_2^* v ‘ = q 2 q 1 v q 1 − 1 q 2 − 1 = q 2 q 1 v q 1 ∗ q 2 ∗
其中 q1 和 q2 可以先乘起来,这点与矩阵相同。假设有个 q=q2q1
v ‘ = q 2 q 1 v q 1 − 1 q 2 − 1 = q v q − 1 v^`=q_2q_1vq_1^{-1}q_2^{-1}=qvq^{-1} v ‘ = q 2 q 1 v q 1 − 1 q 2 − 1 = q v q − 1
旋转指数形式:
e u θ = c o s θ + u s i n θ e^{uθ}=cosθ+usinθ e u θ = cos θ + u s in θ
其中 u 为四元数虚部,也即 ijk 三组基组成的三维向量。
v ‘ = q v q − 1 = e u θ / 2 v e − u θ / 2 v^`=qvq^{-1}=e^{uθ/2}ve^{-uθ/2} v ‘ = q v q − 1 = e u θ /2 v e − u θ /2
# 3. 平移,缩放 平移和缩放相对于旋转就简单多了。
平移矩阵:
[ 1 0 0 v x 0 1 0 v y 0 0 1 v z 0 0 0 1 ] \left[ \begin{matrix} 1 & 0 & 0 & v_x \\ 0 & 1 & 0 & v_y \\ 0 & 0 & 1 & v_z \\ 0 & 0 & 0 & 1 \\ \end{matrix} \right] 1 0 0 0 0 1 0 0 0 0 1 0 v x v y v z 1
因为平移不是线性变换,而是仿射变换,描述 3 维物体的平移使用三阶矩阵是不行的,得使用四阶矩阵。这时候要给三维向量多一个维度也即 w,此时的向量为 (x,y,z,w), 其中 w 为 1。这个叫做齐次坐标要转成三维坐标只需要给前面三个分量依次除于 w 即可。即(x/w,y/w,z/w)。
缩放矩阵:
x_t & 0 & 0 \\ 0 & y_t & 0 \\ 0 & 0 & z_t \\
想要缩放 x 轴,只需要改变 xt 即可,对于 yz 同理。如果 xyz 的缩放相同,整个物体就会等比例缩放,如果 xyz 缩放不同,物体看起来会压缩或者拉伸。
# 4. 复合矩阵 与旋转同理,可以将平移,缩放,旋转矩阵分别乘起来得到一个新的矩阵,新的矩阵的几何意义就是对物体进行平移,缩放,旋转。因为平移需要四阶矩阵,所以旋转,缩放得化成四阶矩阵,除第四列四行为 1,其他四行和四列为 0。
缩放矩阵 (四阶形式):
x_t & 0 & 0 & 0\\ 0 & y_t & 0 & 0 \\ 0 & 0 & z_t & 0\\ 0 & 0 & 0 & 1\\