初探四元数

来源:互联网 发布:淘宝接单大厅 编辑:程序博客网 时间:2024/05/21 08:52
 

      说到四元数,就不得了解它的来源。 从古时候的打结计数,到十进制整数,小数,有理数,无理数,实数,再到后来的复数。数的扩展好像到了尽头,有人已经断言:扩充到此,数域已经完备了。复数,通常是为我们所熟知的二元复数,已经在几何方面得到了应用,成功的把几何问题转换成数学问题(复数域,复平面)。关于复数的几何意义(表示空间中的点或向量),二维空间也能通过复数表示。理所当然,人们就思索关于三维空间和复数的关系。我想在这里说点关于向量的东西,向量在20世纪得到充足的重视和应用,也显示了它的威力,它像是数组,却比数组强大的很,选定一组基后,有序的大小不同的数的组合,可以携带很多信息。这种携带信息的能力就是它的威力所在了吧。多个向量组合后,就成了矩阵。

       数学家们希望能够扩展成一个实部和两个虚部来实现到3D的扩展,但一直都没有解决,最后,数学家威廉·卢云·哈密顿(William Rowan Hamilton, 1805-1865)意识到应该是三个虚部而不是两个,总之就是这样,上面的四元数定义便登上了历史的舞台。你要问为什么,真心不知道,下面是我的猜测。

       在寻找三维空间的复数对应物时,人们发现并不是三元复数所能完成的。我对这句话的理解是这样的,三元复数在复数空间可以表示一个点,但不能表示一个线。三维向量在向量空间描述了一个方向,没有确定的起始点,这个和三维空间或是欧式空间差别很大,很简单的例子就是平行的射线在欧式空间当然不是同一个物体,然而在向量空间是无法区分的。

四元数(Quaternions)是由威廉·卢云·哈密顿在1843年爱尔兰发现的数学概念。用四元复数成功的表示了三维空间,代价是牺牲了交换律。有意思的是,矩阵相乘也是不可交换的,难道是巧合?

四元数的数学定义

Quaternion=ai+bj+ck+d  

  a、b、c、d是实数

  i^2=j^2=k^2=-1

  ij=k ji=-k jk=i kj=-i ki=j ik=-j

  (a^2+b^2+c^2+d^2)的平方根 称为四元数的模,在归一化中用到.

关于四元数的运算和相关推导,网上一搜一大把,我就不一一介绍了。值得强调的是,乘法的不可交换性,还有在后面将要提到的旋转顺序。

例如,Q=Q1*Q2

表示Q是先做Q2的旋转,再做Q1的旋转的结果,而多个四元数的旋转也是可以合并的,根据四元数乘法的定义,可以算出两个四元数做一次乘法需要16次乘法和加法,而3x3的矩阵则需要27运算,所以当有多次旋转操作时,使用四元数可以获得更高的计算效率。

 

----------------------------------------割一下--------------------------------------

        对于我来说,四元数是个新知识,但是我只关心它在3D变换中的旋转应用。即使这样,一开始也被网上铺天盖地的资料困扰,大半都是一知半解,转来转去。在这方面的应用,四元数相比欧拉角和旋转矩阵的优缺点http://hi.baidu.com/luguowei/blog/item/b5475b09543c55d43bc763f2.html这里介绍的比较详细。

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

    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图像的信息数据,所以用四元数再合适不过 了。

  • 为什么四元数可以避免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描述了绕此任意轴旋转的角度,而所有的参数都来自于所有描述旋转的四元数做乘法之后得到的值,可以看出这样一次性的旋转不会带来问题。