万向节死锁原因

3,368 阅读3分钟

什么是欧拉旋转

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轴的旋转,才会导致万向节死锁。而用四元数旋转可直接表示为绕任意轴旋转。通过四元数的表示方法就可以看出

其他好文章