欧拉角、万向节锁、顺规

本文最后更新于:12 天前

最早接触四元数是unity3d里面的旋转,当时不太理解使用四元数的意义(在此时的我看来欧拉角已经可以完全表示一个朝向了),后来在旋转时出了很多莫名其妙的问题,发现有必要remake一下。

参考资料,感谢大佬们

https://krasjet.github.io/quaternion/quaternion.pdf

https://www.bilibili.com/video/BV1SW411y7W1?spm_id_from=333.999.0.0

为什么直接改欧拉角,效果经常与预期不符

现在考虑一个问题:在你修改欧拉角时,意味的到底是“绕自身坐标轴旋转”,还是“绕世界坐标轴旋转”?

在unity里面测试,多测测就会发现:既不是按自身也不是按世界,而是有时按自身有时按世界??

如果你随便拿一支笔(不要用unity),用手先绕X轴旋转90度,再绕Y轴旋转90度;再反过来试一下,会发现得到的位置不一样了。

这是因为旋转不具有交换律,相应的矩阵乘法也不具有交换律。

欧拉角

欧拉角需要区分为两种:动态欧拉角和静态欧拉角,他们都需要定义顺规。

静态欧拉角即绕世界静止坐标系旋转,动态欧拉角即绕自身坐标系旋转,前一个轴的旋转会影响下一个轴。

这里只分析动态欧拉角(我认为更好用)

顺规

考虑这么一个问题:如何实现一个可以自由旋转的飞机(假设面向+Z轴,要求Yaw-Pitch-Roll)?

可以用三个嵌套(做父物体)的箱子,最里面的箱子可以直接用飞机本身,所有物体的坐标都是相对父物体的;

第一个箱子仅绕自身y轴旋转(实现Yaw),第二个仅绕自身x轴旋转(Pitch),第三个仅绕自身z轴旋转(Roll)

通过控制这三个箱子,我们可以用比较好理解的方式合理、正确地旋转飞机。

这样的箱子便是动态欧拉角中的万向节,上述例子其实就是一个顺规为YXZ的动态欧拉角。

注意:这个顺规如果改变的话,飞机的旋转就很奇怪了,这并不是因为其他顺规错了(在数学上都没错)

而是因为我们对飞机的自然直觉就是符合动态欧拉角下的Yaw-Pitch-Roll顺规的。

在遇到其他复杂旋转问题时也可以使用箱子嵌套的方式思考,然后得出一个理想的顺规。

至于万向节锁,个人认为并不是什么大问题(飞机头垂直向上时,Roll和Yaw结果相同),依旧符合我们的自然直觉,且可以通过Pitch化解。

旋转矩阵表示

这里使用列向量

我们通常用一个transform矩阵来表达一个物体的位置,大小,朝向信息。

  • 它表示的是物体从世界坐标的原点(没有缩放、平移、旋转)到当前状态经历的变换。
  • 它能表示物体的坐标系
  • 更一般地,它是物体顶点从局部坐标变换到世界坐标时需要乘上的矩阵。
直接维护Transform

单独的旋转、平移、缩放矩阵形式在此不再多提及,它们直接应用在一个向量(点)上的意义非常明确。

假设有了一个物体,它的Transform为 $T$(已经经过了一些复杂变换),现要让这个物体继续进行某种位移,位移矩阵为 $V$

假如我们直接令 $T =V\times T$,即在左侧乘,效果是怎么样的?

可以想象 $T$ 的右边还有个向量 $v$,考虑这单个 $v$ 的变换,它先变换 $T$,然后再位移 $V$,即最终效果为在世界坐标系下位移了 $V$,很好理解。

如果 $T=T\times V$ 呢?

这个 $v$ 在所有原先的变换前,先进行了位移,然后再变换 $T$,相应的,这个位移本身也会被变换 $T$。

如果把变换前的 $T$ 看做一个坐标系,就可以说,这是在物体自身坐标系下位移了 $V$。

另一个角度,如果要在自身坐标系下位移,可以利用相似矩阵 $TVT^{-1}$,乘上原有的矩阵就变成 $TV$ 了。

总结:

  • 左边乘变换矩阵,相当于在世界(父)坐标系下变换
  • 右边乘变换矩阵,相当于在自身坐标系下变换

用旋转矩阵表示旋转不会遇到歧义、死锁的问题,缺点是占用空间大,运算量大(欧拉角使用3个数,四元数使用4个数,而旋转矩阵使用了16个数),另外不太直观。

从Transform中看

如果把Transform矩阵看成一个仿射变换和一个位移的组合(世界坐标下位移),通常我们说它是先仿射再位移得到的。

为什么?不是因为先位移不对,而是先位移的话,位移的量就不再是矩阵第四列的三个值了。我们说先仿射再位移,是基于位移量直接等于第四列的值来说的。

而从仿射矩阵中分解出缩放和旋转,需要另做一些计算。

我更喜欢用基向量、坐标系的方式来考虑矩阵,它的前三列分别表示了这个坐标系的三个基向量,最后一列表示这个坐标系原点的位置。

四元数表示

$$
\newcommand{\vec}{\bold}
$$

https://krasjet.github.io/quaternion/quaternion.pdf 推导的非常好

四元数表示为 $q=[s, \vec v], \vec v=[x,y,z]$,$q = a+bi+cj+dk$

有三个虚部,满足关系:
$$
i^2 = j^2 = k^2 = ijk = -1
$$
可以推得 $jk=i, ij=k$ 等等关系

四元数乘法也按照多项式相乘规则,展开化简后可得:
$$
q_1 = [s, \vec v], q_2 = [t, \vec u]\
q_1 q_2 = [st-\vec v\cdot \vec u, s\vec u+t\vec v + \vec v \times \vec u]
$$
如果两个四元数的实部都为0(纯四元数),则会得到:
$$
q_1q_2 = [-\vec v\cdot \vec u, \vec v \times \vec u]
$$
下面直接给出结论:

对任意向量 $\vec v$,沿着轴 $\vec u$ 旋转 $\theta$ 度得到 $\vec v’$

可以构造四元数:$v = [0, \vec v], q = [cos(\frac{1}{2}\theta), sin(\frac{1}{2}\theta) \vec u]$

旋转可以用四元数乘法表示:
$$
[0, \vec v’] = qvq^{}
$$
其中 $q^
$ 即将虚部取反,实部不变。注意 $q$ 是一个单位四元数。

同样的,给定一个四元数,也可以轻松得到对应的旋转轴和角度。


欧拉角、万向节锁、顺规
http://www.lxtyin.ac.cn/2022/11/16/2022-11-16-欧拉角、万向节锁、顺规问题的重新理解/
作者
lx_tyin
发布于
2022年11月16日
许可协议