Uso di uno shader come riempimento

Flash Player 10 e versioni successive, Adobe AIR 1.5 e versioni successive

Quando usate uno shader per creare un riempimento, fate ricorso a metodi di un'API di disegno per creare una forma vettoriale. L'output dello shader viene utilizzato per riempire la forma esattamente come è possibile usare qualsiasi immagine bitmap come riempimento bitmap con l'API di disegno. Per creare un riempimento dello shader, chiamate il metodo beginShaderFill() dell'oggetto Graphics nel punto del codice in cui desiderate iniziare a disegnare la forma. Passate l'oggetto Shader come primo argomento al metodo beginShaderFill(), come mostrato nel codice seguente:

var canvas:Sprite = new Sprite(); 
canvas.graphics.beginShaderFill(myShader); 
canvas.graphics.drawRect(10, 10, 150, 150); 
canvas.graphics.endFill(); 
// add canvas to the display list to see the result

Quando usate uno shader come riempimento, impostate tutti i valori dell'immagine di input e dei parametri richiesti dallo shader.

L'esempio seguente dimostra l'uso di uno shader come riempimento. In questo esempio, lo shader crea un gradiente a tre punti, composto da tre colori, uno a ogni vertice del triangolo, con una sfumatura tra i colori. I colori inoltre ruotano per creare un effetto di animazione di rotazione del colore.

Nota: il codice di questo esempio è stato scritto da Petri Leskinen, che ringraziamo per avere condiviso questo esempio. Ulteriori esempi ed esercitazioni sviluppati da Petri sono disponibili all'indirizzo http://pixelero.wordpress.com/.

Il codice ActionScript è presente in tre metodi:

  • init(): il metodo init() viene chiamato quando viene caricata l'applicazione. In questo metodo il codice imposta i valori iniziali per gli oggetti Point che rappresentano i vertici del triangolo e crea e un'istanza di Sprite denominata canvas. In seguito, nel metodo updateShaderFill() il codice disegna il risultato dello shader in canvas una volta per fotogramma. Infine il codice carica il file di codice byte dello shader.

  • onLoadComplete(): nel metodo onLoadComplete() il codice crea l'oggetto Shader denominato shader e imposta i valori iniziali dei parametri. Infine il codice aggiunge il metodo updateShaderFill() come listener per l'evento enterFrame, che viene quindi chiamato una volta per fotogramma per creare un effetto di animazione.

  • updateShaderFill(): il metodo updateShaderFill() viene chiamato una volta per ogni fotogramma per creare l'effetto di animazione. In questo metodo il codice calcola e imposta i valori dei parametri dello shader, quindi chiama il metodo beginShaderFill() per creare un riempimento e chiama altri metodi dell'API di disegno per disegnare il risultato dello shader in un triangolo.

Viene di seguito riportato il codice ActionScript per questo esempio. Utilizzate questa classe come classe di applicazione principale per un progetto costituito solo da ActionScript in Flash Builder o come classe di documento per il file FLA in Flash Professional:

