An overview of rotations

Overview

In this article we’ll discuss what exactly is a rotation and how do we represent one in a computer.

Representing a rotation geometrically

First lets talk about what a rotation is. Geometrically a rotation is an axis specified by a normalized direction vector and an angle . We say that the rigid body is rotated about by an angle

Here I’ve draw the rotation axis as going through the center of the disk. However there is no reason that need be the case. can be any arbitrary axis. The image shows a point on the surface of the disk being rotated to it’s new position .

One way to represent rotations algebraically is to use Euler angles. These are the familar pitch, yaw, and roll you may have heard referenced in aviation games or television shows. However these suffer from a problem known as gimbal lock. Insead we will be using objects known as quaternions.

Quaternions

It turns out that the nicest way to manipulate rotations algebraically is the quaternions . A quaternion is equivalent to a vector in but for one crucial difference, comes equiped with a product operation that makes it a division algebra. Meaning it is possible to multiply and divide quaternions.

The easiest way to represent a quaternion is by the pair where and . is said to be the “real” part of , whereas is the “imaginary” part. With this formalism in hand we will procced to define all the basic operations one might perform on quaternions.

Sum and difference

\[ \tilde{q}_{1} \pm \tilde{q}_{2} = (r_{1} \pm r_{2}, \vec{v}_{1} \pm \vec{v}_{2}) \]

Product

\[ \tilde{q}_{1}\tilde{q}_{2} = (r_{1}r_{2} - \vec{v}_{1} \cdot \vec{v}_{2}, r_{1}\vec{v}_{2} + r_{2}\vec{v}_{1} + \vec{v}_{1} \times \vec{v}_{2}) \] where and are the familar dot product and cross product from

Conjugate

Keeping with the interpretation of as the imaginary part of we can define a complex conjugate which simply involves the negation of .

\[ \tilde{q}^{*} = (r,-\vec{v}) \]

Norm

Like vectors in quaternions have a notion of length that is defined through a norm \[ ||\tilde{q}||^{2} = \tilde{q}\tilde{q}^{*} = r^{2} + ||\vec{v}||^{2} \]

Multiplicative inverse

Using the relationship between the conjugate and the norm we can define the inverse of a quaterion to be \[ \tilde{q}^{-1} = \frac{\tilde{q}^{*}}{||\tilde{q}||^{2}} \] Verify for yourself that

Representing a rotation using quaternions

So how do we use quaternions to compute rotations? We can represent a rotation given by an axis and an angle as a quaternion by utilzing an extension of Euler’s formula \[ \tilde{q} = \left(\cos\left(\frac{\theta}{2}\right),\sin\left(\frac{\theta}{2}\right)\hat{u}\right) \]

Now, we can embed an arbitrary point into by creating a new quaterion . Using this embedding the rotated quaternion can be calculated as \[ \tilde{x}^{\prime} = \tilde{q}\tilde{x}\tilde{q}^{-1} \]

We can extract from by ignoring its real part (which will be anyways). For a proof of this statement see the wikipedia article. It involves multiplying everything out and some algebra tricks to put the result into form of the Rodrigues rotation formula.

Relationship between quaternions and rotation matrices

To convert a quaternion to a rotation matrix we make use of the following formula \[ R= \begin{bmatrix} 1-2s(q_{j}^{2}+q_{k}^{2}) & 2s(q_{i}q_{j} - q_{k}q_{r}) & 2s(q_{i}q_{k} + q_{j}q_{r}) \\ 2s(q_{i}q_{j} + q_{k}q_{r}) & 1 - 2s(q_{i}^{2} + q_{k}^{2}) & 2s(q_{j}q_{k} - q_{i}q_{r}) \\ 2s(q_{i}q_{k} - q_{j}q_{r}) & 2s(q_{j}q_{k} + q_{i}q_{r}) & 1-2s(q_{i}^{2} + q_{j}^{2}) \end{bmatrix} \] where . This matrix R will form the top-left block of our model matrix.

Implementation

The implementation of Quaternion is mostly an exercise in operator overloading. I won’t bother to inline the code but I encourage you to look it over: quaternion.h quaternion.cpp

The only other matter at hand is to modify PhysicsEntity to store an orientation in the form of a Quaternion instance. The concrete realizations of PhysicsEntity and Model can load the orientation into the model matrix like so

m_model_matrix.block(0,0,3,3) = m_orientation.toRotationMatrix();

This must be done in the constructors and in the OnUpdateFromBuffer methods

Results

Here we’ve rotated the cube by degrees about the axis.

code