Utilisation d’un shader comme outil de remplissage de dessin

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

Si vous utilisez un shader pour créer un remplissage de dessin, vous faites appel aux méthodes de l’API de dessin pour créer une forme vectorielle. La sortie du shader permet de remplir la forme, à l’instar de toute image bitmap utilisée en tant que remplissage de bitmap par l’API de dessin. Pour créer un remplissage de dessin, appelez la méthode beginShaderFill() de l’objet Graphics à l’emplacement du code où vous souhaitez commencer à dessiner la forme. Transmettez l’objet Shader en tant que premier argument à la méthode beginShaderFill() , comme illustré dans le code suivant :

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

Lorsque vous utilisez un shader en tant qu’outil de remplissage de dessin, vous définissez les valeurs d’image d’entrée et de paramètre requises par le shader.

L’exemple suivant illustre l’utilisation d’un shader en tant qu’outil de remplissage de dessin. Dans cet exemple, le shader crée un dégradé à trois sommets. Ce dégradé possède trois couleurs, une par sommet d’un triangle, séparées des autres par un fondu dégradé. En outre, les couleurs pivotent pour créer un effet de rotation de couleur animé.

Remarque : le code de cet exemple a été rédigé par Petri Leskinen. Merci Petri de bien vouloir nous en faire profiter. Vous pouvez consulter d’autres exemples et didacticiels rédigés par Petri à l’adresse http://pixelero.wordpress.com/ .

Le code ActionScript réside dans trois méthodes :

  • init() : la méthode init() est appelée lors du chargement de l’application. Dans cette méthode, le code définit les valeurs initiales des objets Point qui représentent les sommets du triangle. Il crée également une occurrence de Sprite appelée canvas . Ultérieurement, dans la méthode updateShaderFill() , le code dessine une fois par image le résultat du shader dans canvas . Enfin, 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 définit également les valeurs initiales des paramètres. Enfin, le code ajoute la méthode updateShaderFill() en tant qu’écouteur de l’événement enterFrame , ce qui signifie qu’il est appelé une fois par image pour créer un effet animé.

  • onEnterFrame() : la méthode updateShaderFill() est appelée une fois par image, ce qui crée l’effet d’animation. Dans cette méthode, le code calcule et définit les valeurs des paramètres du shader. Il appelle ensuite la méthode beginShaderFill() pour créer un remplissage de shader et appelle d’autres méthodes de l’API de dessin pour dessiner le résultat du shader dans un triangle.

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 d’un fichier FLA dans 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(); 
        } 
    } 
}

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

<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); 
    } 
}
Remarque : si vous utilisez un remplissage de shader alors que le rendu est exécuté par le processeur graphique, la zone remplie s’affiche en cyan.

Pour plus d’informations sur le tracé de forme par le biais de l’API de dessin, voir Utilisation de l’API de dessin .