结论

我直接抛出结论:

Gimbal Lock 产生的原因不是欧拉角也不是旋转顺序,而是我們的思维方式和程序的执行逻辑没有对应,也就是说是我们的观念导致这个情况的发生。

他人解释

首先我们看一下欧拉角的定义:

用一句话说,欧拉角就是物体绕坐标系三个坐标轴(x,y,z轴)的旋转角度。

在这里,坐标系可以是世界坐标系,也可以是物体坐标系,旋转顺序也是任意的,可以是xyz,xzy,yxz,zxy,yzx,zyx中的任何一种,甚至可以是xyx,xyy,xzz,zxz等等等等。。。。。。所以说欧拉角多种多样。欧拉角可分为两种情况:

1,静态:即绕世界坐标系三个轴的旋转,由于物体旋转过程中坐标轴保持静止,所以称为静态。

2,动态:即绕物体坐标系三个轴的旋转,由于物体旋转过程中坐标轴随着物体做相同的转动,所以称为动态。

网上的文章,一般都是这样解释的:

是指物体的两个旋转轴指向同一个方向。实际上,当两个旋转轴平行时,我们就说万向节锁现象发生了,换句话说,绕一个轴旋转可能会覆盖住另一个轴的旋转,从而失去一维自由度

通常说来,万向节锁发生在使用Eular Angles(欧拉角)的旋转操作中,原因是Eular Angles按照一定的顺序依次独立地绕轴旋转。让我们想象一个具体的旋转场景,首先物体先绕转X轴旋转,然后再绕Y轴,最后绕Z轴选择,从而完成一个旋转操作(飘飘白云译注:实际是想绕某一个轴旋转,然而Eular Angle将这个旋转分成三个独立的步骤进行),当你绕Y轴旋转90度之后万向节锁的问题就出现了,因为X轴已经被求值了,它不再随同其他两个轴旋转,这样X轴与Z轴就指向同一个方向(它们相当于同一个轴了)。

看得懂吗?我是看不太懂~

我的理解

我们先来考虑一下,旋转到底是怎么个旋转法。

静态的情况很好理解,怎么旋转都不会有问题,万向节的问题是不会出现在静态的旋转过程中的。但是你想像一下动态的旋转,动态的旋转,这里会有两个坐标系,看清楚了,两个坐标系!

  1. 世界坐标系
  2. 物体坐标系

那么这两者是什么关系呢?

一开始,这两个坐标系是重合的,但是旋转开始以后,世界坐标系不会变化,物体坐标系随着旋转就发生变化了。

亲爱的读者,你们先想想,这两个坐标系的关系,你们觉得物体旋转是绕着那个坐标系旋转的?

你会说:

你刚刚不是说了嘛!是绕着物体的坐标系旋转的!

对,没有错,那么在物体旋转的时候,物体的坐标系是不是一直在变化呢?是的!那么我們在给他旋转的参数的时候考虑到这个问题了吗?没有!

就是说我给他的旋转的参数是基于一种假设:每一次旋转都是以物体的坐标系为参考来进行的。就是说我是希望它每一次旋转前,都能够将旋转参数在物体坐标系上进行计算。很简单,一架飞机,作为机长,每次旋转以后他跟着飞机旋转了,后面的旋转操作自然是基于新的物体坐标系来的。

但是实际上,程序解析我给的数据的时候,只是简单地将三个轴的旋转一个个的相乘,也就是说,总的来说还是在最开始的那个坐标系(也就是一直不动的世界坐标系)下面计算的。而且需要注意的是: 每一次进行计算的顺序是确定不变的! 这也是为什么有人会说万向节问题是因为旋转顺序导致的樂。

看一下在OpenGL 实现旋转的代码:

