在三维几何中,有三种用于表示旋转的方式,它们分别是四元数、欧拉角和旋转矩阵。本文将对它们的概念以及运算进行讲解。
本文全部基于左手坐标系进行讨论。
欧拉角
欧拉角用三个角度来描述物体的旋转,这三个角度又被称为roll-pitch-yaw,它们分别代表着物体绕z、x和y轴进行的旋转,其中roll又被称为bank,yaw又被称为heading。通过将三个轴的旋转组合起来,就可以得到最终的旋转结果。因此,不同的旋转顺序所得到的的结果是不同的,这一点需要万分注意。
为了避免欧拉角给定方位的表达式不唯一的问题,我们将欧拉角的数值限制在一定范围以内,称作限制欧拉角。一般将heading和bank限定在[-180,180]度之间,pitch限制在[-90,90]度之间;为了避免万向锁问题,规定万向锁情况下由heading完成绕竖直轴的全部旋转,也就是在限制欧拉角下,如果pitch为+90或-90,则bank为零。
关于万向锁可以参考这篇文章:
https://blog.csdn.net/qq_35957011/article/details/77188036
另外,根据欧拉角对物体进行旋转时,需要考虑所绕的轴是内在(intrinsic)的还是外在(extrinsic)的,“内在”的意思是绕着世界坐标系的坐标轴进行旋转;“外在”的意思是绕着物体本身局部坐标系的坐标轴进行旋转(前提是在旋转前物体自身的坐标系与世界坐标轴是一致的)。需要注意的一点是,如果是外在旋转的话,相当于按相反顺序的轴用内在的方式进行旋转。也就是说如果是让该物体绕自身坐标系按xyz轴的顺序旋转,则相当于将该物体按世界坐标系按zyx轴旋转。
四元数
相比于欧拉角,四元数采用四个数值来表达物体的旋转,一般记为[x,y,z,w],代表了复数w+xi+yj+zk。可以利用它来代表旋转:设物体的方位为绕着n轴旋转θ角度,则可设:[x,y,z,w] = [sin(θ/2)nx,sin(θ/2)ny,sin(θ/2)nz,cos(θ/2)]。这样就可以表达旋转了,我们设这样的四元数为q。
四元数有它自己的旋转公式:
(1)
根据四元数表达旋转的意义可知,q和-q所代表的的实际角位移是相等的。
设单位四元数为[0,0,0,1],任意四元数q乘以单位四元数均为它本身;若乘以[0,0,0,-1]则得到-q。
假设知道了一个三维顶点(x,y,z)和代表旋转的四元数q,我们可以用四元数乘法来计算出按照q旋转后的点p'
p' = qpq-1
其中p=[x,y,z,0], p'为四维向量,且q的旋转轴必须是单位向量。
四元数乘法可以连接多次旋转。举个例子,设两个四元数a和b,先进行a旋转再进行b旋转等价于进行ba所代表的旋转。
相比于欧拉角,四元数有一个特别的优点:可以很方便地做两个四元数之间的插值,该插值算法叫做slerp插值(Spherical Linear Interpolation)。在这里我们隐去推导过程,直接上公式:
(2)
其中t代表插值的比例,ω代表两个四元数之间的夹角(可以通过点乘计算得出)。为了防止出现数值误差,当sinω非常小时可以直接使用简单的线性插值。
旋转矩阵
除了四元数和欧拉角,也可用矩阵的形式来代表旋转。一般3*3的矩阵就可以表示3维空间中任意的旋转了。
设旋转轴为(x,y,z),旋转角度为θ,我们设c=cosθ,s=sinθ,那么可以得到绕任意轴的旋转矩阵:
(3)
绕着单个轴的旋转矩阵如下:
(4)
欧拉角、四元数和旋转矩阵之间的转换
欧拉角转换到旋转矩阵
欧拉角转换到旋转矩阵的方法比较简单,直接上旋转矩阵的叠加就可以,这里列出内在形式下按照zxy轴顺序的计算公式:
(5)
旋转矩阵转换到欧拉角
从旋转矩阵转换到欧拉角需要注意将roll、pitch、bank限定在限制欧拉角的范围以内。假设要通过上一小节的旋转矩阵推导出zxy轴内在形式下的欧拉角,可以这么去做:
设上一小节推导出的矩阵为M,M(1,1)代表矩阵最左上角的项,那么首先可以得到pitch = asin(-M(3,2))。(直接调用C语言内置的函数,范围正好在[-90°,90°]之间)
如果|pitch|为90°,那么按照限定欧拉角的做法,roll此时为0, yaw = atan2(-M(1,3), M(1, 1)) (利用C语言内置的atan2函数,正好可以将范围限制在[-180°,180°]之间)
如果|pitch|不是90°,我们可以推导roll和yaw为:
roll = atan2(M(1, 2), M(2, 2))
yaw = atan2(M(3, 1), M(3, 3))
如果是外在或者其他坐标轴的顺序,推导方法也是大同小异。
四元数转换到旋转矩阵
四元数中记载了旋转轴和旋转角度,那么我们可以通过这些信息根据公式(3)推导出旋转矩阵。
但其实还是有更直接的推导方式,在这里给出结论,已知四元数(x,y,z,w),我们可以得到旋转矩阵:
(6)
旋转矩阵转换到四元数
想将旋转矩阵转换为四元数,可以检查相对于对角线的对称位置上元素的和与差:
(7)
然后可以先用对角线元素和/差的平方根解得四个值中的一个,就能用公式(7)去计算其他三个:
(8)
那么应当用这四种解法中的哪一个呢?Shoemake建议取计算出的w,x,y,z最大的一个(不必解平方根),然后再计算出其他三个,这样可以避免由于分母太小导致的数值不稳定问题。
这种方法不用在意求解的平方根的正负,因为四元数q和-q在旋转方位上是等价的。
欧拉角转换到四元数
从欧拉角转换到四元数,可以将欧拉角的三个旋转都转换为四元数,然后将这三个四元数连接为一个四元数即可。
四元数转换到欧拉角
通过旋转矩阵转换到欧拉角的过程,可以得:
(9)
而已知:
M(3,2) = 2yz - 2wx
M(1,2) = 2xy + 2wz
M(2,2) = 1 - 2x^2 - 2z^2
M(3,1) = 2xz + 2wy
M(3,3) = 1 - 2x^2 - 2y^2
M(1,3) = 2xz - 2wy
M(1,1) = 1 - 2y^2 - 2z^2
带入(9)中可得:
(10)
参考文献:《3D数学基础:图形与游戏开发》 第10章