Native 3D Cube.

In my effort to understand the workings behind 3D in flash and hopefully build my own 3D engine, I have started playing around with native 3D in Flash and I am really starting to understand the basics and how to impliment them. Things like Matrix3D, Point3D and Quaternions are making much more sense to me know after spending the night trawling through the net to find definitions and examples on them.

As this is my first demo, it’s not the most exciting or amazing peice or work, but I think it is, in terms of the code.

What this demo does is just create a cube and rotate it in the ENTER_FRAME event.

There is quite a lot of code, but here it is:

package com.harrynorthover.primitives {

	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;
	import flash.utils.Timer;
	import flash.events.TimerEvent;

	/**
	 * ...
	 * @author Harry Northover
	 */
	public class Cube extends MovieClip {

		private var points:Array = new Array();
		private var shapes:Array = new Array();

		// 3D Properties.
		public var distanceArray = new Array();
		// Lens distance.
		private var fl:Number = 400;

		//Center of the stage.
		private var vpX:Number = stage.stageWidth / 2;
		private var vpY:Number = stage.stageHeight / 2;

		// Render offsets, here you can move the 3D object.
		private var xOffset:Number = 0;
		private var zOffset:Number = fl;
		private var yOffset:Number = 0;

		// Variables used to rotate the cube in the X and Y axis.
		private var angleY:Number = 0.01;
		private var angleX:Number = 0.01;
		private var angleZ:Number = 0.01;

		// Math properties - uh...
		private var cosY:Number = Math.cos(angleY);
		private var sinY:Number = Math.sin(angleY);
		private var cosX:Number = Math.cos(angleX);
		private var sinX:Number = Math.sin(angleX);
		private var cosZ:Number = Math.cos(angleZ);
		private var sinZ:Number = Math.sin(angleZ);

		// Variables to store the distance from each point in the shape, in each axis.
		private var dx:Number = 0;
		private var dy:Number = 0;
		private var dz:Number = 0;

		//Variables that will hold the projection for each point cordinate.
		private var x1:Number = 0;
		private var y1:Number = 0;
		private var z1:Number = 0;

		// Loop variables
		private var w:uint = 0;
		private var j:uint = 0;
		private var i:uint = 0;

		public function Cube() {
			GenerateCube();
			this.addEventListener(Event.ENTER_FRAME, render);
		}
		private function GenerateCube():void {
			// Here we define the vertex by setting its x, y and z positions.
			points.push( { x: -50, y: -50, z: -50 } );
			points.push( { x:50, y: -50, z: -50 } );
			points.push( { x:50, y: 50, z: -50 } );
			points.push( { x:-50, y: 50, z: -50 } );
			points.push( { x:-50, y: -50, z: 50 } );
			points.push( { x:50, y: -50, z: 50 } );
			points.push( { x:50, y: 50, z: 50 } );
			points.push( { x: -50, y: 50, z: 50 } );
			//Then, if we want to draw more than a point, we need to define shapes with those points
			//Each shape (6) will have 4 vertex, the order is important when we want to use the draw api to fill it.
			shapes.push([0, 1, 2, 3]);
			shapes.push([4, 5, 6, 7]);
			shapes.push([0, 4, 7, 3]);
			shapes.push([0, 1, 5, 4]);
			shapes.push([1, 5, 6, 2]);
			shapes.push([3, 7, 6, 2]);
		}
		private function render(e:Event):void {
			//trace(stage.frameRate.toString());
			distanceArray = [];
			this.graphics.clear();
			dx = 0;
			dy = 0;
			dz = 0;
			// Loop to look inside each shape to dop some calculations on the 4 points
			for (j = 0; j < shapes.length; j++) {
				for (i = 0; i < shapes[j].length; i++) {

					x1 = cosY * (sinZ * ( points[shapes[j][i]].y ) + cosZ * (points[shapes[j][i]].x)) - sinY * (points[shapes[j][i]].z);
					y1 = sinX*(cosY*(points[shapes[j][i]].z)+sinY*(sinZ*(points[shapes[j][i]].y)+cosZ*(points[shapes[j][i]].x)))+cosX*(cosZ*(points[shapes[j][i]].y)-sinZ*(points[shapes[j][i]].x));
					z1 = cosX * (cosY * (points[shapes[j][i]].z) + sinY * (sinZ * (points[shapes[j][i]].y) + cosZ * (points[shapes[j][i]].x))) - sinX * (cosZ * (points[shapes[j][i]].y) - sinZ * (points[shapes[j][i]].x));
					//trace(x1);
					//trace(y1);
					//trace(z1);
					// Now store the new cordinates...
					points[shapes[j][i]].x = x1;
					points[shapes[j][i]].y = y1;
					points[shapes[j][i]].z = z1;

					// Now we add the point coordinate to the relative distace var.
					dx += x1;
					dy += y1;
					dz += z1;

					xOffset = 20;
					yOffset = 20;
					zOffset = 20;

					//trace(dx);
					//trace(dy);
					//trace(dz);

					// Next, is the way to get the X and Y points to draw in the stage, taking car about offsets and distance from the camera in the Z axis.
					// Each point will be scaled acording to the distance to the camera. I am using the _x and _y as variables to render, not calculate.
					points[shapes[j][i]]._x = vpX+(points[shapes[j][i]].x+xOffset)*(fl/(points[shapes[j][i]].z+fl+zOffset));//scale;
					points[shapes[j][i]]._y = vpY + (points[shapes[j][i]].y + yOffset) * (fl/(points[shapes[j][i]].z+fl+zOffset));// scale;
				}
				//Ok, you have checked all the points in the shape, now is time too look at the distances
				//This is important, cos the distance to the observer, will mean which shape is render on top.
				//Since we have a sum of distances in X Y and Z, we need an average
				//Next code is the same than dividing by four (cos the four points per shape)
				dx /= shapes[j].length-1;
				dy /= shapes[j].length-1;
				dz /= shapes[j].length-1;
				//We add an element to the distances, and is basically the distance from each point, to the camera. Note than fl is on the Z axis, and is where the camera is.
				//We store and object with the distance, and also a shape ID to know which shape corresponds with the distance.
				distanceArray.push({d:Math.round(Math.sqrt(Math.pow(dx-xOffset, 2)+Math.pow(dy-yOffset, 2)+Math.pow(fl-dz, 2))), index:j});
			}
			//Now, we need to sort the array, to know wich shape is near and need to be render on top. So a simple Sort function.
			distanceArray.sortOn("d");
			//Here is where the fun starts. Now is time to render each polygon
			this.graphics.lineStyle(0,0xFFFFFF,40);
			//for each element in the distance array (the same length than the shape array, we will render the shape.
			for (w = 0; w

You can download the whole thing here: http://harry-northover-code-store.googlecode.com/files/Native%20Cube.zip

Thanks,
Harry.

About Harry

I am a 16 year old web designer/developer and I love any form of interactive media.
This entry was posted in Random and tagged , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

To use reCAPTCHA you must get an API key from https://www.google.com/recaptcha/admin/create