Quaternions are used in computer graphics when a 3D character rotation is involved. Quaternions allows a character to rotate about multiple axis simultaneously instead of sequentially, as matrix rotation allows.

Why use Quaternions to rotate a 3D character when matrices can do the same job? There are two reasons why Quaternions are preferred in computer graphics:

- Matrix rotations suffer from what is known as
**Gimbal Lock**. - Quaternions consume less memory and are faster to compute than matrices.

Gimbal lock is the loss of one degree of freedom in a three-dimensional, three-gimbal mechanism that occurs when the axes of two of the three gimbals are driven into a parallel configuration, "locking" the system into rotation in a degenerate two-dimensional space.

At first, I was thinking to simply develop our math engine with vectors and matrices. But decided to add a Quaternion class to our engine as well. Quaternions, although difficult to understand, are simple to use.

So, let's implement a Quaternion class in the math engine.

## Quaternions

Quaternions are composed of a scalar and a vector. They are represented in various different ways such as:

where **S** is a scalar number and **V** is a vector representing an axis.

Let's implement a Quaternion class. Download the math engine and create a new C++ class file. Call it **R4DQuaternion**. Since we are creating a C++ class in an iOS environment, change the .hpp and .cpp file to .h and .mm, respectively.

In the header file, declare the constructors and data members of the quaternion.

```
namespace R4DEngine {
class R4DQuaternion{
public:
//scalar
float s;
//vector
R4DVector3n v;
//Constructor
R4DQuaternion();
//Constructor
R4DQuaternion(float uS,R4DVector3n& uV);
//Destructor
~R4DQuaternion();
//Copy Constructor
R4DQuaternion(const R4DQuaternion & value);
//Copy Constructor
R4DQuaternion& operator=(const R4DQuaternion& value);
};
}
```

In the .mm file implement the following construction methods:

```
R4DQuaternion::R4DQuaternion(float uS,R4DVector3n& uV):s(uS),v(uV){}
R4DQuaternion::R4DQuaternion(const R4DQuaternion & value){
s=value.s;
v=value.v;
};
R4DQuaternion& R4DQuaternion::operator=(const R4DQuaternion& value){
s=value.s;
v=value.v;
return *this;
};
```

To create an instance of a quaternion in the engine we do the following:

```
//Create an axis vector
R4DEngine::R4DVector3n axis(1,0,0);
//create a quaternion
R4DEngine::R4DQuaternion q(90,axis);
```

## Adding and Subtracting

Quaternions can be added and subtracted among themselves. In quaternion addition and subtraction, the corresponding scalar and vectors from each quaternion are added/subtracted, respectively. Mathematically, quaternion addition/subtraction is represented as follows:

For example, the addition of two quaternions is calculated as follows:

Addition and subtraction is implemented in C++ as follows:

```
void R4DQuaternion::operator+=(const R4DQuaternion& q){
s+=q.s;
v+=q.v;
}
R4DQuaternion R4DQuaternion::operator+(const R4DQuaternion& q)const{
float scalar=s+q.s;
R4DVector3n imaginary=v+q.v;
return R4DQuaternion(scalar,imaginary);
}
//substract
void R4DQuaternion::operator-=(const R4DQuaternion& q){
s-=q.s;
v-=q.v;
}
R4DQuaternion R4DQuaternion::operator-(const R4DQuaternion& q)const{
float scalar=s-q.s;
R4DVector3n imaginary=v-q.v;
return R4DQuaternion(scalar,imaginary);
}
```

If you have been reading my blog for a while, you would have noticed that I overload C++ arithmetic operators often. I do this, because it makes working with the math engine quite simple. Read more about it here.

In the engine we can add and subtract quaternions as follows:

```
//Create an axis vector
R4DEngine::R4DVector3n axis(1,0,0);
//create two quaternions
R4DEngine::R4DQuaternion q(90,axis);
R4DEngine::R4DQuaternion p(10,axis);
//Add quaternions
R4DEngine::R4DQuaternion nQ=q+p;
//Add quaternions
q+=p;
```

## Product

Quaternions can be multiplied among themselves. Mathematically, quaternion multiplication is represented as follows:

Quaternion multiplication is implemented as follows:

```
//multiply
void R4DQuaternion::operator*=(const R4DQuaternion& q){
(*this)=multiply(q);
}
R4DQuaternion R4DQuaternion::operator*(const R4DQuaternion& q)const{
float scalar=s*q.s - v.dot(q.v);
R4DVector3n imaginary=q.v*s + v*q.s + v.cross(q.v);
return R4DQuaternion(scalar,imaginary);
}
R4DQuaternion R4DQuaternion::multiply(const R4DQuaternion& q)const{
float scalar=s*q.s - v.dot(q.v);
R4DVector3n imaginary=q.v*s + v*q.s + v.cross(q.v);
return R4DQuaternion(scalar,imaginary);
}
```

In the engine, we can multiply two quaternions as follows:

```
//Create an axis vector
R4DEngine::R4DVector3n axis(1,0,0);
//create two quaternions
R4DEngine::R4DQuaternion q(90,axis);
R4DEngine::R4DQuaternion p(10,axis);
//Quaternion multiplication
R4DEngine::R4DQuaternion nQ=q*p;
//Quaternion multiplication
q-=p;
//Quaternion multiplication
R4DEngine::R4DQuaternion nP=q.multiply(p);
```

## Scalar Multiplication

Just like vectors and matrices, a quaternion can be multiplied by a scalar. Mathematically, this is represented as follows:

where **k** is a scalar real number.

Quaternion scalar multiplication is done as follows in C++:

```
void R4DQuaternion::operator*=(const float value){
s*=value;
v*=value;
}
R4DQuaternion R4DQuaternion::operator*(const float value)const{
float scalar=s*value;
R4DVector3n imaginary=v*value;
return R4DQuaternion(scalar,imaginary);
}
```

