AnyLeaf Blog

Quaternions: A practical guide

Written on Aug. 6, 2022, 7:53 a.m.
Updated Aug. 11, 2022, 2:32 p.m.

Overview

This article demonstrates how to use quaternions for practical applications. In it, we attempt to build intuition about how you can use quaternions as building blocks to solve geometry problems. This includes computer graphics and attitude systems for air and spacecraft, but applies more generally. You may have read about quaternions having advantages over Euler angles to represent orientations, such as preventing gimbal lock, and advantages over rotation matrices, such as more efficient computation, and compact form. This is true. You may have also read that they're complicated, difficult to use, or counter-intuitive. This isn't!

This article outlines several useful operations between quaternions and vectors, and describes how to perform them. It doesn't describe why they work. There are many sources online where you can learn more about this, including perspectives from numerical algorithms, visualizations (including stereographic projects of 4d space!), and symbolic operations. These can be great for a deeper understanding. This article is tailored towards info that will make you effective at using quaternions as an engineering tool.

Why are we taking this approach instead of building deeper knowledge? I'm aiming for a specific level of intuition-building that's suitable for engineering purposes. We're building intuition so you'll be able to learn a few general tools, then be able to apply them to a broad range of applications. You should be able to recognize when they're appropriate, and how to combine them with existing systems, and with each other. A deeper approach might describe why the arithmetic we define them with works. A shallower approach would provide complete orientation and rotation systems, like a computer graphics library. Hopefully we've hit a sweet spot.

This article uses mathematical notation, in a format that can easily be translated to any procedural programming language. It includes all the information you need to turn these operations into code, in a language-agnostic format. It uses some mathematical conventions, but with limited abstractness.

The key takeaway is that quaternions are a powerful, elegant tool that can be used whenever modelling rotations or orientations in 3D. When viewed this way, they're neither complicated to use, nor to understand.

If you'd like a detailed description, check out this 3Blue1Brown + Ben Eater collaboration. It's a page containing a number of interactive videos that explain and visualize the significance of quaternions, including for rotations. They let you pause the video, then interact with the visualizations. Further, this article doesn't describe the algebra of quaternions; if you're curious, this article goes into detail.


Basics

A quaternion is represented as a set of 4 numbers, labeled \(w\), \(x\), \(y\), and \(z\). In code, this may be represented by a struct (or class) with 4 floating-point fields.

All quaternions used in this article are unit quaternions: Ie with a magnitude of 1. These are also known as versors. Magnitude in this context is defined in a similar way as with vectors: The square root of the sum of squares of each component:

$$ || Q || = \sqrt{w^2 + x^2 + y^2 + z^2} $$

Also note that all vectors in this article are length 3, and represent 3D space.

Orientation and rotation quaternions are equivalent: The distinction is that ones used for orientation describe the operation that rotates the identity quaternion to the orientation. The identity quaternion is defined as having a \(w\) component equal to 1, and all others equal to 0. The distinction is how you use them - it's important to keep track of which quaternions you use for orientation vice rotations, even though the mathematics is the same.

An important distinction: Quaternions directly describe rotations, and aren't tied to any coordinate system, or absolute orientation. Conversely, most computations need a result tied to absolute orientation; a coordinate system. Examples: An aircraft's upright attitude; a 3D model's up orientation; a vector defined by global coordinates.

Quaternions are sometimes compared with matrices as ways to transform space. We'll go over this with more detail below, but the key takeaway is that matrices represent linear transforms; quaternions represent a special case of linear transform: rotations in 3 dimensions.

Many of our operations with quaternions involve vectors. Some knowledge of vectors and linear algebra is required.


Anchoring quaternions to coordinates and directions

Let's examine a 3d model of a boat. Its orientation is stored as a quaternion; one that represents the result of its rotation on the unit quaternion. How do we orient it so that its hull is pointed down? The key in how the model is defined, and how the graphics engine is set up. If you'd like the unit quaternion to represent an upright and level orientation - the boat's model should be defined by an up direction that's the same as the graphics engine expects. If not, you can use a different quaternion to represent up. In an aircraft's attitude system, something similar applies: We move from relative quaternions to absolute orientation by anchoring the system's inputs to, for example the earth's gravitational field.

Now, let's look at vectors: quaternion operations on vectors. As you read through the operations below, you'll notice quaternions can be used to define a rotation between vectors, or rotate a vector to a new position. The theme, is that quaternions represent transitions between 2 or more vectors. In the case where we create a quaternion that points in a direction, we're still anchoring it using 2 vectors: The direction, and a known (eg up direction, which anchors the operation.

What about quaternions operating on other quaternions? These aren't yet anchored, and in most systems, will ultimately act on something else, directly or indirectly.