void configRotateTrans(GLfloat radX, GLfloat radY, GLfloat radZ) {
GLfloat xTrans[4][4] = {0};
GLfloat yTrans[4][4] = {0};
GLfloat zTrans[4][4] = {0};
GLfloat tempMatrix[4][4] = {0}; xTrans[3][3] = 1;
xTrans[0][0] = 1;
xTrans[1][1] = cosf(radX);
xTrans[1][2] = -sinf(radX);
xTrans[2][2] = cosf(radX);
xTrans[2][1] = sinf(radX); yTrans[3][3] = 1;
yTrans[0][0] = cosf(radY);
yTrans[0][2] = sinf(radY);
yTrans[2][2] = cosf(radY);
yTrans[2][0] = -sinf(radY);
yTrans[1][1] = 1; zTrans[3][3] = 1;
zTrans[2][2] = 1;
zTrans[0][0] = cosf(radZ);
zTrans[0][1] = -sinf(radZ);
zTrans[1][0] = sinf(radZ);
zTrans[1][1] = cosf(radZ); // Multiply the 3 matrix
// rotateTrans = xTrans * yTrans * zTrans
multiMatrix(xTrans, yTrans, tempMatrix);
multiMatrix(tempMatrix, zTrans, rotateTrans);

看懂了吗,物体最终在哪个位置是简单粗暴地将绕xyz三个旋转的矩阵连续相乘得到的,计算的顺序是x->y->z,那么比如用户先输入绕y轴转90度,再输入绕x轴转90度。其实程序执行的时候,还是会先将x轴的数据进行计算,再计算y轴的数据。但是如果用户先输入绕y轴转90度,再输入绕z轴转90度,程序还是按照x-y-z的顺序来,只是正好用户也是这样输入。

现在我們明确了两点:

  1. 物体的旋转是以世界坐标系为参考的。
  2. 物体旋转的顺序是确定的,和用户输入的旋转的顺序无关。

那么还是刚刚那两种情况:

操作A:

用户第一次输入: 绕Y轴转90度,第二次输入:绕X轴转90度。

实际程序运行:先繞X轴转90度,再绕Y轴转90度。

操作B:

用户第一次输入: 绕Y轴转90度,第二次输入:绕Z轴转90度。

实际程序运行:先繞Y轴转90度,再绕Z轴转90度。

现在发挥一下想象力,当物体绕Y轴转动90度以后,物体坐标系的X轴和世界坐标系的Z轴是不是变成了同一个轴?好的,那么这个时候,用户无论输入的是绕X轴转还是绕Z轴转,最终物体转动是不是都是绕着这个轴(世界Z轴/物体X轴)。上面的操作A和操作B的结果是一样的!

这就是Gimbal Lock,这并不是什么缺陷,陷阱,而是我們的思维方式是错误的,所以导致这个问题的出现。

参考资料:GimbalLock万向节锁与四元数旋转

最新文章

  1. 基于AngularJs的上传控件-angular-file-upload
  2. Linux 安装基于(PHP5.5)memcache扩展
  3. clip 属性剪裁绝对定位元素
  4. Linux(Ubuntu 14.0)
  5. NumPy 上手一个例子 vectorsum.py
  6. extjs 中动态给gridpanel 复选框赋值
  7. windows下后台运行程序
  8. jquery checkbox勾选/取消勾选checked属性不生效问题
  9. mac OS X 10.10更新gcc 4.9.1后默认无法编译连接的问题
  10. Shodan的http.favicon.hash语法详解与使用技巧
  11. postman(一):主界面模块解析
  12. 海量数据处理之top K问题
  13. http协议文件与数据上传、及上传图片io流错误
  14. 说下spring生命周期
  15. char *a与char a[n]的区别
  16. 单点登录SSO+鉴权
  17. linux curl命令如何上传本地文件夹和下载文件
  18. P1216 数字金字塔
  19. 在springboot中用redis实现消息队列
  20. 20145232 韩文浩 《Java程序设计》第4周学习总结

热门文章

  1. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
  2. Centos6.5下编译安装mysql 5.6
  3. 01.LoT.UI 前后台通用框架分解系列之——小图片背景全屏显示(可自动切换背景)
  4. AutoMapper的介绍与使用(一)
  5. [转载]SQL语句中的日期计算
  6. 从国内流程管理软件市场份额看中国BPM行业发展
  7. docker – 你应该知道的10件事
  8. 在Linux虚拟机下配置jdk的环境变量
  9. Linux网卡驱动安装、防火墙原理
  10. 【腾讯Bugly干货分享】React Native项目实战总结