In ActionScript führen Sie Bitmaptransformationen mithilfe der
Graphics.drawTriangles()
-Methode durch, da 3D-Modelle durch eine Sammlung von Dreiecken im Raum dargestellt werden. (Allerdings unterstützen Flash Player und AIR keinen Tiefenpuffer, sodass Anzeigeobjekte im Prinzip weiterhin flach, d. h. zweidimensional, sind. Dies wird beschrieben unter
Informationen zu 3D-Anzeigeobjekten in Flash Player und der AIR-Laufzeitumgebung
.) Die
Graphics.drawTriangles()
-Methode funktioniert ähnlich wie die
Graphics.drawPath()
-Methode, da zum Zeichnen eines Dreieckpfads ebenfalls ein Satz an Koordinaten benötigt wird.
Um sich mit der Arbeit mit der
Graphics.drawPath()
-Methode vertraut zu machen, sollten Sie den Abschnitt
Zeichenpfade
lesen.
Die
Graphics.drawTriangles()
-Methode verwendet die Syntax „Vector.<Number>“, um die Position der Punkte für den Dreieckpfad anzugeben:
drawTriangles(vertices:Vector.<Number>, indices:Vector.<int> = null, uvtData:Vector.<Number> = null, culling:String = "none"):void
Der erste Parameter von
drawTriangles()
ist der einzige obligatorische Parameter, nämlich der Parameter
vertices
. Dieser Parameter ist ein Zahlenvektor, der die Koordinaten definiert, aus denen die Dreiecke gezeichnet werden. Alle drei Koordinatensets (sechs Zahlen) repräsentieren einen Dreieckpfad. Ohne den
indices
-Parameter sollte die Länge des Vektors immer das Sechsfache betragen, da jedes Dreieck drei Koordinatenpaare benötigt (d. h. drei Sätze an x/y-Werten). Zum Beispiel:
graphics.beginFill(0xFF8000);
graphics.drawTriangles(
Vector.<Number>([
10,10, 100,10, 10,100,
110,10, 110,100, 20,100]));
Keine dieser Dreiecke teilen sich einen Punkt, aber wenn das der Fall wäre, könnte der Wert mithilfe des zweiten
drawTriangles()
-Parameters,
indices
, verwendet werden, um die Werte im Vektor
vertices
für mehrere Dreiecke wiederzuverwenden.
Wenn Sie den
indices
-Parameter verwenden, sollten Sie sich darüber im Klaren sein, dass die
indices
-Werte Punktindizes sind und keine Indizes, die sich direkt auf die
vertices
-Arrayelemente beziehen. Anders ausgedrückt: Eine durch
indices
im
vertices
-Vektor definierte Indexposition ist in Wahrheit die echte Indexposition dividiert durch 2. Für den dritten Punkt eines
vertices
-Vektors verwenden Sie beispielsweise den
indices
-Wert 2, obwohl der erste numerische Wert dieses Punkts bei der Vektorindexposition 4 beginnt.
Sie können zum Beispiel zwei Dreiecke mithilfe des
indices
-Parameters so zusammenführen, dass sie sich in der Diagonale eines Vierecks eine Kante teilen:
graphics.beginFill(0xFF8000);
graphics.drawTriangles(
Vector.<Number>([10,10, 100,10, 10,100, 100,100]),
Vector.<int>([0,1,2, 1,3,2]));
Beachten Sie, dass im
vertices
-Vektor nur vier Punkte angegeben wurden, obwohl ein Quadrat unter Verwendung von zwei Dreiecken gezeichnet wurde. Durch die Verwendung von
indices
werden die beiden Punkte, die beide Dreiecke gemeinsam haben, für jedes Dreieck verwendet. Dadurch reduziert sich die Gesamtzahl der Vertizes von 6 (12 Zahlen) auf 4 (8 Zahlen):
Ein mithilfe des vertices-Parameters aus zwei Dreiecken gezeichnetes Quadrat
Je größer die Dreieckgitter, desto nützlicher wird diese Technik, da dabei die meisten Punkte von mehreren Dreiecken geteilt werden.
Auf Dreiecke können alle Füllungen angewendet werden. Die Füllungen werden auf das resultierende Dreieckgitter wie auf jede sonstige Form angewendet.
Transformieren von Bitmaps
Bitmaptransformationen schaffen die Illusion von Perspektive oder „Textur“ auf einem dreidimensionalen Objekt. Insbesondere können Sie eine Bitmap zum Fluchtpunkt hin verzerren, sodass das Bild kleiner zu werden scheint, während es sich dem Fluchtpunkt nähert. Sie können auch eine zweidimensionale Bitmap verwenden, um eine Oberfläche für ein dreidimensionales Objekt zu erstellen und so den Eindruck erwecken als ob die Textur das dreidimensionale Objekt umwickelte.
Eine zweidimensionale Oberfläche, die einen Fluchtpunkt verwendet und ein von einer Bitmap umwickeltes dreidimensionales Objekt
UV-Zuordnung
Wenn Sie erst einmal mit der Arbeit mit Texturen begonnen haben, werden Sie auch den uvtData-Parameter von
drawTriangles()
verwenden wollen. Dieser Parameter ermöglicht es Ihnen, die UV-Zuordnung für Bitmapfüllungen einzurichten.
Die UV-Zuordnung ist ein Verfahren zur Texturierung von Objekten. Sie ist von zwei Werten abhängig, einem horizontalen U-Wert (x) und einem vertikalen V-Wert (y). Diese basieren nicht auf Pixelwerten, sondern auf Prozentwerten. 0 U und 0 V bezeichnet die Bildecke links oben und 1 U und 1 V die Bildecke rechts unten:
Die Positionen UV 0 und 1 auf einem Bitmapbild
Die Vektoren eines Dreiecks können als UV-Koordinaten angegeben werden, um sich mit den entsprechenden Positionen in einem Bild zu verbinden:
Die UV-Koordinaten eines Dreieckbereichs aus einem Bitmapbild
Die UV-Werte bleiben mit den Punkten des Dreiecks konsistent:
Die Vertizes des Dreiecks werden verschoben und die Bitmap wird verzerrt, um den UV-Wert für einen einzelnen Punkt unverändert zu lassen:
Während auf das mit der Bitmap verbundene Dreieck ActionScript-3D-Transformationen angewendet werden, wird das Bitmapbild aufgrund der UV-Werte auf das Dreieck angewendet. Anstatt also Matrixberechnungen zu verwenden, werden einfach die UV-Werte gesetzt oder angepasst, um einen dreidimensionalen Effekt zu erschaffen.
Die
Graphics.drawTriangles()
-Methode akzeptiert auch eine optionale Information für dreidimensionale Transformationen: den T-Wert. Der T-Wert in „uvtData“ repräsentiert die 3D-Perspektive, oder genauer: den Skalierungsfaktor des verbundenen Vertex. Die UVT-Zuordnung ergänzt die UV-Zuordnung um perspektivische Korrekturen. Wenn ein Objekt beispielsweise in einem 3D-Raum vom Betrachterstandpunkt entfernt positioniert wird, sodass es nur 50 % der „Originalgröße“ zu haben scheint, würde der T-Wert dieses Objekts 0,5 betragen. Da Dreiecke gezeichnet werden, um die Objekte im 3D-Raum zu repräsentieren, bestimmen deren Positionen auf der z-Achse deren T-Werte. Die Gleichung, die den T-Wert bestimmt, lautet wie folgt:
T = focalLength/(focalLength + z);
In dieser Gleichung steht „focalLength“ für die Brennweite oder eine berechnete Bildschirmposition, die bestimmt, wie stark die Perspektive in dieser Sicht ist.
Die Brennweite und der z-Wert
-
A.
-
Standpunkt
-
B.
-
Bildschirm
-
C.
-
3D-Objekt
-
D.
-
focalLength-Wert (Brennweite)
-
E.
-
z-Wert
Der Wert von T wird verwendet, um die Grundformen zu verkleinern, sodass sie scheinbar weiter entfernt sind. Mit diesem Wert werden in der Regel 3D-Punkte auf 2D-Punkte abgebildet. Im Fall der UVT-Daten wird er auch dazu verwendet, um eine Bitmap zwischen den Punkten innerhalb eines Dreiecks mit Perspektive zu skalieren.
Wenn Sie UVT-Werte definieren, folgt der T-Wert direkt den UV-Werten für einen Vertex. Wird der T-Wert miteinbezogen, sind alle drei Werte im
uvtData
-Parameter (U, V und T) stimmig mit den beiden Werten im
vertices
-Parameter (x und y). Mit UV-Werten allein ist uvtData.length == vertices.length. Unter Miteinbeziehung eines T-Werts ist uvtData.length == 1,5*vertices.length.
Im folgenden Beispiel wird gezeigt, wie eine Fläche mithilfe von TVT-Daten im 3D-Raum gedreht werden kann. In diesem Beispiel wird das Bild
„ocean.jpg“ mithilfe der „Hilfsklasse“ „ImageLoader“ geladen, sodass es dem BitmapData-Objekt zugewiesen werden kann.
Hier der Quellcode der ImageLoader-Klasse (speichern Sie diesen Code in eine Datei mit dem Namen „ImageLoader.as“):
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);
}
}
}
Es folgt das ActionScript-Codebeispiel, das Dreiecke, die UV-Zuordnung und T-Werte verwendet, um den Eindruck zu vermitteln, dass das Bild zum Fluchtpunkt hin kleiner wird und sich dreht. Speichern Sie diesen Code in eine Datei mit dem Namen „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);
}
}
}
Um dieses Beispiel zu testen, speichern Sie diese beiden Klassendateien im selben Verzeichnis als ein Bild mit dem Namen „ocean.jpg“. Sie können sehen, wie die Orignalbitmap so transformiert wird, dass sie den Eindruck vermittelt, als ob sie im 3D-Raum in der Ferne verschwindet und sich dreht.
Culling
Culling ist ein Verfahren zur Bestimmung der Oberflächen eines dreidimensionalen Objekts, die nicht gerendert werden sollen, da sie vom aktuellen Betrachterstandpunkt aus nicht zu sehen sind. Im dreidimensionalen Raum ist die Oberfläche der Rückseite eines dreidimensionalen Objekts vom Sichtbereich ausgeschlossen.
Die Rückseite eines 3D-Objekts ist vom Sichtbereich ausgeschlossen
-
A.
-
Standpunkt
-
B.
-
3D-Objekt
-
C.
-
Rückseite des 3D-Objekts
Normalerweise werden immer alle Dreiecke gerendert, unabhängig von ihrer Größe, Form oder Position. Das Cullingverfahren stellt sicher, dass Flash Player oder AIR Ihre 3D-Objekte korrekt rendert. Für kürzere Renderzeiten sollten bestimmte Dreiecke vom Renderprozess ausgeschlossen werden. Stellen Sie sich z. B. einen Würfel vor, der sich im Raum dreht. Egal, zu welchem Zeitpunkt, Sie werden nie mehr als drei Seiten dieses Würfels zu Gesicht bekommen, da sich die anderen Seiten auf der Rückseite des Würfels befinden. Und da diese Seiten verdeckt sind, sollte der Renderer sie auch nicht berechnen und zeichnen. Ohne Culling rendert Flash Player oder AIR sowohl die Vorder- als auch die Rückseite des Würfels.
Ein Würfel hat Seiten, die vom aktuellen Betrachterstandpunkt nicht zu sehen sind
Daher besitzt die
Graphics.drawTriangles()
-Methode einen vierten Parameter zum Festlegen des Cullingwertes:
public function drawTriangles(vertices:Vector.<Number>, indices:Vector.<int> = null, uvtData:Vector.<Number> = null, culling:String = "none"):void
Dieser Parameter gehört zur
TriangleCulling
-Aufzählungsklasse und kann die Werte
TriangleCulling.NONE
,
TriangleCulling.POSITIVE
und
TriangleCulling.NEGATIVE
annehmen. Diese Werte sind abhängig von der Richtung des Dreieckpfads, der die Oberfläche des Objekts definiert. Die ActionScript-API, die das Culling steuert, setzt voraus, dass alle nach außen gerichteten Dreiecke einer dreidimensionalen Form in derselben Pfadrichtung gezeichnet werden. Wenn ein Dreieck umgedreht wird, ändert sich auch dessen Pfadrichtung. An diesem Punkt kann das Dreieck „ausgelesen“ und vom Renderprozess ausgeschlossen werden.
Der
TriangleCulling
-Wert
POSITIVE
schließt alle Dreiecke mit positiver Pfadrichtung (im Uhrzeigersinn) aus. Der
TriangleCulling
-Wert
NEGATIVE
schließt alle Dreiecke mit negativer Pfadrichtung (entgegen dem Uhrzeigersinn) aus. Bei einem Würfel haben die Oberflächen der Vorderseite eine positive Pfadrichtung und die der Rückseite eine negative:
Ein „aufgeklappter“ Würfel, in dem die Pfadrichtung angezeigt wird. Im „zusammengeklappten“ Zustand ist die Pfadrichtung der Rückseite umgekehrt
Um zu sehen, wie das Cullingverfahren funktioniert, beginnen Sie mit dem Beispiel aus dem Abschnitt
UV-Zuordnung
und setzen Sie den culling-Parameter der
drawTriangles()
-Methode auf
TriangleCulling.NEGATIVE
:
container.graphics.drawTriangles(vertices, indices, uvtData, TriangleCulling.NEGATIVE);
Beachten Sie, dass die jeweilige Rückseite des Bildes beim Drehen des Objekts nicht dargestellt wird.
|
|
|