2D Orientation Math3D Orientation MathEuler Angle 欧拉角Order Dependence on Euler AngleGimbal Lock 万向锁Degeneration of Euler Angle 欧拉角的退化Problems of Euler AngleQuaternion 四元数Complex Number and 2D Rotation 复数Euler Angle to QuaternionRotation by QuaternionQuaternion to Rotation MatrixRotation Math by QuaternionGiven Axis Rotation by Quaternion
2D Orientation Math
可以参考 GAMES101 的笔记: 线性变换 。
二维空间中,绕着中心点旋转。而三维空间可以绕着三个轴旋转,也可以绕着任意轴旋转。
3D Orientation Math
可以参考 GAMES101 的笔记: 三维变换 。
空间上的任何一个旋转,可以用三个轴的旋转叠加出来。假设依次沿着 X 轴、 Y 轴、 Z 轴旋转,我们就可以算出很多个 3 乘 3 的矩阵,合在一起,就是上图下面的公式,这就是欧拉角。
Euler Angle 欧拉角
欧拉角非常重要,比如说玩空战模拟游戏、航海游戏,或者开一个游艇或者开一个飞机的时候,你就会知道有个概念叫 Yaw Roll Pitch。Yaw 就是航向角,Pitch 是公角,Roll 是左右摇摆。Yaw Roll Pitch 是欧拉角的一种话术表达,现在的导航、航空器都是用这个很基础的概念。游戏里载具系统,空战模拟系统等也会用到。
Order Dependence on Euler Angle
问题之一:计算是顺序依赖的。X、Y、Z 轴 apply 的顺序不一样的话,得出的角度是不一样的。
欧拉角是有问题的,对它的计算是严格顺序依赖的。X、Y、Z 轴 Apply 的顺序不一样的话,得到的角度不一样。
前面说到二维只有一个度(只能绕原点),但是三维有三个度(XYZ),因此顺序错了结果会完全不一样。当我们用欧拉角的时候,一定要约定旋转顺序,必须先沿 X 轴,再沿 Y 轴,再沿 X 轴,否则整个顺序就是乱的。
Gimbal Lock 万向锁
欧拉角在我们的实践中最有使用价值的就是万向节,万向节是非常符合人类对空间旋转感知的一种表达。比如说在现代游戏引擎里面,让艺术家来表达旋转的时候,用的全是万向节,也就是欧拉角。
用到万向节的技术,例如鸡头架,就是相机放在这,无论人怎么动,它朝向永远是对着屏幕的方向。比如大疆无人机飞的时候其实有很多抖动,但是会发现画面总是很稳定。包括微云台技术,它实际上里面用的也是变了形的万向节,能非常稳定地保持方向。
还有一个应用就是陀螺仪。在没有 GPS 导航的时代,导弹打出去是怎么样不偏航的呢?实际上它有个高速旋转地陀螺,这个陀螺因为惯性的原理,它始终指向一个方向。但是导弹身体会一会上一会左一会右,它怎么能保证陀螺永远指的一个方向?
其实就是做了一个万向节。测量每一个节点的旋转角度,就知道导弹的方向是怎么偏的。把导弹沿着时间轴上的所有的方向偏的方向和它的速度在一起做一个积分,其实就可以算出来导弹的轨迹。当然这里误差非常大。
但是万向节还是有小问题的。
Degeneration of Euler Angle 欧拉角的退化
回顾到旋转方程,会发现高斯欧拉角的这个表达方式,当把它沿着 Y 轴转了 90 度之后,Z 轴就跟 X 轴共轴了。这个时候沿着 Z 轴做的任何一个旋转,实际上是没有太大意义的。只有这两个旋转之间阿尔法角和伽马角之间的差值,才有真正的数学意义。这就是我们经常讲的欧拉角的一个退化情况,这个退化情况会导致整个模型的旋转锁死在某个方向了。
Problems of Euler Angle
- 万向锁
- 难以插值
- 比如说有两个空间上的旋转,我从旋转 1 到旋转 2 插值的时候,它就会出很大的问题。两个旋转不能简单地线性插值做。
- 难以合并旋转
- 拿之前手的两个关节做例子,假如两个关节各自旋转了一定的角度,最后导致的手掌面朝向,实际上不能直接把这两个旋转加在一起算出。
- 难以绕着 XYZ 轴以外的轴旋转
- 在真实世界里面,大部分的旋转并不是严格地沿着空间上的 XYZ 去做的。如果要沿着空间中一个定轴去旋转,这个旋转就会变得很难。
一般来讲,我们在给艺术家做编辑的时候,特别是物体的摆放的时候会经常用。但实际上做动画的时候我们不能用欧拉角,这就是因为欧拉角本身不好插值、叠加,而且也很难做定轴运算。但是欧拉角非常符合我们的自然认知。
Quaternion 四元数
理解四元数之前,首先要理解负数。
可以参考曹泽贤老师的演讲(精准空降):
Complex Number and 2D Rotation 复数
在笛卡尔坐标系里面,复数有一非常好的性质:对于二维空间的任何一个旋转,我可以用一个归一化的一个复数值,就是 (其中 就是负空间的轴,),就能够非常优雅地表表达两个旋转的叠加。
可以参考下之前的二维旋转公式:
就会发现 a 就是 ,b 就是 , 和 相加就可以用 dot product 完成。这样公式就非常简单。
实际上只有在三维空间的旋转,用四元数能够表达,再往上走它就不行了,它实际上是用群论证明了这件事情,就是只有在这种特定的三维空间的这个情况下,这套数学方法是 work 的。可以参考下上面曹则贤的演讲视频。
四元数首先定义了三个虚部 ,那么我们对于任何一个空间上的旋转,可以尝试用 去表达。
这三个虚轴,有一个数学规律: 。
那么 ,可以 ,可以发现三个轴都有这么个关系,两个轴乘起来就是另一个轴。
上图表示的就是四元数不同的表达形式,向量或者实部+虚部。
无论在线性代数,还是解析几何里,我们会定义一个模。它的模就是 模假设等于 1 的话,我们认为它就是一个四元数单位向量。
如果我这个四元数是 normalized 的,或者说是单位的四元数的话,那么它的共轭(conjugate,符号
*
)就是它的逆。如果四元素表达的是旋转,它的逆就表示了相反方向的旋转。
四元数的核心原理跟复数非常的相像,但是它的矩阵乘法的计算步数稍微多一点。
Euler Angle to Quaternion
四元素怎么表达欧拉角?
为什么里面的角度都是二分之一的角度呢?
Rotation by Quaternion
假设用四元数对一个点进行旋转,首先要把这个点的三维坐标变成四元数的形式。把它四元数的实部设成 0,然后把它的三个轴上的投影写到三个虚部里面,也就是 、、。
用四元数在三维空间对点进行旋转时候,实际上是一个表达旋转的四元数 在前,把上面凑出来的四元数(三维空间中的点,实部为 0 的四元数)夹在中间,然后再把 的逆放到后面。
这个有点像线性代数的 SVD 分解,所以其实四元数的很多原理跟矩阵运算是非常接近的。
Quaternion to Rotation Matrix
对于一个 normalize 的四元数,它的共轭就是它的逆。四元数的乘法实际上是矩阵运算。
和 的连乘就是矩阵的连乘,这时候可以得到一个很有意思的公式。就是说任何一个空间上的数字在 rotation 的时候,实际上算出来就是一个 3 乘 3 的矩阵,这个矩阵因为四元数相乘,有些项就消掉了,我们只需要知道它的 ,这个就是旋转的四元数。
这就意味着我们不需要再去算什么 、 了,实际上旋转要做的就是乘上这个矩阵,任何一个方向一个角度都可以被旋转起来。
Rotation Math by Quaternion
当要表达一个反向旋转的时候,我们只要求表达旋转的四元数的逆就可以了。
标准化的(normalize)四元数的逆就是求共轭,共轭就是取反虚部。
当有一个旋转 ,还有个旋转 ,假设想把一个点或者一个向量,按照 、 两次旋转,应该怎么旋转呢?其实旋转的四元数就是 乘 ,公式在这里不展开,但其实可以证明这两个事情是等价的。
假设一个方向 要转到方向 怎么做?
原理也简单,先定义一个 就是它的轴。首先把 叉乘 ,就能通过右手定则找到他们两个向量定义面的法向的方向 。
定义一个四元数,这个四元数它的实部就是 ,它的虚部就是 ,如果算出来 就放到虚部里面。这个 本身就能够表达这个从 向 的旋转。公式看起来简单,但这里面有很多数学推导,这节课不展开。
做动画系统的时候,也不会把这个公式再证明一遍,基本上这些公式从教科书拿过来就可以直接用。
Given Axis Rotation by Quaternion
有了四元数,想表达沿着一个给定轴的旋转也就非常的简单了。
想法也非常的简单,就是说我们定义了任何一个轴,要去旋转它的时候,我们其实定义了一个围绕这个轴旋转的四元数。
假设要转 角,四元数的实部就是 ,虚部是把那个轴的 放进去了,还加上了 。
用这个四元数去运算的话,要去任何一个向量都可以旋转过去。
有了这个数学方法的话,当我们有了个空间方向,给定了任何一个轴,比如说它是一个不是轴对齐的轴的话,其实就可以算出它的旋转了。
这样就把一个非常复杂的空间的旋转,包括大量的三角函数运算的这个问题,变成了一个非常简单的线性代数问题。
假设我们用欧拉角,假设有第一组旋转 ,有第二组旋转 ,这两次旋转的结果想用一个 去表达的话,其实非常的难,很复杂。而且这可能还有多义性,因为旋转超过了 ,这就转了一遍,而且可以正向旋转,也可以反向旋转。
用四元数的时候,就变成一些简单的没有任何歧义的数学运算。所以四元数实际上是哈密顿对数学的一个非常关键的贡献。而且这个贡献是当我们进入了计算机时代,进入了这个游戏的虚拟现实时代的时候非常有用的东西,包括机械在做刚体,和各种轨迹计算的时候也是很有用的。
这就是我们整个游戏动画的一个数学基础,因为 Rotation 是动画的最核心的一个元素。