Quaternions: what and why?

To fully understand about Quaternions, you should first understand what Complex Numbers are. I'll explain what a Quaternion is in a general matter first, and then explain it's basics.

What is it?

A Quaternion represents a rotation of a point in 3D space around an axis. That's it.

The name Quaternion has it's name because it's formed by 4 values (quadruple). Don't worry why it uses 4 values now. Just know that each of the values need to be build using sin/cos to actually means anything.

If you have a point in space, and you want to rotate it around any axis, you can use a Quaternion to do so. You can use other techniques, if you want too. Quaternions are just another option. Depending on your problem, it might better suit your solution.

Why use it?

In 3D programming, if you want to rotate something (like a camera around the character), you can do it using:

Each of them, have pros and cos. I'll list some advantages of each:

Quaternions

  • Easy to interpolate between quaternions - It's usefull for animations or camera movements. You can say: interpolate all values from rotation A to rotationB easily (see SLERP or LERP, for interpolation functions)
  • Less rounding effects - Quaternions suffer way less data loss then matrixes. As you keep stacking data on matrixes, some data might lose precision.
  • No gimbal-lock issue (like Euler Angles does)
  • Ocupy less memory then Matrixes - It's 4 numbers, instead of 16 for a 4x4 matrix.

This is how you rotate 90° on X axis using Quaternions:

#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#define PI 3.14f

float angle = PI/2;
quaternion = glm::quat( glm::vec3(angle, 0 ,0) );
glm::mat4 rotationMatrix = glm::toMat4(quaternion);

Or:

#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#define PI 3.14f

float angle = PI/2.f;
glm::vec3 axis(1, 0, 0);
quaternion = glm::angleAxis(angle, axis);
glm::mat4 rotationMatrix = glm::toMat4(quaternion);

Matrixes

  • Speed - You can stack movements (like translation and scale) in a single matrix and in a single operation, apply it to you 3D object. For Quaternions, you need to translate it to a 4x4 matrix first.

This is how you rotate 90° on X axis using Matrix:

#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#define PI 3.14f

glm::mat4 unitMatrix(1.f);
glm::mat4 rotationMatrix = glm::rotate(unitMatrix, PI/2.f, glm::vec3(1, 0, 0));

Euler Angles

  • Easier to read - It's more human readable. You basically say the angles in each axis you want to rotate.

This is how you rotate 90° on X axis using Euler Angles:

#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#define PI 3.14f

glm::mat4 rotationMatrix = glm::eulerAngleYXZ(0.f, PI/2.f, 0.f);

Or use this:

#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#define PI 3.14f

glm::mat4 rotationMatrix = glm::yawPitchRoll(0.f, PI/2.f, 0.f);

Observations:

  • I'm using GLM_FORCE_RADIANS in the examples because the use of degrees is deprecated._
  • I'm adding <glm/ext.hpp> for simplification purposes.
  • The end result should always be matrixes, as this is what your video card will read.