Voici un diagramme UML de la classe Graphics ainsi que d'autres qui seront très utiles :

api-graphics-astro.jpg

La méthode drawPath

Dessiner avec l'API de flash en version 8 n'était pas des plus simple avec les méthodes : lineTo, moveTo, curveTo
Depuis la version 9 nous avons vu apparaître de nouvelles méthodes comme : drawRect, drawEllipse, drawRoundRect, etc... pour nous facilité la vie et bien maintenant avec ASTRO, nous pouvons créer des chemins graphiques. Il suffit pour cela d'indiquer les commandes de dessin et une collection de points que la méthode drawPath utilisera pour nous faire un joli chemin :

[actionscript]
var commands:Vector.<int> = new Vector.<int>();
commands.push(GraphicsPathCommand.MOVE_TO,GraphicsPathCommand.LINE_TO,
			  GraphicsPathCommand.LINE_TO,GraphicsPathCommand.LINE_TO,
			  GraphicsPathCommand.LINE_TO,GraphicsPathCommand.LINE_TO,
			  GraphicsPathCommand.LINE_TO,GraphicsPathCommand.LINE_TO,
			  GraphicsPathCommand.LINE_TO,GraphicsPathCommand.LINE_TO,
			  GraphicsPathCommand.LINE_TO);

var vertices:Vector.<Number> = new Vector.<Number>();
vertices.push(10,10,40,10,40,20,20,20,20,30,30,30,30,40,20,40,20,60,10,60,10,10);

graphics.clear();
graphics.beginFill(0xff0000);
graphics.drawPath(commands,vertices);

voici le rendu (flash player 10) : path

Un peu de 3D

Nous allons utiliser le méthode drawPath pour faire un carré animé sur les axes X,Y et Z.

Le theorème de Thalès

La 3D n'est rien d'autre qu'une projection de points sur un plan, il suffit d'appliquer le théorème de Thalès :

perspective.gif

Le code suivant crée une surface carré qui effectue une rotation sur l'axe Y :

