An introduction to Quaternions

Quaternions have a a bad rep as being difficult mathematical concepts that are borderline black magic. Thanks to popular engines like Unity and Unreal most developers know what quaternions are and how to use them, but might be wondering how the math behind quaternions actually works.

Quaternions are actually not very difficult to work with, think of them as an angle / axis pair. The main advantage quaternions have is that they interpolate niceley. A quaternion represents a rotation, not an orientation. What's the difference? A rotation describes how to move one basis into another. An orientation is a basis.

In the context of games, we always use unit quaternions (quaternions with a length of 1). Periodically, quaternions might need to be re-normalized due to floating point precision issues.

Defining a quaternion

Let's jump right in and make a quaternion! A quaternion is just a four component touple, much like a Vector4:

struct Quaternion {
    float x; // vector part
    float y; // vector part
    float z; // vector part
    float w; // scalar part
}

There is a reason w comes last, it's important for converting quaternions to matrices. Writing the code for a quaternion is pretty simple. Mathematically, quaternions can be written in several notations. First, just as a four touple of numbers:

$$ q = (q_{0}, q_{1}, q_{2}, q_{3}) = (q_{x}, q_{y}, q_{z}, q_{w}) $$

A more formal definition of quaternions will call them a number system that extends complex numbers. There is a whole history about Hamilton and carving the famous formula in a bridge. I won't re-hash all this, you can read about it on a number of sources. The important thing about this is, that quaternions are complex numbers which can be written with three imaginary components

$$ q = w + xi + yj + zk $$

The meaning of the imaginary numbers \(i\),\(j\) and \(k\) will be described in depth in the section about creating quaternions. Finally, a quaternion can be written as a scalar and a vector where the scalar is the \(w\) component and the vector is made up of the \(x\), \(y\) and \(z\) components.

$$ q = (s, \vec{v}) $$

It's easy to mistake this notation for axis / angle, but it's not. The scalar component has something in relation with the angle of the quaternion, but it's not the angle. Similarly, the vector component has something to do with the axis, but it's not the axis.

Special Quaternion

Quaternions have a multiplicitive identity. This special identity quaternion represents no rotation. The scalar component of this quaternion is one, and the vector component is zero.

Quaternion Identity() {
    //                 x, y, z, w
    return Quaternion (0, 0, 0, 1)
}

Any vector can be turned into a quaternion by leaving the scalar part zero and puting the normalized vector into the vector part of the quaternion. The resulting quaternion, actually any quaternion with a zero scalar value is called a "pure" quaternion.

Quaternion Pure(Vector3 vec) {
    return Quaternion(vec.x, vec.y, vec.z, 0);
}