Uso di uno shader come metodo di fusione

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

L'uso di uno shader come metodo di fusione è analogo all'uso di altri metodi di fusione. Lo shader definisce l'aspetto risultante da due oggetti di visualizzazione che vengono fusi visivamente. Per utilizzare uno shader come metodo di fusione, assegnate all'oggetto Shader la proprietà blendShader dell'oggetto di visualizzazione in primo piano. L'assegnazione di un valore diverso da null alla proprietà blendShader imposta automaticamente la proprietà blendMode dell'oggetto di visualizzazione su BlendMode.SHADER. L'esempio seguente dimostra l'uso di uno shader come metodo di fusione. Tenete presente che in questo esempio si presume che sia disponibile un oggetto di visualizzazione denominato foreground contenuto nello stesso oggetto principale nell'elenco di visualizzazione di altro contenuto di visualizzazione, con foreground che si sovrappone all'altro contenuto:

foreground.blendShader = myShader;

Quando utilizzate uno shader come metodo di fusione, questo deve essere definito con almeno due input. Come mostra l'esempio, non dovete impostare i valori di input nel codice, perché le due immagini fuse vengono usate automaticamente come input dello shader. L'immagine in primo piano viene impostata come seconda immagine, ovvero l'oggetto di visualizzazione a cui viene applicato il metodo di fusione. Viene creata un'immagine di sfondo utilizzando l'insieme di tutti i pixel dietro il riquadro di delimitazione dell'immagine in primo piano. Questa immagine di sfondo viene impostata come prima immagine di input. Se usate uno shader che prevede più di due input, dovete fornire il valore degli input successivi ai primi due.

L'esempio seguente dimostra l'uso di uno shader come metodo di fusione. Questo esempio utilizza un metodo di fusione basato sulla luminosità. Il risultato della fusione è che il valore del pixel più luminoso di uno degli oggetti fusi diventa il pixel visualizzato.

Nota: il codice di questo esempio è stato scritto da Mario Klingemann, che ringraziamo per avere condiviso questo esempio. Potete consultare il lavoro di Mario sul sito all'indirizzo www.quasimondo.com/.

