D Math

Projecting a point onto the view window reduces to a simple right triangle problem, as shown in Screenshot.

Screenshot Projecting a point, (x, y, z), onto the view window.

Java graphics 07fig08.gif


In Screenshot, you find the 2D projected point, (x', y'), from the 3D point, (x, y, z). Remember that z decreases in the direction of the view, so the length along the z-axis from the origin to the 3D point is –z. In this figure, you deal only with the x coordinate, but the y coordinate can be calculated using the same technique. The triangle formed by the lines x and –z is a similar triangle (the angles are the same) to the triangle formed by x' and d. To solve this, however, you need to know d, the distance from the camera to the view window, what we call the view distance. The good news is, you can pick any value for d, the view distance, which will be constant in the normal course of a game. It depends on only how wide you want the view angle to be. For example, if the camera is very close to the view window (short view distance), the camera can see a wide angle of the 3D world. Likewise, if the camera is far from the view window (longer view distance), the camera will have "tunnel vision" because the view angle will be very small. The size of the view angle is your choice. Typically, values for the horizontal view angle vary from 45° to 90°. In the examples in this tutorial, we use 75°. With the horizontal view angle, the view distance can be calculated as shown in Screenshot.

Screenshot Calculating d, the distance between the camera and the view window, based on q, the view angle, and w, the width of the view window.

Java graphics 07fig09.gif


Note that the view distance depends on the size of the window. So, if you give the player an option of changing the size of the window or screen on the fly, you must recalculate the view distance. Now that you know the view distance, you can project a point to the view window using the formula from Screenshot. However, the 2D coordinate system of the view window isn't the same as the view window of the screen, as shown in Screenshot. You need one more step to convert view window coordinates to screen coordinates.

Screenshot Converting a point on the view window, (x, y), to a point on the screen, (x', y').

Java graphics 07fig10.gif


That does it. With these equations, you can project a 3D point onto the screen. The view window and projection are summed up in the ViewWindow class in Listing 7.2.

Listing 7.2 ViewWindow.java
package com.brackeen.javagamebook.math3D;
import java.awt.Rectangle;
/**
 The ViewWindow class represents the geometry of a view window
 for 3D viewing.
*/
public class ViewWindow {
 private Rectangle bounds;
 private float angle;
 private float distanceToCamera;
 /**
 Creates a new ViewWindow with the specified bounds on the
 screen and horizontal view angle.
 */
 public ViewWindow(int left, int top, int width, int height,
 float angle)
 {
 bounds = new Rectangle();
 this.angle = angle;
 setBounds(left, top, width, height);
 }
 /**
 Sets the bounds for this ViewWindow on the screen.
 */
 public void setBounds(int left, int top, int width,
 int height)
 {
 bounds.x = left;
 bounds.y = top;
 bounds.width = width;
 bounds.height = height;
 distanceToCamera = (bounds.width/2) /
 (float)Math.tan(angle/2);
 }
 /**
 Sets the horizontal view angle for this ViewWindow.
 */
 public void setAngle(float angle) {
 this.angle = angle;
 distanceToCamera = (bounds.width/2) /
 (float)Math.tan(angle/2);
 }
 /**
 Gets the horizontal view angle of this view window.
 */
 public float getAngle() {
 return angle;
 }
 /**
 Gets the width of this view window.
 */
 public int getWidth() {
 return bounds.width;
 }
 /**
 Gets the height of this view window.
 */
 public int getHeight() {
 return bounds.height;
 }
 /**
 Gets the y offset of this view window on the screen.
 */
 public int getTopOffset() {
 return bounds.y;
 }
 /**
 Gets the x offset of this view window on the screen.
 */
 public int getLeftOffset() {
 return bounds.x;
 }
 /**
 Gets the distance from the camera to this view window.
 */
 public float getDistance() {
 return distanceToCamera;
 }
 /**
 Converts an x coordinate on this view window to the
 corresponding x coordinate on the screen.
 */
 public float convertFromViewXToScreenX(float x) {
 return x + bounds.x + bounds.width/2;
 }
 /**
 Converts a y coordinate on this view window to the
 corresponding y coordinate on the screen.
 */
 public float convertFromViewYToScreenY(float y) {
 return -y + bounds.y + bounds.height/2;
 }
 /**
 Converts an x coordinate on the screen to the
 corresponding x coordinate on this view window.
 */
 public float convertFromScreenXToViewX(float x) {
 return x - bounds.x - bounds.width/2;
 }
 /**
 Converts a y coordinate on the screen to the
 corresponding y coordinate on this view window.
 */
 public float convertFromScreenYToViewY(float y) {
 return -y + bounds.y + bounds.height/2;
 }
 /**
 Projects the specified vector to the screen.
 */
 public void project(Vector3D v) {
 // project to view window
 v.x = distanceToCamera * v.x / -v.z;
 v.y = distanceToCamera * v.y / -v.z;
 // convert to screen coordinates
 v.x = convertFromViewXToScreenX(v.x);
 v.y = convertFromViewYToScreenY(v.y);
 }
}


In the ViewWindow class, the projection occurs in the project() method, which projects a Vector3D to the ViewWindow and then translates it to screen coordinates. After calling the project() method, the x and y components of the Vector3D are the screen coordinates, and the z component can be ignored. Huzzah, you can project points from 3D space onto the screen! Wait, that's boring. Points are one thing, but the goal is to create a polygon modeler. So let's talk about polygons.



   
Comments