Notes for Tuesday April 9-11:
Splines, Patches and more

 

SPLINES

As we discussed in class, the word "spline" had its origin in ship building. To create smooth hull shapes, ancient ship builders would drive pegs into the ground, and then lay down a very large thin flexible strip of wood (the "spline") that would be forced into a curve by the position of the pegs.

They would then use the resulting smooth curve as a guide for cutting the lumber that they would use to create the hulls of their ships.

In more recent times, beginning in the 1960s, designers in the automotive and aerospace industries started using computer software to generate smooth curves when designing their vehicles. The math they used for this was pretty much the same as what we covered today in class.

In class we first looked at an example of using the same smooth spline both to create both the profile of a object and an animation path. As you can see in the screen capture to the right, the same spline is being used to create the shape of the earthen flask and to specify the path over time of the swimming fish.

 

PARAMETRIC CUBIC CURVES

The underlying math for creating smooth splines is generally to create a set of parametric cubic curves that fit together seamlessly, so that they appear to form a single smooth curve. The general recipe is as follows:

  • Divide the curve into simple curved segments.

  • The position and orientation at the end of each segment is the same as the position and orientation at the beginning of the next segment.

  • The points that begin and end segments are called "key points".

  • Each segment is a parametric curve x(t), y(t), (and optionally z(t)), where t varies between 0.0 and 1.0.

  • In particular, the position along each dimension of every segment is a cubic function:

    x(t) = ax * t3 + bx * t2 + cx * t + dx
    y(t) = ay * t3 + by * t2 + cy * t + dy

After defining the above functions x(t) and y(t), it's easy to draw the resulting spline segment. For example:

   function drawSpline(x, y, dt) {
      let a = [x(0), y(0)];
      for (let t = dt ; t <= 1 ; t += dt) {
         let b = [x(t), y(t)];
         drawLine(a, b); // we assume this function is already defined.
         a = b;
      }
   }

 

TRANSLATING FROM THE HUMAN DESIGNER TO THE COMPUTER

For most human beings, it would be extremely difficult to design such curves by directly typing the coefficients of cubic polynomials. For this reason, we create other ways of defining those coefficients, which are more human-friendly.

All such methods work by transforming some easier to understand set of values into the underlying cubic coefficients (a,b,c,d). In class we have gone over several of the more important such methods, including Hermite splines and Bezier splines.

 

HERMITE SPLINES

If our human user wants to define things in terms of the position and orientation at the beginning and end of each cubic spline segment, then we use the Hermite spline.

We do all the math independently for each coordinate (eg: x and y, or x,y and z).

P0 = value at start of the segment (where t = 0).
P1 = value at end of the segment (where t = 1).
R0 = slope at start of the segment (where t = 0).
R1 = slope at end of the segment (where t = 1).

We create four "basis functions", each of which varies only one thing:

only P0: 2t3 - 3t2 + 1
only P1:-2t3 + 3t2
only R0:  t3 - 2t2 + t
only R1:  t3 - t2

So to get from (P0,P1,R0,R1) to the coefficients (a,b,c,d) that define cubic polynomial a * t^3 + b * t^2 + c * t + d, we apply the Hermite Matrix, which is just a way of describing these four basis functions. Each of the four functions is described in a single column of the Hermite Matrix:

a
b
c
d
 ⇐  2
-3
0
1
-2
3
0
0
1
-2
1
0
1
-1
0
0
 ×  P0
P1
R0
R1

 

BEZIER SPLINES

If our human user wants to define things by moving points around on a screen, then the Bezier spline is a good choice.

Again, we do the math independently for each coordinate.

A = value at start of the segment (where t = 0).
B = value at a first "guide point".
C = value at a second "guide point".
D = value at end of the segment (where t = 1).

The math is basically successive linear interpolations:

   mix (
      mix ( mix(A,B,t) , mix(B,C,t) , t ),
      mix ( mix(B,C,t) , mix(C,D,t) , t ),
      t
   )

where we define mix(a,b,t) as linear interpolation:

(a,b,t) ⇒ a + t * (b - a)

In other words:

   (1-t) * ( (1-t) * ((1-t)*A + t*B)  +  t * ((1-t)*B + t*C) )
     +
     t   * ( (1-t) * ((1-t)*B + t*C)  +  t * ((1-t)*C + t*D) )

When you multiply everything out, this turns into:

       (1-t) * (1-t) * (1-t) * A +
   3 * (1-t) * (1-t) *   t   * B +
   3 * (1-t) *   t   *   t   * C +
         t   *   t   *   t   * D

This gives us what we need to go from key values (A,B,C,D) to cubic coefficients (a,b,c,d). Each line of the above equation can be turned into a column of the characteristic Bezier Matrix:

a
b
c
d
 ⇐  -1
3
-3
1
3
-6
3
0
-3
3
0
0
 1
0
0
0
 ×  A
B
C
D

 

PARAMETRIC CYLINDERS

We went over how to create a parametric cylinder. The key is to realize that the v parameter needs to go from 0 to 1 in five steps, even as the u parameter goes around in a circle (like for a sphere).

Each vertex location and normal is then given by:

      POINT     NORMAL    VALUE OF V

    ( 0,0,-1,   0,0,-1 )   v =  0
    ( c,s,-1,   0,0,-1 )   v = 1/5
    ( c,s,-1,   c,s, 0 )   v = 2/5
    ( c,s, 1,   c,s, 0 )   v = 3/5
    ( c,s, 1,   0,0, 1 )   v = 4/5
    ( 0,0, 1,   0,0, 1 )   v =  1
where c and s stand for cos(2 π u) and sin(2 π u), respectively.

An tube (or open cylinder) is much cylinder, since we need only two values of v:

      POINT     NORMAL    VALUE OF V

    ( c,s,-1,   c,s,0 )    v = 0
    ( c,s, 1,   c,s,0 )    v = 1

 

BEZIER BICUBIC SURFACE PATCHES

We can extend the idea of parametric cubic curves to bicubic patches. Instead of mapping a single parameter t to a curve, we map two parameters u and v to a patch of curved surface: As with cubic curves, we generally find it useful to transform our representation of such surface patches into something easier to understand, perhaps using a Bezier or Hermite transformation.

For example, each point in the above patch was determined by applying a Bezier transformation to a 4x4 matrix P of 16 key points:

[u3 u2 u 1]   •   Bz   •   P   •   BzT   •   [v3 v2 v 1]T

 

 

FUN COMPUTER GRAPHICS VIDEO

At the end of Thursday's class we saw a video clip from the 1996 film Joe's Apartment.

 

HOMEWORK

I am concerned that a number of students are falling behind. So I am going to give a week for those students to catch up. By the time our class meets on Thursday April 18, I need everyone to have completed all the homeworks through homework 7.

Meanwhile, download the code that we worked on in this Thursday's class, which is in shader8.zip.

For extra credit, see if you can apply the cubic spline based motion techniques in shader8 to animating elements of your own scene -- either the scene you created for homework 7, or else a new one.