7 December 2009
You should have a basic understanding of the Adobe Flash authoring interface, working with symbols, and mouse interaction. An awareness of 3D is useful too; you should be familiar with the topics discussed in Mariko Ogawa's article, Exploring the new 3D features in Flash. Links to more information about 3D in Flash are included at the end of this tutorial.
The three-dimensional capabilities of Adobe Flash CS4 Professional allow changes in the zoom and view perspective, and its handling of 3D math makes it easier to navigate in and around a 3D scene. Game developers and animators can now incorporate 3D view and movement more easily than before.
This tutorial explores two different ways to change what is shown on the Stage
Moving the viewpoint is simple and acts like a camera zoom lens. Moving objects on the Stage using the object's x, y, and, z attributes is not much more difficult and offers full movement on each axis—it's like holding an object in your hands with the ability to move it in and out, up and down, and also allows rotations of the scene itself.
The code in this tutorial demonstrates both methods, including how to perform multiple transformations using the Matrix3D class. The sample files contain navigational UI controls for changing the view using both approaches, as shown in Figure 1.
Flash display objects such as Sprites are flat, even when put in a 3D world. As you can with photographs, you can position them any way you want. But to create a three-dimensional structure with depth, you'll need multiple display objects.
In the scene I create in this article, each wall or floor is created in its own Sprite, then rotated into the correct position. As shown in Figure 2, the wall (pink rectangle), which is originally flat, is "lifted" into position by increasing the
rotationY property to 90 degrees. Note that its upper left registration point (0,0) marked in Figure 2 remains the same relative to the other rectangle, the brown floor. It is easiest to position using the registration point and then rotate into the correct 3D orientation. I find that it is also easiest to construct the scene looking down from the top of the model so that x and y are x and y, and z is for height, as I did in this tutorial. Figure 2 is tilted with a 3D perspective so that the wall height can be seen.
For vertical surfaces like walls, the rotation is like picking up one side of a flat board to make it a vertical wall. Once the wall is positioned, Flash Player handles all of the calculations and redraws for you when you move the viewpoint.
The sample Flash project contained in the sample file 3dviewcontrol.zip constructs a 3D object in the sample file ModelSprite.as, creating a new Sprite for each wall, floor, and ceiling. The ModelSprite class contains constants for the size and positions of the walls and ceiling, making them changeable in one spot. The ceiling is a 2D object just like the floor, except its z position is decreased to be closer to the user so that it is "above" the floor. Walls are drawn as flat rectangles, then rotated along the x or y axis to stand them up into position (see Figure 2).
The file 3DViewControl.fla contains a Stage with radio buttons for the two types of navigation, a button to reset the position, and labels for the Slider that gets constructed in ActionScript. Most construction happens in the file Scene.as when the user clicks either of the two option buttons, which invoke the
moveObjectsHandler() functions to set up the two different approaches to changing the view of a 3D scene. With the scene now set up, I describe how each works in the next section.
Your view of a 3D scene is controlled by two variables:
projectionCenter, which defines the x and y coordinates of the viewer; and
fieldOfView, which defines how wide a view of the scene the viewer sees. Decreasing the
fieldOfView value is like zooming in with a camera lens. Both variables are part of the
Changing the view can be done by changing the
projectionCenter variables, which is like moving the camera up/down and left/right. In the sample code, the viewpoint is moved in the function
doDragProjectionCenter with this line of code:
root.transform.perspectiveProjection.projectionCenter = new Point(center.x,center.y);
which sets the projection point to the current mouse position.
You can zoom by pressing Shift and moving the mouse up and down, or you can use the Slider on the left side of the Stage. Zooming in is done by setting a smaller
fieldOfView value, making the objects appear larger.
The sample code has a problem with z-ordering when moving around the scene because re-sorting based on the new z order is not being done. When viewed from the left, the pink wall should be shown in front of the other walls (which it is), but when moving the viewpoint to the right, the tan wall should be in front (which it isn't). The z order hasn't changed, which means the pink wall is being drawn on top of the tan wall. This problem is solvable by sorting the display list using the z-ordering base on the new viewpoint. The
getRelativeMatrix3D method of the Transform class is used to perform this reordering. An explanation and solution to the z order re-sort, titled Using Matrix3D objects for reordering display, is part of the Programming ActionScript 3 for Flash documentation (also linked to at the end of this tutorial, among others).
I added a Timer to continue moving the projection point when the mouse is dragged outside the Stage so you could see a wider range of viewpoint values.
The second approach to changing the view is by moving all the objects in the scene and keeping the viewpoint and field of view the same. At first I thought this would involve more calculations but it is as simple as "change the positions of all the objects on the Stage." Flash handles the 3D view calculations—the code moves objects in the x, y, and z planes by setting the
Start by clicking the Move Objects option button. Two buttons appear: Pan and Orbit. Select Pan, and you can drag the object left and right, up, and down. A more efficient way of setting more than one variable is by using the Matrix3D class because it performs one calculation with the new values instead of performing the calculations after each value is set. In the code, the
moveObjects() function uses
Matrix3D.appendTranslation() to set the x and y positions at the same time:
tray.transform.matrix3D.appendTranslation(offsetX, offsetY, 0);
Zoom moves the object closer to the viewer by decreasing the z position. In the code, this is
tray.z += offsetY, where a negative
offsetY causes the view to zoom in.
I took it further by implementing "Orbit," which is possible only by changing values of the objects themselves. Orbit is an interesting 3D movement, in which the object is rotated in both the y and x axes, enabling you to spin it around and see the sides and back of the object. Simple orbit movement is accomplished by changing the
rotationY properties, or by using the Matrix3D class to perform the rotations, as in this code:
//Perform both rotations together tray.transform.matrix3D.prependRotation(-offsetX / 2, Vector3D.Y_AXIS); tray.transform.matrix3D.prependRotation( offsetY / 2, Vector3D.X_AXIS);
However, because 3D rotations are not commutative—meaning that the order of operation is important and the code performs both y and x rotations multiple times—the image will tilt. To see this, click Orbit, uncheck the No Tilt box, and move the mouse in a circle. Just as if I had done the same operations with a Rubik's Cube in front of me, I get a tilted image (see Figure 3).
While this is natural, it isn't what I want in an orbit feature, so I added the No Tilt check box, which uses the following code in the function
orbitObjects() to avoid the tilt, or z rotation. The code undoes the previous x rotation, then applies the new y rotation and then the new x rotation. This keeps the z rotation zero during all rotations:
//"Undo" the X rotation from previous rotation tray.transform.matrix3D.prependRotation(-currentXrotation, Vector3D.X_AXIS); //Apply the new Y rotation tray.transform.matrix3D.prependRotation(-offsetX / 2, Vector3D.Y_AXIS); //Add the new X rotation to previous X rotation and "re"apply it currentXrotation += offsetY/2; tray.transform.matrix3D.prependRotation(currentXrotation, Vector3D.X_AXIS);
Try moving the mouse in a circle with the No Tilt option selected, and then with the No Tilt option unselected. With it off, a tilt to the object on the z axis appears, even when trying to rotate the object back to its original position. The division by two helps slow the rotation.
resetPosition restores the object's x, y, and z original values and sets all rotations to zero.
Moving objects on the Stage as a way to change a view of a 3D scene is not much more complex than moving the viewpoint. The ability to view a 3D scene and change your view of it opens the door to exploring visual data in useful ways.
For another tutorial about 3D in Flash and ActionScript 3, read my companion article, 3D moving stars in Flash using ActionScript 3.
Below is some additional information from various documentation sources about 3D and Flash: