Rotate Around Axis

In which you build a transformation for rotating around any axis, not just the three standard ones.

There's one other prerequisite to address before diving into a discussion of input systems. You've already worked out matrices for rotating an object around the x-, y-, or z-axes. What you need is a way to rotate around an arbitrary axis, say \(\begin{bmatrix}1&1&1\end{bmatrix}\). The good news is that a rotation around an arbitrary axis can be decomposed into this sequence of rotations around the standard axes:

  1. Rotate around the x-axis so that the axis of rotation lies in the xz-plane.
  2. Rotate around the y-axis so that the axis of rotation aligns with the z-axis.
  3. Rotate around the z-axis by the desired amount.
  4. Unrotate around the y-axis.
  5. Unrotate around the x-axis.

The bad news is that the math gets rather involved. You have to figure out the angles for steps 1 and 2 using dot products. And then you've got five matrices to multiply together. In pseudocode, the algorithm looks something like this:

function rotateAroundAxis(axis, degrees)
  angle1 = degrees needed to put axis in xz-plane
  angle2 = degrees needed to put axis along z-axis
  return Matrix4.rotateX(-angle1) *
         Matrix4.rotateY(-angle2) *
         Matrix4.rotateZ(degrees) *
         Matrix4.rotateY(angle2) *
         Matrix4.rotateX(angle1)

You can figure out the math later if you want. In the meantime, your graphics forebears have worked out a compact form of this matrix and shared it with you.

Suppose you wish to rotate \(a\) radians around axis \(\mathbf{v}\). The matrix will be built out of the components of \(\mathbf{v}\) and these variables derived from \(a\):

$$ \begin{aligned} s &= \sin a \\ c &= \cos a \\ d &= 1 - c \end{aligned} $$

The rotation matrix has this form:

$$ \mathbf{R} = \begin{bmatrix} d v_x v_x+c & d v_x v_y-s v_z & d v_x v_z+s v_y & 0 \\ d v_y v_x+s v_z & d v_y v_y+c & d v_y v_z-s v_x & 0 \\ d v_z v_x-s v_y & d v_z v_y+s v_x & d v_z v_z+c & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} $$

Add a rotateAroundAxis method to your Matrix4 class. Accept parameters for the axis and degrees. Return the rotation matrix. The axis must have unit length for this method to work properly.