Tuesday, December 11, 2007

Quaternions and spatial rotation

Quaternions are non intuitive. A point along the surface of a 4-dimensional sphere, isn’t really something which is imaginable. But if you’re more interested in the application rather than research, well this article might just be for you.

When I started out researching quaternions and their application I was working with animation in games. There's a lot to it, and quite a bit of nonsense too. I found that a bit tiresome so I'll try to get right to it.

The thing about quaternions (I'll refer to them as quats or simply quat, from now on) is that they are defined in a 4-dimensional space referred to as H. This article is about application in 3-dimensions, so one thing you need to understand is that a quat compared to an scalar or vector is never the same thing. One way to look at quats is to visualize them as a rotation around an axis. However, this can lead to incorrect assumptions and wont make much sense in end. The way I chose to picture it, is more like a function with arguments. Input and output in this case is simply something useful in euclidean space (E for short).

A naive camera rotation generally suffers from a gimbal lock, a simple way of avoiding this is by representing the rotation by each axis as two separate quats. Creating these two quats is straight forward, now combine these rotations using the quaternion (Grassmann) product and then extract the rotation matrix from this product.

This was the step that initially confused me. But the trick is to create quats in H space from E values, then do the math (simple product) and finally converting back into E space (extracting the rotation matrix from the quaternion). The result is a rotation matrix which does not suffer from gimbal lock and can transform E space values for you.
In order for the calculations to work you need to use unit quats only.

Vector3 v = {0,0,1}
Q yaw = fromE({0,1,0}, yawAngle) // commonly known as the axis/angle representation
Q pitch = fromE({1,0,0}, pitchAngle)
Q result = mul(yaw, pitch) // magic!
Matrix3x3 m = fromQ(result) // convert back to E space from H space
Vector3 v1 = mul(m, v)

The result is a vector v1, rotated about the two angles yawAngle and pitchAngle around the origin ({0,0,0}). Most people when the first try to rotate things, end up rotating objects around a stick because they fail to realize that rotation is the result of rotation around the origin and translation. If you want the appearance of rotating around some other point you need to translate between that point and the origin before applying the rotation.

There are many great code examples out there and it shouldn't be a problem for you to figure out the precise math involved. Once you get going, it's easy. And hopefully this will help you in getting there faster.