Driehoeken gebruiken voor 3D-effecten

Flash Player 10 of hoger, Adobe AIR 1.5 of hoger

In ActionScript kunt u bitmaptransformaties uitvoeren met de methode Graphics.drawTriangles() , omdat 3D-modellen worden gerepresenteerd door een verzameling driehoeken in de ruimte. Flash Player en AIR ondersteunen echter geen dieptebuffer zodat weergaveobjecten zelf vlak, of 2D, zijn. Dit wordt beschreven in Inzicht in 3D-weergaveobjecten in Flash Player en de AIR-runtime .) De methode Graphics.drawTriangles() is vergelijkbaar met de methode Graphics.drawPath() omdat de methode een set coördinaten neemt om een driehoekpad te tekenen.

Zie voor meer informatie over het gebruik van Graphics.drawPath() , Tekenpaden .

De methode Graphics.drawTriangles() gebruikt een Vector.<Number> om de puntlocaties op te geven voor het driehoekpad:

drawTriangles(vertices:Vector.<Number>, indices:Vector.<int> = null, uvtData:Vector.<Number> = null, culling:String = "none"):void

De eerste parameter van drawTriangles() is de enige vereiste parameter: de parameter vertices . Deze parameter is een vector van getallen die de coördinaten definiëren waarmee de driehoeken worden getekend. Elke drie sets coördinaten (zes getallen) representeren een driehoekpad. Zonder de parameter indices zou de lengte van de vector altijd een factor van zes zijn omdat er voor elke driehoek drie coördinatenparen nodig zijn (drie sets van twee x/y-waarden). Bijvoorbeeld:

graphics.beginFill(0xFF8000); 
graphics.drawTriangles( 
    Vector.<Number>([ 
        10,10,  100,10,  10,100, 
        110,10, 110,100, 20,100]));

Geen van deze driehoeken heeft een gemeenschappelijk punt. Maar als dit wel het geval was, zou de tweede parameter van drawTriangles() - indices - kunnen worden gebruikt om waarden in de vector vertices opnieuw te gebruiken voor meer dan één driehoek.

Houd er bij het gebruik van de parameter indices rekening mee dat de waarden van indices puntindices zijn en geen indices die direct zijn gerelateerd aan de elementen van de array vertices . Met andere woorden: een index in de vector vertices zoals gedefinieerd door indices , is in feite de werkelijke index gedeeld door 2. Voor het derde punt van een vector vertices gebruikt u bijvoorbeeld de waarde 2 voor indices , ook al begint de eerste numerieke waarde van dat punt bij vectorindex 4.

In dit voorbeeld worden twee driehoeken samengevoegd met de parameter indices zodat ze dezelfde diagonale rand hebben:

graphics.beginFill(0xFF8000); 
graphics.drawTriangles( 
    Vector.<Number>([10,10, 100,10, 10,100, 100,100]), 
    Vector.<int>([0,1,2, 1,3,2]));

Zoals u ziet, wordt er een vierkant getekend met behulp van twee driehoeken, maar zijn er slechts vier punten opgegeven in de vector vertices . Met behulp van indices worden de twee punten die worden gedeeld door de twee driehoeken, opnieuw gebruikt voor elke driehoek. Hierdoor wordt het aantal vertices teruggebracht van 6 (12 getallen) naar 4 (8 getallen):

Een vierkant getekend met twee driehoeken met behulp van de parameter vertices

Deze techniek is nuttig bij grotere driehoeknetten waarbij de meeste punten worden gedeeld door meerdere driehoeken.

Alle vullingen kunnen worden toegepast op driehoeken. De vullingen worden op dezelfde manier toegepast op het resulterende driehoeknet als op een andere vorm.

Bitmaps transformeren

Bitmaptransformaties wekken de indruk van perspectief of "structuur" op een driedimensionaal object. Hiermee kunt u een bitmap vervormen in de richting van het verdwijnpunt waardoor de afbeelding steeds kleiner lijkt te worden als deze dichterbij het verdwijnpunt komt. Of u kunt een tweedimensionale bitmap gebruiken om een oppervlak te maken voor een driedimensionaal object, waarbij u de illusie wekt van structuur of een “wikkel” op dat driedimensionale object.