[actionscript]
package {
	import __AS3__.vec.Vector;
	
	import flash.display.*;
	import flash.events.Event;
	import flash.geom.*;
	import flash.text.TextField;

	[SWF(width=500,height=500)]
	public class Tutorial01Surface extends Sprite
	{
		private var surface:Sprite;
		private var commands:Vector.<int>;
		private var vertices:Vector.<Vector3D>;
		
		private const DELTA:Number = 5 * Math.PI / 180;
		private var eyez:Number = 300;
		
		public function Tutorial01Surface()
		{
			createConsole();
			addEventListener(Event.ENTER_FRAME,onRender);
			surface = new Sprite();
			addChild(surface);
			surface.x = stage.stageWidth / 2;
			surface.y = stage.stageHeight / 2;
			
			commands = new Vector.<int>();
			commands.push(GraphicsPathCommand.MOVE_TO,GraphicsPathCommand.LINE_TO,
						  GraphicsPathCommand.LINE_TO,GraphicsPathCommand.LINE_TO,
						  GraphicsPathCommand.LINE_TO);
			
			vertices = new Vector.<Vector3D>();
			vertices.push(new Vector3D(-100,100,0,1),
						  new Vector3D(100,100,0,1),
						  new Vector3D(100,-100,0,1),
						  new Vector3D(-100,-100,0,1),
						  new Vector3D(-100,100,0,1));
		}
		
		private function onRender(e:Event):void {
			var datas:Vector.<Number> = new Vector.<Number>();
	
			// Parcourt tous les points
			for(var i:int = 0; i < vertices.length; i++) {
				var vertex:Vector3D = vertices[i] as Vector3D;
				// Effectue une rotation sur l'axe Y
				vertex = vertices[i] = rotateY(DELTA,vertex);
				
				// Projection
				var xp:Number = vertex.x * eyez / (eyez + vertex.z);
				var yp:Number = vertex.y * eyez / (eyez + vertex.z);
				datas.push(xp,yp);
			}
			drawFace(commands,datas);
		}
		
		private function drawFace(cmds:Vector.<int>, vertices:Vector.<Number>):void {
			surface.graphics.clear();
			surface.graphics.lineStyle(1);
			surface.graphics.beginFill(0xff0000);
			surface.graphics.drawPath(cmds,vertices);
			surface.graphics.endFill();
		}
		
		private function rotateY(delta:Number, vertex:Vector3D):Vector3D {
			var cosTmp:Number = Math.cos(DELTA);
			var sinTmp:Number = Math.sin(DELTA);
			var xp:Number, zp:Number;
			
			xp = vertex.x * cosTmp - vertex.z * sinTmp;
			zp = vertex.x * sinTmp + vertex.z * cosTmp;
			return new Vector3D(xp,vertex.y,zp,1);
		}

		private var console:TextField;
		private function createConsole():void {
			console = new TextField();
			console.width = stage.stageWidth;
			console.height = stage.stageHeight;
			addChild(console);
		}
		
		private function write(msg:*):void {
			console.appendText(msg);
			console.appendText("
");
		}
	}
}

Voici le rendu (flash player 10) : Surface3D

Nous aurions pu utliser la classe Matrix3D pour effectuer des transformations mais cette dernière fait stopper net les navigateurs : IE, FF ou encore Safari.

Dessiner des triangles

La méthode drawTriangles est la méthode idéale pour faire de la 3D sans se prendre la tête mais bien entendu vous devez connaitre le fonctionnement sur la construction d'objet à partir de triangles (Polygon mesh). Reprennons le même que précédemment mais en lui ajoutant une texture :

[actionscript]
package {
	import __AS3__.vec.Vector;
	
	import flash.display.*;
	import flash.events.Event;
	import flash.geom.*;
	import flash.text.TextField;
	
	import mx.core.BitmapAsset;

	[SWF(width=500,height=500)]
	public class Tutorial01Surface extends Sprite
	{
		[Embed(source="assets/flash-logo.png")]
		private var LogoFlash:Class;
		
		private var surface:Sprite;

		private var vertices:Vector.<Vector3D>;
		private var indices:Vector.<int>;
		
		private const DELTA:Number = 5 * Math.PI / 180;
		private var eyez:Number = 200;
		
		private var texture:BitmapAsset;
		
		public function Tutorial01Surface()
		{
			texture = new LogoFlash();
			addEventListener(Event.ENTER_FRAME,onRender);
			surface = new Sprite();
			addChild(surface);
			surface.x = stage.stageWidth / 2;
			surface.y = stage.stageHeight / 2;
			
			vertices = new Vector.<Vector3D>();
			vertices.push(new Vector3D(-100,-100,0,1),
						  new Vector3D(100,-100,0,1),
						  new Vector3D(100,100,0,1),
						  new Vector3D(-100,100,0,1));
						  
			indices = new Vector.<int>();
			indices.push(0,1,3, 1,2,3);
		}
		
		private function onRender(e:Event):void {
			var datas:Vector.<Number> = new Vector.<Number>();
			var uvtData:Vector.<Number> = new Vector.<Number>();
			var uvts:Vector.<Number> = new Vector.<Number>();

			// Parcourt tous les points
			for(var i:int = 0; i < vertices.length; i++) {
				var vertex:Vector3D = vertices[i] as Vector3D;
				// Effectue une rotation sur l'axe Y
				vertex = vertices[i] = rotateY(DELTA,vertex);
				var uvt:Number = eyez / (eyez + vertex.z);
				uvts[i] = uvt;
				// Projection
				var xp:Number = vertex.x * uvt;
				var yp:Number = vertex.y * uvt;
				datas.push(xp,yp);
			}
			uvtData.push(0,0,uvts[0], 1,0,uvts[1], 1,1,uvts[2], 0,1,uvts[3]);
			drawFace(datas,indices,uvtData);
		}
		
		private function drawFace(vertices:Vector.<Number>, indices:Vector.<int>, uvtData:Vector.<Number>):void {
			surface.graphics.clear();
			surface.graphics.beginBitmapFill(texture.bitmapData);
			surface.graphics.drawTriangles(vertices,indices,uvtData);
			surface.graphics.endFill();
		}
		
		private function rotateY(delta:Number, vertex:Vector3D):Vector3D {
			var cosTmp:Number = Math.cos(DELTA);
			var sinTmp:Number = Math.sin(DELTA);
			var xp:Number, zp:Number;
			
			xp = vertex.x * cosTmp - vertex.z * sinTmp;
			zp = vertex.x * sinTmp + vertex.z * cosTmp;
			return new Vector3D(xp,vertex.y,zp,1);
		}
	}
}

Voici un aperçu (flash player 10) : Surface texturée

A suivre... ;)