C++ 四元数->;欧拉角->;旋转矩阵故障(GLM)

C++ 四元数->;欧拉角->;旋转矩阵故障(GLM),c++,math,quaternions,euler-angles,glm-math,C++,Math,Quaternions,Euler Angles,Glm Math,我正在编写一个程序,加载一个包含场景描述的文件,然后使用OpenGL显示它。我所有的数学运算都使用GLM。场景文件中的旋转以四元数格式存储。我的场景管理系统以euler角度的形式对对象进行旋转,这些角度稍后在绘制时转换为旋转矩阵 因此,我的加载过程采用四元数旋转,将它们转换为欧拉角以存储在我的对象类中,然后将这些欧拉角转换为旋转矩阵以进行绘图。我分别使用glm::eulerAngles和glm::eulerAngleYXZ函数来执行这两个操作 然而,我得到了错误的结果。例如,如果我正确理解四元数

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

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

然而,我得到了错误的结果。例如,如果我正确理解四元数{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

在处理欧拉角时,乘法的顺序很重要。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

你现在可能已经明白了。。。但是

该函数的eulerAngle序列是什么:

glm::vec3 euler = glm::eulerAngles(q) * 3.14159f / 180.f;
返回?如果未显式返回“YXZ”序列,则无法正确使用下一个函数:

glm::mat4 transform1 = glm::eulerAngleYXZ(euler.y, euler.x, euler.z);
变量“euler”的序列类型必须与指定的将其转换为旋转矩阵的函数的序列类型相同

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


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

我想结果已经是弧度了,不需要转换

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我认为欧拉角到矩阵的转换可能是个问题,但在那个阶段之前有一个矛盾。例如,四元数(0.5,-0.5,0.5,0.5)和(0.707106,0,0.707106,0)都转换为欧拉角(0,90,0),尽管分别表示两个不同的旋转(+Z到+Y和+Z到+X)当直接转换为矩阵时。如果你想要自己的函数进行实验并了解幕后情况,我给出了一个答案。旁白:至少在0.9.9
glm::eulerAngles(q)
中以弧度为单位返回结果。请看。是的,也注意到了这一点,并且至少在0.9.9中表示为返回弧度。我假设GLM在2012年的原始问题之后的某个时候改变了这一点。(我打赌这对一些人来说很有趣)。