Let \(\mathbf{u}\in\mathbb{R}^3\) be a vector and let the unit quaternion \(\mathbf{q}=(w,\mathbf{v})\) represent a 3D rotation. The standard quaternion expression embeds \(\mathbf{u}\) as the pure quaternion \(\mathbf{p}=(0,\mathbf{u})\) and evaluates
\[\mathbf{p}'=(0,\mathbf{u}')= \mathbf{q}\mathbf{p}\mathbf{q}^{-1}.\]
For a unit quaternion, \(\mathbf{q}^{-1}=\overline{\mathbf{q}}\). Expanding both quaternion products is correct but performs work that cancels out. The same rotation can be reduced to two cross products and a few scalar-vector operations:
\[\boxed{ \mathbf{u}'=\mathbf{u}+2\mathbf{v}\times \left(w\mathbf{u}+\mathbf{v}\times\mathbf{u}\right) }.\]
Definitions and Conventions
A quaternion is written in scalar-vector form, consistent with the notation for quaternions,
\[\mathbf{q}=(w,\mathbf{v}),\qquad w\in\mathbb{R},\quad\mathbf{v}\in\mathbb{R}^3.\]
Quaternion multiplication in this form is
\[(a,\mathbf{x})(b,\mathbf{y})= \left(ab-\mathbf{x}\cdot\mathbf{y}, a\mathbf{y}+b\mathbf{x}+\mathbf{x}\times\mathbf{y}\right).\]
The conjugate and squared norm are
\[\overline{\mathbf{q}}=(w,-\mathbf{v}),\qquad \|\mathbf{q}\|^2=w^2+\mathbf{v}\cdot\mathbf{v}.\]
The derivation uses an active, right-handed rotation with \(\mathbf{p}'=\mathbf{q}\mathbf{p}\mathbf{q}^{-1}\). Libraries that use the opposite sandwich product \(\mathbf{q}^{-1}\mathbf{p}\mathbf{q}\), passive frame rotations, or a different quaternion component order require the corresponding sign or ordering change.
Expanding the Quaternion Product
For the unit-quaternion case, start by multiplying \(\mathbf{q}\) and the pure quaternion \(\mathbf{p}\):
\[\begin{array}{rl} \mathbf{q}\mathbf{p} &=(w,\mathbf{v})(0,\mathbf{u})\\ &=\left(-\mathbf{v}\cdot\mathbf{u}, w\mathbf{u}+\mathbf{v}\times\mathbf{u}\right). \end{array}\]
Introduce the temporary vector
\[\mathbf{r}=w\mathbf{u}+\mathbf{v}\times\mathbf{u}.\]
Right-multiplication by the conjugate then gives
\[\begin{array}{rl} \mathbf{q}\mathbf{p}\overline{\mathbf{q}} &=\left(-\mathbf{v}\cdot\mathbf{u},\mathbf{r}\right)(w,-\mathbf{v})\\ &=\left( -w(\mathbf{v}\cdot\mathbf{u})+\mathbf{r}\cdot\mathbf{v}, (\mathbf{v}\cdot\mathbf{u})\mathbf{v}+w\mathbf{r}-\mathbf{r}\times\mathbf{v} \right). \end{array}\]
The Scalar Part Vanishes
Substituting \(\mathbf{r}\) into the scalar part yields
\[\begin{array}{rl} -w(\mathbf{v}\cdot\mathbf{u})+\mathbf{r}\cdot\mathbf{v} &=-w(\mathbf{v}\cdot\mathbf{u})+ \left(w\mathbf{u}+\mathbf{v}\times\mathbf{u}\right)\cdot\mathbf{v}\\ &=-w(\mathbf{v}\cdot\mathbf{u})+w(\mathbf{u}\cdot\mathbf{v})+0\\ &=0. \end{array}\]
The cross product \(\mathbf{v}\times\mathbf{u}\) is perpendicular to \(\mathbf{v}\), so the rotated quaternion remains pure, as required.
Simplifying the Vector Part
Expand the vector part and use the anti-commutativity of the cross product:
\[\begin{array}{rl} \mathbf{u}' &=(\mathbf{v}\cdot\mathbf{u})\mathbf{v}+w\mathbf{r}-\mathbf{r}\times\mathbf{v}\\ &=(\mathbf{v}\cdot\mathbf{u})\mathbf{v} +w^2\mathbf{u}+w(\mathbf{v}\times\mathbf{u}) -w(\mathbf{u}\times\mathbf{v}) -(\mathbf{v}\times\mathbf{u})\times\mathbf{v}\\ &=w^2\mathbf{u}+2w(\mathbf{v}\times\mathbf{u}) +(\mathbf{v}\cdot\mathbf{u})\mathbf{v} -(\mathbf{v}\times\mathbf{u})\times\mathbf{v}. \end{array}\]
The vector triple-product identity gives
\[(\mathbf{v}\times\mathbf{u})\times\mathbf{v} =(\mathbf{v}\cdot\mathbf{v})\mathbf{u} -(\mathbf{u}\cdot\mathbf{v})\mathbf{v}.\]
Therefore
\[\mathbf{u}'= \left(w^2-\mathbf{v}\cdot\mathbf{v}\right)\mathbf{u} +2(\mathbf{v}\cdot\mathbf{u})\mathbf{v} +2w(\mathbf{v}\times\mathbf{u}).\]
This expression is already the familiar quaternion rotation formula. Since \(\mathbf{q}\) is a unit quaternion,
\[w^2+\mathbf{v}\cdot\mathbf{v}=1,\]
so \(w^2-\mathbf{v}\cdot\mathbf{v}=1-2\mathbf{v}\cdot\mathbf{v}\). Applying the triple-product identity in the form
\[\mathbf{v}\times(\mathbf{v}\times\mathbf{u})= (\mathbf{v}\cdot\mathbf{u})\mathbf{v} -(\mathbf{v}\cdot\mathbf{v})\mathbf{u}\]
then produces the compact result
\[\begin{array}{rl} \mathbf{u}' &=\mathbf{u}+2w(\mathbf{v}\times\mathbf{u}) +2\mathbf{v}\times(\mathbf{v}\times\mathbf{u})\\ &=\boxed{\mathbf{u}+2\mathbf{v}\times \left(w\mathbf{u}+\mathbf{v}\times\mathbf{u}\right)}. \end{array}\]
Two-Cross-Product Form
For implementation, define
\[\mathbf{t}=2\mathbf{v}\times\mathbf{u}.\]
The rotation becomes
\[\boxed{\mathbf{u}'=\mathbf{u}+w\mathbf{t}+\mathbf{v}\times\mathbf{t}}.\]
This form avoids constructing two temporary quaternions and evaluating two full quaternion products. It requires no trigonometric functions when the quaternion is already available. Whether it is measurably faster in a particular application still depends on data layout, compiler optimization, SIMD use, and surrounding code.
I derived this reduction independently while looking for a cheaper way to rotate vectors. Only afterward did I discover that the same identity was already a known result in quaternion-based rotation code.
JavaScript Implementation
The function below expects the quaternion in \([w,x,y,z]\) order and assumes it is normalized:
function rotateVectorByUnitQuaternion(q, u) {
const [w, x, y, z] = q;
const [ux, uy, uz] = u;
const tx = 2 * (y * uz - z * uy);
const ty = 2 * (z * ux - x * uz);
const tz = 2 * (x * uy - y * ux);
return [
ux + w * tx + (y * tz - z * ty),
uy + w * ty + (z * tx - x * tz),
uz + w * tz + (x * ty - y * tx)
];
} For example, the quaternion
\[\mathbf{q}=\left(\cos\frac{\pi}{4},0,0,\sin\frac{\pi}{4}\right)\]
represents a 90-degree rotation around the positive z-axis. Applying it to \((1,0,0)\) returns \((0,1,0)\), up to floating-point rounding.
Non-Unit Quaternions
The conjugate equals the inverse only for a unit quaternion. For an arbitrary nonzero quaternion,
\[\mathbf{q}^{-1}=\frac{\overline{\mathbf{q}}}{\|\mathbf{q}\|^2}.\]
Using \(\mathbf{q}\mathbf{p}\overline{\mathbf{q}}\) without dividing by \(\|\mathbf{q}\|^2\) scales the output by the squared quaternion norm. The general formula is therefore
\[\mathbf{u}'= \frac{ \left(w^2-\mathbf{v}\cdot\mathbf{v}\right)\mathbf{u} +2(\mathbf{v}\cdot\mathbf{u})\mathbf{v} +2w(\mathbf{v}\times\mathbf{u}) }{w^2+\mathbf{v}\cdot\mathbf{v}}.\]
In repeated rotation code, normalizing the quaternion once before the loop is usually simpler than performing this division for every vector. Reject a zero quaternion because it has no inverse and cannot represent a rotation.
Geometric Checks
A correct implementation should satisfy the following invariants:
- The identity quaternion \((1,\mathbf{0})\) leaves every vector unchanged.
- A vector parallel to the rotation axis remains unchanged.
- A unit quaternion preserves vector length: \(\|\mathbf{u}'\|=\|\mathbf{u}\|\).
- Replacing \(\mathbf{q}\) by \(-\mathbf{q}\) gives the same rotated vector.
- Applying \(\overline{\mathbf{q}}\) reverses the rotation.
A shortest-arc quaternion constructed directly from two directions can be obtained from the quaternion between two vectors derivation. For production JavaScript code, Quaternion.js provides the same operation together with quaternion normalization, composition, and interpolation.
References
- Hamilton1844W. R. Hamilton (1844) On Quaternions; or on a New System of Imaginaries in Algebra, The London, Edinburgh, and Dublin Philosophical Magazine and Journal of Science, Series 3, 25(163), 10-13
- Shoemake1985K. Shoemake (1985) Animating Rotation with Quaternion Curves, Proceedings of SIGGRAPH '85, Computer Graphics 19(3), 245-254