Spline surfaces

We have already learned how to use cubic splines to make curves. We can also use bicubic splines to make surfaces. In this case, rather than defining x,y,z in terms of a single parameter t describing parametric movement along a path, we define x,y,z in terms of two parameters u,v which describe parametric position upon a surface.

This gives us a piece of spline surface that looks like a warped square tile in space. To make more complex spline surfaces, we can piece together multiple tiles, matching their positions and surface normals along the edges between them where they join. This is, for example, how the teapot that I showed in class was made.

The general formulation for a single bicubic surface tile is:

x(u, v) = au3v3 + bu3v2 + ... p
with similar equations defining y(u,v) and z(u,v). For each of these equations we need sixteen coefficients [a, b, ... p], for all of the sixteen possible products of u and v u3v3 to u3v2 through 1.

Conveniently, we can describe all 16 possible coefficients by the following matrix/vector product:

[u3 u2 u 1]
[v ]
[1 ]

If we refer to the above matrix of coeffients as C, then the above equation looks like this:

U • C • VT

If you have three such 4×4 coeffient matrices, Cx, Cy and Cz, one for each dimension, then you can then evaluate (x,y,z) locations on the bicubic spline surface by iterating over values of u and v:

for (int u = 0.0 ; u <= 1.0 ; u += ε)
for (int v = 0.0 ; v <= 1.0 ; v += ε)
   drawPoint(eval(Cx,u,v), eval(Cy,u,v), eval(Cz,u,v));
Through variations on the above code, you can also draw curved lines along the u,v surface, as well as small polygons which can be shaded and z-buffered. Each of these polygons has four vertices:

{eval(Cx,u,v), eval(Cy,u,v), eval(Cz,u,v)}

{eval(Cx,u+ε,v), eval(Cy,u+ε,v), eval(Cz,u+ε,v)

{eval(Cx,u+ε,v+ε), eval(Cy,u+ε,v+ε), eval(Cz,u+ε,v+ε)

{eval(Cx,u,v+ε), eval(Cy,u,v+ε), eval(Cz,u,v+ε)

Just as with spline curves, we generally want to find coeffients to define the geometry of a spline surface in a way that is convenient to the user, such as a Hermite or Bezier or B-Spline surface description. Then behind the scenes we convert to the polynomial formulation above.

The general trick for doing this conversion is to use the same Hermite, Bezier etc. conversion matrix that we used for spline curves, but to apply it twice: once for u and once for v.

For example, lets say we have a Bezier description of the surface, in which we describe, each of x, y, and z on the surface by sampling u and v every 1/3 unit. This gives a matrix of 16 knot locations in (u,v):

P =
(0/3,0/3)   (1/3,0/3)   (2/3,0/3)   (3/3,0/3)
(0/3,1/3)   (1/3,1/3)   (2/3,1/3)   (3/3,1/3)
(0/3,2/3)   (1/3,2/3)   (2/3,2/3)   (3/3,2/3)
(0/3,3/3)   (1/3,3/3)   (2/3,3/3)   (3/3,3/3)

At each of those locations the x coordinate has a value, as do y and z. Our goal is to convert this matrix into a matrix C of coefficients. Fortunately, this is easy to do, since we can just use our Bezier matrix B on both sides to convert coordinates in both u and v:

[u3 u2 u 1] B P BT
[v ]
[1 ]

When evaluating U • C • VT, we can use use the coefficent matrix given by C = B • P • BT.