Een tweedimensionaal oppervlak met een verdwijnpunt en een driedimensionaal object waar overheen een bitmap is gewikkeld.

UV-toewijzing

Als u begint te werken met structuren, wilt u waarschijnlijk gebruikmaken van de parameter uvtData van drawTriangles() . Met deze parameter kunt u UV-toewijzing instellen voor bitmapvullingen.

UV-toewijzing is een methode voor het geven van structuur aan objecten. De methode is gebaseerd op twee waarden: een horizontale (x) U-waarde en een verticale (y) V-waarde. De waarden zijn niet gebaseerd op pixelwaarden, maar op percentages. 0 U en 0 V is helemaal linksboven in een afbeelding en 1 U en 1 V is helemaal rechtsonder:

De locaties UV 0 en 1 op een bitmapafbeelding

U kunt vectoren van een driehoek UV-coördinaten geven om deze zelf te koppelen aan de respectieve locaties op een afbeelding:

De UV-coördinaten van een driehoekig gebied van een bitmapafbeelding

De UV-waarden blijven consistent met de punten van de driehoek:

De hoekpunten van de driehoek worden verplaatst en de bitmap wordt vervormd om te zorgen dat de UV-waarden voor een individueel punt gelijk blijven

Aangezien 3D-transformaties in ActionScript worden toegepast op de driehoek die is gekoppeld aan de bitmap, wordt de bitmapafbeelding op basis van de UV-waarden toegepast op de driehoek. Dus in plaats van matrixberekeningen te gebruiken, kunt u de UV-waarden instellen of aanpassen om een driedimensionaal effect te creëren.

De methode Graphics.drawTriangles() accepteert ook optionele informatie voor driedimensionale transformaties: de T-waarde. De T-waarde in uvtData vertegenwoordigt het 3D-perspectief, of specifieker gezegd, de schaalfactor van het toegewezen hoekpunt (vertex). UVT-toewijzing voegt perspectiefcorrectie toe aan UV-toewijzing. Als een object bijvoorbeeld in de 3D-ruimte op afstand van het gezichtspunt is geplaatst zodat het 50% van de “oorspronkelijke” grootte lijkt te zijn, is de T-waarde van dat object 0.5. Aangezien driehoeken worden getekend om objecten in de 3D-ruimte te vertegenwoordigen, bepalen de locaties langs de z-as hun T-waarden. De T-waarde wordt bepaald met de volgende vergelijking:

T = focalLength/(focalLength + z);
In de vergelijking staat focalLength voor een brandpuntsafstand of een berekende locatie op het scherm die bepaalt hoeveel perspectief wordt toegevoegd aan de weergave.
De focuslengte en z-waarde
A.
gezichtspunt

B.
scherm

C.
3D-object

D.
waarde van focalLength

E.
z-waarde

Met behulp van de waarde van T worden basisvormen geschaald zodat ze verder weg lijken. Het is in het algemeen de waarde die wordt gebruikt om 3D-punten om te zetten in 2D-punten. Bij UVT-gegevens wordt de T-waarde ook gebruikt om een bitmap te schalen tussen de punten in een driehoek met perspectief.

Wanneer u UVT-waarden definieert, volgt de T-waarde direct de UV-waarden die zijn gedefinieerd voor een hoekpunt. Door de toevoeging van T komen alle drie waarden in de parameter uvtData (U, V en T) overeen met alle twee waarden in de parameter vertices (x en y). Met alleen UV-waarden geldt uvtData.length == vertices.length. Met de opname van een T-waarde geldt uvtData.length = 1,5*vertices.length.

In het volgende voorbeeld wordt een vlak getoond dat in de 3D-ruimte wordt geroteerd met behulp van UVT-gegevens. Het voorbeeld gebruikt de afbeelding ocean.jpg en de “helperklasse” ImageLoader, die de afbeelding ocean.jpg laadt zodat deze kan worden toegewezen aan het BitmapData-object.

