【问题标题】:Quaternions -> Euler Angles -> Rotation Matrix trouble (GLM)四元数 -> 欧拉角 -> 旋转矩阵问题 (GLM)
【发布时间】:2012-08-16 09:30:42
【问题描述】:

我正在编写一个程序,它加载一个包含场景描述的文件,然后使用 OpenGL 显示它。我将 GLM 用于我的所有数学运算。场景文件中的旋转以四元数格式存储。我的场景管理系统以欧拉角的形式对对象进行旋转,这些角度稍后在绘制时转换为旋转矩阵。

因此,我的加载过程采用四元数旋转,将它们转换为欧拉角以存储在我的对象类中,然后将这些欧拉角转换为旋转矩阵以进行绘图。我正在使用 glm::eulerAngles 和 glm::eulerAngleYXZ 函数(分别)执行这两个操作。

但是,我得到的结果不正确。例如,如果我理解正确,四元数 {0.500 -0.500 0.500 0.500}(即 W X Y Z)应该描述从 +Z 轴到 +Y 轴的箭头旋转。但是,当我运行该程序时,我得到的箭头指向 +X 轴。

我认为我对四元数的理解存在一些缺陷,但我可以通过跳过中间欧拉角形式来获得预期的结果。通过使用 glm::toMat4 将四元数直接转换为旋转矩阵,我得到一个旋转,将我的 +Z 箭头指向 +Y。

考虑到这两种方法看起来既简单又正确,我无法协调这两种不同的输出。为了简化我的问题,为什么这两种看似等效的方法会产生不同的结果:

glm::quat q(.5, -.5, .5, .5);
glm::vec3 euler = glm::eulerAngles(q) * 3.14159f / 180.f; // eulerAngleYXZ takes radians but eulerAngles returns degrees
glm::mat4 transform1 = glm::eulerAngleYXZ(euler.y, euler.x, euler.z);
// transform1 rotates a +Z arrow so that it points at +X

glm::quat q(.5, -.5, .5, .5);
glm::mat4 transform2 = glm::toMat4(q);
// transform2 rotates a +Z arrow so that it points at +Y

【问题讨论】:

  • 如果您想要自己的功能进行实验并了解幕后情况,我给出了答案here
  • 旁白:至少从 0.9.9 开始,glm::eulerAngles(q) 以弧度返回其结果。见glm/gtc/quaternion.hpp

标签: c++ math quaternions euler-angles glm-math


【解决方案1】:

你现在可能已经想通了……但是

eulerAngle 序列有什么作用:

glm::vec3 euler = glm::eulerAngles(q) * 3.14159f / 180.f;

返回?如果它没有显式返回一个 'YXZ' 序列,你将无法正确使用下一个函数:

glm::mat4 transform1 = glm::eulerAngleYXZ(euler.y, euler.x, euler.z);

您的变量“euler”必须与您指定的将其转换为旋转矩阵的函数具有相同的序列类型。

查看here 后,函数“glm::eulerAngles”返回“XYZ”作为俯仰、偏航和滚动。因此,假设它们是“YXZ”或偏航、俯仰、滚动是不正确的。

如前所述,对于欧拉角和旋转矩阵,顺序很重要!

【讨论】:

    【解决方案2】:

    在处理欧拉角时,乘法的顺序很重要。 YXZ 和 XYZ 产生非常不同的旋转。

    您可以为每个轴计算单独的矩阵,然后按照您需要的顺序将它们相乘。

    glm::quat q(.5, -.5, .5, .5);
    glm::vec3 euler = glm::eulerAngles(q) * 3.14159f / 180.f;
    
    glm::mat4 transformX = glm::eulerAngleX(euler.x);
    glm::mat4 transformY = glm::eulerAngleY(euler.y);
    glm::mat4 transformZ = glm::eulerAngleZ(euler.z);
    
    glm::mat4 transform1 =
        transformX * transformY * transformZ; // or some other order
    

    【讨论】:

    • 这似乎会遇到完全相同的问题。欧拉角仅对它们计算的顺序有效。将它们放入矩阵并不能消除这一事实。
    • @Markus 我认为我将欧拉角转换为矩阵可能是问题所在,但在该阶段之前存在差异。例如,尽管表示两个不同的旋转(+Z 到 +Y 和直接转换为矩阵时分别为 +Z 到 +X)。
    【解决方案3】:

    我认为结果已经是弧度了,不需要转换。

    glm::quat q(.5, -.5, .5, .5);
    glm::vec3 euler = glm::eulerAngles(q); // * 3.14159f / 180.f;
    
    glm::mat4 transformX = glm::eulerAngleX(euler.x);
    glm::mat4 transformY = glm::eulerAngleY(euler.y);
    glm::mat4 transformZ = glm::eulerAngleZ(euler.z);
    
    glm::mat4 transform1 =
        transformX * transformY * transformZ; // or some other order
    

    【讨论】:

    • 是的,也注意到了这一点,至少从 0.9.9 开始,glm/gtc/quaternion.hpp 中将返回弧度。我认为自 2012 年最初的问题以来,GLM 在某个时候改变了这一点。(打赌这对某些人来说很有趣)。
    猜你喜欢
    • 1970-01-01
    • 2013-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多