Previously I raved about quaternions.
Now the biggest complaint about quaternions is that you can’t visualise them… which I kind of half agree with and half don’t. Yes Euler angles are easier to visualise, e.g. having 0,0,0 is clearly pointing north, and 0,180,0 is clearly pointing south, but then again quaternions aren’t hideously bad:
[w x y z]
[1 0 0 0] - This points north
[0 0 1 0] - This points south
So w is 1 when the quaternion is ‘identity’, and the other axes are 1 when there is a ‘full’ rotation around that axis (‘full’ in the sense of ‘as far as you can go in that direction before you start coming back on yourself’… so basically 180 degrees). A twist around Z would go to [0 0 0 1].
Another thing which is great about quaternions though is there is no ‘history’ on them. If you use Euler angles you have to have a rotate order, e.g. decide that you are going to rotate around Y, then X, then Z.
What happens then if you are in an orientation and want to rotate in a different order? Well you can’t easily, you’d have to switch to a Matrix or Quaternion, change the rotate order and recalculate the new angles.
An extra thing you can do with quaternions, which you can’t easily do with the other representations, is LERP or SLERP. This basically means to move from one orientation to another along the shortest path. It’s breathtakingly simple to LERP, you simply linearly interpolate and then normalise.
But then again, sometimes Euler angles seem nicer… sometimes it’s nice to have set ‘axes’ that you rotate around, like say a world-space pivot around the Y axis, keeping the horizon nice and level. Aren’t Euler angles better at that kind of thing? Well actually you can do that with quaternions (and matrices) too. Quaternions allow you to rotate the orientation around any axis, so if you want to artificially limit yourself to one particular axis (like, say, positive Y) you can. But if you keep it as a quaternion, you have the option of rotating around other axes too, and using Lerp and Slerp.
Or course there are many advantages to having an orientation in matrix form as well, especially when you have to transform many points. The strategy I’ve found which works brilliantly is to keep all your orientations as quaternions as long as possible, and then right before you need to transform points or get axes, convert to a matrix. This is because the conversion from quaternion to matrix is quite elegant, but the conversion the other way is messier, and has branches.
If you want to display the orientation to the user, say for debugging purposes, Euler angles are useful. It’s pretty simple to go from quaternion to Euler and back.
Now for the confession: there is one ugly thing about quaternions, which is that for every orientation there is not one but TWO quaternions which describe it. Eg (0 0 1 0) and (0 0 -1 0) are the same. This is a bit like say having +180 and -180 being the same thing. It’s not a big deal, but it does mean you have to be careful that when you LERP between two quaternions you pick the right one. For example, if you did a LERP with angles between 20 and 30 degrees, but accidentally picked the -350 version instead of +10 degrees, you’d go a very long way round. It’s the same with quaternions, if you find a rotation is going to take more than 180 degrees, you need to flip one of them. Don’t let that put you off, quaternions are awesome in every other way.
Hopefully I’ve convinced you to use quaternions, but if not, to finish off, another cool trick : to find the angle between two orientations, first multiply the conjugate (w -x -y -z) of orientation A with orientation B. Find the length of the imaginary part (i.e sqrt(x*x + y*y + z*z)) and then asin it and multiply by two. Voilà – there is your angle! Try doing that with matrices!!
[You can also acos the real part, but asin is more robust for small angles... In fact come to think of it, atan2(len(imag), real) would probably be better yet!]