Notes for Thursday April 9 class -- Making shapes with splines, part 2

What we covered in this lecture

We first showed how to create more interesting surface of revolusion shapes using the uvToLathe function. Then we implemented various techniques required to be able to extrude a profile shape through a spline path, in order to create more general shapes.

The last example we implemented was a gold ring, made by extruding ring profile (created with a Bezier spline) along a circular path.

I won't include lots of code in these notes, because all of the code we created in class is included below with the homework.

Creating a brass tack
We created a Bezier spline profile that is pointy at z = -1, then forms a narrow tube, and then finaly flairs out wide very near z = 1. We then used uvToLathe to turn this into the shape of a brass tack. We created a brass material for it, which is basically yellow-orange metal.

The code for this is in index.html.

Extruding a profile along a path
The remainder of these notes will be spent describing the challenging problem of properly extruding a profile curve along a 3D path, to create an extruded shape.

We implemented this in class, and created an example.

The Hairy Ball Theorem
The simplest way to create an extrusion would be to use the heading direction W at each point along the path to create cross vectors U and V, which can then be used as a plane to draw the point along the profile as vertices.

Unfortunately, there is no way to do this consistently, without at some point creating a pinch point, where either U or V collapses to zero length. The reason is due to the Hairy Ball Theorem, which was first stated by Poincaré in the 19th century, and finally proven by Luitzen Egbertus Jan Brouwer in 1912.

Essentially, if you try to comb down hairs all over a sphere, at some place you end up having a cowlick -- a place where the hairs cannot line up parallel to one another. This applies to our situation as follows:

if you are travelling along an arbitrary path in 3D, you can think of the direction along the path as a point on a sphere. You can then think of the direction of your desired cross vector as one of those hairs you are trying to comb down.

There is no arrangement of cross vectors that will work for every situation. Sooner or later, the path will turn in a way that you hit one of those cowlicks.

Adding a cross vector to a sampled path
We get around the Hairy Ball problem by moving along the path from start to finish, building cross vectors as we go, making sure that each cross vector is consistent with the one before.

We wrote the code to implement this in class. It is in lib6.js, within function sampleBezierPath().

Shape images
The logic to create an extrusion shape is complex enough, without needing to worry about also converting the result into a triangle mesh. So make things easier, we split the problem into two parts:
  1. Create the result of the extrusion as a shape image.

  2. Convert the resulting shape image into a triangle mesh.

A shape image is simple an image, with n rows and m columns, in which every pixel is a set of (x,y,z) coordinates.

We describe it as a three dimensional array. For example, given a shape image si, the x coordinate of column i in row j is: si[j][i][0].

Extruding a profile along a path, to create a shape image
The key to extruding a profile along a sampled path is to obtain, at every step along the path, a pair of mutually orthogonal cross vectors (U,V) that can serve as a coordinate system in which to draw out the profile at that point along the path.

If W is the direction of the path at that point, the U,V,W form the three directions of a mutually orthogonal coordinate system, with the point P along the path as the origin. Essentially, we need to transform each point (x,y,0) of the profile by matrix multiplication:

Ux Vx Wx Px   x
Uy Vy Wy Py   y
Uz Vz Wz Pz   0
0  0  0  1    1
We implemented this in class within lib6.js, in the function extrudeToShapeImag().

The key, as you can see in that implementation, is to keep using the U from the previous step along the path, with the new W at the next step along the path, to compute a new V via cross product, then use a second cross product to compute the new U.

Converting a shape image to a triangle mesh
The only tricky thing about converting a shape image to a triangle mesh is that we need to compute the surface normal at each vertex. We do this by first computing two tangent vectors: du and dv.

We get du by subtracting the location of the vertex at the previous column from the vertex at the next column:

du = Vi+1,j - Vi-1,j
We get dv by subtracting the location of the vertex at the previous row from the vertex at the next row:
dv = Vi,j+1 - Vi,j-1
We also need to deal with end cases. If the shapes wraps around (eg: in the case of a cylinder), then we need to use a vertex on the other side of the mesh for the subtraction.

We implemented this in class within lib6.js, as function shapeImageToTriangleMesh().

Because it is so useful to extrude a profile along a path, we added a function extrude() within lib6.js to combine the two steps of the process into one:

let extrude = (profile, path) => shapeImageToTriangleMesh( extrudeToShapeImage(profile, path) );
Creating a gold ring
Finally, we implemented a ring by implementing function createRingShape() within index.html, just like the ring that I wear on my finger.

First we implemented function createCircularPath(n) that samples points (together with cross vectors) along a circular path.

Then we created a Bezier spline in the shape of a cross section of the ring: rounded on the outside, and flat on the inside where the ring touches the finger.

That code is all found toward the end of index.html.

Homework 7, due before start of class on Thursday April 16
The code that we ended up with at the end of class is in hw7.zip.

Starting with that code, create your own original scene that makes use of splines. You have lots of flexibility in this assignment, but two things are essential:

  • You need to use a spline to create a 3D shape;
  • You need to use a spline to create movement over time.
There are lots of opportunities for extra credit here. For example, you can use Hermite splines rather than Bezier splines.

If you are really ambitious, you might want to create animated people or creatures, using spline based surfaces of revolution for the different body parts.

This is an assignment you can really have fun with, because you now have the tools you need both to create really interesting shapes and really interesting animation paths of translation and/or rotation over time.