在看过网上文章后,发现有一些文章描述含糊其词,说明作者对万向节锁的理解不够充分;有的文章前后矛盾,误导学习者;有些文章则连欧拉角是什么都没有理解。这样混杂的文章将原本非常简单的一个万向节锁问题解释的乱七八糟,复杂无比。这里我试着用图形的方式将这个问题讲解清楚。
万向轴锁是由于采用欧拉角描述物体在三维世界的朝向所带来的问题。
参考文章及其问题见文章最后,行文中“文章X”这样的引用亦即引用编号为此的参考文章。
什么是欧拉角
欧拉角描述方式是用三个数分别表示物体依次绕某一轴旋转的角度,注意旋转轴并非世界坐标系坐标轴,而是旋转后的物体坐标系轴。欧拉角描述方式参见文章1中“Definition”一节,文章中图我引用过来
图片中蓝色为世界坐标系,红色为物体坐标系,绿色线为第一次旋转后红X轴所在的位置。
这篇wiki文章针对此图解释的中文版为:
zxz 順規的歐拉角可以靜態地這樣定義:
- α 是 x-軸與交點線的夾角,
- β 是 z-軸與Z-軸的夾角,
- γ 是交點線與X-軸的夾角。
我们可以看到最终物体坐标系是由三步变换来的。第一步,绕当前红Z轴(和蓝z轴重合)旋转α度;第二步,绕绿N轴(即当前的红X轴)旋转β度;第三步,绕当前的红Z轴(即图中的可以看到的红Z轴的位置)旋转γ 度。
在旋转的三步中,我们可以看到,每次旋转都是绕物体坐标系轴旋转的。
一个演示程序
使用方法
这里有一个演示程序,来自文章2(下载地址见本文参考文章部分)
演示程序经过测试可以在wine下成功运行。演示程序的使用方法:分别使用上下箭头和insert/pageup键旋转物体,发现分别是绕x轴和z轴旋转。按r键复位,按左右箭头将物体绕y轴旋转90度,然后你会发现使用上下箭头和insert/pageup键旋转物体造成的效果是一样的,这就是万向节锁。
演示程序的解释
我们说万向节锁是欧拉角表示方式造成的,那和这个演示程序有什么关系呢?请看演示程序的源码:
glLoadIdentity();//resettheview glTranslatef(-camera_pos[0],-camera_pos[1],-camera_pos[2]);//movecamera glRotatef(camera_roll,0.0f,0.0f,1.0f);//RotateX,Y,Z glRotatef(camera_yaw,0.0f,1.0f,0.0f); glRotatef(camera_pitch,1.0f,0.0f,0.0f); //modelobjects-justdrawframeandcubes glColor3f(0.5,0.5,0.5);//origin glutWireCube(1.0);
我们知道openGL中glTranslate,glRotate方法改变的是绘图坐标的位置和旋转,并且每次改变是在上次改变的基础上进行的,连续三个glRotate方法的行为和欧拉角表示方法行为相同,都是使用物体坐标系(或者说绘图坐标系)。
好了,到这里我们就已经证明了欧拉角造成了万向轴锁。那欧拉角又为什么会产生万向轴锁呢?我们用图来表示一种特殊情况下这五句话的执行效果。
首先glLoadIdentity();将绘图坐标归位
然后glTranslatef(0,0,1);移动绘图坐标
然后绕z轴旋转
然后绕y轴旋转,这里要注意,绘图坐标的旋转按绘图坐标当前的状态进行旋转(即绕绘图坐标自身的y轴旋转),所以旋转的效果是
最后绕x轴旋转(此时的绘图x轴已经和第一次旋转时的z轴重合)
这下就清楚了,你可以想象一下在第一步绕z轴旋转的时候转50度,然后再继续进行后面的步骤,你会发现效果和在最后一步绕x轴旋转50度效果是一模一样的。这就是万向节锁,造成万向节锁的原因是使用这种连续glRotate方法造成的。可以发现如果你想产生一个万向节锁,那你只需要在第二次旋转转90度即可。
为什么叫Gimbal Lock?
看一个陀螺仪就知道了
陀螺仪的旋转和刚才说的依次按zyx轴旋转相似, 将这个陀螺仪按z轴旋转后,沿y轴的旋转就是按照位置改变后的y轴进行旋转。
总结
好了,这就是万向节锁。再多说什么都是废话。
在这里我评论一些文章,希望大家思考一下:
http://blog.donews.com/wanderpoet/archive/2005/07/04/453608.aspx
以及其翻译
http://coazure-code.blogspot.com/2010/01/gimbal-lock.html
http://www.cnblogs.com/soroman/archive/2006/10/11/526163.html
http://www.cnblogs.com/soroman/archive/2008/03/24/1118996.html
我相信这篇文章就是误导源,文中举的telescope和high flying aircraft的例子使用的是世界坐标系描述旋转望远镜,和欧拉角没有任何关系,其推发现的需要更换轴向描述旋转也和万向节锁毫不相干,并且仔细思考后会发现使用欧拉角描述望远镜的旋转不会发生文中所谓的“万向节锁”。
并且我对这个文章中给出的演示图片非常不满,图中的x轴为什么不会跟随旋转呢?文中竟然解释:Since the X component has already been evaluated it doesn’t get carried along with the other two axis。这里分明就是为了拼凑出轴重合的效果而主观臆造的,作者估计并不清楚为什么这个轴会重合,重合的是什么轴。
还有文章对欧拉角也有误解,认为欧拉角就是以世界坐标系为参考的:
http://www.sineysoft.com/blog/post/Quaternions.html
我比较认同的一篇文章:
http://www.cnblogs.com/Baesky/archive/2011/09/04/GimbalLock.html
参考资料:
1.维基百科http://en.wikipedia.org/wiki/Euler_angles
我们看到这篇文章上没有标注是否有争议,说明其中的内容是获得认可的。
2.gamedev的一篇旧文章http://archive.gamedev.net/archive/reference/programming/features/qpowers/
其中的演示程序 http://archive.gamedev.net/archive/reference/programming/features/qpowers/CameraEuler.zip
附件打包:gimbal.tar