PS2 Linux Programming
Rotating with Quaternions
Quaternions crop up a lot in game development, since they are an efficient way to store and effect rotations in 3D-space. The main problem with encoding rotations in a 3x3 matrix is the inevitable numerical drift encountered by using the finite precision arithmetic within a computer. A 3x3 rotation matrix is orthogonal, and it's 9 components encode the 3 degrees of freedom of the rotation. As computations on the matrix are performed, the components of the matrix naturally drift, violating the orthogonal constraint. This means that the matrix is no longer a valid rotation matrix and abnormalities in the transform will start to appear. These abnormalities are manifested as visual distortions and artefacts within the rendered object on screen.
One solution to this problem is to regularly check that the matrix is orthogonal and correct it if necessary. Although quite simple to achieve, this is computationally expensive, and the act of correcting the matrix itself may alter the encoded rotation in unexpected ways.
Encoding rotations with a quaternion can solve many of the problems mentioned above. Since quaternions have 4 degrees of freedom there is only 1 redundant constraint, which is far easier to enforce than matrix orthogonality. A wise choice of encoding also allows the use of quaternion algebra (as will be described below) to easily manipulate rotations in quaternion form.
In this tutorial therefore, quaternions will be used to illustrate the rotation of an object round an arbitrary axis in 3D space. This particular application is well suited to quaternion maths and is also a very common manipulation that is required within 3D computer games development.
A quaternion, a, can be considered as an extension of a complex number :
to an entity with four components:
where a1, a2 and a3 are coefficients of the hyper-imaginary quantities i, j and k.
Quaternions can be added, subtracted and multiplied by real numbers and by each other using the usual laws of algebra but subject to the following laws of multiplication:
(Note the cyclic order of multiplication - similar to vector products).
The above laws can be written more compactly as:
For any Quaternion given by:
a0 is called the scalar or real part, and is sometimes written Sa. The remainder:
is called the vector or pure part, and is written Va or a'.
A Quaternion is said to be pure, or a pure vector, if it's scalar part is zero.
The conjugate of a Quaternion, a, is written and is defined by
The norm or modulus of a Quaternion is written as and is defined by:
Notice that for all Quaternions and 0 means that a = 0.
A Quaternion is said to be a unit Quaternion if = 1.
If then .
If we define a unit (pure vector) Quaternion as
then we know that
Now consider a unit Quaternion given by b = b0 + b', then we must have
and so we can put for a unique angle in the range . From this we see that:
and as for , then . is called the argument of b.
Unless b is real (no vector part) then and we have:
which gives the Quaternion b as:
(Notice the similarity with the result from complex numbers.)
A very useful property of Quaternions is that we can use them to rotate shapes in 3D space about a specified axis passing through the origin. This cuts down on the amount of calculations when compared to using matrix transformations.
The result below is given without proof.
Given a unit Quaternion , the transformation rotates the point with position vector p (pure Quaternion) through an angle about the axis I.
[Notice that this remarkable result depends on the fact that is always a pure Quaternion.]
For the case of multiple rotations about possible different axes, the above process can be adapted as follows.
Suppose that we want to follow the first rotation, given by the transformation , by a second rotation of about some axis . Notice that, from the first rotation, and so operating on this position vector for the second rotation gives:
This result shows that for multiple rotations, we simply multiply the Quaternions together in the order of rotation from right to left, i.e. the latest rotation will be the left multiple in the sequence.
It is often necessary at some point within the graphics pipeline to convert a quaternion into a rotation matrix so that calculations can be performed in matrix form say by the vector units within the PlayStation2. Given a quaternion q = (w, x, y, z), where w is the real part and (x,y,z) is the vector part, the rotation matrix can be written as:
Thus a point P(x,y,z) can be rotated round the origin with the quaternion q, to give the point P’(x’,y’,z’) using the relationship:
In the example code, a cube is rotated around an arbitrary axis using quaternions. A quaternion utility class has been constructed and is contained within the files quaternion.h and quaternion.cpp. An vector (I) is created which is the axis of rotation (this vector is through two opposite corners of the cube and it’s centre). A quaternion is created from the axis of rotation and an angle by which the vertices of the cube are to be rotated by – this quaternion is produced using the quaternion class method SetQuaternion(). A rotation matrix is then obtained from the rotation quaternion and this matrix is used by the vector unit to rotate the vertices of the cube to provided the desired result.
A quaternion has been used to rotate the vertices of a cube around an arbitrary axis. In the example provided a rotation matrix has been produced from the rotation quaternion. Note that it is possible to produce compound rotations by performing quaternion multiplication and it is left to the reader to investigate the code to implement these features.
Dr Henry S Fortuna
University of Abertay Dundee
(Thanks to Dr Nigel Lucas for Notes on Quaternions)