Curso AS3

Script Cube Sphere 3D no Flash CS4

Retirei do Google Code os scripts que escrevi sobre objetos 3D usando os novos recursos do CS4.

Eu os escrevi no lançamento do CS4 para conhecer os novos recursos, na época achei divertido e escrevi mais do que eu “deveria”.

Vou deixar os scripts neste post.

[update] Apenas uma observação, estas classes não são o início de uma Engine 3D, são apenas para estudos dos novos recursos. Ambas as classes foram escritas muito rapidamente, não há otimização alguma. =) [/update]

Cube 3D

/**
*
* @author	Erick Souza
* @website	http://blog.ericksouza.com
* @version	0.3
*
**/
 
package com.esouza.Flash3D.object
{
	import flash.display.*;
	import flash.events.*;
	import flash.net.*;
	import flash.geom.*;
	import flash.utils.getDefinitionByName;
 
	public class Cube extends Sprite
	{
		private var container:Sprite;
		private var vEdge:Vector.;
 
		static private var MATERIAL:Object = null;
		static private var BGCOLOR:Number;
		static private var KEEPRATIO:Boolean = false;
 
		static private var WIDTH:Number = 200;
		static private var HEIGHT:Number = 200;
		static private var DEPTH:Number = 200;
 
		static private var ROTATIONX:Number = 0;
		static private var ROTATIONY:Number = 0;
		static private var ROTATIONZ:Number = 0;
 
		public function Cube(_m:Object = null, _w:Number = 200, _h:Number = 200, _d:Number = 200):void
		{
			WIDTH = _w;
			HEIGHT = _h;
			DEPTH = _d;
			MATERIAL = _m;
		}
 
		public function draw():Sprite
		{
			this.container = new Sprite();
			this.container.z = 1;
 
			this.update();
 
			return this.container;
		}
 
		public function update():void
		{
			if(!MATERIAL) trace('Material null.');
 
			this.removeAllChild(this.container);
 
			this.vEdge = new Vector.();
 
			this.drawEdge('top',	90,	Vector3D.X_AXIS,	0,			-HEIGHT/2,	0);
			this.drawEdge('bottom', 90,	Vector3D.X_AXIS,	0,			HEIGHT/2,	0);
			this.drawEdge('front',	0,	Vector3D.Z_AXIS,	0,			0,			-DEPTH/2);
			this.drawEdge('back',	0,	Vector3D.Z_AXIS,	0,			0,			DEPTH/2);
			this.drawEdge('left',	90, Vector3D.Y_AXIS,	-WIDTH/2,	0,			0);
			this.drawEdge('right',	90, Vector3D.Y_AXIS,	WIDTH/2, 	0,			0);
 
			this.upDepth();
		}
 
		private function drawEdge(name:String, degrees:uint, axis:Vector3D, x:Number, y:Number, z:Number):void
		{
			var e:Sprite = this.edge(name);
			e.name = name;
 
			var m3:Matrix3D = new Matrix3D();
			m3.appendRotation(degrees, axis);
			m3.appendTranslation(x, y, z);
			e.transform.matrix3D = m3;
 
			this.container.addChild(e);
			this.vEdge.push(e);
		}
 
		private function edge(_name:String):Sprite
		{
			var name:String, type:String;
			var edge:Sprite = new Sprite();
			edge.name = _name;
 
			if(MATERIAL)
			{
				name = MATERIAL.all ? 'all' : _name;
				var mat:* = MATERIAL[name] ? MATERIAL[name] : BGCOLOR;
				type = this.checkTypeMat(mat);
			}
			else
			{
				this.drawBg(edge, BGCOLOR);
			}
 
			if(type == 'bmd')
			{
				var bm:Bitmap = materialBtm(MATERIAL[name], _name);
				bm.x = -bm.width/2;
				bm.y = -bm.height/2;
				edge.addChild(bm);
			}
			else if(type == 'number')
			{
				this.drawBg(edge, MATERIAL[name]);
			}
			else if(type == 'mc')
			{
				this.drawBg(edge, BGCOLOR);
				edge.addChild(this.applyMc(mat, _name));
			}
			else if(type == 'string')
			{
				this.drawBg(edge, BGCOLOR);
				this.loadImage(mat, edge);
			}
 
			return edge;
		}
 
		private function applyMc(_mat:Class, _name:String):MovieClip
		{
			var matName = _mat.toString().replace('[object ', '').replace('[class ', '').replace(']', '');
			var mat:Class = getDefinitionByName(matName) as Class;
 
			var mc:MovieClip = new mat();
			var objratio:Object = this.ratio(mc, _name);
 
			mc.scaleX = objratio.sx;
			mc.scaleY = objratio.sy;
			mc.x = -mc.width / 2;
			mc.y = -mc.height / 2;
 
			return mc;
		}
 
		private function drawBg(_face:Sprite, _color:Number):void
		{
			var o:Object = this.widthHeight(_face.name);
 
			if(!MATERIAL)	_face.graphics.lineStyle(1, 0x0000FF);
			else			_face.graphics.beginFill(_color);
 
			_face.graphics.drawRect(-o.w/2, -o.h/2, o.w, o.h);
			_face.graphics.endFill();
		}
 
		private function materialBtm(bmd:BitmapData, _name:String):Bitmap
		{
			var objratio:Object = this.ratio(bmd, _name);
 
			var m:Matrix = new Matrix();
			m.scale(objratio.sx, objratio.sy);
			m.tx = objratio.x;
			m.ty = objratio.y;
 
			var nbmd:BitmapData = new BitmapData(objratio.w, objratio.h, false, BGCOLOR);
			nbmd.draw(bmd, m, null, null, null, true);
			var bm:Bitmap = new Bitmap(nbmd);
			return bm;
		}
 
		private function loadImage(url:String, mc:Sprite):void
		{
			var lo:Loader = new Loader();
			lo.load(new URLRequest(url));
			mc.addChild(lo);
			lo.contentLoaderInfo.addEventListener(Event.INIT, onImageLoaded);
		}
 
		private function onImageLoaded(evt:Event):void
		{
			var mc:Sprite = Sprite(evt.currentTarget.content.parent.parent);
 
			var bmd:BitmapData = new BitmapData(evt.target.content.width, evt.target.content.height);
			bmd.draw(evt.target.content);
 
			var bm:Bitmap = materialBtm(bmd, mc.name);
			bm.x = -bm.width/2;
			bm.y = -bm.height/2;
 
			mc.removeChild(evt.target.content.parent);
			mc.addChild(bm);
		}
 
		private function checkTypeMat(_mat:*):String
		{
			var type:String = 'mc';
 
			if(typeof _mat == 'number' || typeof _mat == 'string')	type = typeof _mat;
			else if(String(_mat as BitmapData) != 'null')			type = 'bmd';
 
			return type;
		}
 
		private function ratio(obj:Object, _name:String = null):Object
		{
			var o:Object = this.widthHeight(_name);
			var r:Number = obj.width / obj.height;
			var w:Number, h:Number;
 
			if(obj.width >= o.w){w = o.w; h = Math.round(w / r);}
			if(h >= o.h){h = o.h; w = Math.round(h / r);}
 
			var sx:Number = ((w / obj.width) * 10) / 10;
			var sy:Number = ((h / obj.height) * 10) / 10;
			var ox:Number = (o.w - w) / 2;
			var oy:Number = (o.h - h) / 2;
 
			if(!KEEPRATIO){sx = o.w / obj.width; sy = o.h / obj.height; ox = 0; oy = 0;}
 
			return {sx: sx, sy: sy, x: ox, y: oy, w: o.w, h: o.h};
		}
 
		private function widthHeight(_faceName:String):Object
		{
			var w:Number, h:Number;
 
			if(_faceName == 'top' || _faceName == 'bottom')		{ w = WIDTH; h = DEPTH; }
			else if(_faceName == 'front' || _faceName == 'back'){ w = WIDTH; h = HEIGHT; }
			else if(_faceName == 'right' || _faceName == 'left'){ w = DEPTH; h = HEIGHT; }
 
			return {w: w, h: h};
		}
 
		public function upDepth():void
		{
			this.vEdge.sort(reorder);
			var n:uint = this.vEdge.length;
			while(n--) this.container.setChildIndex(this.vEdge[n], this.vEdge.length-1);
		}
 
		private function reorder(x:Sprite, y:Sprite):Number
		{
			return x.z - y.z;
		}
 
		private function doRotation(_value:Number, axis:Vector3D):void
		{
			var n:uint = this.vEdge.length;
			while(n--) Sprite(this.container.getChildAt(n)).transform.matrix3D.appendRotation(_value, axis);
			this.upDepth();
		}
 
		private function removeAllChild(_container:Sprite):void
		{
			var n:int = _container.numChildren;
			for(var i:uint = 0; i < n; i++) _container.removeChild(_container.getChildAt(0));
		}
 
		//GATTER : SETTER
 
		public function set material(_obj:Object):void
		{
			MATERIAL = _obj;
		}
 
		public function get material():Object
		{
			return MATERIAL;
		}
 
		override public function set rotationX(_value:Number):void
		{
			ROTATIONX = ROTATIONX - _value;
			this.doRotation(ROTATIONX, Vector3D.Y_AXIS);
			ROTATIONX = _value;
		}
 
		override public function get rotationX():Number
		{
			return ROTATIONX;
		}
 
		override public function set rotationY(_value:Number):void
		{
			ROTATIONY = ROTATIONY - _value;
			this.doRotation(ROTATIONY, Vector3D.X_AXIS);
			ROTATIONY = _value;
		}
 
		override public function get rotationY():Number
		{
			return ROTATIONY;
		}
 
		override public function set rotationZ(_value:Number):void
		{
			ROTATIONZ = ROTATIONZ - _value;
			this.doRotation(ROTATIONZ, Vector3D.Z_AXIS);
			ROTATIONZ = _value;
		}
 
		override public function get rotationZ():Number
		{
			return ROTATIONZ;
		}
 
		override public function set width(_value:Number):void
		{
			WIDTH = _value;
		}
 
		override public function get width():Number
		{
			return WIDTH;
		}
 
		override public function set height(_value:Number):void
		{
			HEIGHT = _value;
		}
 
		override public function get height():Number
		{
			return HEIGHT;
		}
 
		public function set depth(_value:Number):void
		{
			DEPTH = _value;
		}
 
		public function get depth():Number
		{
			return DEPTH;
		}
 
		public function set keepRatio(_b:Boolean):void
		{
			KEEPRATIO = _b;
		}
 
		public function get keepRatio():Boolean
		{
			return KEEPRATIO;
		}
 
		public function set bgcolor(_n:Number):void
		{
			BGCOLOR = _n;
		}
 
		public function get bgcolor():Number
		{
			return BGCOLOR;
		}
	}
}

