为什么使用四元数

转载:http://www.game798.com/html/2007-05/3689.htm

好吧,我必须承认到目前为止我还没有完全理解四元数,我一度把四元数理解为轴、角表示的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)。但这种描述法却不适合插值。

那到底什么是Gimbal Lock呢?正如前面所说,因为欧拉描述中针对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函数就可以完成这个插值过程。

时间: 2024-10-12 15:32:42

为什么使用四元数的相关文章

基于四元数的姿态解算算法图解

下面的两个地址是我存放在百度云网盘的附件,分别是基于四元数的互补滤波法的图解和梯度下降法的图解.笔者采用MindManager思维导图软件对上述两种算法进行详细的解释,非常形象. 希望这种方式能够让大家快速.准确的理解这两种算法的流程. 互补滤波法: http://pan.baidu.com/s/1c0b8qJ2 梯度下降法: http://pan.baidu.com/s/1sjI1l5F

四元数quaternion

四元数的简单方法运用四元数在Unity3D中的作用就是拿来表示旋转. AngleAxis 创建一个旋转,绕着某个轴旋转,返回结果是一个四元数. 跟ToAngleAxis实现的是相反的功能. Angle 返回两个旋转值(四元数)之间的角度,返回值是float类型的角度值. (不知道这个值算出来后有什么用) Dot 点乘,我也不太理解其意义. 参见 eulerAngles 返回表示旋转的欧拉角度(Vector3 即3个值) (如果调用的是某个物体,则表示该物体当前位置是从原始位置怎么旋转过来的, 其

欧拉角、四元数和矩阵的对比(转)

三维空间的旋转可以用欧拉角,旋转矩阵,轴-角,四元数,双四元数来表示,本文主要总结这些表示方法的优缺点. 一.  欧拉角(Euler-Angles) 1.1    介绍 欧拉角包括3个旋转,根据这3个旋转来指定一个刚体的朝向.这3个旋转分别绕x轴,y轴和z轴,分别称为Pitch,Yaw和Roll,如下图所示.欧拉角可以表示成z-x-z,x-y-x,z-y-z等形式,旋转的顺序影响结果. Pitch Yaw Roll 图1. 欧拉角的表示 欧拉角很重要的一个优点就是直观,容易理解. 欧拉角主要有下

WorldWind源码剖析系列:四元数类

PluginSDK中的Quaternion4d类可能是感觉Microsoft.DirectX. Quaternion类不太实用或不够用,自己有重新写的. 四元数是英国数学家哈密顿(W.R.Hamilton)在1843年发现的,由于矩阵论的不断丰富和不断完善,人们更乐意采用矩阵来解决实际工程中的问题,这导致四元数在相当长的时间里没有被人们重视,更没有得到实际的应用.随着计算机图形学的发展,人们发现利用四元数可以很好地处理解决旋转运算等问题,这一理论又开始被人们重视,并在许多领域逐渐得到应用. 四元

四元数

四元数与欧拉角之间的转换 在3D图形学中,最常用的旋转表示方法便是四元数和欧拉角,比起矩阵来具有节省存储空间和方便插值的优点.本文主要归纳了两种表达方式的转换,计算公式采用3D笛卡尔坐标系: 图1 3D Cartesian coordinate System (from wikipedia) 定义分别为绕Z轴.Y轴.X轴的旋转角度,如果用Tait-Bryan angle表示,分别为Yaw.Pitch.Roll. 图2 Tait-Bryan angles (from wikipedia) 一.四元

Quaternion:通过API对Quaternion(四元数)类中的方法属性进行测试(一)

1.差值方法Lerp 返回一个四元数,返回From与To的差值,并以Time.detaltime*speed变化着 Quaternion.Lerp(From.rotation,To.Rotation,Time.detaltime*speed); 例如 以下代码中C,D将以A.Rotation为起始点,以B.rotation为结束点以total为速度进行变化 using UnityEngine; using System.Collections; pubilc class Eaxmble:Mono

四元数运动学笔记(3)四元数和旋转相关的约定表述

1.四元数的约定表述1.1 四元数表述的差异1.2 Hamilton vs JPL1.2.1元素的顺序1.2.2 左手系和右手系1.2.3 旋转操作的对象1.2.4 旋转操作的方向1.3 文章采用的表述1.4扰动和时间导数1.4.1右扰动和左扰动1.4.2 Hamilton表示下的(L-G)的四元数时间导数1.4.3 其他有用的表述方式1.5 barfoot书中表述2.旋转角速率表示旋转积分2.1零阶积分2.2一阶积分2.3归一化处理 1.四元数的约定表述 1.1 四元数表述的差异 根据实部虚部

四元数运动学笔记(4)旋转的雅克比矩阵

1.相对于旋转向量的雅克比2.相对于四元数的雅克比2.1相关公式2.2推导雅克比 1.相对于旋转向量的雅克比 这里在全局系下利用左扰动进行推导: 2.相对于四元数的雅克比 2.1相关公式 三叉积公式: 纯实部的四元数和四元数相乘,这里是实数 两个纯虚四元数相乘: 2.2推导雅克比 由以上三个公式可以得到以下公式的推导,其中这里的在涉及到四元数相乘的情况时,都是四元数的表示形式(纯实部四元数和纯虚部四元数),其他情况下则是正常的标量和三维向量. 旋转过程相对于四元数的雅克比 null

求多个四元数的平均数

最近要对前几帧数据进行平均数采样.所以又造了一个轮子 此方法经过一些单数和双数的基本测试,除了无效四元数这种特殊情况. Quaternion Average(Quaternion[] quatArray) { var result = new Quaternion(); var count = quatArray.Length; var error = 0; while (count > 1) { if (error >= 10000) break; error++; var k = 0; f

欧拉角与四元数(计算,编程)

欧拉角 四元数计算公式 四元数的基本数学方程为 : q = cos (a/2) + i(x * sin(a/2)) + j(y * sin(a/2)) + k(z * sin(a/2)) 其中a表示旋转角度,(x,y,z)表示旋转轴 下面是如何把具体的四元数与旋转轴和旋转角度对应起来. 1.指出旋转轴和旋转角度,如何转化为四元素. 假定旋转轴是:RAxis = Z轴,换算成三维空间单位向量就是RAxis = [0 0 1],旋转60度 那么转化成四元数就是 q.w=cos(60°/2) = 0.