As you can see in the code, we define the cube by the positions in 3D space of its eight vertices. We use the standard xyz-coordinate system (with units interpreted as pixels) as our fixed and stationary coordinate system:
The vertices in our example are [70,70,70], [-70,70,70] etc. In other words, each side of the cube is 140 pixels long, and the cube is centered at the origin.
Initially, the yz-plane serves as our view plane; that is, we assume that the computer screen coincides with the yz-plane. The observer is initially located on the postive x-axis; that is, the unit view vector is [1,0,0]. The distance of the observer from the origin, stored in the code in a variable fLen, is set in our example to 2000. As you will see below, the value of fLen determines the distortion for perspective: the higher values correspond to less distortion. The intial positon vector of the observer is [fLen,0,0].
The main function in the script, renderView(theta:Number,phi:Number), takes two parameters. The first parameter represents the angle by which the position of the observer is rotated horizontally, in degrees, measured counterclockwise from the positive x-axis. The angle corresponds to the angle theta in spherical coordinates. The second parameter represents the phi coordinate in the spherical coordinates; that is, the angle (in degrees) between the new position vector of the observer and the positive z-axis. (Phi is a nondirected angle between 0 and 180 degrees.) The distance, fLen, of the observer from the origin does not change. The only thing that changes are the two view angles theta and phi.
Each time we call the function renderView(theta,phi), the function renders a new view of our object corresponding to the new view angles theta and phi. The new view is obtained as follows. We take the normalized new position vector of the observer to be our new unit view vector, u. Easy calculations give the coordinates of the new unit view vector:
Our new view plane, is the plane through the origin perpendicular to the view vector u. We choose a new orthogonal coordinate system in our 3D space, which we will call the new view coordinate system. The x-axis in the new coordinate system is parallel to the view vector u and passes through the origin. The new z-axis lies on the new view plane and is chosen in such a way that the old positive z-axis when projected onto the new view plane, falls onto the new positive z-axis. (In other words, we assume that there is no rotation of the object about the vector u.) The new y-axis lies in the new view plane, is orthogonal to the new z-axis and directed in such a way that the new coordinate system is right-handed.
The transformation matrix from coordinates of a point in the stationary coordinate system to its coordinates in the new view coordinate system is given by:
Thus, a point P with coordinates P=[px,py,pz] in the stationary coordinate system has the following coordinates P=[pnewx,pnewy,pnewz] with respect to the new coordinate system:
As you can see in the code, renderView(t,p) uses a helper function to calculate the coordinates in the new view coordinate system for all the vertices of the cube.
After the coordinates of the vertices in the new view coordinate system are calculated, the vertices are projected onto the new view plane that represents the computer screen. In the new coordinate system, this projection is simply the projection onto the new yz-plane. Thus, if we neglect perspective (that is, use the orthographic model), a point P=[pnewx,pnewy,pnewz] projects onto the point [pnewy,pnewz] on the view plane. In our examples, we do allow for perspective and use the following projection formulas which create the perspective effect:
These formulas are only an approximation of true perspective but they are simple and they work well unless the object is too close to the camera or too large. For mathematical objects like parametric surfaces or graphs of functions, too much perspective takes away from clarity. That is why we use large values for fLen which produce very little perspective.
As you can see in the code, when we project a vertex (after calculating its new coordinates in the new view coordinate system), we use the formulas above but we change the sign of the second coordinate of the projection. This is because Flash's vertical coordinate axis points downward, its horizontal axis to the right.
To determine which of the faces of the cube should appear in front and which behind, we use a very simple depth sorting method. After the new coordinates of all vertices are computed, we find the midpoint (in new view coordinates) of each face. The midpoint is understood as the point whose three coordinates are arithmetical averages of the corresponding coordinates of the face's vertices. Then we calculate the distance of each midpoint from the current position of the observer. Using ActionScript 3 array sorting methods, we sort the faces according to their distance from the observer. After the faces are sorted, and the vertices projected, we draw the faces from back to front; that is, we use the painter's algorithm.
For simple objects like a cube or any other convex body, it would be sufficient to sort face's according to their x-coordinate in the new view system rather than to their distance from the observer. For more complex mathematical surfaces the latter method gives better results even if the observer is situated far away.
On the next page, we discuss the code.