Utilisation d’un shader comme mode de fondu

Flash Player 10 et les versions ultérieures, Adobe AIR 1.5 et les versions ultérieures

Utiliser un shader comme mode de fondu s’apparente à l’utilisation des autres modes de fondu. Le shader définit le résultat de deux objets d’affichage fondus visuellement. Pour utiliser un shader en tant que mode de fondu, affectez à votre objet Shader la propriété blendShader de l’objet d’affichage en premier plan. Affecter une valeur autre que null à la propriété blendShader définit automatiquement la propriété blendMode de l’objet d’affichage sur BlendMode.SHADER. Le code suivant illustre l’utilisation d’un shader en tant que mode de fondu. Notez que cet exemple part du principe qu’un objet d’affichage appelé foreground figure dans le même parent que l’autre contenu d’affichage dans la liste d’affichage, sachant que foreground chevauche l’autre contenu :

foreground.blendShader = myShader;

Lorsque vous utilisez un shader en tant que mode de fondu, deux entrées au moins doivent être spécifiées. Comme indiqué dans l’exemple, vous ne définissez pas les valeurs d’entrée dans le code. Les deux images fondues sont automatiquement utilisées en tant qu’entrées du shader. L’image en premier-plan fait office de seconde image (c’est à cet objet d’affichage qu’est appliqué le mode de fondu). Une image d’arrière-plan est créée à partir du composite de tous les pixels figurant derrière le cadre de sélection de l’image en premier-plan. Cette image en arrière-plan est définie comme la première image d’entrée. Si vous utilisez un shader qui attend plus de deux entrées, vous en indiquez la valeur à partir de la troisième entrée.

L’exemple suivant illustre l’utilisation d’un shader en tant que mode de fondu. Cet exemple utilise un mode de fondu Eclaircir basé sur la luminosité. Ce fondu a pour résultat d’afficher le pixel le plus clair de l’un ou l’autre des objets fondus.

Remarque : le code de cet exemple a été rédigé par Mario Klingemann. Merci Mario de bien vouloir nous en faire profiter. Pour consulter d’autres exemples de code rédigés par Mario, ainsi que ses commentaires, voir www.quasimondo.com/.

Le code ActionScript important figure dans les deux méthodes suivantes :

  • init() : la méthode init() est appelée lors du chargement de l’application. Dans cette méthode, le code charge le fichier de pseudo-code binaire du shader.

  • onLoadComplete() : dans la méthode onLoadComplete(), le code crée l’objet Shader appelé shader. Il dessine ensuite trois objets. Le premier, backdrop, est un arrière-plan gris foncé placé derrière les objets fondus. Le deuxième, backgroundShape, est une ellipse dégradée verte. Le troisième, foregroundShape, est une ellipse dégradée orange.

    L’ellipse foregroundShape est l’objet de premier plan du fondu. L’image d’arrière-plan du fondu est composée de la section de backdrop et de la section de backgroundShape qui sont recouvertes par le cadre de sélection de l’objet foregroundShape. L’objet foregroundShape est affiché en première position dans la liste d’affichage. Il recouvre partiellement backgroundShape et totalement backdrop. En raison de ce chevauchement, sans application d’un mode de fondu, l’ellipse orange (foregroundShape) est entièrement affichée et masque une section de l’ellipse verte (backgroundShape) :

    Toutefois, si le mode de fondu est affiché, la section la plus lumineuse de l’ellipse verte est visible, car elle est plus claire que la section de foregroundShape qui la recouvre :

Vous trouverez ci-dessous le code ActionScript associé à cet exemple : Utilisez cette classe en tant que classe d’application principale d’un projet ActionScript uniquement dans Flash Builder, ou en tant que classe de document du fichier FLA dans 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; 
        } 
    } 
}

Le code source du noyau du shader LumaLighten, utilisé pour la création du fichier « LumaLighten.pbj » de pseudo-code binaire Pixel Bender, est indiqué ci-dessous :

<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; 
    } 
}

Pour plus d’informations sur l’utilisation des modes de fondu, voir Application de modes de fondu.

Remarque : lorsqu’un programme shader Pixel Bender est exécuté en tant que fusion dans Flash Player ou AIR, les fonctions d’échantillonnage et outCoord() ne se comportent pas comme dans les autres contextes. En mode de fusion, une fonction d’échantillonnage renvoie toujours le pixel en cours d’évaluation par le shader. Il est, par exemple, impossible d’ajouter un décalage à outCoord() pour échantillonner un pixel environnant. De même, si vous utilisez la fonction outCoord() dans un contexte autre qu’une fonction d’échantillonnage, ses coordonnées renvoient toujours 0. Il est ainsi impossible de se baser sur la position d’un pixel pour affecter la combinaison des images fusionnées.