Introduction to animating with splines

Keyframe animation is the process of creating an animation by listing specific values at particular times. For the times in between those "key" times, values are interpolated. For example, if we want to animate the z rotation of a short head nod, we might specify the following sequence of key times/values:

double headNod[][] = { {0,0}, {0.25,-0.5}, {0.5,0.5}, {0.75,0} };
The above data specifies a rotation of the neck joint about the x axis that is 0.75 seconds long. At the start of the movement, the head is level. After 1/4 second, the head has rotated to a negative angle about the x axis, so as to lift the chin. After 1/2 second the head has rotated into a positive angle about the x axis, as to lower the chin. After 3/4 second (the end of the animated movement), the head has returned to a level orientation.

The question remains of how to interpolate this data, so as to define values between these key times. The simplest form of interpolation is linear interpolation, in which we draw a straight line between successive time/value pairs.

If a time lies between two particular key times timek and timek+1, and if the values at those two key times are, respectively, valuek and valuek+1, then linear interpolation at this time, where timek ≤ time < timek+1, can be computed by:

value = valuek + (valuek+1 - valuek) * (time - timek) / (timek+1 - timek)
A deficiency of linear interpolation is that it produces animations which contain sudden changes in velocity at the key times. To create smoother interpolations, we would like to match the slope at the end of one interval, and the beginning of the next one. To do this, we can use cubic polynomial splines, which will allow us to specify any slopes we want at the beginning and at the end of an interval:
at3 + bt2 + ct + d
Creating a smooth interpolating function by converting beginning and end values and beginning and end slopes to the four coefficients (a,b,c,d) of a cubic polynomial is called Hermite interpolation, named for the french mathematician Charles Hermite, who originated the method.

In the following discussion, we will refer to the value at t=0 as P1, the value at t=1 as P4, the derivative at t=0 as R1, the derivative at t=1 as R4. This slightly odd notation is for compatibility with other forms of splines that we will be discussing later on in the class.

As we discussed in class, this method of going from values and derivatives to the coefficients of a cubic polynomial is done by realizing that we can create the following orthogonal basis for cubic polynomials:

 2t3-3t2+1 -2t3+3t2 t3-2t2+t t3-t2

These four polynomials are "orthogonal" in the sense that each one affects one and only one of our four geometric constraints: The first affects only P1, the second affects only P4, the third affects only R1, and the fourth affects only R4.

The desired cubic polynomial is just a weighted sum of these four basis cubic polynomials:

at3 + bt2 + ct + d = P1 (2t3-3t2+1) + P4 (-2t3+3t2) + R1 (t3-2t2+t) + R4 (t3-t2)

We can also express this as a matrix×vector product.

 a 2 -2 1 1 P1 b ← -3 3 -2 -1 P4 c 0 0 1 0 R1 d 1 0 0 0 R4
The matrix that does the transformation is called the Hermite matrix. I've highlighted column two of the Hermite matrix so you can see that each column just consists of the coefficients of one of the basis polynomials.

The above discussion only talks about splines that go between t=0 and t=1. What about the more general case where time varies between timek and timek+1?

To handle this we need to multiply the left and right slopes by the width of the interval:

P1 = value_at_timek
P4 = value_at_timek+1
R1 = slope_at_timek × (timek+1 - timek)
R4 = slope_at_timek+1 × (timek+1 - timek)

Then the result will be correct when applied the cubic polynomial is evaluated at 0 ≤ t < 1, and the resulting value is used at:

time = timek + t (timek+1 - timek).

The second part of your homework, which is all due on Thursday March 22 before class begins, is to implement Hermite splines, and then use them to create an interesting animation.

Your animation should specify time/value pairs for each scalar quantity that you wish to vary over time. To approximate the slope at any timek you can use:

slope_at_timek = (valuek+1 - valuek-1) / (timek+1 - timek-1)

For the slope at time0 you can use:

slope_at_time0 = 2 (value1 - value0) / (time1 - time0)
and for the slope at the last timen you can use:
slope_at_timen = 2 (valuen - valuen-1) / (timen - timen-1)

Use the time-varying scalar quantities produced by your Hermite splines as arguments to your translate, rotate and scale method calls at each frame of your animation. to your translate, rotate and scale method calls. See if you can tell a visual story. :-)