Dans ActionScript, vous effectuez des transformations de bitmap à l’aide de la méthode
Graphics.drawTriangles()
, car les modèles 3D sont représentés par un ensemble de triangles dans l’espace. (Flash Player et AIR ne prennent néanmoins pas en charge une mémoire tampon de profondeur, car les objets d’affichage sont toujours essentiellement plats, ou 2D. Pour plus d'informations, voir
Présentation des objets d’affichage 3D dans les moteurs d’exécution de Flash Player et d’AIR
.) La méthode
Graphics.drawTriangles()
est similaire à la méthode
Graphics.drawPath()
, en ce qu’elle accepte un ensemble de coordonnées pour tracer un tracé triangulaire.
Pour vous familiariser avec l’utilisation de
Graphics.drawPath()
, voir
Tracés de dessin
.
La méthode
Graphics.drawTriangles()
utilise une propriété Vector.<Number> pour spécifier l’emplacement des points sur le tracé triangulaire :
drawTriangles(vertices:Vector.<Number>, indices:Vector.<int> = null, uvtData:Vector.<Number> = null, culling:String = "none"):void
Le premier paramètre de
drawTriangles()
,
vertices
, est le seul paramètre obligatoire. C’est un vecteur de nombres définissant les coordonnées par lesquelles vos triangles sont tracés. Trois ensembles de coordonnées (six nombres) représentent un tracé triangulaire. Sans le paramètre
indices
, la longueur du vecteur doit systématiquement être un facteur de six, car chaque triangle nécessite trois paires de coordonnées (trois ensembles de deux valeurs x/y). Exemple :
graphics.beginFill(0xFF8000);
graphics.drawTriangles(
Vector.<Number>([
10,10, 100,10, 10,100,
110,10, 110,100, 20,100]));
Ces triangles n’ont pas de points en commun, mais si tel était le cas, le second paramètre de
drawTriangles()
,
indices
, permettrait de réutiliser des valeurs du vecteur
vertices
pour plusieurs triangles.
Lorsque vous utilisez le paramètre
indices
, gardez à l’esprit le fait que les valeurs
indices
représentent des index de point, pas des index en rapport direct avec les éléments du tableau
vertices
. En d’autres termes, un index du vecteur
vertices
tel qu’il est défini par
indices
correspond en fait à l’index réel divisé par 2. Pour le troisième point d’un vecteur
vertices
, par exemple, utilisez une valeur
indices
de 2, même si la première valeur numérique de ce point commence à l’index vectoriel 4.
Par exemple, fusionnez deux triangles de sorte qu’ils aient en commun le bord diagonal, par le biais du paramètre
indices
:
graphics.beginFill(0xFF8000);
graphics.drawTriangles(
Vector.<Number>([10,10, 100,10, 10,100, 100,100]),
Vector.<int>([0,1,2, 1,3,2]));
Vous remarquerez que, bien qu’un carré résulte du tracé de deux triangles, seuls quatre points ont été spécifiés dans le vecteur
vertices
. Grâce à
indices
, les deux points partagés par les deux triangles sont réutilisés pour chacun d’eux. Le nombre total de sommets passe donc de 6 (12 nombres) à 4 (8 nombres).
Carré tracé à l’aide de deux triangles à l’aide du paramètre vertices
Cette technique s’avère utile pour les maillages triangulaires plus grands, dans lesquels la plupart des points sont partagés par plusieurs triangles.
Il est possible d’appliquer tous les remplissages aux triangles. Ils sont appliqués au maillage triangulaire résultant comme ils le seraient à toute autre forme.
Transformation d’images bitmap
Les transformations de bitmap donnent une illusion de perspective ou « texture » à un objet en trois dimensions. Vous pouvez notamment distordre une bitmap en direction d’un point de fuite, afin que l’image semble diminuer à mesure qu’elle se rapproche de celui-ci. Vous pouvez aussi utiliser une bitmap en deux dimensions pour créer une surface sur un objet en trois dimensions, donnant ainsi l’impression qu’il possède une texture ou « enveloppe ».
Surface en deux dimensions utilisant un point de fuite et objet en trois dimensions enveloppé dans une bitmap
Mappage des coordonnées UV
Lorsque vous commencerez à manipuler les textures, vous souhaiterez utiliser le paramètre uvtData de
drawTriangles()
. Ce paramètre vous permet de définir le mappage des coordonnées UV pour les remplissages de bitmap.
Le mappage des coordonnées UV est une méthode d’application d’une texture à des objets. Il repose sur deux valeurs, une valeur U horizontale (x) et une valeur V verticale (y). Ces valeurs sont basées sur des pourcentages et non sur des valeurs de pixels. 0 U et 0 V correspondent au coin supérieur gauche d’une image, 1 U et 1 V à son coin inférieur droit :
Emplacements UV 0 et 1 sur une image bitmap
Il est possible d’affecter des coordonnées UV aux vecteurs d’un triangle de sorte qu’ils s’associent aux emplacements respectifs sur une image :
Coordonnées UV d’une zone triangulaire sur une image bitmap
Les valeurs UV restent en phase avec les points du triangle.
Les sommets du triangle se déplacent et l’image bitmap se distord pour que les valeurs UV d’un point individuel restent identiques.
Au fur et à mesure que des transformations 3D ActionScript sont appliquées au triangle associé à la bitmap, celle-ci est appliquée au triangle en fonction des valeurs UV. Par conséquent, au lieu d’utiliser des calculs matriciels, définissez ou réglez les valeurs UV pour créer un effet tridimensionnel.
La méthode
Graphics.drawTriangles()
accepte également une information facultative pour les transformations tridimensionnelles : la valeur T. La valeur T de uvtData représente la perspective 3D ou, plus spécifiquement, le facteur d’échelle du sommet associé. Le mappage des coordonnées UVT ajoute une correction de perspective au mappage des coordonnées UV. Par exemple, si un objet de l’espace 3D est éloigné du point de vue de telle sorte qu’il semble mesurer 50 % de sa taille « d’origine », sa valeur T correspond à 0,5. Comme les objets de l’espace 3D sont représentés à l’aide de triangles, l’emplacement de ceux-ci le long de l’axe z détermine leur valeur T. L’équation qui représente la valeur T est la suivante :
T = focalLength/(focalLength + z);
Dans cette équation, focalLength représente une distance focale ou un emplacement à l’« écran » calculé qui détermine la quantité de perspective de l’affichage.
Distance focale et valeur z
-
A.
-
point de vue
-
B.
-
écran
-
C.
-
objet 3D
-
D.
-
valeur focalLength
-
E.
-
valeur z
La valeur T permet de mettre à l’échelle des formes simples pour donner l’impression qu’elles se trouvent au loin. C’est généralement la valeur utilisée pour convertir les points 3D en points 2D. Dans le cas des données UVT, elle permet aussi de mettre à l’échelle une bitmap entre les points d’un triangle avec perspective.
Lorsque vous définissez des valeurs UVT, la valeur T suit directement les valeurs UV définies pour un sommet. Avec l’inclusion de T, chaque trio de valeurs du paramètre
uvtData
(U, V et T) correspond à chaque paire de valeurs du paramètre
vertices
(x et y). Avec les valeurs UV seules, uvtData.length == vertices.length. Avec l’inclusion d’une valeur T, uvtData.length = 1,5*vertices.length.
L’exemple suivant illustre un plan qui pivote, par le biais de données UVT, dans un espace 3D. Il utilise l’image ocean.jpg et une classe « d’interaction », ImageLoader, qui charge l’image afin qu’il soit possible de l’affecter à l’objet BitmapData.
La source de la classe ImageLoader (enregistrez ce code dans le fichier ImageLoader.as) se présente comme suit :
package {
import flash.display.*
import flash.events.*;
import flash.net.URLRequest;
public class ImageLoader extends Sprite {
public var url:String;
public var bitmap:Bitmap;
public function ImageLoader(loc:String = null) {
if (loc != null){
url = loc;
loadImage();
}
}
public function loadImage():void{
if (url != null){
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onIoError);
var req:URLRequest = new URLRequest(url);
loader.load(req);
}
}
private function onComplete(event:Event):void {
var loader:Loader = Loader(event.target.loader);
var info:LoaderInfo = LoaderInfo(loader.contentLoaderInfo);
this.bitmap = info.content as Bitmap;
this.dispatchEvent(new Event(Event.COMPLETE));
}
private function onIoError(event:IOErrorEvent):void {
trace("onIoError: " + event);
}
}
}
Le code ActionScript qui utilise des triangles, le mappage des coordonnées UV et des valeurs T pour que l’image semble pivoter et diminuer au fur et à mesure qu’elle se rapproche d’un point de fuite est indiqué ci-dessous. Enregistrez-le dans un fichier que vous nommerez Spinning3dOcean.as :
package {
import flash.display.*
import flash.events.*;
import flash.utils.getTimer;
public class Spinning3dOcean extends Sprite {
// plane vertex coordinates (and t values)
var x1:Number = -100, y1:Number = -100, z1:Number = 0, t1:Number = 0;
var x2:Number = 100, y2:Number = -100, z2:Number = 0, t2:Number = 0;
var x3:Number = 100, y3:Number = 100, z3:Number = 0, t3:Number = 0;
var x4:Number = -100, y4:Number = 100, z4:Number = 0, t4:Number = 0;
var focalLength:Number = 200;
// 2 triangles for 1 plane, indices will always be the same
var indices:Vector.<int>;
var container:Sprite;
var bitmapData:BitmapData; // texture
var imageLoader:ImageLoader;
public function Spinning3dOcean():void {
indices = new Vector.<int>();
indices.push(0,1,3, 1,2,3);
container = new Sprite(); // container to draw triangles in
container.x = 200;
container.y = 200;
addChild(container);
imageLoader = new ImageLoader("ocean.jpg");
imageLoader.addEventListener(Event.COMPLETE, onImageLoaded);
}
function onImageLoaded(event:Event):void {
bitmapData = imageLoader.bitmap.bitmapData;
// animate every frame
addEventListener(Event.ENTER_FRAME, rotatePlane);
}
function rotatePlane(event:Event):void {
// rotate vertices over time
var ticker = getTimer()/400;
z2 = z3 = -(z1 = z4 = 100*Math.sin(ticker));
x2 = x3 = -(x1 = x4 = 100*Math.cos(ticker));
// calculate t values
t1 = focalLength/(focalLength + z1);
t2 = focalLength/(focalLength + z2);
t3 = focalLength/(focalLength + z3);
t4 = focalLength/(focalLength + z4);
// determine triangle vertices based on t values
var vertices:Vector.<Number> = new Vector.<Number>();
vertices.push(x1*t1,y1*t1, x2*t2,y2*t2, x3*t3,y3*t3, x4*t4,y4*t4);
// set T values allowing perspective to change
// as each vertex moves around in z space
var uvtData:Vector.<Number> = new Vector.<Number>();
uvtData.push(0,0,t1, 1,0,t2, 1,1,t3, 0,1,t4);
// draw
container.graphics.clear();
container.graphics.beginBitmapFill(bitmapData);
container.graphics.drawTriangles(vertices, indices, uvtData);
}
}
}
Pour tester cet exemple, enregistrez ces deux fichiers de classe dans le même répertoire qu’une image nommée « ocean.jpg ». Vous pouvez constater la transformation appliquée à la bitmap d’origine pour qu’elle semble disparaître au loin et pivoter dans l’espace 3D.
Culling
Le culling est un processus qui détermine quelles surfaces d’un objet en trois dimensions ne doivent pas être rendues par le moteur de rendu car elles ne sont pas visibles à partir du point de vue actuel. Dans l’espace 3D, la surface « arrière » d’un objet en trois dimensions n’est pas visible à partir du point de vue.
L’arrière d’un objet 3D n’est pas visible à partir du point de vue.
-
A.
-
point de vue
-
B.
-
objet 3D
-
C.
-
arrière d’un objet en trois dimensions
Par essence, tous les triangles sont systématiquement rendus, quelles que soient leur taille, forme et position. Le culling (élimination) garantit que Flash Player ou AIR rend votre objet 3D correctement. En outre, pour éviter les cycles de rendu superflus, il est parfois souhaitable que le moteur de rendu omette certains triangles. Soit un cube en rotation dans l’espace. A tout moment donné, vous ne voyez jamais plus de trois de ses faces car celles qui ne sont pas visibles font face à l’autre direction, de l’autre côté du cube. Comme ces faces ne sont pas visibles, il est inutile que le moteur de rendu les trace. Sans élimination (culling), Flash Player ou AIR rend les faces avant et arrière.
Certaines faces d’un cube ne sont pas visibles à partir du point de vue actuel.
C’est pourquoi la méthode
Graphics.drawTriangles()
gère un quatrième paramètre qui permet de définir une valeur de culling :
public function drawTriangles(vertices:Vector.<Number>, indices:Vector.<int> = null, uvtData:Vector.<Number> = null, culling:String = "none"):void
Le paramètre culling correspond à une valeur de la classe d’énumération
TriangleCulling
:
TriangleCulling.NONE
,
TriangleCulling.POSITIVE
et
TriangleCulling.NEGATIVE
. Ces valeurs sont fonction de la direction du tracé triangulaire définissant la surface de l’objet. L’API ActionScript qui permet de déterminer le culling considère comme acquis que tous les triangles orientés vers l’extérieur d’une forme 3D sont tracés dans le même sens. Le retournement d’une face de triangle entraîne un changement de direction du tracé. A ce point, il est possible de supprimer le triangle du rendu.
Si la valeur de
TriangleCulling
est définie sur
POSITIVE
, les triangles dont le tracé a une direction positive (sens horaire) sont supprimés. Si la valeur de
TriangleCulling
est définie sur
NEGATIVE
, les triangles dont le tracé a une direction négative (sens antihoraire) sont supprimés. Dans le cas d’un cube, les surfaces orientées vers l’avant ont un tracé à la direction positive et les surfaces orientées vers l’arrière, un tracé à la direction négative.
Cube « déroulé » illustrant le sens du tracé. Lorsque le cube est « enroulé », le sens du tracé de la face arrière est inversé.
Pour comprendre le fonctionnement du processus d’élimination (culling), reprenez l’exemple de la section
Mappage des coordonnées UV
et définissez le paramètre de culling de la méthode
drawTriangles()
sur
TriangleCulling.NEGATIVE
:
container.graphics.drawTriangles(vertices, indices, uvtData, TriangleCulling.NEGATIVE);
Vous pouvez constater que la face « arrière » de l’image n’est pas rendue lorsque l’objet pivote.
|
|
|