Sphere 3D

/**
*
* @author	Erick Souza
* @website	http://blog.ericksouza.com
* @version	0.2
*
**/
 
package com.esouza.Flash3D.object
{
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
 
	public class Sphere extends Sprite
	{
		private var container:Sprite;
 
		private var vertices:Vector.;
		private var indices:Vector.;
		private var uvt:Vector.;
		private var pvertices:Vector.;
 
		private var perspective:PerspectiveProjection;
		private var m3:Matrix3D;
 
		static private var MATERIAL:BitmapData;
		static private var ROTATIONX:Number = 0;
		static private var ROTATIONY:Number = 0;
		static private var ROTATIONZ:Number = 0;
		static private var RADIUS:Number = 5;
 
		public function Sphere(_m:BitmapData = null, _r:Number = 5):void
		{
			MATERIAL = _m;
			RADIUS = _r;
		}
 
		public function draw():Sprite
		{
			this.container = new Sprite();
 
			this.makeVectors();
			this.update();
 
			return this.container;
		}
 
		private function makeVectors():void
		{
			this.vertices = new Vector.();
			this.uvt = new Vector.();
			this.indices = new Vector.();
 
			var x:Number, y:Number, fX:Number, fY:Number, fZ:Number;
			var w:int = 360/10, h:int = 180/10, loop:uint = 0;
 
			for (var i:uint = 0 ; i < w; i++)
			{
				for (var n:uint = 0 ; n < h; n++)
				{
					x = (i / (w - 1)) * 2;
					y = (n / (h - 1) - .5);
 
					fX = Math.cos(y * Math.PI) *  Math.cos(x * Math.PI);
					fY = Math.sin(y * Math.PI);
					fZ = Math.cos(y * Math.PI) *  Math.sin(x * Math.PI);
 
					this.vertices.push(fX * RADIUS, fY * RADIUS, fZ * RADIUS);
					this.uvt.push(i / (w - 1), n / (h - 1), 0);
 
					if(n < h - 1) this.indices.push(loop, loop+h+1, loop+1, loop+h, loop+h+1, loop++);
				}
				loop++;
			}
		}
 
		public function update():void
		{
			this.perspective = new PerspectiveProjection();
			this.pvertices = new Vector.();
 
			this.m3 = perspective.toMatrix3D();
			this.m3.prependTranslation(0, 0, 1);
 
			this.m3.prependRotation(ROTATIONX - 90,	Vector3D.Y_AXIS);
			this.m3.prependRotation(ROTATIONY,	Vector3D.X_AXIS);
			this.m3.prependRotation(ROTATIONZ,		Vector3D.Z_AXIS);
 
			Utils3D.projectVectors(this.m3,this.vertices, this.pvertices, this.uvt);
 
			this.container.graphics.clear();
			if(MATERIAL) this.container.graphics.beginBitmapFill(MATERIAL, null, false, true);
			else this.container.graphics.lineStyle(1, 0x0000FF);
			this.container.graphics.drawTriangles(this.pvertices, this.indices, this.uvt, TriangleCulling.NEGATIVE);
			this.container.graphics.endFill();
		}
 
		//GATTER : SETTER
 
		public function set material(_m:BitmapData):void
		{
			MATERIAL = _m;
		}
 
		public function get material():BitmapData
		{
			return MATERIAL;
		}
 
		public function set radius(_r:Number):void
		{
			RADIUS = _r;
		}
 
		public function get radius():Number
		{
			return RADIUS;
		}
 
		override public function set rotationX(_value:Number):void
		{
			ROTATIONX = _value;
			this.update();
		}
 
		override public function get rotationX():Number
		{
			return ROTATIONX;
		}
 
		override public function set rotationY(_value:Number):void
		{
			ROTATIONY = _value;
			this.update();
		}
 
		override public function get rotationY():Number
		{
			return ROTATIONY;
		}
 
		override public function set rotationZ(_value:Number):void
		{
			ROTATIONZ = _value;
			this.update();
		}
 
		override public function get rotationZ():Number
		{
			return ROTATIONZ;
		}
	}
}

