在这篇文章中,我们简单了解一下表示3D旋转的矩阵、欧拉角以及四元数之间是如何互相转换的。
部分内容可能有计算错误,如果有错希望大家可以指出~
转换为矩阵
欧拉角
欧拉角即绕轴旋转,但轴是有不同定义的。例如对象空间(Object Space)的轴是轴,直立空间(Upright Space, 原点位于物体中心,三个轴平行于世界坐标轴)的轴也是轴。因此,还得分情况讨论。
在模型(Model)变换阶段,物体由对象空间变换到世界空间,这里就需要从对象空间到直立空间的矩阵了:
M对象→直立=PHB
其中,它们分别对应的是俯仰、航向和滚转这三个动作。这里的旋转顺序可以自由决定。这三个旋转矩阵的内容如下(右手系,变成左手系转置一下就行):
PHB=Rx(p)=Ry(h)=Rz(b)=1000cospsinp0−sinpcosp=cosh0−sinh010sinh0cosh=cosbsinb0−sinbcosb0001
在视图(View)变换阶段,物体由世界空间变换到相机的对象空间,这里需要将直立空间变换到对象空间的矩阵:
M直立→对象=M对象→直立−1=B−1H−1P−1
接下来要求旋转矩阵的逆矩阵,由于旋转矩阵是正交矩阵,因此只需求旋转矩阵的转置即可。
四元数
可以通过扩展四元数乘法qvq−1得出,这里直接给出结论了:
定义四元数
q=[w,(x,y,z)]=[cos(2θ),(nxsin(2θ),nysin(2θ),nzsin(2θ))
其中,θ是要旋转的角度,n^=(nx,ny,nz)是单位旋转轴。
那么它转换的矩阵如下(右手系,变成左手系转置一下就行)
1−2y2−2z22xy+2wz2xz−2wy2xy−2wz1−2x2−2z22yz+2wx2xz+2wy2yz−2wx1−2x2−2y2
转换为欧拉角
可以直接从旋转矩阵来求解三个欧拉角,需要具体情况具体分析。例如下面的矩阵是左手坐标系中混合好的旋转矩阵:
coshcosb+sinhsinpsinb−coshsinb+sinhsinpcosbsinhcospsinbcospcosbcosp−sinp−sinhcosb+coshsinpsinbsinhsinb+coshsinpcosbcoshcosp
首先立马就能求出俯仰角p:
p=arcsin(−m32),p∈[−90°,90°]
知道p后,就能确定cosp的值了,然后就能求出h和b的值了。这得分两种情况来考虑:
-
cosp=0:先求h,发现m31=sinhcosp,m33=coshcosp,那么有
sinhcosh=cospm31=cospm33
然后就能用C/C++提供的atan2(y, x)
来求出h了,这个函数返回以弧度表示的 y/x 的反正切
atan2(sinh,cosh)=arctan(coshsinh)=arctan(tanh)=h
因此有
h=atan2(m31,m33)
这里利用 y/x 的特性把cosp约分了,cosp是正的,所以能约。
类似有
b=atan2(m12,m22)
-
cosp=0: 此时p=±90°,说明 发生了万向锁。这里令b=0°,然后化简上面的大矩阵:
coshsinhsinp000−sinp−sinhcoshsinp0
然后就能求h了:
h=atan2(−m13,m11)
将矩阵转换为欧拉角总结如下:
phb=arcsin(−m32)={atan2(m31,m33),cosp=0atan2(−m13,m11),cosp=0={atan2(m12,m22),cosp=00,cosp=0
四元数
可以对 “欧拉角->四元数”中得出的的结论进行逆向工程;也可以先把四元数转换为矩阵,然后再把得到的矩阵转换为欧拉角。这里康康第二种思路。
把矩阵的值代入上边的结论中,然后进行化简便能得到:
phb=arcsin(−2(yz−wx))={atan2(xz+wy,1/2−x2−y2),cosp=0atan2(−xz+wy,1/2−y2−z2),cosp=0={atan2(xy+wz,1/2−x2−z2),cosp=00,cosp=0
这个是从对象空间到直立空间的欧拉角,如果想要从直立空间到对象空间的欧拉角,只需求四元数的共轭,将x,y,z取负即可。
转换为四元数
可以对由四元数转换的矩阵进行逆向工程。检查对角线元素的总和,即矩阵的迹(Trace),有:
tr(M)=m11+m22+m33=(1−2y2−2z2)+(1−2x2−2z2)+(1−2x2−2y2)=3−4(x2+y2+z2)=3−4(1−w2)(单位四元数模长是1)=4w2−1
因此有
w=2m11+m22+m33+1
类似地,有
xyz=2m11−m22−m33+1=2−m11+m22−m33+1=2−m11−m22+m33+1
由于平方根是非负的,我们只能在这4个分量里选1个分量,让它作为非负根,而不是让所有4个分量全非负。
因此还得寻找其他方法计算剩余的3个分量——检查对角矩阵元素的总和与差值:
m21+m12m21−m12m13+m31m13−m31m23+m32m32−m23=4xy=4wz=4xz=4wy=4yz=4wx
使用这些式子和上面其中一个分量就能将四元数从旋转矩阵中提取出来:
wxyz=2m11+m22+m33+1⇒x=4wm32−m23y=4wm13−m31z=4wm21−m12=2m11−m22−m33+1⇒w=4xm32−m23y=4xm21+m12z=4xm13+m31=2−m11+m22−m33+1⇒w=4ym13−m31x=4ym21+m12z=4ym32+m23=2−m11−m22+m33+1⇒w=4zm21−m12x=4zm13+m31y=4zm32+m23
那我们该使用哪一行呢?w,x,y,z哪个有最大绝对值就用哪个,因为如果太小了的话会让数值不稳定,也就是突然抖动。为了避免开平方,只需比较这四个分量对应的m11±m22±m33哪个最大就行,然后先计算出它,再用后面的式子去计算其他分量。
欧拉角
和欧拉角转换矩阵一样,也要分两种情况讨论:
-
从对象空间到直立空间的四元数:
由于直立空间和世界空间的坐标轴平行,有
phb=[cos(p/2)(sin(p/2)00)]=[cos(h/2)(0sin(h/2)0)]=[cos(b/2)(00sin(b/2))]
它们分别按x,y,z轴旋转。接下来按ZYX顺序进行旋转的组合,得到四元数:
q对象→直立(b,h,p)=phb=cos(p/2)sin(p/2)00cos(h/2)0sin(h/2)0cos(b/2)00sin(b/2)=cos(p/2)cos(h/2)sin(p/2)cos(h/2)cos(p/2)sin(h/2)sin(p/2)sin(h/2)cos(b/2)00sin(b/2)=cos(p/2)cos(h/2)cos(b/2)−sin(p/2)sin(h/2)sin(b/2)sin(p/2)cos(h/2)cos(b/2)+sin(p/2)cos(h/2)sin(b/2)cos(p/2)sin(h/2)cos(b/2)−sin(p/2)cos(h/2)sin(b/2)cos(p/2)cos(h/2)sin(b/2)+sin(p/2)sin(h/2)cos(b/2)
q直立→对象(b,h,p)=q对象→直立(b,h,p)∗=cos(p/2)cos(h/2)cos(b/2)−sin(p/2)sin(h/2)sin(b/2)−sin(p/2)cos(h/2)cos(b/2)−sin(p/2)cos(h/2)sin(b/2)−cos(p/2)sin(h/2)cos(b/2)+sin(p/2)cos(h/2)sin(b/2)−cos(p/2)cos(h/2)sin(b/2)−sin(p/2)sin(h/2)cos(b/2)
参考资料