# Quaternion to Matrix

Converting a quaternion to a matrix can be trivial. Recall that a 3x3 matrix (and the upper left 3x3 sub matrix of a 4x4 matrix) is composed of three column vectors. These column vectors describe the basis of the matrix. The easiest way to convert a quaternion to a matrix is to multiply three basis vectors (x, y and z) by the quaternion and place the results in the resulting matrix.

Matrix3 ToMatrix_NonOptimal(Quaternion quat) {
// Basis vectors
Vector3 right = Vector3(1, 0, 0);
Vector3 up = Vector3(0, 1, 0);
Vector3 forward = Vector3(0, 0, 1);

// Rotate basis vectors by Quaternion
right = Mul(right, quat);
up = Mul(up, quat);
forward = Mul(forward, quat);

// Return basis vectors as matrix
return Matrix3(
right.x, up.x, forward.x,
right.y, up.y, forward.y,
right.z, up.z, forward.z
);

// Just so there is no confusion, the above constructor takes arguments
// in row order, but stores them in column order (transposed).
// That is, it creates the following array in memory:
// [right.x, right.y, right.z, up.x, up.y, up.z, forward.x, forward.y, forward.z]
}

## Optimize

Ken Shoemake presents a more optimal way of converting quaternions to matrices in Chapter 6 of Graphics Gems II, Quaternions and 4x4 Matrices . Shoemake's method can be dificult to grasp at first, but converting quaternions to matrices is a common enough operation that it is worth understanding and implementing. So, let's explore this method.

Suppose we want to multiply two quaternions $$q$$ and $$p$$ together. The formula for this was covered in the Multiplying Quaternions section. The formula looks like this:

qp = \begin{alignedat}{6} & \phantom{+} &q_x p_w \textcolor{red}{i} & {+} &q_y p_z \textcolor{red}{i} & {-} &q_z p_y \textcolor{red}{i} & {+} &q_w p_x \textcolor{red}{i} & {,} \\ & {-} &q_x p_z \textcolor{green}{j} & {+} &q_y p_w \textcolor{green}{j} & {+} &q_z p_x \textcolor{green}{j} & {+} &q_w p_y \textcolor{green}{j} & {,} \\ & \phantom{+} &q_x p_y \textcolor{blue}{k} & {-} &q_y p_x \textcolor{blue}{k} & {+} &q_z p_w \textcolor{blue}{k} & {+} &q_w p_z \textcolor{blue}{k} & {,} \\ & {-} &q_x p_x & {-} &q_y p_y & {-} &q_z p_z & {+} &q_w p_w \end{alignedat}

Since we're left multiplying, this rotates $$q$$ by $$p$$, the above multiplication can be expressed as a matrix / vector multiplication by treating $$q$$ as a vector and $$p$$ as a matrix, like so:

$$qp = R(p)q = \begin{bmatrix} \phantom{+}w_{p} & \phantom{+}z_{p} & -y_{p} & \phantom{+}x_{p} \\ -z_{p} & \phantom{+}w_{p} & \phantom{+}x_{p} & \phantom{+}y_{p} \\ \phantom{+}y_{p} & -x_{p} & \phantom{+}w_{p} & \phantom{+}z_{p} \\ -x_{p} & -y_{p} & -z_{p} & \phantom{+}w_{p} \end{bmatrix} \begin{bmatrix} x_{q} \\ y_{q} \\ z_{q} \\ w_{q} \end{bmatrix}$$

I changed the notation up a little to put the focus on which elements of $$q$$ and $$p$$ are being used and where, instead of on $$q$$ and $$p$$. The quaternion product is either a function of $$p$$ or $$q$$. Above it's a function of $$q$$. To find the function of $$p$$, first re-arrange the quaternion multiplication formula so that the components of $$p$$ line up, like so:

