In this example, you’re going to build a 3D engine based on perspective scaling in 19 lines of code. Before Flash 10 there was no native support for 3D and all you had were x and y coordinates to play around with. So you needed to add another dimension to get 3D – a z-axis. So the trick to creating a z-axis was to use perspective scaling. Which means that as an object moves away from you it gets small and as it moves towards you it get larger. But we need to quantify this idea (make some math out of it) so we can program it. And that comes from Thales Theorem.
Imagine that you are in your home looking out the window. As you approach the window objects outside look larger and as you get farther away from the window objects outside look smaller. Your distance from the window is called your focal length (fl), the window is your projection plane (or viewport), and your eye is the vanishing point.
Now don’t move – this fixes your focal length – and watch outside as objects move closer to and farther away from your window. As a bird flies closer to the window it looks larger and as it flies away it looks smaller. This is your z-axis – the distance between the outside object and your window pane. And the equation that governs the behavior that you see is given below;
sizeRatio = size/SIZE = fl/(fl + z)
where your sizeRatio equals “one” when your outside object is at the window and “zero” when your object (bird) flies far away (off to infinity). This equation works and is illustrated in the graphic below as a Blender monkey peering at a projection plane.
When dealing with multiple objects that overlap, perspective scaling alone is not enough. In the Flash Player you need to z-sort. This is even an issue with Gumbo (Flex 4). When creating a 3D carousel for example you need to z-sort the objects as they spin to put the closest one on top of the stack. The technical name is transposition and in AS2 it was easily accomplished using the swapDepths method. But in AS3 it is a little more complicated.
In AS3, the display list functions as an array and each display object has an index. The index start at zero and goes up to the number of objects on your stage where index zero is the bottom object. So since the display object is a child you can change its position using the setChildIndex method.
Since all your objects are in an array, you can sort that array by z and then set the indices of your array objects based on z. And that’s how it is presently done! Here’s a sort code snippet that illustrates the concept
private function sortmyZ():void
for(var i:uint =0; i<numObjects; i++)
var myObject:MYObject3D = myObjects[i];
The code snippet sorts the objects in reverse numerical order from high to low based on the myZvalue of your objects. Thus, the objects further away from your projection plane get a lower index value placing them on the bottom of the stack.
This method will need to be called each time your 3D engine iterates the position of your objects. Typically this occurs on an onEnterFrame event.
With that said, you’re now ready to build your3D engine.
3D Flash Engine in 19 Lines of Code
Here is the Demo, Download, Youtube, and Discussion.
Youtube: How it was made
Here are the steps for creating the program:
1. Start by importing the Sprite class; this is where you are going to draw a ball that you will animate in 3D.
import flash.display.Sprite;//imports sprite class
2. Next declare your variables zposition, Angle, and focal length.
var zposition:Number = 0;//z postion
var myAngle:Number =0;//Angle of myBall
var fl:Number = 250; //focal length
3. Next create your ball and add it to the stage.
var myBall:Sprite = new Sprite();//instantiates myBall sprite
myBall.graphics.beginFill(0xFF0000);//Assigns a ball color
myBall.graphics.drawCircle(0, 0, 40);//draws your ball at (0,0)
myBall.graphics.endFill();//ends the fill
addChild(myBall);//adds the ball to the stage
4. Next create your onEnterFrame listener which loops through your equations of motion. This is the heart of all 3D engines.
addEventListener(Event.ENTER_FRAME, onEnterFrame);//loops equations
5. Finally, create the function that will be looped. These are your equations of motion which govern the perspective as it is changed and converts 3D to 2D (or projects onto the viewport).
var scale:Number = fl / (fl + zposition);//scale perspective
if(Math.abs(myAngle)>=20) myAngle=-myAngle;//change sign
myBall.x = 300*Math.sin(myAngle)*scale+300; //ball orbit x
myBall.y = 300*Math.cos(myAngle)*scale; //ball orbit y
myBall.scaleX = scale;//scales perspective in x
myBall.scaleY = scale;//scales perspective in y
zposition = myAngle*100;} //increments z
Though this is not Papervision it illustrates a number of elements that every 3D engine possesses;
- a frame looper/renderer
- perspective (z-coordinate)
- projection onto a viewport
- primitive or basic shape
- addition of a color (or material)
And all of this in just 19 line of code. If only it would have stayed this simple. Papervision started off with only 20 classes, now it is in the hundreds and growing. But as they say, no pain no gain.
Click more below to see the paste-able code. Just cut and past the code below into flash and watch the magic of perspective occur.