# GLM conversion from euler angles to quaternion and back does not hold

I am trying to convert the orientation of an OpenVR controller that I have stored as a glm::vec3 of Euler angles into a glm::fquat and back, but I get wildly different results and the in-game behavior is just wrong (hard to explain, but the orientation of the object behaves normally for a small range of angles, then flips in weird axes).

This is my conversion code:

// get orientation from OpenVR controller sensor data

const glm::vec3 eulerAnglesInDegrees{orientation[PITCH], orientation[YAW], orientation[ROLL]};
debugPrint(eulerAnglesInDegrees);

const glm::vec3 result{glm::degrees(glm::eulerAngles(quaternion))};
debugPrint(result);

// result should represent the same orientation as eulerAnglesInDegrees


I would expect eulerAnglesInDegrees and result to either be the same or equivalent representations of the same orientation, but that is apparently not the case. These are some example values I get printed out:

39.3851 5.17816 3.29104
39.3851 5.17816 3.29104

32.7636 144.849 44.3845
-147.236 35.1512 -135.616

39.3851 5.17816 3.29104
39.3851 5.17816 3.29104

32.0103 137.415 45.1592
-147.99 42.5846 -134.841


As you can see above, for some orientation ranges the conversion is correct, but for others it is completely different.

What am I doing wrong?

I've looked at existing questions and attempted a few things, including trying out every possible rotation order listed here, conjugating the quaternion, and other random things like flipping pitch/yaw/roll. Nothing gave me the expected result.

How can I convert euler angles to quaternions and back, representing the original orientation, using glm?

Some more examples of discrepancies:

original:      4; 175;   26;
computed:   -175;   4; -153;
difference:  179; 171;  179;

original:     -6; 173;   32;
computed:    173;   6; -147;
difference: -179; 167;  179;

original:      9; 268;  -46;
computed:   -170; -88;  133;
difference:  179; 356; -179;

original:    -27; -73;  266;
computed:    -27; -73;  -93;
difference:    0;   0;  359;

original:    -33; 111;  205;
computed:    146;  68;   25;
difference: -179;  43;  180;


I tried to find a pattern to fix the final computed results, but it doesn't seem like there's one easy to identify.

GIF + video of the behavior:

Visual representation of my intuition/current understanding:

• The above picture shows a sphere, and I'm in the center. When I aim the gun towards the green half of the sphere, the orientation is correct. When I aim the gun towards the red half of the sphere, it is incorrect - it seems like every axis is inverted, but I am not 100% sure that is the case.
• What operation are you performing after the round-trip conversion that's revealing unwanted behavior? There's a decent chance the error is there, and the change of angle representation is just making it visible. – DMGregory Feb 22 '20 at 3:08

The results are not what you expect, but they are not wrong. It’s just that for a given orientation there are at least two “paths” through Euler angles that lead there.

For instance, the identity quaternion is trivially converted to Euler angles [0,0,0]. But doing three 180-degree rotations around each axis leaves you in the same orientation, too. That means that [180,180,180] is a valid Euler angle representation of that quaternion, too.

Now since your character appears to be a human, it’s probable that their head can’t roll at 180-degree angles, so here is a simple method that you can use to fix your values:

if (std::fabs(result.z) >= 90) {
result.x += 180.f;
result.y = 180.f - result.y;
result.z += 180.f;
}