欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

四元数与欧拉角

程序员文章站 2023-12-29 11:44:10
...

一、前言

欧拉角与四元数都被用来处理图像学中的旋转。两者各有优劣,下面我们对它们做详细的比较。

二、欧拉角

欧拉角是表示朝向的最简单最直观方法,只需存储绕 X、Y、Z 轴旋转的角度,非常容易理解。你可以用vec3来存储一个欧拉角:

vec3 EulerAngles( RotationAroundXInRadians, RotationAroundYInRadians, RotationAroundZInRadians);

这三个旋转是依次施加的,通常的顺序是:Y-Z-X(但并非一定要按照这种顺序)。顺序不同,产生的结果也不同。
不过,面对更加复杂的情况时,欧拉角就显得力不从心了。例如:

  • 对两个朝向进行插值比较困难。简单地对X、Y、Z角度进行插值得到的结果不太理想。
  • 实施多次旋转很复杂且不精确:必须计算出最终的旋转矩阵,然后据此推测出欧拉角。
  • “臭名昭著”的“万向节死锁”(Gimbal Lock)问题有时会让旋转“卡死”。其他一些奇异状态还会导致模型方向翻转。(参考视频:https://www.bilibili.com/video/av35803395/
    四元数与欧拉角
  • 不同的角度可产生同样的旋转(例如-180°和180°)
  • 容易出错——如上所述,一般的旋转顺序是YZX,如果用了非YZX顺序的库,就有麻烦了。
  • 某些操作很复杂:如绕指定的轴旋转N角度。

三、四元数

四元数由4个数 [x y z w] 构成(这里我们不考虑数学上的定义,只考虑图像学方面的应用),RotationAxis 为旋转轴,RotationAngle 为旋转的角度。下图的旋转用四元数可表示为:

// RotationAngle is in radians
x = RotationAxis.x * sin(RotationAngle / 2)
y = RotationAxis.y * sin(RotationAngle / 2)
z = RotationAxis.z * sin(RotationAngle / 2)
w = cos(RotationAngle / 2)

四元数与欧拉角

1、四元数各值的意义

四元数的形式不如欧拉角直观,xyzxyz 分量大致代表了各个轴上的旋转分量,而w=cos(RotationAngle/2)w=\cos(RotationAngle/2)。举个例子,假设你在调试器中看到了这样的值[0.7 0 0 0.7][ 0.7\ 0\ 0\ 0.7 ]x=0.7x=0.7,比 yyzz 的大,因此主要是在绕 X 轴旋转;而 2arccos(0.7)=1.592\arccos(0.7) = 1.59 弧度,所以旋转角度应该是 90°90°
同理,[0 0 0 1](w=1)[0\ 0\ 0\ 1] (w=1) 表示 RotationAngle=2arccos(1)=0RotationAngle = 2\arccos(1) = 0,当旋转角度为 00 时因此这是一个单位四元数(unit quaternion),表示没有旋转。

2、四元数转换为旋转矩阵

四元数与欧拉角

3、参考源码

// Ogre 中的实现
mat4 ToRotationMatrix(quat& q)
{
    mat4 matR;

    float x = q.x;
    float y = q.y;
    float z = q.z;
    float w = q.w;

    float fTx = x + x;
    float fTy = y + y;
    float fTz = z + z;
    float fTwx = fTx * w;
    float fTwy = fTy * w;
    float fTwz = fTz * w;
    float fTxx = fTx * x;
    float fTxy = fTy * x;
    float fTxz = fTz * x;
    float fTyy = fTy * y;
    float fTyz = fTz * y;
    float fTzz = fTz * z;

    matR[0][0] = 1.0f - (fTyy + fTzz);
    matR[0][1] = fTxy - fTwz;
    matR[0][2] = fTxz + fTwy;
    matR[0][3] = 0.0f;

    matR[1][0] = fTxy + fTwz;
    matR[1][1] = 1.0f - (fTxx + fTzz);
    matR[1][2] = fTyz - fTwx;
    matR[1][3] = 0.0f;

    matR[2][0] = fTxz - fTwy;
    matR[2][1] = fTyz + fTwx;
    matR[2][2] = 1.0f - (fTxx + fTyy);
    matR[2][3] = 0.0f;

    matR[3][0] = 0.0f;
    matR[3][1] = 0.0f;
    matR[3][2] = 0.0f;
    matR[3][3] = 1.0f;

    return matR;
}

参考资料
[1] OpenGL 教程 旋转 : https://github.com/cybercser/OpenGL_3_3_Tutorial_Translation/blob/master/Tutorial%2017%20Rotations.md
[2] Ogre Quaternion :https://bitbucket.org/sinbad/ogre/src/3cbd67467fab3fef44d1b32bc42ccf4fb1ccfdd0/OgreMain/src/OgreQuaternion.cpp?at=default

欢迎关注个人公众号,实时推送最新博文!
四元数与欧拉角

上一篇:

下一篇: