游戏引擎中为什么要用四元数表示旋转而不用欧拉角旋转?

个人观点,仅供参考,如有错误可太刺激了

四元数的简单概念和使用

欧拉角通常用于表示一个物体的旋转状态,而不是表示旋转过程

欧拉角描述的是物体相对于某个参考坐标系的朝向或旋转状态,通常以不同的轴(例如,绕X轴、Y轴和Z轴)的旋转角度来表示。这可以让你知道物体是如何朝向的,但它不提供旋转的完整信息。 当你用三个欧拉角表示一个旋转状态时,绕三个轴旋转的顺序不同,会得到不同的旋转结果。这些性质,就导致了以下这些问题:

欧拉角存在的问题

  1. 万向锁(Gimbal Lock): Gimbal Lock 是一个常见的问题,会导致旋转自由度的丢失
  2. 非唯一性: 欧拉角表示不是唯一的,相同的旋转可以用多种不同的欧拉角组合来表示,这很扯淡
  3. 不连续性: 欧拉角旋转可能会导致不连续性,特别是在插值时,会导致角度的突然跳跃,使得动画过渡不平滑
  4. 旋转顺序依赖: 欧拉角旋转的结果依赖于旋转轴的顺序,因此必须明确定义旋转顺序
  5. 数学计算复杂性: 进行欧拉角旋转计算需要需要复杂的矩阵运算

四元数的优点:

  1. 一个四元数通常需要存储4个分量(w、x、y、z),而旋转矩阵通常需要存储9个分量(3x3矩阵)。由于存储空间较小,四元数在内存中占用更少的空间。
  2. 计算效率: 四元数的乘法运算相对于矩阵乘法来说计算更快,因为四元数只涉及4个分量的乘法和加法,而矩阵涉及9个分量的乘法和加法。这在计算机图形和游戏中非常重要,因为需要频繁执行旋转操作。
  3. 插值: 四元数在插值(如球形线性插值)方面表现更好。插值旋转矩阵涉及到矩阵分解和插值,而四元数的插值通常更简单和高效。
  4. 避免万向锁: 四元数在避免万向锁问题上更稳定。欧拉角旋转和旋转矩阵都可能在特定情况下遇到万向锁问题,而四元数通常不会。
  5. 四元数既可以表示朝向,也能表示变换到当前朝向的旋转变换

怎么理解优点5:也能表示变换到当前朝向的旋转变换?

案例: 一个游戏对象,在世界空间中以某个姿态摆放着,已知该物体的面朝方向的欧拉角表示为 forward = (roll, pitch, yaw),求其 Up 向量和 Right 向量

  • 一般计算方法:非常简单且好理解,用叉乘
    glm::vec3 forward = getObjectTransform().Rotation; // 物体的朝向
    glm::vec3 worldUp = glm::vec3(0.0f, 1.0f, 0.0f); 
    
    glm::vec3 RightInWorld = glm::normalize(glm::cross(worldUp, forward)); 
    glm::vec3 UpInWorld = glm::normalize(glm::cross(forward, Right)); 
    
  • 用四元数计算: 因为当前朝向的四元数同时也代表了物体的局部坐标空间中物体朝向变换到世界空间中的当前朝向的旋转变换,因此把该四元数变换应用给局部UpRight就能得到物体当前在世界空间中的的UpRight
    glm::quat forwardQuad = glm::quat(getObjectTransform().Rotation);
    
    glm::vec3 UpInWorld = glm::rotate(forwardQuad, glm::vec3(0.0f, 1.0f, 0.0f);
    glm::vec3 RightInWorld = glm::rotate(forwardQuad, glm::vec3(1.0f, 0.0f, 0.0f));
    

二者计算量其实差不多,根据需要选择方法即可。

你可能感兴趣的:(游戏引擎,游戏引擎)