Notes on making various shapes

These notes are to help you make different kinds of shapes. Remember that our goal is to describe various shapes in terms of the two arrays

```
int faces[][];
double vertices[][6];
```

As we said in class, we will make room for a normal vector to each vertex, so each vertex contains not three numeric values but rather six. Eventually we will create the illusion of smooth curved surfaces by using this normal vector data - two adjoining polygonal faces of a shape can be made to appear smooth and rounded by having them share vertices, since they will then share the same normal vector at that vertex.

But we are not going to use the surface normal yet. But I'm going to define them when I describe the shapes below, so that you'll be ready when it is time to do shading and lighting.

TUBE

We make curved shapes by having different faces share vectors, so that they will have the same surface normal at that point. For example, as we discussed in class, to describe an n sided approximation to an open cylindrical tube (where the opening is along the z axis) we need a total of 2n vertices. There is a row of back vertices 0..n-1

vi = { cos θ , sin θ , -1 , cos θ , sin θ , 0 }

and a row of front vertices n..2n-1 :

vn+i = { cos θ , sin θ , 1 , cos θ , sin θ , 0 }

where θ = 2π i / n .

We also need n faces, each with four vertices:

```
face[i][0] =    i;
face[i][1] = (i + 1) % n;
face[i][2] = (i + 1) % n + n;
face[i][3] =    i        + n;
```

Given a geometry object

```
Geometry g = new Geometry();
```

you can implement the above logic by defining a method `tube(int n)` in the `Geometry` class. Implementing this method consists of filling in a geometry object's `faces[]` and `vertices[]` arrays as described above.

GLOBE

To create a sphere as a longitude/latitude globe, we again need to create an array of vertices, and also an array of faces that index into the vertices array. We can create a method in the Geometry class called `globe(int m, int n)` where `m` is the number of longitude steps around the equator of our polygon approximation to a sphere, and `n` is the number of steps from the south pole to the north pole.

Internally we allocate `m × n` vertices.

There is a little trickiness here because we are thinking of this as a two dimensional array of vertices, but our Geometry data structure for storing vertices is indexed by a single number. We are going to deal with this as follows: First we will act as though we really two have two indices (i,j) , and then we will come up with a single index I to describe the index pair (i,j) .

As we discussed in class, the location of a single vertex on the globe vi,j in is given by computing the polar coordinates:

θ = 2π i / m
φ = -π/2 + π j / (n-1)

x = cos θ cos φ
y = sin θ cos φ
z = sin φ

vi,j = { x , y , z ,   x , y , z }

Note that the normal vector for each vertex is the same as its location. This is only true in the special case where the shape is a unit sphere.

As we said above, we really need to this data into a singly-indexed array of vertices. We do that by defining a single array

```
double vertices[ m * n ][6];

```
which is indexed by `I = i + m * j`. For convenience you mght want to define a function within the geometry object that does this mapping:
```
double I(int i, int j) { return (i % m) + m * j; }

```
The faces will refer to this single index. The globe will have `m × (n-1)` faces, each with four vertices.
```
int faces[][] = new int[m * (n-1)][4];

```
Using our handy dandy index mapping function `I(i,j)`, each face is described as a counterclockwise loop of four vertex indices:
```
face[i + m * j][0] = I(i,j);
face[i + m * j][1] = I(i+1,j);
face[i + m * j][2] = I(i+1,j+1);
face[i + m * j][3] = I(i,j+1);
```

DISK

A flat circular disk can be approximated by an n-sided polygon. In this case it is useful to introduce one extra vertex, in the center of the disk, so that you can define the disk as a ring of triangles. There will be n+1 vertices:

θ = 2π i / n

vi = { cos θ , sin θ , 0 ,   0 , 0 , 1 }     where     0 ≤ i < n

vn = { 0 , 0 , 0 ,   0 , 0, 1 }

Rather than one giant polygon, it is better to use `n` triangular faces:

```
int i1 = (i + 1) % n;
face[i][0] = i;
face[i][1] = (i + 1) % n;
face[i][2] = n;

```
CYLINDER WITH END-CAPS

You can make a closed cylinder adding extra vertices and faces to your open tube. Instead of 2n vertices and n rectangular faces, you have all that plus the vertices and faces you would need for two sets of disks (one for the front and one for the back).

So you need a total of 2n + n+1 + n+1 = 4n + 2 vertices, and a total of n rectangular faces, plus 2n triangular faces.

HOMEWORK

Your assignment, due next Wednesday, February 25, is to implement some of these shapes - as many as you can - and to make a cool and fun animated scene using them. Also, see if you can make other sorts of shapes, like extruded shapes with non-circualar cross-section, such as an elliptical cylinder, or a cylinder with a star-shaped cross-section.

If you are ambitious, you might also try a torus. The location of one surface point on a torus is as follows:

x = cos θ (R + r cos φ)
y = sin θ (R + r cos φ)
z = r sin φ

where R is the radius of the large ring, and r is the radius (ie half-thickness) of the tube.