Graphics Programming, Sheet 4, by Mike Roam. rev10apr2000

Displaying 3D objects on a 2D screen...

If we had a 3-D video projector, it would be easy to show our objects with no further math, but since we're trying to draw on a 2-D screen, we've got to "project" our objects onto a plane. This will be similar to putting a picture on a window that shows the things we can see THROUGH the window. (See picture at right.)

We already have a drawDot() method that can draw 2-D dots onto a screen: now we just have to figure out where our 3-D dots belong on the viewscreen, and then draw them there using the drawDot() method.

projection
We're going to lock the camera (eyeball) into one place and lock a viewscreen into place parallel to the X and Y axes. (see diagram at right.) Then for any point "P" we can figure out where to put it on the viewscreen (at a point called Sx, Sy). (See Diagram Below.) sideview
Side-View of origin with viewscreen
(X axis gets positive as it goes into the page)

Here is the same picture as above, with distance labels. Check out "E" and "S" which will be called "distEyeToOrigin" and "distScreenToOrigin" in your program.

By "Similar Triangles" we can solve for "Sy", which tells us where to draw on the view screen.

Similar Triangles
"y is to E-z as Sy is to E-S"
expressed algebraically:
y/(E-z)=Sy/(E-s)
Solved for Sy.........
Sy = ((E - S) * y)/ (E-z)
Sy= ((E - S) * y) / (E - z)
Similarly for Sx.........
Sx = ((E - S) *x)/ (E-z)
Sx = ((E - S) *x)/ (E-z)

Axes and 3D rotation matrices

After you've got your 3D points, and lines showing up on the screen with perspective, let's begin to think about moving the points around and looking at them from different angles. It turns out that moving the points or moving the camera are basically the same thing: we have a function that tells us where the new points are when we put in old points. This function is going to receive 3D points and return 3D points, and will have "matrix multiplication" going on inside, with a matrix (2-dimensional array) that tells us how to change the old points.

Standard 3D coordinate system (from the computer graphics bible: "Computer Graphics: Principles and Practice" (2nd ed.) by Foley, vanDam, Feiner, & Hughes.)

We're using a "right-hand" system, with the axes in order (xyz) being reached through counterclockwise 90° movements, the way fingers curl on your right hand. (Illustration at right.) This means that the positive part of the Z axis comes out of the screen toward the viewer.

Rotate r° around Zaxis
cos(r) -sin(r) 0 0
sin(r) cos(r) 0 0
0 0 1 0
0 0 0 1

Rotate t° around Xaxis
1 0 0 0
0 cos(t) -sin(t) 0
0 sin(t) cos(t) 0
0 0 0 1

Rotate s° around Yaxis
cos(s) 0 sin(s) 0
0 1 0 0
-sin(s) 0 cos(s) 0
0 0 0 1

TRANSLATE (move) 3D:
1 0 0 Dx
0 1 0 Dy
0 0 1 Dz
0 0 0 1

SCALE (resize) 3D:
Sx 0 0 0
0 Sy 0 0
0 0 Sz 0
0 0 0 1

Note: to use one these matrices, "M", multiply any points from your 3D object into the matrix to find out where your object should on our screen: Example: screenPt = M * originalPt (note: originalPt goes on right of M!)

Note2: Java and C++ expect to be given radians (rather than degrees) when calculating sine and cosine (and other trigonometric functions). To convert a number "d" (which is in degrees) into "r" radians, use "r = d * (π/ 180)"
Example with 180°: r = 180 * (π/ 180) = π radians
Example with 90°: r=90*(π/180) = π/2 radians

Note3: how to do "matrix multiplication"
Here is an example using a 3D point [x,y,z] multiplied against a 3 x 3 matrix [A..I].
(Note that the point goes on the RIGHT side.)

A B C x x' (Ax + By + Cz)
D E F times y = y' (Dx + Ey + Fz)
G H I z z' (Gx + Hy + Iz)



Hint: put the finger tips of your RIGHT hand (held vertical) on the x,y,z and then swing your hand up and to the left (horizontal): your finger tips will line up with the A,B,C that get multiplied by the x,y,z to give the first answer. (A*x + B*y + C*z).
Another example, using real live numbers, shows that [1..9] times [3,5,7] equals [34,79,124]:

 1 2 3			 3	 x' (1*3 + 2*5 + 3*7) =	(3 + 10 + 21) = 34
4 5 6 times 5 = y' (4*3 + 5*5 + 6*7) = (12 + 25 + 42) = 79
7 8 9 7 z' (7*3 + 8*5 + 9*7) = (21 + 40 + 63) = 124
123 3  x' (1*3 + 2*5 + 3*7) =(3 + 10 + 21) = 34
456 times 5 = y' (4*3 + 5*5 + 6*7) = (12 + 25 + 42) = 79
789 7  z' (7*3 + 8*5 + 9*7) =(21 + 40 + 63) = 124

Here's a code sample with which you can test your three-D lines: just add the following method to your drawGrid and call the method from init. (Don't forget to give it some z values.)

void lineTest3D( double z1, double z2 ) //Written by Sandy and Mike and Aaron/* Must be given two z values, and will draw a cone with the nosenear 0,0,z1 */{	/* upper right quadrant... */	/* steep up to right */ drawLine3D( 5, 5, z1, 10, 20, z2 );	/* shallow to right */ drawLine3D( 5, 5, z1, 20, 10, z2 );	/* up at 45 degree (slope=1) */ drawLine3D( 5, 5, z1, 20, 20, z2 );	/* */	/* upper left quadrant ... */	/* steep up to left */ drawLine3D( - 5, 5, z1, - 10, 20, z2 );	/* shallow to left */ drawLine3D( - 5, 5, z1, - 20, 10, z2 );	/* up to left at 45degree (slope=-1) */ drawLine3D( - 5, 5, z1, - 20, 20, z2 );	/* */	/* lower right quadrant ... */	/* steep down to right */ drawLine3D( 5, - 5, z1, 10, - 20, z2 );	/* shallow down to right */ drawLine3D( 5, - 5, z1, 20, - 10, z2 );	/* down to right 45 degree (slope=-1)*/ drawLine3D( 5, - 5, z1, 20, - 20, z2 );	/* */	/* lower left quadrant */	/* steep down to left */ drawLine3D( - 5, - 5, z1, - 10, - 20, z2 );	/* shallow down to left */ drawLine3D( - 5, - 5, z1, - 20, - 20, z2 );	/* down to left 45 degree (slope=1)*/ drawLine3D( - 5, - 5, z1, - 20, - 10, z2 );	/* */	/* verticals */	/*vertical up*/ drawLine3D( 0, 5, z1, 0, 20, z2 );	/*vertical down*/ drawLine3D( 0, - 5, z1, 0, - 20, z2 );	/* */	/* horizontals */	/*horizontal right*/ drawLine3D( 5, 0, z1, 20, 0, z2 );	/*horizontal left*/ drawLine3D( - 5, 0, z1, - 20, 0, z2 );}