Posts anteriores a respeito.

3 Responses to “Script Cube Sphere 3D no Flash CS4”

  1. kvyn Says:

    Thanks for the update…this is really cool.
    1. Based on you knowledge is it possible to dynamically scale the object’s sides to makes it a box like shape instead of a dvd size etc ?

    2. Is it possible to dynamically mask bitmap materials

  2. Tiago Diaz Says:

    Opa, tudo bem erick? Atualmente eu estava minerando na internet mais informações sobre drawEdges e descobri que ambos estamos aprimorando e estudando a mesma coisa… Gostaria de saber se você está afim de montar uma equipe comigo para montarmos uma engine 3D Baseanda no Flash CS4 ++, tenho um bom conhecimento em OOP e sou especialista em interatividade a alguns anos… Se estiver interessado entre em contato comigo!

    Seu trabalho ficou muito bom! Eu já consegui fazer alguns outros objetos 3D como Torus, Cilindro, etc…

    Grato pela atenção…

  3. Leandro Says:

    Olá Erick,

    Gostaria de saber se você tem um .fla com exemplo do cubo e da esfera, pois estou com dificuldades para usar estas classes, o tempo todo esta dando erro, hehe, tentei arrumar o que estava dando erro e no fim não funcionou.

    Bem, devo estar fazendo algo errado, mas não descobri o que, se você puder passar um exemplo agradeço muito.

    Desculpe o incomodo e parabéns pelo trabalho, você é fera.

Leave a Reply