Cheata 3D


12
May 11

Wolleb : Yo Yo Yo : Once a Month


19
Jul 09

Problems and Solutions

I have had a look at the away3d render code and read a few articles about the drawTriangles(). It seems that this method is not necessarily the fastest solution, due to a missing z-buffer implementation. Papervision is in Flash 9 sometimes even faster than in Flash 10!

Well, what does this mean? I think the core issue is that the Flash Drawing API is unfortunately not fast enough to handle more than 20′000 triangles. I have decided to try-out Alchemy… I will first have to setup my windows machine, since my Mac is still running on Tiger.


11
Jul 09

UV Mapping

The Flash plugin is required to view this object.

I have tried to wrap a bitmap around the cube, but it hasn’t worked so far. The problem is, there are 8 points to and 3 x 12  indices to render a cube. To map the bitmap each vertex needs its own uv map position.

But if you look at uv map that starts top left at 0,0 and ends at bottom right 1,1, you will notice that the point at the vertext at 0,0 should also be at 1,0. There is the problem. Analising a .obj file exported from Modo shows that a cube needs more points than eight to be properly uv mappped.UVMAP

I think, I will have to run more than 8 points per cube. Points 3 and 1 need to be cloned 2 times so that the different uv coordinates can be applied. Points 7 and 5 will be cloned once. The number of points increases by 6 to total 14 points per cube. This seems to be a lot more points. I will show the results in the next article.

Here is the current code:

package core
{
	import __AS3__.vec.Vector;
 
	import flash.display.Bitmap;
	import flash.display.Sprite;
	import flash.display.TriangleCulling;
	import flash.events.Event;
	import flash.utils.getTimer;
 
	import mx.core.Application;
 
	public class GameEngine extends Sprite
	{
		private var _lastTime:int;
 
		private const third:Number = 1/3;
 
		private var _vertices:Vector. = new Vector.();
		private var _render:Vector. = new Vector.();
		private var _indices:Vector. = new Vector.();
		private var _uvtData:Vector. = new Vector.();
		private var _cubes:Vector. = new Vector.(); 
 
		// Rubiks Cube properties
		private var _type:uint = 3; // 3 x 3 cube
		private var _size:Number = 100;
		private var _gap:Number = 20;
		private var _halfSize:Number = _size / 2;
		private var _offset:Number = _size + _gap;
 
		private var _focalLength:Number = 1000;
		private var _radius:Number = 100;
		private var _rHalf:Number = _radius / 2;
 
		private var a:Number = Math.PI / 360;
		private	var cos:Number = Math.cos(a);
		private	var sin:Number = Math.sin(a);
 
		private var _sp:Sprite = new Sprite();
 
		[Embed(source='assets/bmp2.png')]
		private var Chee:Class;
		private var _img:Bitmap = new Chee as Bitmap;
 
		public var xRot:Boolean;
		public var yRot:Boolean;
		public var zRot:Boolean;		
 
		public function GameEngine()
		{
			super();
			init();
		}
 
		private function onAdded(e:Event):void
		{
			_sp.x = Application.application.width / 2;
			_sp.y = Application.application.height / 2;
 
			if(this.hasEventListener(Event.ADDED_TO_STAGE))
			this.removeEventListener(Event.ADDED_TO_STAGE, onAdded);
 
			if(!this.hasEventListener(Event.RESIZE))
			this.addEventListener(Event.RESIZE, onAdded);
		}
 
		private function init():void
		{
			// Set World
			this.addEventListener(Event.ADDED_TO_STAGE, onAdded);
			addChild(_sp);
 
			var i:uint = 0;
			for(var r:uint = 0; r < _type; r++)
			{
				for(var c:uint = 0; c < _type; c++)
				{
					for(var d:uint = 0; d < _type; d++)
					{
						var s:DepthSorter= new DepthSorter();
						s.name = i.toString();
						s.zIndex = i;
						_sp.addChild(s);
						_cubes.push(s);
						makeCube(i,r,c,d);
						i++
					}
				}
			}
			this.addEventListener(Event.ENTER_FRAME, update);
			//update(null);
		}
 
		private function makeCube(index:uint, r:uint, c:uint, d:uint):void
		{
			var v0:uint = 0 + 8 * index;
			var v1:uint = 1 + 8 * index;
			var v2:uint = 2 + 8 * index;
			var v3:uint = 3 + 8 * index;
			var v4:uint = 4 + 8 * index;
			var v5:uint = 5 + 8 * index;
			var v6:uint = 6 + 8 * index;
			var v7:uint = 7 + 8 * index;
 
			if(index == 0)
			{
				_uvtData.push(1,third, 0.75,third, 1,0, 0.25,0, 0.25,third, 1,1, 1,0, 0,0);
				_indices.push(v2,v6,v0);
				_indices.push(v6,v4,v0);
				_indices.push(v6,v7,v4);
				_indices.push(v7,v5,v4);
				_indices.push(v7,v3,v5);
				_indices.push(v3,v1,v5);
				_indices.push(v3,v2,v1);
				_indices.push(v2,v0,v1);
				_indices.push(v3,v7,v2);
				_indices.push(v7,v6,v2);
				_indices.push(v0,v4,v1);
				_indices.push(v4,v5,v1);
			}
 
			// Create 8 3D-Points
			for(var i:uint = 0; i < 2; i++)
			{
				for(var j:uint = 0; j < 2; j++)
				{
					for(var p:uint = 0; p < 2; p++) 					{ 						var xPos:Number = (i * _size - _halfSize) + c * (_size + _gap) - _offset; 						var yPos:Number = (j * _size - _halfSize) + r * (_size + _gap)- _offset; 						var zPos:Number = (p * _size - _halfSize) + d * (_size + _gap)- _offset; 						_vertices.push(xPos, yPos, zPos); 					}		 				} 			}  		} 		 		private function compare(a:DepthSorter, b:DepthSorter):Number  		{ 			var aZ:uint = a.name as uint; 			if(a.zIndex > b.zIndex)
				return -1;
			else
				return 1;
		}
 
		private function update(e:Event):void
		{
			var thisTime:int = getTimer();
			var fps:Number = thisTime - _lastTime;
			_lastTime = thisTime;
			//trace(fps);
 
			// Update
 
			/**
			 * RENDER LOOP, converts 3d to screen and applies matrices
			 * */
 
			_render = new Vector.();
			var j:uint = 0;
 
			for(var i:uint = 0; i < 216; i++)
			{
				var xPos:Number = _vertices[i*3];
				var yPos:Number = _vertices[i*3+1];
				var zPos:Number = _vertices[i*3+2];
 
				var x1:Number;
				var y1:Number;
				var z1:Number;
 
				if(xRot) // X Rotation
				{
					x1 = xPos;
					y1 = cos * yPos - sin * zPos;
					z1 = cos * zPos + sin * yPos;
				}
				if(yRot) // Y Rotation
				{
					if(true)
					{
						x1 = cos * xPos - sin * zPos;
						y1 = yPos;
						z1 = cos * zPos + sin * xPos;
					}else
					{
						x1 = xPos;
						y1 = yPos;
						z1 = zPos;
					}
				}
				if(zRot) // Z Rotation
				{
					x1 = cos * xPos - sin * yPos;
                    y1 = cos * yPos + sin * xPos;
                    z1 = zPos;
				}
 
				if(!zRot && !xRot && !yRot)
				{
					x1 = xPos
                    y1 = yPos
                    z1 = zPos;
				}
 
				_vertices[i*3] = x1;
				_vertices[i*3+1] = y1;
				_vertices[i*3+2] = z1;
				if(i % 8 == 0)
				{
					_cubes[j].zIndex = z1;
					j++;
				}
 
				// Render
				var scale:Number = _focalLength / (_focalLength + _vertices[i*3+2]);
				_render.push(_vertices[i*3] * scale, _vertices[i*3+1] * scale);
			} 
 
			// Draw
				for(var t:uint = 0; t < 27; t++)
				{
					with(_cubes[t].graphics)
					{
 
							clear();
							lineStyle(1,0);
							//drawCircle(300,300,t *10);
							beginBitmapFill(_img.bitmapData);
							//beginFill(0xFF9900);
								var f:uint = t*16;
								drawTriangles(_render.slice(f,f+16), _indices, _uvtData, TriangleCulling.POSITIVE);
							endFill();
 
					}
				} 
 
				// sort
				_cubes.sort(compare);
				for(var q:uint = 0; q < 27; q++)
				{
					_sp.addChild(_cubes[q]);
				}
 
		}
 
	}
 
}

