Unity中旋转方式的探究与对万向节死锁(Gimbal Lock)的理解

Gimbal Lock

Gimbal Lock的原理网上已经有很多资料,详细可以看介绍视频。视频讲到Gimbal Lock的时候提到x,y,z三个坐标轴是有从属关系(hierarchical system)的,也就是说对于如图所示的系统,绕y轴旋转的时候x,z轴都会随着改变;绕x旋转的时候z轴会改变;绕z旋转的时候y,x都不会变,正是因为这样,所以当物体绕x旋转90°时y轴与z轴会处在同一平面,此时DoF就会减少1,导致了Gimbal Lock的现象。

 

Unity中物体旋转方式

首先我们以Unity3D来看看物体在其中是如何旋转的,这篇文章中提到

Editor中Transform组件的旋转轴是父节点的模型空间坐标轴,如果没有父节点,则旋转轴是世界空间坐标轴

脚本中用Rotate函数在Space.World中进行旋转,旋转轴就是世界坐标系的坐标轴

脚本中用Rotate函数在Space.Self中进行旋转,旋转轴就是局部坐标系的坐标轴

 并且在文章中还做了实验:

1. 静态欧拉角

这种情况对应着上面所述的使用Space.World进行旋转,以及Inspector中的旋转。即使旋转轴在旋转的过程中保持不变,旋转的顺序会决定最后的旋转结果。我们看下面的例子会很清晰的理解:

  • 情形一:首先绕世界坐标系的x轴旋转90度,再绕世界坐标系的y轴旋转90度

RotateOrder1

  • 情形二:首先绕世界坐标系的y轴旋转90度,再绕世界坐标系的x轴旋转90度

RotateOrder2

可以看到,由于旋转顺序的不同,最终导致了旋转结果的不同!(究其本质,是因为矩阵乘法不满足交换律)

Inspector中的rotation值

上述文章中提到的现象应该是针对的是脚本的情况,因为在Inspector测试中发现不论第一种情形还是第二种情形旋转的结果是一样的。之后我针对inspector中Transform控件的rotation值进行了一些测试,来探究该值究竟是如何影响物体旋转的,在测试后得出了结论:假设物体初始状态(没有任何旋转)是A,将rotation的值变为(x1,y1,z1)后得到的状态是B,此时B的位置是是按照z-x-y的顺序(Unity文档中提到的顺规)将物体从初始状态A(即rotation设置为0,0,0)依次绕自身z轴,y轴,x轴旋转z1,y1,x1角度得到的。若此时再将rotation的值变为(x1,y1,z2),称为状态C,那么实际上物体发生的变化不是在B的基础上绕z轴旋转z2-z1角度,而是重新在A状态的基础上重新计算了旋转角(x1,y1,z2),得到状态C。再将物体从现状态B变换过去,所以我们观察到的现象是物体不一定是按照局部坐标系或者世界坐标系旋转的。

Inspector旋转中的万向节死锁

在得到了上述结论之后我们就能对在inspector旋转出现的Gimbal Lock现象做出解释了。我们先将rotation中x的值改为90°,然后再改变y的值与z的值,会发现改变这两个值物体都是在同一个方向上进行旋转的,这种现象就是我们遇到的Gimbal Lock。原因就是实际上在每一次有新的rotation值的时候Unity都重新进行了一次计算,旋转角度为(90°,y1°,z1°)时,进行的过程是先将物体绕z轴旋转z1°,再绕x轴旋转90°,此时z轴转到了现在世界坐标系y轴的位置上,意思就是说接下来在y轴旋转y1°的操作与原来绕z轴旋转z1°实际上是在同一个方向,这就是在世界坐标系下旋转(静态欧拉角)的Gimbal Lock现象。对于局部坐标系下旋转(动态欧拉角)的情况之前的参考文章也有提到,其与世界坐标系不同的是物体以当前旋转的坐标作为状态A再进行操作,其他过程与上述情况类似,产生Gimbal Lock的情况也是类似的。

                                                                                  

                                 图1:初始位置                               图2:绕x轴旋转90°后z轴所在的位置与世界坐标系下z轴位置重合

总结一下,视频中提到的从属关系实际上说的是三维旋转的顺规问题,也正是由于这种机制,物体在某个旋转方向上会失去一个DoF(Degree of Freedom),这种现象就是Gimbal Lock,解决方法就是采用四元数旋转。

 

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页