package 
{ 
    import flash.display.Shader; 
    import flash.display.Sprite; 
    import flash.events.Event; 
    import flash.geom.Point; 
    import flash.net.URLLoader; 
    import flash.net.URLLoaderDataFormat; 
    import flash.net.URLRequest; 
     
    public class ThreePointGradient extends Sprite 
    { 
        private var canvas:Sprite; 
        private var shader:Shader; 
        private var loader:URLLoader; 
         
        private var topMiddle:Point; 
        private var bottomLeft:Point; 
        private var bottomRight:Point; 
         
        private var colorAngle:Number = 0.0; 
        private const d120:Number = 120 / 180 * Math.PI; // 120 degrees in radians 
         
         
        public function ThreePointGradient() 
        { 
            init(); 
        } 
         
        private function init():void 
        { 
            canvas = new Sprite(); 
            addChild(canvas); 
             
            var size:int = 400; 
            topMiddle = new Point(size / 2, 10); 
            bottomLeft = new Point(0, size - 10); 
            bottomRight = new Point(size, size - 10); 
             
            loader = new URLLoader(); 
            loader.dataFormat = URLLoaderDataFormat.BINARY; 
            loader.addEventListener(Event.COMPLETE, onLoadComplete); 
            loader.load(new URLRequest("ThreePointGradient.pbj")); 
        } 
         
        private function onLoadComplete(event:Event):void 
        { 
            shader = new Shader(loader.data); 
             
            shader.data.point1.value = [topMiddle.x, topMiddle.y]; 
            shader.data.point2.value = [bottomLeft.x, bottomLeft.y]; 
            shader.data.point3.value = [bottomRight.x, bottomRight.y]; 
             
            addEventListener(Event.ENTER_FRAME, updateShaderFill); 
        } 
         
        private function updateShaderFill(event:Event):void 
        { 
            colorAngle += .06; 
             
            var c1:Number = 1 / 3 + 2 / 3 * Math.cos(colorAngle); 
            var c2:Number = 1 / 3 + 2 / 3 * Math.cos(colorAngle + d120); 
            var c3:Number = 1 / 3 + 2 / 3 * Math.cos(colorAngle - d120); 
             
            shader.data.color1.value = [c1, c2, c3, 1.0]; 
            shader.data.color2.value = [c3, c1, c2, 1.0]; 
            shader.data.color3.value = [c2, c3, c1, 1.0]; 
             
            canvas.graphics.clear(); 
            canvas.graphics.beginShaderFill(shader); 
             
            canvas.graphics.moveTo(topMiddle.x, topMiddle.y); 
            canvas.graphics.lineTo(bottomLeft.x, bottomLeft.y); 
            canvas.graphics.lineTo(bottomRight.x, bottomLeft.y); 
             
            canvas.graphics.endFill(); 
        } 
    } 
}

Viene di seguito riportato il codice sorgente per il kernel dello shader ThreePointGradient, usato per creare il file del codice byte “ThreePointGradient.pbj” Pixel Bender:

<languageVersion : 1.0;> 
kernel ThreePointGradient 
< 
    namespace : "Petri Leskinen::Example"; 
    vendor : "Petri Leskinen"; 
    version : 1; 
    description : "Creates a gradient fill using three specified points and colors."; 
> 
{ 
    parameter float2 point1 // coordinates of the first point 
    < 
        minValue:float2(0, 0); 
        maxValue:float2(4000, 4000); 
        defaultValue:float2(0, 0); 
    >; 
     
    parameter float4 color1 // color at the first point, opaque red by default 
    < 
        defaultValue:float4(1.0, 0.0, 0.0, 1.0); 
    >; 
     
    parameter float2 point2 // coordinates of the second point 
    < 
        minValue:float2(0, 0); 
        maxValue:float2(4000, 4000); 
        defaultValue:float2(0, 500); 
    >; 
     
    parameter float4 color2 // color at the second point, opaque green by default 
    < 
        defaultValue:float4(0.0, 1.0, 0.0, 1.0); 
    >; 
     
    parameter float2 point3 // coordinates of the third point 
    < 
        minValue:float2(0, 0); 
        maxValue:float2(4000, 4000); 
        defaultValue:float2(0, 500); 
    >; 
     
    parameter float4 color3 // color at the third point, opaque blue by default 
    < 
        defaultValue:float4(0.0, 0.0, 1.0, 1.0); 
    >; 
     
    output pixel4 dst; 
     
    void evaluatePixel() 
    { 
        float2 d2 = point2 - point1; 
        float2 d3 = point3 - point1; 
         
        // transformation to a new coordinate system 
        // transforms point 1 to origin, point2 to (1, 0), and point3 to (0, 1) 
        float2x2 mtrx = float2x2(d3.y, -d2.y, -d3.x, d2.x) / (d2.x * d3.y - d3.x * d2.y); 
        float2 pNew = mtrx * (outCoord() - point1); 
         
        // repeat the edge colors on the outside 
        pNew.xy = clamp(pNew.xy, 0.0, 1.0); // set the range to 0.0 ... 1.0 
         
        // interpolating the output color or alpha value 
        dst = mix(mix(color1, color2, pNew.x), color3, pNew.y); 
    } 
}
Nota: se utilizzate un riempimento dello shader durante il rendering nell'unità di elaborazione grafica (GPU), l'area piena verrà colorata ciano.

Per ulteriori informazioni sul disegno di forme mediante l'API di disegno, vedete Uso dell'API di disegno.