Quaternions
Ken Shoemake
Department of Computer and Information Science
University of Pennsylvania
Philadelphia, PA 19104
Abstract
Of the many mathematical tools used in computer graphics, most are well covered
in standard texts; quaternions are not. This article is intended to provide tutorial
material on quaternions, including what they are, why they are useful, how to use
them, where to use them, and when to be careful.
Introduction
Computer graphics uses quaternions as coordinates for rotations and orientations.
At SIGGRAPH 1985, quaternion curve methods were introduced to computer
graphics to facilitate rotation animation. Although this is a rather specialized
environmental niche, quaternions work so well they are able to compete
successfully both with more general coordinates such as matrices, and with other
special coordinates such as Euler angles.
Quaternion use has since expanded to include new curve methods and new
applications, including physically based modeling, constraint systems, and user
interfaces. This is because when a quaternion implementation is compared to other
alternatives, it is usually simpler, cheaper, and better behaved.
Thats the good news. The bad news is that researchers and implementors must
learn some new mathematics, and quaternions are not taught in core mathematics
and science courses. However, neither are homogeneous coordinates; and a broad
view reveals that quaternions are simply a more sophisticated use of the four-
component homogeneous coordinates to which we are already accustomed.
Rotations
What can be so unusual about three-dimensional rotations that they warrant their
own coordinate system? Put simply, because rotations do not commute, they cannot
be treated as vectors. Suppose Tx(d) is translation along the x axis by d, and Rx(q) is
rotation around the x axis by q ; similarly for Ty , Tz, Ry , and Rz. Then
T y(45cm)T x(90cm) commutes, meaning it equals Tx(90cm)T y(45cm); but
1
Ry(45)Rx(90) „ Rx(90)Ry(45). (As usual, BA means the composition of action A
followed by action B.) Note also that if we take the composition Ry(180)Rx(180) we
get the same result as Rz(180)!
It takes some study to unravel all the implications of these elementary observations,
but they are far-reaching and often surprising. The set of all 3-dimensional rotations
is not organized as a simple 3-dimensional vector space, but as a closed curved 3-
dimensional manifold, which is also a (continuous) group. This group is known as
SO(3). (For special and orthogonal.) Manifolds are generalizations of surfaces; this
one has the topology of real 3-dimensional projective space, RP3, and also a natural
distance measure related to rotation angle. Although a vector space such as the
translations trivially splits into a product of lines, SO(3) does not split. Instead, it has
a more sophisticated description as a fiber bundle over the sphere of directions, S2,
with fiber space the planar rotations, SO(2).
Unit quaternions have the remarkable property of capturing all of the geometry,
topology, and group structure of 3-dimensional rotations in the simplest possible
way. (Technically, they form what is called a universal covering.)
Quaternion definitions
Quaternions can be defined in several different, equivalent ways. It is helpful to
know them all, since each form is useful. Historically, quaternions were conceived
by Hamilton as like extended complex numbers, w+ix+jy+kz, with i2 = j2 = k2 = —1, ij
= k = —ji, with real w, x, y, z. (In honor of Hamilton, mathematicians denote the
quaternions by H.) Notice the non-commutative multiplication, their novel feature;
otherwise, quaternion arithmetic is pretty much like real arithmetic. Hamilton was
also quite aware of the more abstract possibility of treating quaternions as simply
quadruples of real numbers [x, y, z, w ], with operations of addition and
multiplication suitably defined. But it happens that the components naturally group
into the imaginary part, (x, y, z), for which Hamilton coined the term vector, and the
purely real part, w , which he called a scalar. Later authors (notably Gibbs)
appropriated Hamiltons terminology and extracted from the clean operations of
quaternion arithmetic the somewhat messierbut more generaloperations of
vector arithmetic. Courses today teach Gibbs dot and cross products, so it is
convenient to reverse history and describe the quaternion product using them.
Thus we usually will want to write a quaternion as [v, w], with v = (x, y, z). We will
2
identify real numbers s with quaternions [0, s], and vectors v ˛ R3 with quaternions
[v, 0]. Here are some basic facts.
Forms
q def= [v, w]
= [(x, y, z), w]
= [x, y, z, w]
= ix+jy+kz+w
; v ˛ R3, w ˛ R
; x, y, z, w ˛ R
; x, y, z, w ˛ R
; x, y, z, w ˛ R, i2 = j2 = k2 = ijk = —1
N o r m
N(q) def= qq* = q*q
= w2 + vÆv
= w2 + x2 + y2 + z2
Norm facts
N(qq«) = N(q)N(q«)
N(q*) = N(q)
Inverse
q—1 = q* / N(q)
Unit quaternion facts
Let N(q) = N(q«) = N(v ) = 1. Then:
(for some v )
q = [v sin W, cos W]
N(qq«) = 1
q—1 = q*
v 2 = —1
ev W = 1 + v W + (v W)2/2! +
= [v sin W, cos W]
Addition
q + q« = [v, w] + [v«, w«]
def= [v + v«, w + w«]
Multiplication
qq« = [v, w][v«, w«]
def= [v·v«+wv«+w«v, ww«—vÆv«]
Multiplication facts
(pq)q« = p(qq«)
1q = q1 = [0, 1][v, w]
= [1v, 1w] = [v, w]
sq = qs = [0, s][v, w]
= [sv, sw]
vv« = [v, 0][v«, 0]
= [v·v«, —vÆv«]
Bilinearity
p(sq+s«q«) = spq + s«pq«
(sq+s«q«)p = sqp + s«q«p
Conjugate
q* = [v, w]*
def= [—v, w]
Conjugation facts
(q*)* = q
(pq)* = q*p*
(p+q)* = p*+q*
3
Notice that N(q) is a scalar, so the description of q—1 is well-defined. Otherwise, the
non-commutativity of multiplication requires explicit expressions, such as pq—1,
instead of p / q.
The preceding list contains both definitions and consequences. It is a useful exercise
to treat the consequences as lemmas, and prove them from the definitions. Each
proof should be a straightforward computation.
Quaternions as rotations
The relationship of quaternions to three-dimensional rotations is contained in
Theorem 1. Let p be a point in three-dimensional (projective) space, represented as a
quaternion using its homogeneous coordinates, p = (x:y:z:w) @ [(x, y, z), w] = [v, w];
and let q be any non-zero quaternion. Then:
1) The product qpq—1 takes p = [v, w] to p« = [v«, w], with N(v) = N(v«).
2) Any non-zero real multiple of q gives the same action.
3) If N(q) = 1, then q = [v sin W, cos W] acts to rotate around unit axis v by 2W.
Proof. Let us first dispose of part 2. This is trivial, since the inverse of sq is q—1s—1, and
scalar multiplication commutes. Thus (sq)p(sq)—1 = sqpq—1s—1 = qpq—1ss—1 = qpq—1. So
we can henceforth assume q is a unit quaternion, as stipulated in part 3, without loss
of generality. For q a unit quaternion, q—1 = q*, so we can write the action as qpq*.
Now part 1 is simpler. Trivially, the action on a scalar gives that scalar, since scalar
multiplication commutes. Similarly, the action on a vector, [v, 0], gives some vector,
as we now show. The scalar part of any quaternion S(q) can be extracted using the
formula 2S(q) = q + q*. So consider 2S(qpq*) = (qpq*) + (qpq*)* = qpq* + qp*q*. Since
quaternion multiplication is bilinear, we can factor this as q(p+p*)q* = q(2S(p))q* =
2S(p). Hence the action of q on p = [v, w] gives [v«, w]. Because multiplication
preserves norms, N(p) = N(p«); and since w is unchanged, N(v) = N(v«).
Finally we turn to part 3, the heart of the theorem, and consider the situation in
Figure 1, where N(v0) = N(v1) = 1 and q = v1v0* = [v0·v1, v0Æv1]. We can identify W
as the angle between v0 and v1, so that v0Æv1 = cos W. Then let v = (v0·v1)/||v0·v1||,
a unit vector in the direction of the cross productthus perpendicular to v0 and v1.
Now we can write q = [v sin W, cos W]. (We shall assume v1 „ –v0, else q = –1, and
the action is the identity.) We show that v2v1* = (qv0q*)v1* has the same compo-
nents (dot and cross products) as v1v0*; so qv0q* lies in the same plane as v0 and v1,
and also forms an angle of W with v1.
4
v0·v1
v0
v1
= qv0q*
Figure 1. Geometry of action
v2
Substituting the definition of q in (qv0q*)v1* gives (qv0(v1v0*)*)v1*, which simplifies
to q(v0v0)(v1*v1*). Since v0 and v1* are unit vectors, they square to —1, leaving q.
(qv0q*)v1* = (qv0(v1v0*)*)v1*
= qv0(v0v1*)v1*
= q(v0v0)(v1*v1*)
= q(—1)(—1)
= v1v0*
This confirms the equality, so the picture is accurate. Furthermore, q acts on v1 = qv0
to produce a vector which is also in the same plane, at an angle of W with qv0q*. (We
simply observe that (qv1q*)(qv0q*)* = (q(qv0)q*)(qv0q*)* = q(qv0q*)(qv0q*)* = q.)
Interpreting this result in the terms stated in the theorem, we have just showed that
the action of q on v0 and on v1 is, as required, to rotate around the axis v by an angle
of 2W. In fact, the action will be this same rotation on any vector p, as is shown by
splitting p into s0v0+s1v1+sv . Bilinearity allows us to examine the action on v0, v1,
and v separately.
We already know the action on v0 and on v1, so consider the action on v . Observe
that multiplication fails to commute simply because of the cross product. But in the
product qv = [v sin W, cos W][v , 0] the cross product is zero, so qv = v q, and qv q* =
v qq* = v , which is consistent with the interpretation of v as the axis of rotation.
Thus the action of q on every vector is a rotation around v by 2W, which concludes
the proof of part 3, and of Theorem 1. z
Corollary. Every three-dimensional rotation is the action of some unit quaternion.
Proof. Using part 3 of Theorem 1 we can get any axis and any angle. z
Quaternion rotation facts
Observe that the combination of rotation by q1 followed by q2 is given by q = q2q1,
since
q2(q1pq1*)q2* = (q2q1)p(q2q1)* = qpq*.
5
Because quaternion multiplication is bilinear, it can be expressed in matrix form,
and in two different ways. Multiplication on the left by q = [(x, y, z), w] = [v, w] gives
qp as Lqp, where p is now treated as a 4-dimensional column vector. The matrix Lq is
Lq =
ί
ºŒ
˚y
˚w —z
˚x
˚z ˚w —x ˚y
—y ˚x ˚w ˚z
—x —y —z ˚w
Ͽ
ߜ
Ø
= º
wI+(v·-) v
˚w
—vT
ø
ß
The 2·2 matrix is a block partition of the Lq matrix, and (v·-) is the 3·3 matrix
expressing the cross product of v with an arbitrary vector, namely
(v·-) =
˚0 —z
˚z
—y ˚x
˚y
˚0 —x
˚0
Ø
Œ
º
ø
œ
ß
Multiplication on the right by q gives pq as Rqp, where Rq is
Rq =
ί
ºŒ
˚w ˚z —y ˚x
—z ˚w ˚x
˚y
˚y —x ˚w ˚z
—x —y —z ˚w
Ͽ
ߜ
Ø
= º
wI—(v·-) v
˚w
—vT
ø
ß
Multiplication on the right by q* gives pq* as Rq*p, where Rq* is
Rq* =
ί
ºŒ
˚w —z
˚y —x
˚z ˚w —x —y
—y ˚x ˚w —z
˚x
˚z ˚w
˚y
Ͽ
ߜ
Ø
= º
wI+(v·-) —v
˚w
vT
ø
ß
Multiplication on the left by q and on the right by q* gives qpq* as Qp, where Q =
LqRq* is
Q =
ί
ºŒ
Ø
= º
w2+x2—y2—z2
2(xy—wz)
2(xy+wz) w2—x2+y2—z2
2(xz—wy)
2(yz+wx) w2—x2—y2+z2
2(xz+wy)
2(yz—wx)
0
0
0
0
w2+x2+y2+z2
Ͽ
ߜ
0
(wI+(v·-))2+vvT
0T
ø
ß
˚N(q)
0
0
This simplifies to
Q =
@
ί
ºŒ
ί
ºŒ
N(q)—2(y2+z2)
2(xy—wz)
2(xy+wz)
2(xz—wy)
0
N(q)—2(x2+z2)
2(yz+wx)
0
2(xz+wy)
2(yz—wx)
N(q)—2(x2+y2)
0
0
0
0
N(q)
Ͽ
ߜ
1—s(y2+z2)
s(xy—wz)
s(xy+wz) 1—s(x2+z2)
s(xz—wy)
s(xz+wy) 0
s(yz—wx)
0
s(yz+wx) 1—s(x2+y2) 0
1
0
0
0
Ͽ
ߜ
; s = 2 / N(q)
6
The equivalence assumes Q acts on homogeneous coordinates, so each entry of the
matrix can be divided by N(q) without changing the effect. When N(q) = 1, Q
simplifies to
Q =
ί
ºŒ
1—2(y2+z2)
2(xy—wz)
2(xy+wz) 1—2(x2+z2)
2(xz—wy)
2(xz+wy) 0
2(yz—wx)
0
2(yz+wx) 1—2(x2+y2) 0
1
0
0
0
Ͽ
ߜ
These observations produce the following core quaternion routines.
typedef struct {float x,y,z,w;} Quat;
typedef float HMatrix[4][4];
#define X 0
#define Y 1
#define Z 2
#define W 3
/* Return quaternion product qL * qR. */
Quat Qt_Mul(Quat qL, Quat qR)
{
Quat qq;
qq.w = qL.w*qR.w - qL.x*qR.x - qL.y*qR.y - qL.z*qR.z;
qq.x = qL.w*qR.x + qL.x*qR.w + qL.y*qR.z - qL.z*qR.y;
qq.y = qL.w*qR.y + qL.y*qR.w + qL.z*qR.x - qL.x*qR.z;
qq.z = qL.w*qR.z + qL.z*qR.w + qL.x*qR.y - qL.y*qR.x;
return (qq);
}
/* Return norm of quaternion, the sum of the squares of the components. */
#define Qt_Norm(q) ((q).x*(q).x + (q).y*(q).y + (q).z*(q).z + (q).w*(q).w)
/* Construct rotation matrix from (possibly non-unit) quaternion.
* Assumes matrix is used to multiply column vector on the left:
* vnew = mat vold. Works correctly for right-handed coordinate system
* and right-handed rotations. */
void Qt_ToMatrix(Quat q, HMatrix mat)
{
double Nq = Qt_Norm(q);
double s = (Nq > 0.0) ? (2.0 / Nq) : 0.0;
double xs = q.x*s,
double wx = q.w*xs,
double xx = q.x*xs,
double yy = q.y*ys,
mat[X][X] = 1.0 - (yy + zz); mat[Y][X] = xy + wz; mat[Z][X] = xz - wy;
mat[X][Y] = xy - wz; mat[Y][Y] = 1.0 - (xx + zz); mat[Z][Y] = yz + wx;
mat[X][Z] = xz + wy; mat[Y][Z] = yz - wx; mat[Z][Z] = 1.0 - (xx + yy);
mat[X][W] = mat[Y][W] = mat[Z][W] = 0.0;
mat[W][X] = mat[W][Y] = mat[W][Z] = 0.0;
mat[W][W] = 1.0;
ys = q.y*s,
wy = q.w*ys,
xy = q.x*ys,
yz = q.y*zs,
zs = q.z*s;
wz = q.w*zs;
xz = q.x*zs;
zz = q.z*zs;
}
7
/* Construct a unit quaternion from rotation matrix. Assumes matrix is
* used to multiply column vector on the left: vnew = mat vold. Works
* correctly for right-handed coordinate system and right-handed rotations.
* Translation and perspective components ignored. */
Quat Qt_FromMatrix(HMatrix mat)
{
/* This algorithm avoids near-zero divides by looking for a large component
* first w, then x, y, or z. When the trace is greater than zero,
* |w| is greater than 1/2, which is as small as a largest component can be.
* Otherwise, the largest diagonal entry corresponds to the largest of |x|,
* |y|, or |z|, one of which must be larger than |w|, and at least 1/2. */
Quat qu;
float tr, s;
tr = mat[X][X] + mat[Y][Y]+ mat[Z][Z];
if (tr >= 0.0) {
s = sqrt(tr + mat[W][W]);
qu.w = s*0.5;
s = 0.5 / s;
qu.x = (mat[Z][Y] - mat[Y][Z]) * s;
qu.y = (mat[X][Z] - mat[Z][X]) * s;
qu.z = (mat[Y][X] - mat[X][Y]) * s;
} else {
int h = X;
if (mat[Y][Y] > mat[X][X]) h = Y;
if (mat[Z][Z] > mat[h][h]) h = Z;
switch (h) {
#define caseMacro(i,j,k,I,J,K) \
case I:\
s = sqrt( (mat[I][I] - (mat[J][J]+mat[K][K])) + mat[W][W] );\
qu.i = s*0.5;\
s = 0.5 / s;\
qu.j = (mat[I][J] + mat[J][I]) * s;\
qu.k = (mat[K][I] + mat[I][K]) * s;\
qu.w = (mat[K][J] - mat[J][K]) * s;\
break
caseMacro(x,y,z,X,Y,Z);
caseMacro(y,z,x,Y,Z,X);
caseMacro(z,x,y,Z,X,Y);
#undefine caseMacro
}
}
if (mat[W][W] != 1.0) {
s = 1.0/sqrt(mat[W][W]);
qu.w *= s;
qu.x *= s;
}
return (qu);
}
qu.y *= s;
qu.z *= s;
This last routine converts a rotation matrix to a unit quaternion, but it may not be
the same as the one with which you created the matrix. Part 2 of Theorem 1 implies
that quaternions are homogeneous coordinates for rotations. Thus q and —q give the
same rotation matrix, and the extraction routine can return either one; sometimes
the choice matters.
Remember that SO(3) has the topology of 3-dimensional real projective space (RP3),
but unit quaternions form a hypersphere (S3) in four dimensions, which is
topologically different. The identification of opposite points is what makes up the
difference.
8