Quaternion math routines



Quaternions are an alternate way to represent the rotation part of a transformation, and can be easier to manipulate than matrices. As with a matrix, you can encode a geometric transformations in one, concatenate several of them to merge multiple transformations, and apply them to a vector, but they can only store pure rotations. The big advantage is that you can accurately interpolate between two quaternions to get a part-way rotation, avoiding the gimbal problems of the more conventional euler angle interpolation.

Quaternions only have floating point versions, without any _f suffix. Other than that, most of the quaternion functions correspond with a matrix function that performs a similar operation.

Quaternion means 'of four parts', and that's exactly what it is. Here is the structure:

typedef struct QUAT
{
   float w, x, y, z;
}

You will have lots of fun figuring out what these numbers actually mean, but that is beyond the scope of this documentation. Quaternions do work -- trust me.

extern QUAT identity_quat;
Global variable containing the 'do nothing' identity quaternion. Multiplying by the identity quaternion has no effect.

void get_x_rotate_quat(QUAT *q, float r);
void get_y_rotate_quat(QUAT *q, float r);
void get_z_rotate_quat(QUAT *q, float r);
Construct axis rotation quaternions, storing them in q. When applied to a point, these quaternions will rotate it about the relevant axis by the specified angle (given in binary, 256 degrees to a circle format).

void get_rotation_quat(QUAT *q, float x, float y, float z);
Constructs a quaternion that will rotate points around all three axis by the specified amounts (given in binary, 256 degrees to a circle format).

void get_vector_rotation_quat(QUAT *q, float x, y, z, float a);
Constructs a quaternion that will rotate points around the specified x,y,z vector by the specified angle (given in binary, 256 degrees to a circle format).

void quat_to_matrix(const QUAT *q, MATRIX_f *m);
Constructs a rotation matrix from a quaternion.

void matrix_to_quat(const MATRIX_f *m, QUAT *q);
Constructs a quaternion from a rotation matrix. Translation is discarded during the conversion. Use get_align_matrix_f() if the matrix is not orthonormalized, because strange things may happen otherwise.

void quat_mul(const QUAT *p, const QUAT *q, QUAT *out);
Multiplies two quaternions, storing the result in out. The resulting quaternion will have the same effect as the combination of p and q, ie. when applied to a point, (point * out) = ((point * p) * q). Any number of rotations can be concatenated in this way. Note that quaternion multiplication is not commutative, ie. quat_mul(p, q) != quat_mul(q, p).

void apply_quat(const QUAT *q, float x, y, z, *xout, *yout, *zout);
Multiplies the point (x, y, z) by the quaternion q, storing the result in (*xout, *yout, *zout). This is quite a bit slower than apply_matrix_f(), so only use it to translate a few points. If you have many points, it is much more efficient to call quat_to_matrix() and then use apply_matrix_f().

void quat_interpolate(const QUAT *from, *to, float t, QUAT *out);
Constructs a quaternion that represents a rotation between from and to. The argument t can be anything between 0 and 1 and represents where between from and to the result will be. 0 returns from, 1 returns to, and 0.5 will return a rotation exactly in between. The result is copied to out. This function will create the short rotation (less than 180 degrees) between from and to.

void quat_slerp(const QUAT *from, *to, float t, QUAT *out, int how);
The same as quat_interpolate(), but allows more control over how the rotation is done. The how parameter can be any one of the values:

QUAT_SHORT - like quat_interpolate(), use shortest path
QUAT_LONG - rotation will be greater than 180 degrees
QUAT_CW - rotate clockwise when viewed from above
QUAT_CCW - rotate counterclockwise when viewed from above
QUAT_USER - the quaternions are interpolated exactly as given




Back to Contents