Notes on perspective, representing polygons, viewports; homework due Feb 18

 

(1) Notes on perspective:

I realized, as I was writing up these notes, that it will be easier for you if you can combine the two steps of

into a single operation.

With that in mind, an easier model for the perspective transformation is one where the "pinhole" of the viewpoint is in positive f - specifically at the point (0,0,f) - and the "focal plane" is at the origin, centered at (0,0,0) .

So a better matrix is:

1 0 0 0
0 1 0 0
0 0 0 1/f
0 0 1/f 1
This matrix does both steps at once. It transforms:
x   x   x
y y == y
z   1/f   1/f
1   z/f+1   (z+f)/f
which results in the point:
(x',y',z')   =   ( fx/(z+f)   ,   fy/(z+f)   ,   1 / (z+f) ).

If you use this transformation, then shapes that started out on the z = 0 plane will, conveniently, remain at their original size.

So my recommendation is that you implement perspective with the code:


    xp = f * x / (z + f);
    yp = f * y / (z + f);
    zp =  1.0  / (z + f);

 

(2) Notes on representing polygons:

As I said in class, a good general representation for approximating 3D surfaces by polygons is the "vertex/face" representation:


   double vertices[][6];
   int faces[][6];
where: A vertex consists of both a location and a normal. If normals differ, then you need to store two separate vertices.

As we said in class, you might want to create a java class to handle geometry, containing methods for creating and transforming specific kinds of shapes:


   public class Geometry
   {
      double vertices[][];
      int faces[][];
      Matrix4x4 matrix;

      public void cube() { ... }
      public void tube(int n) { ... }
      public void globe(int m, int n) { ... }
      ...
   }
The inclusion of a matrix within the geometry object itself allows you to set things like scale at the time the geometry is created. When you animate this shape, you should think of this matrix as being nested inside the animation transformations. To do this:
  1. Copy your animation matrix to a temporary matrix;
  2. PostMultiply that temporary matrix by the geometry's matrix;
  3. Use the result to transform the vertices of the geometry for display.
Here is an implementation of the cube-making method, to help you get things started:

      public void cube() {
         vertices = new double[24][6];
         faces    = new int[6][4];

         addPoly4(0,  0,  -1,-1,-1,  -1,-1,+1,  -1,+1,+1,  -1,+1,-1,  -1, 0, 0);
         addPoly4(1,  4,  +1,-1,-1,  +1,+1,-1,  +1,+1,+1,  +1,-1,+1,  +1, 0, 0);
         addPoly4(2,  8,  -1,-1,-1,  +1,-1,-1,  +1,-1,+1,  -1,-1,+1,   0,-1, 0);
         addPoly4(3, 12,  -1,+1,-1,  -1,+1,+1,  +1,+1,+1,  +1,+1,-1,   0,+1, 0);
         addPoly4(4, 16,  -1,-1,-1,  -1,+1,-1,  +1,+1,-1,  +1,-1,-1,   0, 0,-1);
         addPoly4(5, 20,  -1,-1,+1,  +1,-1,+1,  +1,+1,+1,  -1,+1,+1,   0, 0,+1);
      }

      void addPoly4(int f, int v,
                    double ax,double ay,double az, double bx,double by,double bz,
                    double cx,double cy,double cz, double dx,double dy,double dz,
                    double nx,double ny,double nz) {

         setVertex(v    , ax, ay, az, nx, ny, nz);
         setVertex(v + 1, bx, by, bz, nx, ny, nz);
         setVertex(v + 2, cx, cy, cz, nx, ny, nz);
         setVertex(v + 3, dx, dy, dz, nx, ny, nz);

         for (int i = 0 ; i < 4 ; i++)
            faces[f][i] = v + i;
      }

      void setVertex(int v, double x,double y,double z,double nx,double ny,double nz) {
         vertices[v][0] = x;
         vertices[v][1] = y;
         vertices[v][2] = z;
         vertices[v][3] = nx;
         vertices[v][4] = ny;
         vertices[v][5] = nz;
      }

 

(3) Viewport:

As we discussed in class, you are much better off modeling your objects with small floating point vertex values, and then translating to pixels only when you want to render the image. In this way, you can keep model info separate from resolution info, and you will be able to make computer graphic models that work equally well on a movie screen or an iPhone.

The final translation of your (x,y) coordinates from floating point values to screen coordinates is called the viewport transformation. Assuming your view into the 3D world extends from -0.5 to 0.5 in x at the focal plane (ie: one unit wide, centered at the origin), then your viewport transformation to pixels can be implemented as follows:


         // x = x coordinate on the focal plane (ie: after perspective transformation)
         // y = y coordinate on the focal plane (ie: after perspective transformation)
         // W = applet window width
         // H = applet window height

         int pixelX = (int)(W/2 + W * x);
         int pixelY = (int)(H/2 - W * y);
Note that (0,0) will end up on the middle of the applet window, which is what you want.

 

Homework due Wednesday, February 18, before class:

For homework I would like you to switch over to using the vertices/faces scheme for representing shapes in your 3D scene.

Also, implement perspective. As I described above, you should do this after the matrix transformation of each vertex, as:

x → fx/(z+f)       y → fy/(z+f)       z → 1 / (z+f)

For now, you can just draw each face by using java.awt.drawLine() to connect the face's vertices, after applying the viewport transformation to each vertex.

Make an interesting animated scene. In addition to the cube shape, make at least one other interesting shape. See if you can implement the method to make an open tube: tube(int n). Hint: Your tube should have 2n vertices and n faces, where each face has 4 sides.