Your assignment is to enhance the results of using your motion machine by putting "meat" on the bones, so to speak, by making shapes that that consist of polyhedral meshes (ie: surfaces formed from meshes of polygons). If you are feeling creative, please feel free to change the content of your motion machine for this assignment.
The simplest way to create a polyhedral mesh is as a two dimensional array of vertices, where each vertex contains both a location vector and a normal vector:
double vertices[nrows][ncols][6];The six values per vertex refer, respectively, to {x,y,z,normalx,normaly,normalz}. You can make many useful shapes this way. For example, to generate a unit sphere that is swept out parametrically by a longitude angle θ and a latitude angle φ:
vertices = new double[NPHI+1][NTHETA+1]; for (int i = 0 ; i <= NPHI ; i++) { // PHI (LATITUDE) VARIES FROM -PI/2 TO +PI/2 double phi = Math.PI * (double)i / NPHI - Math.PI/2; for (int j = 0 ; j <= NTHETA ; j++) { // THETA (LONGITUDE) VARIES FROM 0 TO 2*PI double theta = 2 * Math.PI * (double)j / NTHETA; double v[] = vertices[i][j]; // SET THE LOCATION VECTOR, FROM LONGITUDE AND LATITUDE v[0] = Math.cos(phi) * Math.cos(theta); v[1] = Math.cos(phi) * Math.sin(theta); v[2] = Math.sin(phi); // SET THE NORMAL VECTOR v[3] = v[0]; v[4] = v[1]; v[5] = v[2]; } }This defines a sphere whose "north/south" poles are in positive and negative z. Notice that in the above example, the normal vector has the same values as the location vector. This is true only in the special case of a unit sphere.
Since you're going to be rendering your polyhedral mesh in wireframe (ie: just drawing the lines) you won't need to use the normal vectors yet. But it's a good idea to put them in now, because you're going to need to use them later.
As a minimum, use the parametrized sphere as your geometry,
but transform it as appropriate for your content.
For example, if you're creating limbs for a moving
humanoid character, you probably want to stretch the
geometry along the limb direction,
by scaling your geometry along one local axis
(for example, invoking something like
km.scale(0.2,1.5,0.2);
in the local coordinate system).
When you do this, remember to surround your
scale
call
with matching
push()
and
pop()
calls,
so that the entire remaining subtree doesn't
get scaled - just the geometry at that limb.
The following fragment of code will give you the idea:
... km.rotateZ(values[L_HIP_Z]); // SWING HIP OUT km.rotateX(values[L_HIP_X]); // BEND AT HIP push(); // LOCALLY: km.translate(0,-1.5,0); // MOVE TO MIDDLE OF THIGH km.scale(0.2,1.5,0.2); // SCALE THIGH SHAPE drawUnitSphere(g); // DRAW THIGH ELLIPSOID pop(); km.translate(0,-3,0); // MOVE FROM HIP TO KNEE km.rotateX(values[L_KNEE_X]); // BEND KNEE ...
For extra credit, try making other sorts of shapes. For example, try to figure out the parametric description of a torus, or a section from a general second-order surface. Try to make polyhedral topologies which are not rectangular meshes. For example, try making a sphere that is a refinement of a dodecahedron or icosahedron.
Better yet, surprise me.