Hier is de bron van de klasse ImageLoader. Sla deze code op in een bestand met de naam 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); 
    } 
    } 
}

En hier is het ActionScript waarin driehoeken, UV-toewijzing en T-waarden worden gebruikt om de afbeelding kleiner te laten worden in de richting van een verdwijnpunt en te laten roteren. Sla deze code op in een bestand met de naam 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); 
        } 
    } 
}

U kunt dit voorbeeld testen door deze twee klassenbestanden op te slaan in dezelfde map als de afbeelding "ocean.jpg". U kunt zien hoe de oorspronkelijke bitmap wordt getransformeerd zodat het lijkt of de bitmap verdwijnt in de verte en roteert in de 3D-ruimte.

Schifting

Schifting is het proces waarin wordt bepaald welke vlakken van een driedimensionaal object de renderer niet hoeft te renderen omdat ze vanuit het huidige gezichtspunt niet zichtbaar zijn. In de 3D-ruimte is het oppervlak aan de “achterzijde” van een driedimensionaal object verborgen vanuit het gezichtspunt.
De achterzijde van een 3D-object is niet zichtbaar vanuit het gezichtspunt.
A.
gezichtspunt

B.
3D-object

C.
de achterzijde van een driedimensionaal object

Driehoeken worden altijd gerenderd, ongeacht de grootte, vorm of positie. Schifting zorgt dat Flash Player of AIR het 3D-object correct rendert. Daarnaast wilt u soms dat de renderer sommige driehoeken overslaat zodat er minder rendercycli nodig zijn. Denk aan een kubus die roteert in de ruimte. U ziet nooit meer dan drie zijden van de kubus. Er zijn altijd drie zijden uit zicht die de andere kant van de kubus op wijzen. Aangezien deze zijden niet zichtbaar zijn, hoeft de renderer ze niet te tekenen. Zonder schifting rendert Flash Player of AIR zowel de zijden aan de voor- als aan de achterkant.

Een kubus heeft zijden die niet zichtbaar zijn vanuit het huidige gezichtspunt.

Daarom heeft de methode Graphics.drawTriangles() een vierde parameter om een schiftingswaarde in te stellen:

public function drawTriangles(vertices:Vector.<Number>, indices:Vector.<int> = null, uvtData:Vector.<Number> = null, culling:String = "none"):void

De parameter culling is een waarde van de opsommingsklasse TriangleCulling : TriangleCulling.NONE , TriangleCulling.POSITIVE en TriangleCulling.NEGATIVE . Deze waarden zijn afhankelijk van de richting van het driehoekpad dat het oppervlak van het object definieert. De ActionScript-API voor het bepalen van de schifting veronderstelt dat alle naar buiten wijzende driehoeken van een 3D-vorm worden getekend met dezelfde padrichting. Nadat een driehoek rond heeft gedraaid, verandert ook de padrichting. Op dat moment kan de driehoek worden geschift, wat betekent dat de driehoek niet meer wordt gerenderd.

Dus met voor TriangleCulling de waarde POSITIVE verwijdert u driehoeken met een positieve padrichting (rechtsom) uit het renderproces. Met voor TriangleCulling de waarde NEGATIVE verwijdert u driehoeken met een negatieve padrichting (linksom) uit het renderproces. In het geval van een kubus hebben de oppervlakken aan de voorzijde een positieve padrichting en hebben de oppervlakken aan de achterzijde een negatieve padrichting:

De padrichting is zichtbaar op een uitgeklapte kubus. Ingeklapt is de padrichting aan de achterzijde omgekeerd.

Als u wilt zien hoe schifting werkt, begint u met het eerdere voorbeeld voor UV-toewijzing en stelt u de parameter culling van de methode drawTriangles() in op TriangleCulling.NEGATIVE :

container.graphics.drawTriangles(vertices, indices, uvtData, TriangleCulling.NEGATIVE);

Zoals u ziet, wordt de achterzijde van de afbeelding niet gerenderd terwijl het object roteert.