Natural Object Rotation
Volume Number: 15
Issue Number: 3
Column Tag: Programming Techniques
Natural Object Rotation without Quaternions
by Kas Thomas
The usual way of doing free-rotations isn't
necessarily the best way.
User interface design in 3D applications remains a difficult area. The problem of how
best to allow user access to features like object, face, and vertex selection;
translation, scaling, and rotation; and selection and movement of lights and camera, is
still largely an open question. Most interfaces are highly modal and rely on the use of
unfamiliar widgets, glyphs, or icons. Most end-users, alas, remain confused.
One of the most fundamental operations in 3D design is object rotation. This may, in
fact, be the single most important mode of object manipulation. Users expect to be able
to rotate objects at will. (This is why, for example, the Apple 3D Viewer supports free
rotation as the default mouse-drag behavior.) Most interfaces, the 3D Viewer's
included, support simultaneous rotation on x- and y-axes, keyed to mouse horizontal
and vertical movements. That is to say, side-to-side displacement of the mouse results
in an apparent rotation of the 3D object about the yaw (y) axis, while up-and-down
(or fore-and-aft) dragging of the mouse causes rotation on the pitch (x) axis. Since
the mouse has only two degrees of freedom, z-axis rotations are ignored. The code for
achieving the rotation usually looks something like this:
delta_x = mousePtNew.h - mousePtOld.h;
delta_y = mousePtNew.v - mousePtOld.v;
// now rotate on the X-axis by the amount of vertical motion (dy)
// and rotate the object around the Y-axis by the amount of
// lateral motion (dx):
RotateObject( delta_y, delta_x, 0.0 );
The RotateObject function typically stuffs the (appropriately scaled) argument values
into a 4X4 rotation matrix and performs a matrix multiplication with the object's
global "rotation matrix" to calculate the new orientation of the object.
The problem with this approach is that object motion is not constrained to just the x-
and y-axes. Cross-coupling of axis rotations inevitably causes some motion of the
object about the third (z) axis. This well-known effect (which is responsible for
"gimbal lock") arises because the three degrees of rotational freedom that would seem
to be available in a Cartesian coordinate system are not truly independent.
Translations in Cartesian 3-space are independent, because they combine (via vector
addition) in commutative fashion. Rotations on Cartesian axes are not independent,
because their combination (via matrix multiplication) is not commutative.
The reason this is a problem for user-interface design is that mixed x/y-axis object
rotation (using the kind of code shown above) gives confusing feedback to the user.
Some z-axis crossover always occurs. The unexpected z-axis rotation that occurs is
counterintuitive in and of itself; but there is also the very serious problem of
pointing-device hysteresis: This refers to a situation where rotational positioning of
objects depends not only on the final position of the mouse or trackball, but the path it
took getting there. In other words, when you drag the mouse from Point A to Point B,
the final orientation of the object can be different each time depending on the exact
path the cursor took. Dragging the cursor back to Point A may or may not restore the
object to its original position. (Usually it does not.)
This behavior goes against Apple's own Quickdraw[TM] 3D User Interface Guidelines
(as published in the original SDK for QD3D), where it is stated: "To support
interaction, the application must complement every user action with appropriate
feedback.
It's hard to conceive of how a pointing device with serious built-in hysteresis and a
propensity to generate uncommanded third-axis rotations can be said to provide
"appropriate feedback.
The Way Out
Because of programmers' traditional slavish adherence to Euler-angle rotation
methods, there would seem, at first, to be no way out of the "uncommanded z-rotation
dilemma. But in fact, as first pointed out by Ken Shoemake (at SIGGRAPH '85),
quaternion algebra provides a solution to this very problem.
Quaternions were conceived (as an extension of complex numbers to higher
dimensions) in 1843 by the mathematician William Hamilton. They bear a strong
resemblance to complex numbers - that is, numbers of the form a + bi, where a is a
real number and bi is the so-called imaginary term (i being equivalent to the square
root of -1). A quaternion is a four-component number (hence the name) of the form:
q = a + bi + cj + dk
Where i2 = j2 = k2 = -1. Just as complex numbers can be written as ordered pairs
(a, bi), quaternions can be considered as a grouping of a scalar quantity with a vector
quantity, q = (s, v ) where s is the scalar component and v is a 3D vector in ijk-space.
In this view of things, an ordinary 3D vector can be considered a kind of degenerate
quaternion; that is, a quaternion with a zero-valued scalar component. Such a
pure-vector quaternion is known as a "pure quaternion." Also, just as ordinary
vectors can be normalized (a process in which the components of the vector are scaled
by the vector's magnitude) to give unit vectors, quaternions can be normalized to give
"unit quaternions." Space doesn't permit a full discussion of quaternion algebra here,
but the resemblances to vector algebra and complex-number arithmetic are extensive.
(See Chapter 15 of Advanced Animation and Rendering Techniques by Watt, or a good
math text, for further details.)
Perhaps the most intuitive way to consider quaternions is to regard them as pairings
of rotational angles with rotational axes. The scalar part of a quaternion can be seen as
the amount of rotation, while the vector part represents the axis on which the rotation
takes place. A pure-vector quaternion is thus an axis without a specified rotation.
The significance of quaternion algebra for graphics programmers lies in the fact that
rotations can be calculated in a way that makes arc intervals add and subtract like
vectors, which is to say commutatively. This is because quaternions assume a
parametrization of coordinate space based on the natural rotational axes of objects. In