为什么要使用四元数

来源:互联网 发布:大革命1060设置优化 编辑:程序博客网 时间:2024/05/29 04:57

为 了回答这个问题,先来看看一般关于旋转(面向)的描述方法-欧拉描述法。它使用最简单的x,y,z值来分别表示在x,y,z轴上的旋转角度,其取值为 0-360(或者0-2pi),一般使用roll,pitch,yaw来表示这些分量的旋转值。需要注意的是,这里的旋转是针对世界坐标系说的,这意味着 第一次的旋转不会影响第二、三次的转轴,简单的说,三角度系统无法表现任意轴的旋转,只要一开始旋转,物体本身就失去了任意轴的自主性,这也就导致了万向 轴锁(Gimbal Lock)的问题。鉴于欧拉角插值动画时有错误,因此不能使用欧拉角的方式来进行球面方式插值,相应地,就可以采用四元数的方式来解决这个问题。如果系统还是使用欧拉角表示,要先转换为四元数,然后再进行插值,再转换回来欧拉角表示。

四元数的应用范围很广泛,它的定义如下:

四元数是简单的超复数。 复数是由实数加上虚数单位 i 组成,其中i^2 = -1。 相似地,四元数都是由实数加上三个虚数单位 i、j、k 组成,而且它们有如下的关系: i^2 = j^2 = k^2 = -1, i^0 = j^0 = k^0 = 1 , 每个四元数都是 1、i、j 和 k 的线性组合,即是四元数一般可表示为a + bk+ cj + di,其中a、b、c 、d是实数。
对于i、j、k本身的几何意义可以理解为一种旋转,其中i旋转代表X轴与Y轴相交平面中X轴正向向Y轴正向的旋转,j旋转代表Z轴与X轴相交平面中Z轴正向向X轴正向的旋转,k旋转代表Y轴与Z轴相交平面中Y轴正向向Z轴正向的旋转,-i、-j、-k分别代表i、j、k旋转的反向旋转。

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

四元数的虚部可以使用qv, 实部使用qw,那么就可表示为(qv, qw)的形式。


1.四元数和轴-角对
  绕轴n旋转θ角:n是一个向量,根据左手或右手法则定义旋转的正方向, θ角表示旋转的量。  那么表示这个旋转的四元数为:


2. 四元数的模


代入轴-角对的公式求模。 n为单位向量,最后可以得到四元数的模为1.称为单位四元数。


3. 四元数的共轭


四元数和它的共轭代表相反的角位移,因为相当于旋转轴反向。


4. 四元数乘法(叉乘)


5. 优点

通俗的讲,一个四元数(Quaternion)描述了一个旋转轴和一个旋转角度。这个旋转轴和这个角度可以通过 Quaternion::ToAngleAxis转换得到。当然也可以随意指定一个角度一个旋转轴来构造一个Quaternion。这个角度是相对于单位四元数而言的,也可以说是相对于物体的初始方向而言的。


当用一个四元数乘以一个向量时,实际上就是让该向量围绕着这个四元数所描述的旋转轴,转动这个四元数所描述的角度而得到的向量。

有多种方式可表示旋转,如 axis/angle、欧拉角(Euler angles)、矩阵(matrix)、四元组等。 相对于其它方法,四元组有其本身的优点:


    四元数不会有欧拉角存在的 gimbal lock 问题
    四元数由4个数组成,旋转矩阵需要9个数
    两个四元数之间更容易插值
    四元数、矩阵在多次运算后会积攒误差,需要分别对其做规范化(normalize)和正交化(orthogonalize),对四元数规范化更容易
    与旋转矩阵类似,两个四元组相乘可表示两次旋转


6. 四元数转换为矩阵



7. 四元数插值





代码:

quat slerp(quat qa, quat qb, double t) {// quaternion to returnquat qm = new quat();// Calculate angle between them.double cosHalfTheta = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z;// if qa=qb or qa=-qb then theta = 0 and we can return qaif (abs(cosHalfTheta) >= 1.0){qm.w = qa.w;qm.x = qa.x;qm.y = qa.y;qm.z = qa.z;return qm;}// Calculate temporary values.double halfTheta = acos(cosHalfTheta);double sinHalfTheta = sqrt(1.0 - cosHalfTheta*cosHalfTheta);// if theta = 180 degrees then result is not fully defined// we could rotate around any axis normal to qa or qbif (fabs(sinHalfTheta) < 0.001){ // fabs is floating point absoluteqm.w = (qa.w * 0.5 + qb.w * 0.5);qm.x = (qa.x * 0.5 + qb.x * 0.5);qm.y = (qa.y * 0.5 + qb.y * 0.5);qm.z = (qa.z * 0.5 + qb.z * 0.5);return qm;}double ratioA = sin((1 - t) * halfTheta) / sinHalfTheta;double ratioB = sin(t * halfTheta) / sinHalfTheta; //calculate Quaternion.qm.w = (qa.w * ratioA + qb.w * ratioB);qm.x = (qa.x * ratioA + qb.x * ratioB);qm.y = (qa.y * ratioA + qb.y * ratioB);qm.z = (qa.z * ratioA + qb.z * ratioB);return qm;}

更多,请参考:

http://www.cnblogs.com/mengdd/archive/2013/08/05/3238223.html
http://blog.csdn.net/candycat1992/article/details/41254799
http://blog.csdn.net/jin_syuct/article/details/49785541


1. C++标准模板库从入门到精通 

http://edu.csdn.net/course/detail/3324

2.跟老菜鸟学C++

http://edu.csdn.net/course/detail/2901

3. 跟老菜鸟学python

http://edu.csdn.net/course/detail/2592

4. 在VC2015里学会使用tinyxml库

http://edu.csdn.net/course/detail/2590

5. 在Windows下SVN的版本管理与实战 

 http://edu.csdn.net/course/detail/2579

6.Visual Studio 2015开发C++程序的基本使用 

http://edu.csdn.net/course/detail/2570

7.在VC2015里使用protobuf协议

http://edu.csdn.net/course/detail/2582

8.在VC2015里学会使用MySQL数据库

http://edu.csdn.net/course/detail/2672

0 0
原创粉丝点击