Rotating a vector using a quaternion

Rotating a vector is one of the most common applications of quatenrions, and is a building block for other operations. Here's how it's done:

$$ \vec{v}' = Q \vec{v} Q^{-1} $$

Where \( \vec{v} \) is the original vector, \( \vec{v}' \) is the rotated vector, \( Q \) is the quaternion that defines the rotation, and \( Q^{-1} \) is its inverse. The inverse of a quaternion is that quaternion with the same w component, and the negation of the others. So, if \(Q = [1, 2, 0, -1] \), \(Q^{-1} = [1, -2, 0, 1] \).

The multiplication operations above are defined as follows. Note that to multiply a quaternion by a vector, convert the vector to a quaternion with \(w=0\), and \(x\), \(y\), and \(z\) are the vector's components.

$$ w = L_w R_w - L_x R_x - L_y R_y - L_z R_z $$ $$ x = L_w R_x + L_x R_w + L_y R_z - L_z R_y $$ $$ y = L_w R_y - L_x R_z + L_y R_w + L_z R_x $$ $$ z = L_w R_z + L_x R_y - L_y R_x + L_z R_w $$

$$ Q_{LR} = L R = [w, x, y, z] $$


Specifying a quaternion that describes the rotation from one vector to another

$$ w = v1 \cdot v2 $$ $$ [x, y, z] = v1 \times v2 $$ $$ Q_{rotation} = \frac{ [w, x, y, z] }{ ||[w, x, y, z]|| } $$

There are multiple rotations that can describe this; the equation above describes the shortest rotaton.

Note: The above approach will fail if the vectors are parallel; to correct this in code, check that the dot product is equal to 1 or -1. If equal to 1, return the identity quaternion. If equal to -1, return the identity quaternion rotated by π radians. To do this, construct a rotation-around-axis (described below), using a vector orthogonal to either input vector as the axis, and π as the angle. You can construct the orthogonal vector by projecting any unit vector onto the plane with either input vector as its normal. (This is a standard linear algebra procedure)

This is a versatile operation! Earlier, we mentioned how quaternions aren't anchored to coordinates or directions. Let's say we'd like a 3d model to align with a certain directional vector. To do this, we use the operation above, with \( \vec{v1} \) as the up vector the model uses, and \( \vec{v2} \) as the vector defining the direction.


Specifying a quaternion that describes rotation around an axis

To create a quaternion that describes the rotation of amount \( \theta \) around axis \( \vec{v} \), use this equation:

$$ w = \cos{\frac{\theta}{2}} $$ $$ x = \sin{\frac{\theta}{2}} \vec{v} _x $$ $$ y = \sin{\frac{\theta}{2}} \vec{v} _y $$ $$ z = \sin{\frac{\theta}{2}} \vec{v} _z $$

$$ Q_{rotation} = [w, x, y, z] $$


Rotating an orientation, and composing rotations

To rotate a quaternion representing an orientation, perform quaternion multiplication with the rotation quaternion on the left.

$$ Q_o' = Q_r Q_o $$

To compose multiple rotations, multiply them together, using the equation from earlier in this article:

$$ Q_{r12} = Q_{r2} Q_{r1} $$

When multiple rotations are composed in this way, they are applied right to left. For example, this is how you would apply 2 rotations to an orientation:

$$ O_{r12} = Q_{r2} Q_{r1} O $$

Where \( O \) is the initial orientation, and \( O_{r12} \) is the orientation after applying \(Q_{r1} \) followed by \( Q_{r2} \). Note that equivalently, you could compose the rotations first, then apply them. (eg by storing as a variable, or using parentheses to group the rotations)

Quaternion multiplication is non-commutative, meaning order matters.


Quaternions for change of basis

Matrices are the most common way to describe change-of-basis operations in linear algebra. For change of basis operations that are purely rotational (don't stretch or skew the space), quaternions are a more efficient (an arguably more intuitive) approach.

To do this, create a rotation quaternion that rotates between 2 vectors, as described above. Set the first vector to the starting basis vector you wish wish to change, and the second vector to its equivalent in the new basis.


Construction from Euler angles

Creating an orientation quaternion from Euler angles follows from 2 points above: #1: Orientation quaternions are rotations of the identity quaternion. #2: We can construct a rotation around an axis using an axis vector and rotation amount. So, to construct an orientation from angles, we could combine rotations from each basis vector:

$$ O_x = fromAxisAngle([1, 0, 0], \phi) $$ $$ O_y = fromAxisAngle([0, 1, 0], \psi) $$ $$ O_z = fromAxisAngle([0, 0, 1], \theta) $$ $$ O = O_x O_y O_z $$

Where \( \phi \), \( \psi \), and \( \theta \) are Euler angles around \(x\), \(y\), and \(z\) axes respectively.

Alternatively, we can combine some operations with the following approach:

$$ cy = \cos(\frac{\theta}{2}) $$ $$ sy = \sin(\frac{\theta}{2}) $$ $$ cp = \cos(\frac{\psi}{2}) $$ $$ sp = \sin(\frac{\psi}{2}) $$ $$ cr = \cos(\frac{\phi}{2}) $$ $$ sr = \sin(\frac{\phi}{2}) $$

$$ w = cr \cdot cp \cdot cy + sr \cdot sp \cdot sy $$ $$ x = sr \cdot cp \cdot cy - cr \cdot sp \cdot sy $$ $$ y = cr \cdot sp \cdot cy + sr \cdot cp \cdot sy $$ $$ z = cr \cdot cp \cdot sy - sr \cdot sp \cdot cy $$

$$ O = [w, x, y, z] $$

One example of this use is changing the orientation of computer-graphics objects in response to user input. For example, modifying camera orientation in response to moues movements. You could create a rotation around the X axis ( \(\vec{1, 0, 0} \) ) with one around the y axis ( \(\vec{1, 0, 0} \) ), then apply both of these to the current orientation: \( O_{new} = R_x R_y O \) The rotation amount would be the degree of input in the given directions.


Creating an orientation defined by 2 worldspace vectors

We can construct a quaternion from 2 vectors anchored in any two (non-identical) directions. In computer graphics libraries, this is often created from up and forward vectors.

( todo)


Spherical linear interpretation (SLERP)

(todo)


An example using several of the above techniques

Let's consider the case where we are modelling a chain of atoms connected to each other by chemical bonds. We'll focus on a single bond: The We can ignore the subtleties for now, and model the situation like this:

We can break this problem down into determining the orientation and position of each individual atom, using the previous atom's orientation and position.

We will define two vectors that describe 2 of the 4 points on a tetrahedron. (These represent the 2 bonds coming out of each atom.):

$$ \vec{bondToNext} = \frac{ [1, 1, 1 }{ ||[1, 1, 1]|| } $$ $$ \vec{bondFromThis} =\frac{ [1, -1, -1 }{ ||[1, -1, -1 ]|| } $$

$$ bondToNextWorldspace = rotateVec(O_{prev}, \vec{bondToNext}) $$ $$ bondFromThisWorldspace = rotateVec(O_{prev}, \vec{bondFromThis}) $$

$$ R_{bondAlignment}= fromUnitVecs(-1 \times \vec{bondFromThisWorldspace}, \vec{bondToNextWorldspace}) $$

$$ R_{aroundAxis} = fromAxisAngle(\vec{bondFromThisWorldspace}, \theta) $$

$$ O = R_{bondAlignment} R_{aroundAxis} O_{prev} $$


On information content

We'll compared quaternions, rotation matrices, and Eulr angles from the perspective of information. You might notice that a 3D rotation matrix has 9 numerical values, while a quaternion, which can represent the same rotation, has only 4. This begs the question: given that a quaternion with 4 values can represent any 3d rotation, why do rotation matrices have 5 extra values? The answer is that matrices can be used to represent more than rotations: They can represent any linear transformation, of which rotations are a subset.

Matrices can be used to stretch, skew, sheer, and rotate, in any combination, makin them more flexible. If we are only rotating, matrices encode extra information - this results in more value to store, and less-efficient computation. It also means they're an under-constrained system. With this in mind: Use Quaternions if only modeling rotation. Use matrices if modelling other linear transforms.

Note that compared to Euler angles, quaternions store an extra value. (4 value in a quaternion, vs 3 in Euler angles) This extra value is due to the constraint that the ones we're using are strictly unit quaternions; this explains the extra degree of freedom.


A note on rotors and bivectors

You may have heard some backlash recently against quaternions, eg describing them as an obfuscated, unintuitive, specialized case of Rotors. Rotors can be used for everything quaternions can. For the practical approach we've taken here, rotors have no advantage, and the criticisms of them as being difficult don't apply. Quaternions have the distinct advantage of being standardized on domains like computer graphics and attitude determination.

An exercise: Eigenvalues and eigenvectors

For a given linear transform, eigenvectors are vectors that don't change direction when the transform is applied. Eigenvalues are the scale factor the length of these vectors. These are usually discussed in contexts of matrices, but apply to quaternions as well.

This 3Blue1Brown video has information that might help. It has info on the significance of eigenvectors on rotations. It also includes an alternative way of defining linear transforms using them, that maps directly to one of the techniques we described above.


Conclusion

Bottom line: If you're modeling something that uses 3D rotations or orientation, quaternions should be in your toolkit. You should know what operations they can be used for, and be able to look up how to apply them.


References