万向节死锁原因

53次阅读

共计 1503 个字符,预计需要花费 4 分钟才能阅读完成。

什么是欧拉旋转

transform.Rotate(x, y, z);  

上面是 Unity 中,旋转的表示的常用方法,里面的三个分量 x、y、z 就是欧拉角,这三个分量分别是绕 x 轴、y 轴、z 轴旋转的角度。

静态欧拉角

所谓静态欧拉角,就是其旋转轴使用的是静止不动的参考系。例如:

transform.Rotate(new Vector3(0, 10, 0), Space.World); // 物体围绕世界坐标系的 y 轴旋转 10 度 

这里面物体围绕世界坐标系的轴的旋转角度就是静态欧拉角。还有一种情况就是子物体绕其父物体的坐标系的轴的旋转角度也是静态欧拉角(也就是 Unity 编辑器中 Transform 组件中的旋转数值,其显示的旋转轴既不是世界坐标系的坐标轴,也不是本地坐标系的坐标轴。编辑器中 transform 的旋转轴是父节点的坐标轴)。

动态欧拉角

动态欧拉角,使用的是刚体本身作为参考系,因而会随着刚体的旋转而旋转。例如:

transform.Rotate(new Vector3(0, 10, 0), Space.Self); // 物体围绕自身坐标系的 y 轴旋转 10 度 

这里面物体围绕自身坐标系的轴的旋转角度就是动态欧拉角。

二者之间的关系

静态欧拉角和动态欧拉角之间是可以相互转化的,具体转化可以参考这篇文章。
其结论就是: 在 Space.World 中旋转以 Z-X-Y 归顺旋转角度(x、y、z),等价于在 Space.Self 中分别顺次旋转(0,y,0)、(x,0,0)、(0,0,z)。
例如:

privatevoid Rotate_World(float x, float y, float z) {transform.Rotate(x, y, z, Space.World);  
}  
privatevoid Rotate_Self(float x, float y, float z) {transform.Rotate(0, y, 0, Space.Self);  
    transform.Rotate(x, 0, 0, Space.Self);  
    transform.Rotate(0, 0, z, Space.Self);  
}  

以上两段代码就是等价的。

万向节死锁现象

我们已经明白了什么是动态欧拉角与静态欧拉角,且二者可互相转化,但只有动态欧拉角才有万向节死锁现象,静态欧拉角不会产生万向节死锁,解释如下。
假如一个物体的物体坐标系 A 和世界坐标系 B 重合,物体坐标系 A 先围 A 的 Y 轴转 50 度得到新的物体坐标系 C(旋转前 A 和 B 的 y 轴还处于同一平面,从世界坐标系 B 来看,物体确实围绕 y 中轴旋转了),然后物体坐标系 C 在绕 C 的 x 轴转 90 度得到新的物体坐标系 D(旋转前 C 和 B 的 X 轴还处于同一平面,从世界坐标系 B 来看,物体确实围绕 X 中轴旋转了),这时候我们会发现新的物体坐标系 D 的 Z 轴和世界坐标系 B 的 Y 轴重合了,这时候我们再让物体坐标系 D 绕 D 的 z 轴转 10 度,从世界坐标系 B 来看,就好像是绕 y 轴旋转了,好像缺失了一个轴,这就是万向节死锁。

如何产生万向节死锁

从上面的过程就可以看到,要产生万向节锁,只需针对规顺的中间的那个坐标轴,进行 90 度的旋转,就会使得顺规前后两头的坐标轴产生共线。对于 Unity 中使用的 Z -X- Y 顺规,这个中间的坐标轴就是 X 轴。

四元数为什么会解决万向节死锁

欧拉旋转的本质是将绕任意轴旋转最终分解为绕 x,y,z 轴的旋转,才会导致万向节死锁。而用四元数旋转可直接表示为绕任意轴旋转。通过四元数的表示方法就可以看出

其他好文章

  • 强烈推荐, 我这篇博客可以说是对这篇博客的小总结。
  • 冯乐乐大神的文章,里面有欧拉旋转运行流程
  • Unity 圣典,用画图法证明万向节死锁。
  • 四元数的相关计算
  • 《3D 数学基础:图形与游戏开发》

正文完
 0