qp = \begin{alignedat}{6} { } &q_{w}p_{x}\textcolor{red}{i}& {-} &q_{z}p_{y}\textcolor{red}{i}& {+} &q_{y}p_{z}\textcolor{red}{i}& {+} &q_{x}p_{w}\textcolor{red}{i}& {,} \\ { } &q_{z}p_{x}\textcolor{green}{j}& {+} &q_{w}p_{y}\textcolor{green}{j}& {-} &q_{x}p_{z}\textcolor{green}{j}& {+} &q_{y}p_{w}\textcolor{green}{j}& {,} \\ {-} &q_{y}p_{x}\textcolor{blue}{k}& {+} &q_{x}p_{y}\textcolor{blue}{k}& {+} &q_{w}p_{z}\textcolor{blue}{k}& {+} &q_{z}p_{w}\textcolor{blue}{k}& {,} \\ {-} &q_{x}p_{x}& {-} &q_{y}p_{y}& {-} &q_{z}p_{z}& {+} &q_{w}p_{w}& \end{alignedat}

The formula is still the same, we just shuffled a few of the terms around. This time write $$q$$ as the matrix and $$p$$ as the vector, like so:

$$qp = L(q)p = \begin{bmatrix} \phantom{+}w_{q} & -z_{q} & \phantom{+}y_{q} & \phantom{+}x_{q} \\ \phantom{+}z_{q} & \phantom{+}w_{q} & -x_{q} & \phantom{+}y_{q} \\ -y_{q} & \phantom{+}x_{q} & \phantom{+}w_{q} & \phantom{+}z_{q} \\ -x_{q} & -y_{q} & -z_{q} & \phantom{+}w_{q} \end{bmatrix} \begin{bmatrix} x_{p} \\ y_{p} \\ z_{p} \\ w_{p} \end{bmatrix}$$

Knowing these $$L$$ and $$R$$ matrices, a 4x4 matrix can be created from a quaternion. A quaternion $$q$$ rotates a vector $$\vec{v}$$ using quaternion multiplication, like so: $$q\vec{v}q^{-1}$$. When dealing with unit quaternions, the inverse and conjugate of the quaternion is the same, that is $$q^{-1} = q^{*}$$. Since $$q^{*}$$ just negates the vector part of $$q$$, the rotation matrix of $$q$$ can be constructed as:

$$Rot(q) = L(q)R(q^{*})$$

Substituting tha actual matrices, we get:

$$Rot(q) = L(q)R(q^{*}) = \begin{bmatrix} \phantom{+}w & -z & \phantom{+}y & \phantom{+}x \\ \phantom{+}z & \phantom{+}w & -x & \phantom{+}y \\ -y & \phantom{+}x & \phantom{+}w & \phantom{+}z \\ -x & -y & -z & \phantom{+}w \end{bmatrix} \begin{bmatrix} \phantom{+}w & -z & \phantom{+}y & -x \\ \phantom{+}z & \phantom{+}w & -x & -y \\ -y & \phantom{+}x & \phantom{+}w & -z \\ \phantom{+}x & \phantom{+}y & \phantom{+}z & \phantom{+}w \end{bmatrix}$$

Take note, the right side matrix, $$R(q^{*})$$ is not the same as $$R(q)$$, the signs on the vector part of the quaternion are flipped. Doing the actual matrix multiplication leaves us with the following matrix:

$$\tiny \begin{bmatrix} (w,-z,y,x) \cdot (w,z,-y,x) & (w,-z,y,x) \cdot (-z,w,x,y) & (w,-z,y,x) \cdot (y,-x,w,z) & (w,-z,y,x) \cdot (-x,-y,-z,w) \\ (z,w,-x,y) \cdot (w,z,-y,z) & (z,w,-x,y) \cdot (-z,w,x,y) & (z,w,-x,y) \cdot (y,-x,w,z) & (z,w,-x,y) \cdot (-x,-y,-z,w) \\ (-y,x,w,z) \cdot (w,z,-y-x) & (-y,x,w,z) \cdot (-z,w,x,y) & (-y,x,w,z) \cdot (y,-x,w,z) & (-y,x,w,z) \cdot (-x,-y,-z,w) \\ (-x,-y,-z,w) \cdot (w,z,-y,x) & (-x,-y,-z,w) \cdot (-z,w,x,y) & (-x,-y,-z,w) \cdot (y,-x,w,z) & (-x,-y,-z,w) \cdot (-x,-y,-z,w) \end{bmatrix}$$

