查看: 6975|回复: 12

转贴:给那些同我一样搞了2年3D游戏的还不清楚四元数的...

  [复制链接]
  • TA的每日心情
    奋斗
    2013-7-4 23:49
  • 签到天数: 21 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    发表于 2013-8-2 22:02:19 | 显示全部楼层 |阅读模式
    分享到:
    转贴:给那些同我一样搞了2年3D游戏的还不清楚四元数的朋友

    原文来自:http://www.cgjoy.com/thread-814-1-1.html  (由 铁豌豆 发表于 2008-8-13 21:42:28


    内容转载如下:

    好吧,我必须承认到目前为止我还没有完全理解四元数,我一度把四元数理解为轴、角表示的4维向量,也就在下午我才从和同事的争辩中理解了四元数不完全是角、轴这么简单,为此写点心得给那些同我一样搞了2年3D游戏的还不清楚四元数的朋友。

    为什么使用四元数
    为了回答这个问题,先来看看一般关于旋转(面向)的描述方法-欧拉描述法。它使用最简单的x,y,z值来分别表示在x,y,z轴上的旋转角度,其取值为0-360(或者0-2pi),一般使用roll,pitch,yaw来表示这些分量的旋转值。需要注意的是,这里的旋转是针对世界坐标系说的,这意味着第一次的旋转不会影响第二、三次的转轴,简单的说,三角度系统无法表现任意轴的旋转,只要一开始旋转,物体本身就失去了任意轴的自主性,这也就导致了万向轴锁(Gimbal Lock)的问题。
    还有一种是轴角的描述方法(即我一直以为的四元数的表示法),这种方法比欧拉描述要好,它避免了Gimbal Lock,它使用一个3维向量表示转轴和一个角度分量表示绕此转轴的旋转角度,即(x,y,z,angle),一般表示为(x,y,z,w)或者(v,w)。但这种描述法却不适合插值。
    那到底什么是GimbalLock呢?正如前面所说,因为欧拉描述中针对x,y,z的旋转描述是世界坐标系下的值,所以当任意一轴旋转90°的时候会导致该轴同其他轴重合,此时旋转被重合的轴可能没有任何效果,这就是Gimbal Lock,这里有个例子演示了Gimbal Lock,点击这里下载。运行这个例子,使用左右箭头改变yaw为90°,此时不管是使用上下箭头还是Insert、Page Up键都无法改变Pitch,而都是改变了模型的roll。
    那么轴、角的描述方法又有什么问题呢?虽然轴、角的描述解决了Gimbal Lock,但这样的描述方法会导致差值不平滑,差值结果可能跳跃,欧拉描述同样有这样的问题。

    什么是四元数
    四元数一般定义如下:
    q=w+xi+yj+zk
    其中w是实数,x,y,z是虚数,其中:
    i*i=-1
    j*j=-1
    k*k=-1
    也可以表示为:
    q=[w,v]
    其中v=(x,y,z)是矢量,w是标量,虽然v是矢量,但不能简单的理解为3D空间的矢量,它是4维空间中的的矢量,也是非常不容易想像的。
    四元数也是可以归一化的,并且只有单位化的四元数才用来描述旋转(面向),四元数的单位化与Vector类似,
    首先||q|| = Norm(q)=sqrt(w2 + x2 + y2 + z2)
    因为w2 + x2 + y2 + z2=1
    所以Normlize(q)=q/Norm(q)=q / sqrt(w2 + x2 + y2 + z2)

    说了这么多,那么四元数与旋转到底有什么关系?我以前一直认为轴、角的描述就是四元数,如果是那样其与旋转的关系也不言而喻,但并不是这么简单,轴、角描述到四元数的转化:
        w   =   cos(theta/2)

        x   =   ax * sin(theta/2)

        y   =   ay * sin(theta/2)

        z   =   az * sin(theta/2)
    其中(ax,ay,az)表示轴的矢量,theta表示绕此轴的旋转角度,为什么是这样?和轴、角描述到底有什么不同?这是因为轴角描述的“四元组”并不是一个空间下的东西,首先(ax,ay,az)是一个3维坐标下的矢量,而theta则是级坐标下的角度,简单的将他们组合到一起并不能保证他们插值结果的稳定性,因为他们无法归一化,所以不能保证最终插值后得到的矢量长度(经过旋转变换后两点之间的距离)相等,而四元数在是在一个统一的4维空间中,方便归一化来插值,又能方便的得到轴、角这样用于3D图像的信息数据,所以用四元数再合适不过了。

    关于四元数的运算法则和推导这里有篇详细的文章介绍,重要的是一点,类似与Matrix的四元数的乘法是不可交换的,四元数的乘法的意义也类似于Matrix的乘法-可以将两个旋转合并,例如:
    Q=Q1*Q2
    表示Q的是先做Q2的旋转,再做Q1的旋转的结果,而多个四元数的旋转也是可以合并的,根据四元数乘法的定义,可以算出两个四元数做一次乘法需要16次乘法和加法,而3x3的矩阵则需要27运算,所以当有多次旋转操作时,使用四元数可以获得更高的计算效率。

    为什么四元数可以避免Gimbal Lock
    在欧拉描述中,之所以会产生Gimbal Lock是因为使用的三角度系统是依次、顺序变换的,如果在OGL中,代码可能这样:
    glRotatef( angleX, 1, 0, 0)

    glRotatef( angleY, 0, 1, 0)

    glRotatef( angleZ, 0, 0, 1)


    注意:以上代码是顺序执行,而使用的又是统一的世界坐标,这样当首先旋转了Y轴后,Z轴将不再是原来的Z轴,而可能变成X轴,这样针对Z的变化可能失效。
    而四元数描述的旋转代码可能是这样:
    TempQ = From Eula(x,y,z)
    FinalQ =CameraQ * NewQ
    theta, ax, ay, az = From (FinalQ)
    glRotatef(theta, ax, ay, az);
    其中(ax,ay,az)描述一条任意轴,theta描述了绕此任意轴旋转的角度,而所有的参数都来自于所有描述旋转的四元数做乘法之后得到的值,可以看出这样一次性的旋转不会带来问题。这里有个例子演示了使用四元数不会产生Gimbal Lock的问题。

    关于插值
    使用四元数的原因就是在于它非常适合插值,这是因为他是一个可以规格化的4维向量,最简单的插值算法就是线性插值,公式如:
    q(t)=(1-t)q1+t q2
    但这个结果是需要规格化的,否则q(t)的单位长度会发生变化,所以
    q(t)=(1-t)q1+t q2 / || (1-t)q1+t q2 ||
    如图:


    尽管线性插值很有效,但不能以恒定的速率描述q1到q2之间的曲线,这也是其弊端,我们需要找到一种插值方法使得q1->q(t)之间的夹角θ是线性的,即θ(t)=(1-t)θ1+t*θ2,这样我们得到了球形线性插值函数q(t),如下:
    q(t)=q1 * sinθ(1-t)/sinθ + q2 * sinθt/sineθ
    如果使用D3D,可以直接使用D3DXQuaternionSlerp函数就可以完成这个插值过程。

    (转贴完)




    回复

    使用道具 举报

  • TA的每日心情
    开心
    2020-1-18 12:34
  • 签到天数: 1673 天

    连续签到: 2 天

    [LV.Master]伴坛终老

    发表于 2013-8-3 09:58:29 | 显示全部楼层
    好像很神奇的样子
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    慵懒
    2014-8-4 09:17
  • 签到天数: 14 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    发表于 2013-8-5 07:55:54 | 显示全部楼层
    学习 了,帮顶
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2014-11-15 21:16
  • 签到天数: 179 天

    连续签到: 1 天

    [LV.7]常住居民III

    发表于 2013-8-6 15:34:40 | 显示全部楼层
    拜读一下,有助于理解博士的小四。。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2013-8-20 15:04
  • 签到天数: 4 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2013-8-15 15:24:43 | 显示全部楼层
    学习了,顶一个
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2013-8-29 10:20:41 | 显示全部楼层
    好厉害,,虽然还是不是很懂。。。。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    郁闷
    2013-9-1 08:07
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2013-9-1 09:18:05 | 显示全部楼层
    完全看不懂 好好学习慢慢研究吧
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2013-10-15 11:19
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2013-10-15 12:18:11 | 显示全部楼层
    没有用力去理解 感觉很高端 以后再来
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2013-12-10 13:32:01 | 显示全部楼层
    很高深的样子,学习,没准以后用得着
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2021-7-16 10:04
  • 签到天数: 530 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2014-10-29 23:09:50 | 显示全部楼层
    看了一天,还是没有看懂和陀螺仪的关系
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-12-24 21:55 , Processed in 0.207517 second(s), 34 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.