HW3: 3D Meshes

Due Friday 1/8 @ 11:00am.

Where & What to Hand In

Note that it's important to always use exactly the specified filename when handing in work for a CS class. (Canvas may automatically append a number to your filename; that's okay.) For instructions on creating a screenshot file, see HW0.

Your Tasks

This assignment builds on HW2, in which you constructed vertex sets for a variety of 3D shapes. In this one, you'll create triangle meshes for their surfaces, as well as designing a shape of your own. There are four tasks below:

  1. Meshes for old shapes
  2. Screenshots of old shapes
  3. Your own shape
  4. Screenshots of your shape

Download the starter code, meshes.py, as well as the helper file gfx_helper_mayavi.py. As always, there are a number of TODO comments that you should follow, paying attention to the docstrings that define the behavior of each function.

Each function for creating and returning a mesh should call a separate function (like the ones you wrote in HW2) to generate the vertices for it. You may use your own code from HW2 or my HW2 solutions (which I'll post once everyone has submitted theirs). Keep in mind that my solutions may put the vertices in a different order than yours did!

A. Meshes for old shapes

Change the bodies of each of these methods to match their docstrings, and then add calls in main() to display each one in the correct octant:

  1. cube() — fill in the body, and display in octant 1 (+++).
  2. ell() — fill in the body, and display in octant 2 (-++).
  3. prism() — fill in the body, and display a pentagonal prism in octant 3 (--+).
  4. Also display a cylinder (a prism with many sides) in octant 4 (+-+).
  5. sphere() — fill in the body, and display in octant 5 (++-).
  6. torus() — fill in the body, and display in octant 6 (-+-).

As always, I'll test your functions with many different values of K (avoiding invalid values or ones that would correspond to degenerate shapes).

Hints

If you'd like, you may modify the behavior of prism() to produce better results for high K values — the example screenshots below show this. Here's an updated signature and docstring that you could use:

def prism(K):
  """
  Returns a 2-tuple (verts, tris) representing a triangle mesh of the surface
of a regular K-gon prism.  If K <= 6, verts is 3x(2K) and tris is (4K-4)x3;
otherwise verts is 3x(2K+2), with an extra vertex in the middle of each end-cap,
and tris is (4K-2)x3.  (Adding the extra vertex prevents extra-narrow triangles
on the end-caps.)  See prismVerts().
  """

In addition, you may find it useful to define helper functions for building your triangle arrays. By defining these four functions, I was able to build all the triangle arrays just with function calls and array manipulations, without hard-coding any rows of the arrays.

def fanDiskTriangles(K, start=0, flip=False):
  """
  Returns a (K-2)x3 array of vertex indices for the triangulation of a K-polygon
in the plane, with indices numbered counterclockwise.  Arguments:
  - K: number of vertices in the polygon.
  - start (default 0): the starting index of the K consecutive indices around
      the polygon.
  - flip (default False): when False, triangles are oriented right-handed /
      counterclockwise; when True, they are left-handed / clockwise.
  """

def wheelDiskTriangles(K, hub=0, start=1, flip=False):
  """
  Returns a Kx3 array of vertex indices for the triangulation of a K-polygon
in the plane, with a central "hub" vertex and K vertices in a loop around it,
numbered counterclockwise.  Arguments:
  - K: number of vertices around the outside of the polygon.
  - hub (default 0): the index of the vertex in the middle of the disk.
  - start (default 1): the starting index of the K consecutive indices around
      the polygon.
  - flip (default False): when False, triangles are oriented right-handed /
      counterclockwise; when True, they are left-handed / clockwise.
  """

def indexLoop(idx):
  """
  Given a 1-D array or list, returns the same as a 1-D array with element #0
repeated at the end.
  """

def triangleStrip(bot, top):
  """
  Given two 1-D arrays or lists (each of length N) of vertex indices (bot and
top), returns a (2N-2)x3 array of indices, each row of which is a triangle in
a zigzagging strip between these parallel sets of indices:
  
          0  1  2  3  4  5
  top ->  *--*--*--*--*--*
          | /| /| /| /| /|
          |/ |/ |/ |/ |/ |
  bot ->  *--*--*--*--*--*
          0  1  2  3  4  5
  
  The triangles are oriented so that their right-hand-rule outward directions
are all facing out of the page.
  """

B. Screenshots of old shapes

Take eight screenshots of your shapes, as described below, and put them in your PDF. In each screenshot, the edges and face normals of your shapes should be rendered. In addition, the Mayavi orientation widget should be displayed; if you don't see it, click the “Toggle axis indicator” button in the Mayavi menu bar. Each screenshot should be looking in a different direction:

Here's what these pictures should look like. Notice that I've used a low K-value for the sphere and torus (so the facets and normals are more easily distinguished), that I've implemented the extra prism feature (so there's a vertex in the middle of the cylinder end-cap), that I've zoomed each view in to fill the frame, and that I've moved the orientation widget so that it doesn't cover any of my shapes:

C. Your own shape

Design your own shape that fits within the unit cube. Your shape (and the code you write for it) must have all of these properties:

In your program, create a new figure that will display after the old one (for step A) is closed, and then display your shape in that, just centered on the origin.

The names must be correct in order to receive full credit. Any shape that meets the specification above (other than a cylinder, which you've already written) will be accepted, but I'd encourage you to get creative!

We'll all share these shapes with each other to use as sample objects in future projects.

D. Screenshots of your shape

Take at least three screenshots of your custom shape, showing it from as many different angles as are needed to show off its features.

Here are some pictures of my shape:

Rubric

This assignment is worth 20 points.

Whether a function “returns correct values” is evaluated with respect to the location of vertices, shape of all arrays, connectivity of the surface, absence of redundant faces or vertices, and correct orientation for all faces.

Since correct versions of all *Verts() functions were provided to you, any incorrect vertex array (except in the custom shape) will lead to an automatic 0 for that shape.

CriterionPoints
meshes.pdf shows all screenshots.1
Program runs from command line as python meshes.py.1
Displays window and keeps it open, then displays another after the first closes.1
Shows cube, L, prism, cylinder, sphere, and torus in correct locations.1
Shows custom shape at the origin.1
All functions are named correctly and have complete docstrings.1
cube() and ell() return correct values.2
prism() returns correct values for several arguments.2
sphere() returns correct values for several arguments.2
torus() returns correct values for several arguments.2
my_shape() returns correct values for several arguments.2
Custom shape fits snugly in unit cube.1
Custom shape takes at least one parameter.1
Custom shape has a curved surface.1
Custom shape has a sharp edge.1
Total20