In order to do this week's homework (due Tuesday Oct 2), the following notes from class should be useful.
Please note:
At the end of the lecture I was kind of rushing
to get through things,
and I ended up saying something that was just
plain wrong.
Sorry about that!
No, you don't put the line drawing routines inside the doubly nested loops. The line drawing part only comes later, when you do the frame-by-frame animation of your transformed shapes. So please just forget about that confusing bit at the end of the lecture, and use the following notes as your reference. :-) |
The basic idea is that you are going to create your shape objects just once, when your program starts, and then render them at each animation frame by transforming each shape and drawing the transformed shape as a set of lines.
You probably will want to create an Java class Shape, that contains a transformation matrix, a vertices[] array, and a faces[] array (see below).
Your Shape object will also contain
two temporary arrays
NOTES ON REPRESENTING 3D SHAPES WITH POLYGONS
A shape can be represented as an object that contains:
For each latitude n, where 0 < n <= N,
the location of vertex m is given by:
The sphere shape will have M * N rectangular faces.
If we let angle theta take on each of the N values around a circle:
Because we need to separately store vertices that
have different normals, there will be 24 vertices;
one for each corner of each face of the cube.
For example, the cube's four vertices on its leftmost
face (the face that points into negative x), are:
The face data for the cube is rather simple, as we discussed in class:
At every animation frame,
for each shape in your scene you'll want to:
In your Shape object
you might want to maintain two arrays
How do I project my transformed vertex (x,y,z) onto a pixel (px,py)?
If we were using a real camera with perspective, you'd do something
fancier, but for now I'd like you to do something simpler.
Suppose your applet window is W pixels wide and H pixels high.
Then all you need to do is:
int px[]
and
As we discussed in class,
when you want a shape to have a visible edge with a crease,
then you should use different vertices
on the two sides of the edge
(ie: vertices that have the same x,y,z but with different nx,ny,nz),
so you can create a discontinuity in surface
normal along that edge.
But if you want to create the illusion
of a continuous curved surface, then you should
make two adjacent polygonal faces share the same
vertices.
double vertices[NVERTICES][6]
int faces[NFACES][]
Sphere
Let's say you want to create an approximation of a sphere,
where longitude is represented by M steps around the equator
and latitude is represented by N steps from south pole to north pole.
You can allocate M * (N+1) vertices:
M vertices for each of the N+1 latitudes.
θ = 2 * π * m / M
φ = π * n / N - π/2
x = cos θ cos φ
y = sin θ cos φ
z = sin φ
Notice that to march through the vertex values,
you're going to need double nested for
loops in order to iterate through all your values of m
and all your values of n
.
Torus
The torus is remarkably similar to the sphere.
The vertex equations for a torus are given by:
θ = 2 * π * m / M
φ = 2 * π * n / N
x = (a + b * cos θ) * cos φ
y = (a + b * sin θ) * cos φ
z = b sin φ
where a and b refer to the major and minor radius, respectively.
Cylinder
To create an approximation of a cylinder,
where the circle is represented by N steps (eg: N=8 or N=20)
you need to create the central tube
and two end caps:
θ = 2π i / N , where i = 0, 1, 2, .... N-1
then we can create the central tube with 2N vertices (each with x,y,z and normal nx,ny,nz),
where the first N vertices are:
[cosθ, sinθ, -1, cosθ, sinθ, 0]
and the last N vertices are:
[cosθ, sinθ, +1, cosθ, sinθ, 0]
Each of the faces of this central tube will have four sides,
so the face[][]
array needs to consist of:
The front cap will contain N+1 vertices, including
the added central point [0,0,1, 0,0,1],
and its faces will consist of N triangles.
The back cap will also contain N+1 vertices, including
the added central point [0,0,-1, 0,0,-1],
and its faces will also consist of N triangles.
I leave it as an exercise for you to
create these two end caps.
When you've built the complete cylinder,
you should have 4N+2 vertices and 3N faces.
0 1 N+1 N
1 2 N+2 N+1
... ... ... ...
N-2 N-1 2N-1 2N-2
N-1 0 N 2N-1
Cube
As we discussed in class, a cube is rather simple.
You would model the vertices as a unit cube
(with extent -1 to +1 in each of the three dimensions),
and then rely on the shape's matrix to
transform these vertices in order to
create all other box-like shapes.
Notice that I have ordered these four vertices in counterclockwise
order, if you are looking at this face of the cube from the outside.
I leave it to you to create the vertices for the other five faces
of the cube.
-1 -1 -1 -1 0 0
-1 -1 +1 -1 0 0
-1 +1 +1 -1 0 0
-1 +1 -1 -1 0 0
TRANSFORMING AND RENDERING SHAPES
0 1 2 3
4 5 6 7
... ... ... ...
20 21 22 23
java.awt.Graphics
method
drawLine
between
the (px,py) that corresponds to
successive vertices in that face.
int px[NV]
and
int py[NV]
into which you
can place your transformed and projected vertex data every frame.
px = (int)(W/2 + x*W/2);
py = (int)(H/2 - y*W/2);
The above operations will ensure that your object will be centered at the
middle of the image, and will be about the right size
to fit in the image.
If you find that your object is turning out really huge,
so it's hard to see it in the applet image,
then try scaling everything down by using
your matrix scale operation.