11
Jul 09

Rubiks cube with drawTriangles()

The Flash plugin is required to view this object.

This is my first attempt  to render a 3×3 rubiks cube. The beef is in the drawTriangles() method of the Graphics class.

To calculate each frame, matrices are applied to the 3d Points and rendered down to 2d vertices. The Array of 2d vertices is then passed to the drawTriangles() meathod along with the indices. (AdvancED Actionscript Animation)

The engine draws each cube into it’s own Shape. After the cubes have been drawn, the Shapes will be sorted. The Shapes are actually DepthSort objects that inherit from Shape and extend it with an additional zIndex property.

Right click swf to view source.


10
Jul 09

Rubiks Cube with Flash Cheata 3D

Cheetah

Cheetah

After reading AdvancED Actionscript 3.0 Animation, I have decided to give a self-made Flash 3D Engine a shot. The idea is to create a small and fast 3d framework that out-powers the 3 major engines (Away, Papervision, Alternative). through incorporation of Pixel Bender, minimising function calls and if possible passing byte-arrays to OpenGL via “Alchemy”. The Framework shall provide 3D Vertice management on byte-level with Depth-Sorting,  rotation matrices and UV mapping , a Camera Object, a Render Engine, and eventually an Obj parser.

The Books I am using are:

  • AdvancED Actionscript 3.0 Animation – Keith Peters – friedsofed – ISBN: 978 – 1 – 4302 – 1608 – 7
  • Actionscript 3.0 Animation “Making things move” – Keith Peters – friendsofed – ISBN: 1 – 59059 – 791 – 5
  • 3D Math Primer – Fletcher Dunn and Ian Parberry – Wordware – ISBN: 1 – 55622 – 911 – 9

To instantiate the engine, the code should look similar to this:

var engine:Cheata = new Cheata();

addChild(engine);

engine.data = _initVertices:Vector<Number>;

engine.startRendering();

engine.startRotatingX(anglePerSeconds:Number);

I hope this experiment will show the differences among FP 10 3D-Engines.