4.4. Quaternions 173
Likewise, the composite rotation quaternion qnet can be found and applied to
vector v (in its quaternion form, v) as follows:
Notice how the quaternion product must be performed in an order opposite
to that in which the rotations are applied (q 3 q 2 q 1 ). This is because quaternion
rotations always multiply on both sides of the vector, with the uninverted
quaternions on the left and the inverted quaternions on the right. As we saw
in Equation (4.3), the inverse of a quaternion product is the reverse product of
the individual inverses, so the uninverted quaternions read right-to-left while
the inverted quaternions read left -to-right.
4.4.4. Quaternion-Matrix Equivalence
We can convert any 3D rotation freely between a 3 × 3 matrix representation
R and a quaternion representation q. If we let q = [ qV qS ] = [ qVx qVy qVz qS ] =
[ x y z w ], then we can fi nd R as follows:
Likewise, given R we can fi nd q as follows (where q[0] = qVx , q[1] = qVy ,
q[2] = qVz , and q[3] = qS). This code assumes that we are using row vectors
in C/C++ (i.e., that the rows of matrix R[row][col] correspond to the rows
of the matrix R shown above). The code was adapted from a Gamasutra article
by Nick Bobic, published on July 5, 1998, which is available here: htt p://www.
gamasutra.com/view/feature/3278/rotating_objects_using_quaternions.php.
For a discussion of some even faster methods for converting a matrix to a
quaternion, leveraging various assumptions about the nature of the matrix,
see htt p://www.euclideanspace.com/maths/geometry/rotations/conversions/
matrixToQuaternion/index.htm.
void matrixToQuaternion(
const float R[3][3],
float q[/*4*/])
{
float trace = R[0][0] + R[1][1] + R[2][2];
net 1 2 3
1 2 3 net
;
.
=
′==
R RRR
v vR R R vR
net 3 2 1
3 2 1 11112 3 net net^1
q qqq;
v q q q vq q q−−−q vq−.
=
′==
22
22
22
12 2 2 2 2 2
2 2 12 2 2 2.
2 2 2 2 12 2
y z xy zw xz yw
xy zw x z yz xw
xz yw yz xw x y