Quaternions -> Euler Angles -> Rotation Matrix trouble (GLM)

iondune picture iondune · Aug 21, 2012 · Viewed 16.6k times · Source

I'm writing a program that loads a file containing a scene description and then displays it using OpenGL. I'm using GLM for all of my math operations. Rotations in the scene file are stored in quaternion format. My scene management systems takes rotations for objects in the form of euler angles, and these angles are later converted to a rotation matrix when drawing.

My loading process thus takes the quaternion rotations, converts them to euler angles for storage in my object class, then converts these euler angles to rotation matrices for drawing. I'm using the glm::eulerAngles and glm::eulerAngleYXZ functions (respectively) to perform these two operations.

However, I am getting incorrect results. For example, if I understand correctly the quaternion {0.500 -0.500 0.500 0.500} (that's W X Y Z) should describe the rotation taking an arrow from the +Z axis to the +Y axis. When I run the program, however, I get the arrow pointing along the +X axis.

I would assume that there is some flaw in my understanding of the quaternions, but I am able to get my expected results by skipping the intermediary euler angle form. By converting the quaternion directly to a rotation matrix using glm::toMat4, I get a rotation that points my +Z arrow towards +Y.

I'm having trouble reconciling these two different outputs, considering that both methods seem both simple and correct. To simplify my question, why is it that these two seemingly equivalent methods produce different results:

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

Answer

dinkelk picture dinkelk · Oct 20, 2012

You have probably figured this out by now... but

What eulerAngle sequence does the function:

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

return? If it does not return explicitly an 'YXZ' sequence, you will not be able to use the next function properly:

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

Your variable 'euler' must be the same sequence type as the function you specify to transform it into a rotation matrix.

After looking here it looks like the function 'glm::eulerAngles' returns 'XYZ' as pitch, yaw, and roll. Thus, assuming they are 'YXZ', or yaw, pitch, roll is incorrect.

As said before, with Euler angles and rotation matrices, order matters!