Rotating vectors using quaternions

To rotate a vector by a quaternion, turn the vector into a pure quaternion. This can be done by creating a quaternion with no scalar part and treating the (normalized) vector as it's vector part. For example, converting a vector \(\vec{v}\) to a quaternion \(v'\) would look like this:

$$ \vec{v} = (v_x, v_y, v_z) \\ v' = (\hat{v_x}, \hat{v_y}, \hat{v_z}), 0 $$

Next, left multiply this by the desired quaternion, and right multiply it by the inverse (conjugate if normalized) of the quaternion. Rotating \(v'\) by some quaternion \(q\) would look like this:

$$ r = q \cdot v' \cdot q^{-1} $$

The new, rotated vector is stored in the vector part of the result. The real part of the resulting quaternion should be 0. This type of rotation is easy to implement, but it's not very optimal. For most games doing two quaternion multiplications is fairly quick, but we can write something omre optimal and easier to understand.

Since this isn't the final multiplication formula, I won't go into detail on why the inverse post multiply is needed. This video does a great job of explaining how the formula works

Optimizing

Consider the formula: \(r = q \cdot v' \cdot q^{-1}\). We already know that hte real part of the resulting quaternion is going to be zero, but how is the vector part calculated?

The real part is not really interesting, it evaluates to 0. But the vector part, that can be simplified!

$$ \begin{aligned} \vec{v'} &= (\vec{q_v} \cdot \vec{v})\vec{q_v} + q_{s}^{2}\vec{v} + q_s(\vec{q_v} \times \vec{v}) + q_s\vec{v} \times (-\vec{q_v}) + (\vec{q_v} \times \vec{v}) \times (-\vec{q_v}) \\ &= (\vec{q_v} \cdot \vec{v})\vec{q_v} + q_s^{2}\vec{v} + q_s(\vec{q_v} \times \vec{v}) + q_s(\vec{q_v} \times \vec{v}) + \vec{q_v} \times (\vec{q_v} \times \vec{v}) \\ &= (\vec{q_v} \cdot \vec{v})\vec{q_v} + q_s^{2}\vec{v} + 2q_s(\vec{q_v} \times \vec{v}) + (\vec{q_v} \cdot \vec{v})\vec{q_v} - (\vec{q_v} \cdot \vec{q_v})\vec{v} \\ &= 2(\vec{q_v} \cdot \vec{v})\vec{q_v} + (q_s^{2} - \vec{q_v} \cdot \vec{q_v})\vec{v} + 2q_s(\vec{q_v} \times \vec{v}) \end{aligned} $$

This simplifie equation \(2(\vec{q_v} \cdot \vec{v})\vec{q_v} + (q_s^{2} - \vec{q_v} \cdot \vec{q_v})\vec{v} + 2q_s(\vec{q_v} \times \vec{v})\) is both easier to implement and uses less operations, making it more efficient.

// Could also be called Rotate(vector, quaternion) or something similar
Quaternion Mul(Vector3 v, Quaternion q) {
    Vector3 u = Vector3(q.x, q.y, q.z);
    float s = q.w;

    return 2.0 * Dot(u, v) * u + (s * s - Dot(u, u)) * v + 2.0 * s * cross(u, v);

    /* Implemented with add / scale functions
    Add(
      Add(
        Scale(u, 2 * Dot(u, v)),
        Scale(v, s * s - Dot(u, u))
      ),
      Scale(Cross(u, v), 2 * s)
    )*/
}