Doing all of the actual dot products, the above matrix simplifies to:

$$\begin{bmatrix} w^{2}+x^{2}-y^{2}-z^{2} & 2xy - 2wz & 2xz + 2wy & 0 \\ 2xy + 2wz & w^{2} - x^{2} + y^{2} - z^{2} & 2yz - 2wx & 0 \\ 2xz - 2wy & 2yz + 2wx & w^{2} - x^{2} - y^{2} + z^{2} & 0 \\ 0 & 0 & 0 & w^{2} + x^{2} + y^{2} + z^{2} \end{bmatrix}$$

Why does the last row simplify to 0? Looking at element $$[3,0]$$, $$(-x,-y,-z,w) \cdot (w,z,-y,x)$$ the dot product is $$(-x)w + (-y)z + (-z)(-y) + wx$$. Substituting some actual numbers $$x=2,y=3,z=4,w=5$$, the dot product becomes: $$(-2)5 + (-3)4 + (-4)(-3) + 5(2)$$ and that simplifies to $$(-10) + (-12) + 12 + 10$$ which is $$0$$ as expected.

Converting this formula to code is trivial. To convert to a 3x3 matrix instead of a 4x4 matrix just omit the last row and column.

Matrix4 ToMatrix(Quaternion q) {
float ww = q.w * q.w;
float xx = q.x * q.x;
float yy = q.y * q.y;
float zz = q.z * q.z;

float wx = q.w * q.x;
float wy = q.w * q.y;
float wz = q.w * q.z;

float xy = q.x * q.y;
float xz = q.x * q.z;

float yz = q.y * q.z;

return Matrix4(
ww + xx - yy - zz, 2 * xy - 2 * wz, 2 * xz + 2 * wy, 0,
2 * xy + 2 * wz, ww - xx + yy - zz, 2 * yz - 2 * wx, 0,
2 * xz - 2 * wy, 2 * yz + 2 * wx, ww - xx - yy + zz, 0,
0, 0, 0, ww + xx + yy + zz
);

// Just so there is no confusion, the above constructor takes arguments
// in row order, but stores them in column order (transposed).
// See the non-optimal example for memory layout.
}

## With Vectors

It's less efficient, but easier to understand quaternion to matrix conversion if we think about basis vectors. The upper 3x3 submatrix of a 4x4 rotation matrix is the basis vectors of said matrix. We can simply take the x, y and z basis vectors, multiply them by the quaternion and store them back into a matrix.

Matrix4 ToMatrix(Quaternion q) {
Vector3 r = q * Vector3(1, 0, 0); // Right basis vector
Vector3 u = q * Vector3(0, 1, 0); // Up basis vector
Vector3 f = q * Vector3(0, 0, 1); // Forward basis vector

return Matrix4( // OpenGL matrix convention
r.x, r.y, r.z, 0,
u.x, u.y, u.z, 0,
f.x, f.y, f.z, 0,
0  , 0  , 0  , 1
);
}

## From Matrix

Similar to how we converted a quaternion to a matrix with basis vectors, we can convert a matrix to a quaternion as well. We simply need the forward and up basis vectors of the matrix, then we can do a quaternion look at. Assuming the input matrix is generic, we should ortho-normalize it first.

Quaternion FromMatrix(Matrix4 m) {
Vector3 up = Normalized(Vector3(m, m, m));
Vector3 forward = Normalized(Vector3(m, m, m));
Vector3 right = Cross(up, forward);
up = Cross(forward, right);

return lookAt(forward, up);
}