Script.it .Nam Myoho Renghe Kyo.

Script.it
[AS3.0] 3D basics #01

While working on 3D in flash it feels like a good idea to explain a little bit on my approach on this interesting subject. Starting from the basics this article is ment for those who want some more insight on how 3D in flash is done. Nothing fancy, just the basics.

The Vertex.
A vertex is a point in 3 dimension space. In my approach a vertex is a Vector3D object ( x, y, z ).
Nothing difficult there, as its a native as3.0 class.

The Polygon.
Polygon




































In a 3d program each mesh is often made out of multiple triangles.
These triangles are called polygons.
Each polygon is made up from 3 vertices. In my system i made a custom polygon class which has 3 vertices in it.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
package{
    public var vertices:Vector.<Vector3D> = new Vector.<Vector3D>(3, true);
    public class Polygon ( $pointA:Vector3D, $pointB:Vector3D, $pointC:Vector3D ){
          vertices[0] = $pointA;
          vertices[1] = $pointB;
          vertices[2] = $pointC:
    }
}

+ Drawing the polygon.
The above part is pretty straight forward.
So now we have an object which has 3 points in it whom we can draw.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
 //very basic drawing
 public function render( $graphics:Graphics ):void {
         $graphics.lineStyle( 1, 0 );
         $graphics.moveTo( vertices[0].x, vertices[0].y );
         for( var i:int = 1; i < vertices.length; i++){
              $graphics.lineTo( vertices[i].x, vertices[i].y );
         }
          $graphics.lineTo( vertices[0].x, vertices[0].y );
 }

In the code above we just loop thru the vertices and draw them. Ofc this is not the best way to do it, but it shows the basic concept.

+ Transforming the polygon.
So now what if we want to move , rotate, scale the points in 3D space ? How do we go about such an operation ? In my approach i transform the vertices with a transformation matrix. This can be done by hand:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
final public function transformVector(m:Matrix3D, i:Vector3D):Vector3D {
            const x:Number = i.x, y:Number = i.y, z:Number = i.z;
            const d:Vector.<Number> = m.rawData;
            const o:Vector3D = new Vector3D;
 
            o.x = x * d[0] + y * d[4] + z * d[8]  + d[12];
            o.y = x * d[1] + y * d[5] + z * d[9]  + d[13];
            o.z = x * d[2] + y * d[6] + z * d[10] + d[14];
            o.w = x * d[3] + y * d[7] + z * d[11] + d[15];
			return o;
        }

This seems a nice way to do so, but flash has a native function inside the Matrix3D class which can do this for you. This function is named transformVector.
So how do we implement this ?

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
final public function transform( $matrix:Matrix3D ):void {
	for (var i:int = 0; i < vertices.length; i++) {
		vertices[i] = $matrix.transformVector( vertices[i] );  //transform the points with a matrix3D
		vertices[i].w = fov / ( fov - vertices[i].z );             //do some perspective correction, fov = 250
		vertices[i].project();                                          //project the points to 2D space.
	}
}

What this basicly does is transform each point according to the matrix i pass it. For example i pass a matrix3D object with a rotation like so:

?View Code ACTIONSCRIPT
1
2
3
4
var transformMatrix:Matrix3D = new Matrix3D;
transformMatrix.appendRotation( 45, Vector3D.Y_AXIS );
 
myPolygon.transform( transformMatrix );

First i make a matrix3D object which i rotate in 3D space. Then i transform the polygon (aka each point inside the polygon)

This looks nice but in my system i like to have the tranformed vertices seperate from the initial vertices. This way i still have my original geometry and my transformed one. So i have a second list of vertices inside the Polygon class which will store the translated points. When i tranform the vertices i will not stoore the changes within themselves but in that seperate list.
When i draw the Polygon, i don’t draw the actual vertices, but instead i draw the transformed vertices:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
   public var vertices:Vector.<Vector3D> = new Vector.<Vector3D>(3, true);
   public var transformedVertices:Vector.<Vector3D> = new Vector3D(3, true);
    public class Polygon ( $pointA:Vector3D, $pointB:Vector3D, $pointC:Vector3D ){
          vertices[0] = $pointA;
          vertices[1] = $pointB;
          vertices[2] = $pointC:
    }
 
    //transformations:
    final public function transform( $matrix:Matrix3D ):void {
	    for (var i:int = 0; i < vertices.length; i++) {
		    transformedVertices[i] = $matrix.transformVector( vertices[i] );  //transform the points with a matrix3D
		    transformedVertices[i].w = fov / ( fov - transformedVertices[i].z );             //do some perspective correction, fov = 250
		    transformedVertices[i].project();                                          //project the points to 2D space.
	    }
     }
 
    //drawing:
    public function render( $graphics:Graphics ):void {
           $graphics.lineStyle( 1, 0 );
           $graphics.moveTo( transformedVertices[0].x, transformedVertices[0].y );
           for( var i:int = 1; i < transformedVertices.length; i++){
                $graphics.lineTo( transformedVertices[i].x, transformedVertices[i].y );
            }
            $graphics.lineTo( transformedVertices[0].x, transformedVertices[0].y );
     }
 
}

+ Depth sorting the polygon.
For this post i will keep this very basic. There are other, faster and better sorting methods but this will do for now.
What we basicly want to do is get some sort of depth value for our polygon.
This way we can sort a list of polygons and draw them in correct order ( most front first and most back last).
For this we need a getter function inside our polygon class which will calculate the depth of our polygon.

?View Code ACTIONSCRIPT
1
2
3
4
5
6
public function get depth():Number {
	var value:Number =transformedVertices[0].z < transformedVertices[1].z ? transformedVertices[0].z : transformedVertices[1].z;
	value      = value      < transformedVertices[2].z ? value 	 : transformedVertices[2].z;
 
	return value  +0.0001;
}

The code above gets the smallest z value from 1 of our 3 vertices and sets that as a depth for the polygon. This works good enough for our sorting. Another simpel method is to sum up all 3 z values and then divide them by 3.

Now we need to have a sorting method to sort the list of polygons according to this depth value. The easy way to do this is like so:

?View Code ACTIONSCRIPT
1
        myListOfPolygons.sortOn( "depth",Array.NUMERIC | Array.DESCENDING );

The code above takes an Array with polygon on which we sort the list by the depth of each Polygon. After sorting your list you can draw the polygons.

Well, thats it for now.
More to come next time.

Have fun!
Rackdoll

Creative Commons License
[AS3.0] 3D basics #01 by Script.it, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Netherlands License.

Comments are closed.

Categories
Archives
Live Supporters