Faire de la 3D avec la classe Graphics d'ASTRO (update)
Par Olivier Bugalotto le samedi, mai 17 2008, 21:53 - ASTRO - Lien permanent
La classe Graphics sous ASTRO se voit ajouter de nouvelles fonctionnalités qui utilisent à outrance les tableaux typés.
Il faut savoir qu'actuellement il n'y a pas de documentation, il faut donc se debrouiller tout seul mais un outil m'aide beaucoup : ClassBrowser
Voici un diagramme UML de la classe Graphics ainsi que d'autres qui seront très utiles :

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 :
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 :

Le code suivant crée une surface carré qui effectue une rotation sur l'axe Y :
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("\n"); } } }
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 :
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... 

Commentaires
Hey,
enfin un français en avance sur les autres, ton site est une mine d'or.
Petite question quand tu dis que la classe Matrix3D est buggée, tu parles pour la méthode appendRotation ?
++
Salut, merci à toi cela fait plaisir
Tout a fait la méthode Matrix3D.appendRotation() à un gros bug mais le player est en version prerelease, il faut attendre encore un peu
Pour la docs :

http://download.macromedia.com/pub/...
Salut et merci pour l'info, j'aurais préféré qu'elle soit disponible plus tôt