Multiplying a quaternion by a scalar in the engine is done as follows:

```
//Create an axis vector
R4DEngine::R4DVector3n axis(1,0,0);
//create a quaternion
R4DEngine::R4DQuaternion q(90,axis);
//scalar multiplication
R4DEngine::R4DQuaternion nQ=q*3;
//scalar multiplication
q*=3;
```

## Norm

Mathematically, the norm of a quaternion is represented as follows:

For example, the norm of quaterion **q** is calcuated as follows:

This can be implemented as follows in C++:

```
//norm
float R4DQuaternion::norm(){
float scalar=s*s;
float imaginary=v*v;
return sqrt(scalar+imaginary);
}
```

To get a quaternion's magnitude in the engine we do the following:

```
//Create an axis vector
R4DEngine::R4DVector3n axis(1,0,0);
//create a quaternion
R4DEngine::R4DQuaternion q(90,axis);
//Magnitude (Norm)
float magnitude=q.norm();
```

## Unit Norm

The unit norm of a quaternion, also known as **Normalized** quaternion, is calculated as follows:

For example, normalizing the quaternion **q** is calculated as follows:

The normalization of a quaternion is implemented as follows:

```
//unit-norm
void R4DQuaternion::normalize(){
if (norm()!=0) {
float normValue=1/norm();
s*=normValue;
v*=normValue;
}
}
```

To normalize a quaternion in the engine we call the following function:

```
//Create an axis vector
R4DEngine::R4DVector3n axis(1,0,0);
//create a quaternion
R4DEngine::R4DQuaternion q(90,axis);
//Normalize
q.normalize();
```

The type of unit-norm quaternion we will use for rotations are of the form:

And is implemented as:

```
//Unit-Norm Quaternion (Special Form)
void R4DQuaternion::convertToUnitNormQuaternion(){
float angle=DegreesToRad(s);
v.normalize();
s=cosf(angle*0.5);
v=v*sinf(angle*0.5);
}
```

I will talk more about it later in this article.

## Conjugate

The conjugate of a quaternion is very important in computing the **inverse** of a quaternion. Mathematically, the conjugate of quaternion **q** is calculated as follows:

The conjugate is implemented as follows:

```
//conjugate
R4DQuaternion R4DQuaternion::conjugate(){
float scalar=s;
R4DVector3n imaginary=v*(-1);
return R4DQuaternion(scalar,imaginary);
}
```

A quaternion's conjugate is calculated by calling the following function:

```
//Create an axis vector
R4DEngine::R4DVector3n axis(1,0,0);
//create a quaternion
R4DEngine::R4DQuaternion q(90,axis);
//Quaternion conjugate
R4DEngine::R4DQuaternion conjugate=q.conjugate();
```

## Inverse

The ability to divide in quaternion arithmetic is very important. To be able to divide a quaternion, you need its inverse. By definition the inverse quaternion satisfies the following:

The inverse of a quaternion is defined as:

The inverse of a quaternion is done as follows:

```
//inverse
R4DQuaternion R4DQuaternion::inverse(){
float absoluteValue=norm();
absoluteValue*=absoluteValue;
absoluteValue=1/absoluteValue;
R4DQuaternion conjugateValue=conjugate();
float scalar=conjugateValue.s*absoluteValue;
R4DVector3n imaginary=conjugateValue.v*absoluteValue;
return R4DQuaternion(scalar,imaginary);
}
```

To get the inverse of a quatertion in the engine, we do the following:

```
//create a quaternion
R4DEngine::R4DQuaternion q(90,axis);
//Quaternion inverse
R4DEngine::R4DQuaternion conjugate=q.inverse();
```

## Rotating a Vector

There are two types of quaternions:

- Real Quaternions
- Pure Quaternions

A real quaternion has a **Zero** vector term. Think of them as real numbers:

A pure quaternion has a **Zero** scalar term. Think of them as vectors:

A vector rotation occurs when you multiply a pure quaternion **p** by a unit-norm quaternion **q** and its inverse:

Where **p** represents your vector in quaternion form. And **q** represents a unit-norm quaternion in the form of:

Rotating a vector using quaternions is implemented as follows:

```
R4DVector3n R4DVector3n::rotateVectorAboutAngleAndAxis(float uAngle, R4DVector3n& uAxis){
//convert our vector to a pure quaternion
R4DQuaternion p(0,(*this));
//normalize the axis
uAxis.normalize();
//create the real quaternion
R4DQuaternion q(uAngle,uAxis);
//convert quaternion to unit norm quaternion
q.convertToUnitNormQuaternion();
//Get the inverse of the quaternion
R4DQuaternion qInverse=q.inverse();
//rotate the quaternion
R4DQuaternion rotatedVector=q*p*qInverse;
//return the vector part of the quaternion
return rotatedVector.v;
}
```

Notice that we convert the vector into a pure quaternion and convert the real quaternion into the special unit-norm form.

Let's do a simple test. Let's rotate a vector about the x-axis by 90 degrees.

In main.mm test the following:

```
int main(int argc, const char * argv[]) {
//Vector to rotate
R4DEngine::R4DVector3n v(0,1,0);
//axis of rotation: x-axis
R4DEngine::R4DVector3n axis(1,0,0);
//rotate vector v about axis by 90 degrees
R4DEngine::R4DVector3n rotatedVector=v.rotateVectorAboutAngleAndAxis(90, axis);
//print result
rotatedVector.show();
return 0;
}
```

Build the project using **Command+B**. The result should show the vector:

`(0,1,0)`

Being rotated to:

`(0,0,1)`

As shown here:

## Source Code

The complete source code can be found here. Feel free to download it and play with it.