Perspective

<< Astronomy | FinalProjectsTrailIndex | CanyonAnimation >>

3D projection article

Fr Chris explanation of Rotation and Perspective

Point3D.java
public class Point3D {
	public static final double screenDistance=150.0;
	private double x;
	private double y;
	private double z;
	public Point3D(double x0, double y0, double z0){
		x=x0;
		y=y0;
		z=z0;
	}
	public Point3D(int x0, int y0, int z0){
		x=x0;
		y=y0;
		z=z0;
	}
	// see http://www.mathorama.com/geom/lessons/stereo2.html
	// or http://en.wikipedia.org/wiki/3D_projection#Perspective_projection
	public int viewX(Point3D viewpoint){
		double depth= this.z-viewpoint.getZ();//D+E
		double width=this.x-viewpoint.getX();//w analogous to h
		int ox= (int)Math.round(width*screenDistance/depth); //coord where eye is at (0,0)
		return (int)viewpoint.getX()+ox;
	}
	public int viewY(Point3D viewpoint){
		double depth= this.z-viewpoint.getZ();//D+E
		double height=this.y-viewpoint.getY();//h
		int oy= (int)Math.round(height*screenDistance/depth);
		return (int)viewpoint.getY()+oy;
	}
	public double getX(){return x;}
	public double getY(){return y;}
	public double getZ(){return z;}
	public void setX(double value){ this.x=value;}
	public void setY(double value){ this.y=value;}
	public void setZ(double value){ this.z=value;}
}

Cube.java
import java.awt.Color;
import java.awt.Graphics;


public class Cube {
	  private Point3D v[];//vertices
	  private Color color;
      public Cube(Point3D topFrontLeftCorner, double size, Color c){
    	        this.color=c;
    	        v=new Point3D[8];
    	        v[0]=topFrontLeftCorner;
    	        v[1]=new Point3D(topFrontLeftCorner.getX()+size,topFrontLeftCorner.getY(),topFrontLeftCorner.getZ());
    	        v[2]=new Point3D(topFrontLeftCorner.getX()+size,topFrontLeftCorner.getY()+size,topFrontLeftCorner.getZ());
    	        v[3]=new Point3D(topFrontLeftCorner.getX(),topFrontLeftCorner.getY()+size,topFrontLeftCorner.getZ());
    	        v[4]=new Point3D(topFrontLeftCorner.getX(),topFrontLeftCorner.getY(),topFrontLeftCorner.getZ()+size);
    	        v[5]=new Point3D(topFrontLeftCorner.getX()+size,topFrontLeftCorner.getY(),topFrontLeftCorner.getZ()+size);
    	        v[6]=new Point3D(topFrontLeftCorner.getX()+size,topFrontLeftCorner.getY()+size,topFrontLeftCorner.getZ()+size);
    	        v[7]=new Point3D(topFrontLeftCorner.getX(),topFrontLeftCorner.getY()+size,topFrontLeftCorner.getZ()+size);
      }
      /**
       * 
       * @param g  the Graphics object to draw on
       * @param v  the viewpoint
       */
      public void draw(Graphics g, Point3D vp){
    	  	 Color oldColor=g.getColor();
    	  	 g.setColor(color);
    	  	 connect(g,vp,0,1);
    	  	 connect(g,vp,1,2);
    	  	 connect(g,vp,2,3);
    	  	 connect(g,vp,3,0);
    	  	 connect(g,vp,4,5);
   	  	 connect(g,vp,5,6);
   	  	 connect(g,vp,6,7);
   	  	 connect(g,vp,7,4);
   	  	 connect(g,vp,0,4);
   	  	 connect(g,vp,0,4);
   		 connect(g,vp,1,5);
   		 connect(g,vp,2,6);
   		 connect(g,vp,3,7);	 
    	  	 g.setColor(oldColor);
      }
      public void connect(Graphics g, Point3D vp, int a, int b){
    	  	g.drawLine((v[a]).viewX(vp) , v[a].viewY(vp),v[b].viewX(vp) , v[b].viewY(vp) );
      }
}

CubeViewer.java
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
/**
 * Demonstrates an 3D Object like a cube
 * and makes a "First-person" point-of view
 * using the arrow keys to move up and down, left and right
 * @author Chris Thiel, OFMCap
 * size of applet should be 800 x 600
 */

@SuppressWarnings("serial")
public class CubeViewer extends Applet implements KeyListener
{
	public static double amount=10.0; //amount of change each arrow will change
	Point3D view;
	Cube cube;
	public void init(){
		view=new Point3D(400,300,0);
		cube=new Cube(new Point3D(300,200,100), 200.0, Color.BLUE);
		this.addKeyListener(this);
	}
	public void paint(Graphics g){
		String vx="x = "+view.getX();
		String vy="y = "+view.getY();
		String vz="z = "+view.getZ();
		g.drawString(vx, 20, 20);
		g.drawString(vy, 20, 35);
		g.drawString(vz, 20, 50);
		g.drawString("Click Screen for focus.  Use Arrows to view left and right, a to go forward, z to go back", 20, 580);
		cube.draw(g, view);
	}
	@Override
	public void keyPressed(KeyEvent e) {
		int keyCode=e.getKeyCode();
        if(keyCode==38){ //up
        	    view.setY(view.getY()+amount);
        } else if (keyCode==40){ //down
        		view.setY(view.getY()-amount);
        } else if (keyCode==37){ //left
        		view.setX(view.getX()-amount);
        } else if (keyCode==39){ //right
        		view.setX(view.getX()+amount);
        }else if (keyCode==65){ //forward
        		view.setZ(view.getZ()+amount);
        }else if (keyCode==90){ //back
        		view.setZ(view.getZ()-amount);
        }
        repaint();
	}
	@Override
	public void keyReleased(KeyEvent e) {}
	@Override
	public void keyTyped(KeyEvent e) {}
}

Explorations

  • What happens when you go past the cube? Can you change this so you don't draw the cub if it is behind your point of view?
  • Change the screenDistance--what effect does this have?
  • Change the box's size and/or location.
  • Add a red box in a different location
  • Make an Object that is different from a cube like a Letter or a Table
  • Draw the Cube differently. Rather than drawing the "wireframe" use g.fillPolygon (draw the furthest face first
  • Add a rotation transform so you aren't always looking ahead