A Simple 3D Pipeline

At this point, you can outline a simple 3D pipeline for drawing a polygon:

  1. Apply the transform.
  2. Project it onto the view window.
  3. Draw.

The Simple3DTest1 class in implements this 3D pipeline. It transforms, projects, and draws two polygons that make up a tree.

Listing 7.6 Simple3DTest1.java

import com.brackeen.javagamebook.test.GameCore;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.geom.GeneralPath;
import com.brackeen.javagamebook.input.*;
import com.brackeen.javagamebook.math3D.*;
/**
 A 3D test to demonstrate drawing polygons.
*/
public class Simple3DTest1 extends GameCore {
 public static void main(String[] args) {
 new Simple3DTest1().run();
 }
 // create solid-colored polygons
 private SolidPolygon3D treeLeaves = new SolidPolygon3D(
 new Vector3D(-50, -35, 0),
 new Vector3D(50, -35, 0),
 new Vector3D(0, 150, 0));
 private SolidPolygon3D treeTrunk = new SolidPolygon3D(
 new Vector3D(-5, -50, 0),
 new Vector3D(5, -50, 0),
 new Vector3D(5, -35, 0),
 new Vector3D(-5, -35, 0));
 private Transform3D treeTransform = new Transform3D(0,0,-500);
 private Polygon3D transformedPolygon = new Polygon3D();
 private ViewWindow viewWindow;
 private GameAction exit = new GameAction("exit");
 private GameAction zoomIn = new GameAction("zoomIn");
 private GameAction zoomOut = new GameAction("zoomOut");
 public void init() {
 super.init();
 InputManager inputManager = new InputManager(
 screen.getFullScreenWindow());
 inputManager.setCursor(InputManager.INVISIBLE_CURSOR);
 inputManager.mapToKey(exit, KeyEvent.VK_ESCAPE);
 inputManager.mapToKey(zoomIn, KeyEvent.VK_UP);
 inputManager.mapToKey(zoomOut, KeyEvent.VK_DOWN);
 // make the view window the entire screen
 viewWindow = new ViewWindow(0, 0,
 screen.getWidth(), screen.getHeight(),
 (float)Math.toRadians(75));
 // give the polygons color
 treeLeaves.setColor(new Color(0x008000));
 treeTrunk.setColor(new Color(0x714311));
 }
 public void update(long elapsedTime) {
 if (exit.isPressed()) {
 stop();
 return;
 }
 // cap elapsedTime
 elapsedTime = Math.min(elapsedTime, 100);
 // rotate around the y-axis
 treeTransform.rotateAngleY(0.002f*elapsedTime);
 // allow user to zoom in/out
 if (zoomIn.isPressed()) {
 treeTransform.getLocation().z += 0.5f*elapsedTime;
 }
 if (zoomOut.isPressed()) {
 treeTransform.getLocation().z -= 0.5f*elapsedTime;
 }
 }
 public void draw(Graphics2D g) {
 // erase background
 g.setColor(Color.black);
 g.fillRect(0, 0, screen.getWidth(), screen.getHeight());
 // draw message
 g.setColor(Color.white);
 g.drawString("Press up/down to zoom. Press Esc to exit.",
 5, fontSize);
 // draw the tree polygons
 trandformAndDraw(g, treeTrunk);
 trandformAndDraw(g, treeLeaves);
 }
 /**
 Projects and draws a polygon onto the view window.
 */
 private void trandformAndDraw(Graphics2D g,
 SolidPolygon3D poly)
 {
 transformedPolygon.setTo(poly);
 // translate and rotate the polygon
 transformedPolygon.add(treeTransform);
 // project the polygon to the screen
 transformedPolygon.project(viewWindow);
 // convert the polygon to a Java2D GeneralPath and draw it
 GeneralPath path = new GeneralPath();
 Vector3D v = transformedPolygon.getVertex(0);
 path.moveTo(v.x, v.y);
 for (int i=1; i<transformedPolygon.getNumVertices(); i++)
{
 v = transformedPolygon.getVertex(i);
 path.lineTo(v.x, v.y);
 }
 g.setColor(poly.getColor());
 g.fill(path);
 }
}

Simple3DTest1 draws a tree that constantly spins around the y-axis. You can move the tree closer to or farther from the camera by pressing the up/down keys. See the screenshot in .

Screenshot Screenshot of Simple3DTest1.

Java graphics 07fig14

In Simple3DTest1, instead of using a plain Polygon3D, you use the SolidPolygon3D subclass. The 3D polygons are drawn in the transformAndDraw() method. This method transforms and projects the polygon. To draw a polygon, you first convert it to a GeneralPath (part of the java.awt.geom package). The Graphics2D interface provides methods to fill GeneralPaths, so the polygon drawing is done for you. Notice that the tree polygons are never actually transformed. They are copied to a scratch polygon, which is then transformed. If the actual tree polygons were transformed, over time they would eventually accumulate floating-point errors. One transform isn't enough to create any noticeable error, but after many transforms, errors might start to creep in and could result in distorted polygons. So, copy the polygon to the scratch polygon and then transform the scratch polygon. A few problems crop up with Simple3DTest1. Perhaps you noticed a few of them:

Let's get started on fixing these problems! First up: free camera movement.