Man, you always have this mythological explanations
It is partly true what youâre saying. But your explanation is wrong. Euler angles can be reliable under certain circumstances. Iâm expecting Bunny to sweep in to correct me in a highly detailed essay, but when eulerAngles work this is because youâre locked onto an axis-aligned plane. Under the hub, they are simply computed from the quaternions, and this computation is very lousy for two reasons: 1) the two mathematical models are very incompatible with each other, 2) there is a human bias in that code, and Iâve found discontinuities in it, moreso than what is normally expected from this kind of math. But the real issue with this computation I describe below under âthe crux of the problemâ.
I have an example lying on my hard disk, where I freely move an avatar on top of the globe and Iâm tracking itâs forward and upward vectors, smoothly, without any problems or jitter. I am able to fully rely on its local Y rotation in eulerAngles to extract its local yaw rotation, and this works without any problem. But the reason I can do this is because Iâve locked it in only a few degrees of freedom by using quaternions. In local space, it only actually rotates about its local Y axis, and this is why the computation does work as expected.
The crux of the problem
The same rotation can be described with multiple angle combinations. Quaternions on the other hand, map 1 to 1. So when you inverse from quaternion â Euler you lack any context to know what result is actually correct, if there are several. Iâm sure there is a way to do it, but itâs incredibly hard, and Unity simply didnât want to do it, because it would still be unreliable and that would defeat the purpose of Quaternions.
Iâve done the full research on this when I made an ortho transform, where the goal was to simplify a rotation of the cube to only 90 degrees, and I analyzed whether axis flipping would introduce new original transformations (it looked like it would) and how many (this was a hard problem, completely non-intuitive). This analysis allowed me to formalize the problem, and make a compact solution without having to rely on quaternions or matrices, and also helped me determine once and for all how many unique rotations there are, and if you need a mirror, should you include a mirror on both X and Y, or just X, or to even include Z.
To do this, I had to make a prop with designated faces, otherwise itâs impossible to do. And Iâd advise anyone to try this, because youâll quickly learn how many ambiguous rotations you can make, ones that sound completely different on paper, but end up equal to each other.
All in all there are 24 unique ways to rotate a cube with 90 degrees rotations (including identity rotation), and you need just one X-axis mirror, to enable all kinds of mirrors imaginable. For example, imagine a game like Minecraft, where you can rotate a block in place, and you want to enable flipping the cube on all three axes. Well, you need only 48 transformations in total. I needed that because you can easily encode such transformation in only 6 bits, which is incredibly important if youâre making a voxel-based game. As a point of comparison, Quaternion on its own (no mirror) consumes a whopping 128 bits.
Iâve made an OrthoTransform struct in the end, which is easily convertible back to Quaternion or Matrix, but you rotate that however you want, and it gives you a code, a simple integer between 0 and 64 (2^6), but also detects ambiguities, so the last 16 combinations arenât actually used. You need to track X and Y rotations fully (4 rotations x 90 degrees; so thatâs 2 bits each), however Z can be tracked partially (just 0 and 90), to cover the full scope of 24 possible transformations, and thatâs five bits. You then add one X mirror as a sixth.
In other words, our 3D reality is a lie, at least when it comes to rotations. You end up with less degrees of freedom than the space itself seemingly allows for.