Back to Entry Page

Animating with Perspective,
Or: Vanishing Points

Two Approaches

The examples below create an illusion of motion in the third dimension or Z-axis. Each has certain advantages, each certain limitations. Drag the red ball upward to observe the illusion in each case. (Drag a bit slowly or you might lose your grip.)

In Example 1 the object's size diminishes steadily as it moves up the screen. Because this change implies a vanishing point at the top of the screen rather than the depicted horizon, I've limited the ball's travel to the horizon's Y coordinate.

Example 2 shows a more complete implementation of perspective. Here the ball's size is derived from its distance along a line that intersects the vanishing point (X=200, Y=124). If you move the ball in a straight line from left to right across the screen you'll see that this procedure creates parabolic distortion: the ball shrinks as it reaches the center of the screen and then grows again. Howevever, the illusion of depth is otherwise more convincing in the second example.

The code used in each example is discussed below.

Example 1 (perspective1.fla): simple percentage reduction in size without true perspective; object can't move past horizon line.

Example 2 (perspective2.fla): Object size is adjusted according to its position on a line drawn from the implied "front" of the screen to the vanishing point. Note the parabolic distortion.

Example 2: True Perspective

We'll start with the more complex example. Here's the code that determines object size, installed in an enterFrame handler on the object itself:

  //compute length to vanishing point
  xSide = this._x - vanX;
  ySide = this._y - vanY;
  backHypo = Math.sqrt((ySide*ySide)+(xSide*xSide));
	
  //compute length of diagonal from nearest lower corner of screen
  if(this._x < 200){
    xSide = this._x - 0;
    ySide = this._y - 400;
    foreHypo = Math.sqrt((ySide*ySide)+(xSide*xSide));
  }
  else{
    xSide = this._x - 400;
    ySide = this._y - 400;
    foreHypo = Math.sqrt((ySide*ySide)+(xSide*xSide));
  }
	
  pct = (backHypo)/(foreHypo+backHypo);
  this._width = basicWidth * pct;
  this._height = basicHeight* pct;

The math used here should look familiar: it's that good old Pythagorean equation, first seen in the "Noisy Room" demo. Here we're calculating two hypotenuses or distance values: the first (backHypo) represents the distance from the object's present location to the vanishing point.

The second hypotenuse, foreHypo, represents the object's distance from a point along the lower edge (or illusory "front") of the screen. When these two hypotenuse segments are connected they form a line leading from the edge of the screen to the vanishing point, or in other words a perspective line.

Note that we have to ask first if the object's horizontal (x) position is greater or less than 200, that is, to the left or right of the midpoint. The perspective line always runs to the nearer edge of the screen.

By comparing the length of the two hypotenuses we can determine how far the object has traveled along its perspective line. We express this ratio as a percentage (that is, a decimal between 0 and 1) in the variable pct. I've stored the native width and height of the object in the variables basicWidth and basicHeight. By multiplying these numbers by the percentage value we determine the adjusted dimensions.

I'm not enough of a geometer to explain why this process introduces parabolic distortion--no doubt someone in the class will be able to enlighten the rest of us; but the distortion is there, so even if this method is truer to perspectival theory, you may want to try a simpler method, to wit:

Example 1: Implied Perspective

Here's the crucial code from the first example, which you'll find refreshingly brief:

  pct = (this._y/124)/10;
  this._width = basicWidth * pct
  this._height = basicHeight * pct

Here the value assigned to pct is simply the ratio of the object's vertical position (_y) to the number 124, which is the y coordinate of the vanishing point. Multiplying by 10 puts this in percentage form and lets us apply it to the width and height variables to adjust the object's size.

Strictly speaking there are no perspective lines here; there is only a single gradient. While this eliminates the parabolic distortion it also means the ball can continue to recede all the way to the top of the screen, which breaks with the illusion of a horizon. For this reason I don't use the standard startDrag() and stopDrag() code but fall back instead on specific X and Y tracking within the enterFrame handler:

  if(pickedUp == true){
    this._x = _root._xmouse;
    if(_root._ymouse>115) this._y = _root._ymouse;
  }

The if condition here prevents further movement beyond the horizon level (which is actually at Y=124; the lower number allows for the fact that the top edge of the object reaches the horizon before the registration point does). While this simpler illusion may be less geometrically correct, it seems to work well enough on a small display.

No doubt there are better ways than these to simulate three-dimensional movement. Let us know when you find them.

Source Files

The source files (.fla) for both the above examples may be found on Crow in the directory MMShare/perspective.


University of Baltimore Logo

Copyright © 2002 School of Information Arts and Technologies