Il codice ActionScript importante è presente in questi due metodi:

  • init(): il metodo init() viene chiamato quando viene caricata l'applicazione. In questo metodo il codice carica il file di codice byte dello shader.

  • onLoadComplete(): nel metodo onLoadComplete() il codice crea l'oggetto Shader denominato shader e quindi disegna tre oggetti. Il primo, backdrop, è uno sfondo grigio scuro dietro gli oggetti fusi. Il secondo, backgroundShape, è un'ellissi sfumata verde. Il terzo oggetto, foregroundShape, è un'ellissi sfumata arancione.

    L'ellissi foregroundShape è l'oggetto in primo piano della sfumatura. L'immagine di sfondo della sfumatura è formata dalla parte di backdrop e la parte di backgroundShape che si sovrappongono al riquadro di delimitazione dell'oggetto foregroundShape. L'oggetto foregroundShape è l'oggetto in primo piano nell'elenco di visualizzazione. Si sovrappone parzialmente con backgroundShape e totalmente con backdrop. A causa di questa sovrapposizione, se non viene applicato un metodo di fusione, l'ellissi arancione (foregroundShape) viene visualizzata completamente e parte dell'ellissi verde backgroundShape) viene nascosta da quest'ultima:

    Se invece viene applicato un metodo di fusione, la parte più luminosa dell'ellisse verde si intravede, perché è più luminosa della porzione di foregroundShape che la copre:

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.BlendMode; 
    import flash.display.GradientType; 
    import flash.display.Graphics; 
    import flash.display.Shader; 
    import flash.display.Shape; 
    import flash.display.Sprite; 
    import flash.events.Event; 
    import flash.geom.Matrix; 
    import flash.net.URLLoader; 
    import flash.net.URLLoaderDataFormat; 
    import flash.net.URLRequest; 
     
    public class LumaLighten extends Sprite 
    { 
        private var shader:Shader; 
        private var loader:URLLoader; 
         
        public function LumaLighten() 
        { 
            init(); 
        } 
         
        private function init():void 
        { 
            loader = new URLLoader(); 
            loader.dataFormat = URLLoaderDataFormat.BINARY; 
            loader.addEventListener(Event.COMPLETE, onLoadComplete); 
            loader.load(new URLRequest("LumaLighten.pbj")); 
        } 
         
         
        private function onLoadComplete(event:Event):void 
        { 
            shader = new Shader(loader.data); 
             
            var backdrop:Shape = new Shape(); 
            var g0:Graphics = backdrop.graphics; 
            g0.beginFill(0x303030); 
            g0.drawRect(0, 0, 400, 200); 
            g0.endFill(); 
            addChild(backdrop); 
             
            var backgroundShape:Shape = new Shape(); 
            var g1:Graphics = backgroundShape.graphics; 
            var c1:Array = [0x336600, 0x80ff00]; 
            var a1:Array = [255, 255]; 
            var r1:Array = [100, 255]; 
            var m1:Matrix = new Matrix(); 
            m1.createGradientBox(300, 200); 
            g1.beginGradientFill(GradientType.LINEAR, c1, a1, r1, m1); 
            g1.drawEllipse(0, 0, 300, 200); 
            g1.endFill(); 
            addChild(backgroundShape); 
             
            var foregroundShape:Shape = new Shape(); 
            var g2:Graphics = foregroundShape.graphics; 
            var c2:Array = [0xff8000, 0x663300]; 
            var a2:Array = [255, 255]; 
            var r2:Array = [100, 255]; 
            var m2:Matrix = new Matrix(); 
            m2.createGradientBox(300, 200); 
            g2.beginGradientFill(GradientType.LINEAR, c2, a2, r2, m2); 
            g2.drawEllipse(100, 0, 300, 200); 
            g2.endFill(); 
            addChild(foregroundShape); 
             
            foregroundShape.blendShader = shader; 
            foregroundShape.blendMode = BlendMode.SHADER; 
        } 
    } 
}

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

<languageVersion : 1.0;> 
kernel LumaLighten 
< 
    namespace : "com.quasimondo.blendModes"; 
    vendor : "Quasimondo.com"; 
    version : 1; 
    description : "Luminance based lighten blend mode"; 
> 
{ 
    input image4 background; 
    input image4 foreground; 
 
    output pixel4 dst; 
     
    const float3 LUMA = float3(0.212671, 0.715160, 0.072169); 
 
    void evaluatePixel() 
    { 
        float4 a = sampleNearest(foreground, outCoord()); 
        float4 b = sampleNearest(background, outCoord()); 
        float luma_a = a.r * LUMA.r + a.g * LUMA.g + a.b * LUMA.b; 
        float luma_b = b.r * LUMA.r + b.g * LUMA.g + b.b * LUMA.b; 
         
        dst = luma_a > luma_b ? a : b; 
    } 
}

Per ulteriori informazioni sull'uso dei metodi di fusione, vedete Applicazione dei metodi di fusione.

Nota: quando un programma di shader Pixel Bender viene eseguito come un metodo di fusione in Flash Player o AIR, le funzioni di campionamento e outCoord() si comportano in maniera diversa rispetto ad altri contesti. In un metodo di fusione, una funzione di campionamento restituisce sempre il pixel in corso di valutazione. Non potete, ad esempio, aggiungere un offset a outCoord() per campionare un pixel vicino. Analogamente, se utilizzate la funzione outCoord() al di fuori di una funzione di campionamento, le sue coordinate sono sempre valutate a 0. Non potete, ad esempio, utilizzare la posizione di un pixel per influenzare il modo in cui le immagini fuse sono combinate.