Definizione dei valori di input e dei parametri

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

Molti shader di Pixel Bender sono definiti per usare una o più immagini di input che vengono successivamente elaborate. Ad esempio, accade di frequente che uno shader accetti un'immagine d'origine e come risultato fornisca la stessa immagine con un effetto applicato. A seconda del modo in cui viene usato lo shader, il valore di input può essere specificato automaticamente oppure è possibile inserirlo esplicitamente. Analogamente, molti shader contengono parametri che vengono usati per personalizzare i risultati. Prima di usare lo shader dovrete inoltre impostare esplicitamente un valore per ogni parametro.

La proprietà data dell'oggetto Shader viene usata per impostare gli input e i parametri e per stabilire se un dato shader richiede input e parametri. La proprietà data è un'istanza ShaderData.

Identificazione di input e parametri degli shader

Il primo passaggio nella definizione dei valori di input e parametri di uno shader consiste nello stabilire se un dato shader richieda immagini di input o parametri. A ogni istanza Shader è associata una proprietà data contenente un oggetto ShaderData. È possibile accedere ad eventuali input o parametri richiesti dallo shader come a proprietà dell'oggetto ShaderData. I nomi delle proprietà corrispondono ai nomi specificati per gli input e i parametri nel codice sorgente dello shader. Se ad esempio uno shader definisce un input chiamato src , all'oggetto ShaderData è associata una proprietà denominata src che rappresenta quell'input. Ogni proprietà che rappresenta un input è un'istanza ShaderInput e ogni proprietà che rappresenta un parametro è un'istanza ShaderParameter.

Idealmente, l'autore dello shader dovrebbe documentare la funzione dello shader, indicando quali parametri e valori delle immagini di input sono richiesti, cosa rappresentano, le impostazioni appropriate e così via.

Tuttavia, se lo shader non è corredato dalla necessaria documentazione (e non avete a disposizione il codice sorgente), potete esaminare i dati dello shader per identificare input e parametri. Le proprietà che rappresentano gli input e i parametri sono aggiunte dinamicamente all'oggetto ShaderData. Di seguito potete usare un ciclo for..in per esaminare l'oggetto ShaderData e stabilire se lo shader associato definisce input o parametri. Come descritto in Accesso ai metadati dello shader , è possibile accedere a qualunque valore dei metadati definito per uno shader come a una proprietà dinamica aggiunta alla proprietà Shader.data . Quando usate questa tecnica per identificare gli input e i parametri dello shader, controllate il tipo di dati delle proprietà dinamiche. Se è un'istanza ShaderInput, la proprietà rappresenta un input. Se è un'istanza ShaderParameter, la proprietà rappresenta un parametro. Altrimenti, è un valore dei metadati. L'esempio seguente illustra come utilizzare un ciclo for..in per esaminare le proprietà dinamiche di una proprietà data di uno shader. Ogni input (oggetto ShaderInput) viene aggiunto a un'istanza Vector il cui nome è inputs . Ogni parametro (oggetto ShaderParameter) viene aggiunto a un'istanza Vector il cui nome è parameters . Infine, ogni proprietà dei metadati viene aggiunta a un'istanza Vector il cui nome è metadata . Notate che questo esempio presuppone che sia già stata creata un'istanza Shader con nome myShader :

var shaderData:ShaderData = myShader.data; 
var inputs:Vector.<ShaderInput> = new Vector.<ShaderInput>(); 
var parameters:Vector.<ShaderParameter> = new Vector.<ShaderParameter>(); 
var metadata:Vector.<String> = new Vector.<String>(); 
 
for (var prop:String in shaderData) 
{ 
    if (shaderData[prop] is ShaderInput) 
    { 
        inputs[inputs.length] = shaderData[prop]; 
    } 
    else if (shaderData[prop] is ShaderParameter) 
    { 
        parameters[parameters.length] = shaderData[prop]; 
    } 
    else 
    { 
        metadata[metadata.length] = shaderData[prop]; 
    } 
} 
 
// do something with the inputs or properties

Definizione dei valori degli input dello shader

Molti shader richiedono una o più immagini di input che sono usate nella successiva fase di elaborazione. Tuttavia, quando usate un oggetto Shader, spesso l'input viene specificato automaticamente. Ad esempio, supponete che uno shader richieda un input e che lo shader sia usato come filtro. Quando il filtro viene applicato a un oggetto di visualizzazione o a un oggetto BitmapData, l'oggetto in questione viene automaticamente impostato come input. In questo caso non occorre impostare esplicitamente un valore per l'input.

In alcuni casi tuttavia, specialmente se uno shader richiede più input, occorre impostare esplicitamente il valore di input. Ogni input che viene definito in uno shader è rappresentato in ActionScript da un oggetto ShaderInput. L'oggetto ShaderInput è una proprietà dell'istanza ShaderData all'interno della proprietà data dell'oggetto Shader, come spiegato in Identificazione di input e parametri degli shader . Ad esempio, supponete che uno shader richieda un input chiamato src e che lo shader sia collegato a un oggetto Shader chiamato myShader . In questo caso, per accedere all'oggetto ShaderInput corrispondente all'input src è necessario usare l'identificatore seguente:

myShader.data.src

Ogni oggetto ShaderInput ha una proprietà input che viene usata per impostare il valore dell'input. Per specificare i dati di un'immagine, dovete impostare la proprietà input su un'istanza BitmapData. Per specificare dati binari o numerici, potete invece impostare la proprietà input su un'istanza BitmapData o Vector.<numero>. Per informazioni dettagliate e limitazioni nell'uso delle istanze BitmapData o Vector.<Numero> come un input, vedete il listato ShaderInput.input nella Guida di riferimento di Adobe ActionScript 3.0 per la piattaforma Adobe Flash .

Oltre alla proprietà input , a un oggetto ShaderInput sono associate proprietà che consentono di stabilire quale tipo di immagine è richiesta dall'input. Tra le altre, ricordiamo le proprietà width , height , e channels . Ogni oggetto ShaderInput prevede anche una proprietà index che consente di stabilire se l'input richiede di specificare un valore esplicito. Se uno shader richiede più input rispetto quanti ne vengono impostati automaticamente, dovete impostare i valori per quegli input. Per informazioni sui vari modi di usare uno shader e per sapere quando i valori di input vengono impostati automaticamente, vedete Uso di uno shader .

Definizioni dei valori dei parametri dello shader

Alcuni shader definiscono i valori dei parametri che lo shader usa per creare i risultati. Ad esempio, uno shader che altera la luminosità di un'immagine può specificare un parametro di luminosità che determina a che livello l'operazione deve influenzare la luminosità. Un singolo parametro definito in uno shader può richiedere uno o più valori, a seconda della definizione del parametro fornita nello shader. Ogni parametro che viene definito in uno shader è rappresentato in ActionScript da un oggetto ShaderParameter. L'oggetto ShaderParameter è una proprietà dell'istanza ShaderData all'interno della proprietà data dell'oggetto Shader, come spiegato in Identificazione di input e parametri degli shader . Ad esempio, supponete che uno shader definisca un parametro chiamato brightness e che lo shader sia rappresentato da un oggetto Shader chiamato myShader . In questo caso per accedere all'oggetto ShaderParameter corrispondente al parametro brightness , è necessario usare l'identificatore seguente:

myShader.data.brightness

Per specificare uno o più valori per il parametro, dovete creare un array di ActionScript contenente i valori appropriati e assegnarli alla proprietà value . La proprietà value è definita come un'istanza Array, in quanto è possibile che un singolo parametro dello shader richieda più valori. Anche se il parametro dello shader richiede un singolo valore, dovete inserirlo in un oggetto Array per assegnarlo alla proprietà ShaderParameter.value . L'elenco seguente indica come impostare un singolo valore come proprietà value :

myShader.data.brightness.value = [75];

Se il codice sorgente di Pixel Bender per lo shader definisce un valore predefinito per il parametro, un array contenente il valore o i valori predefiniti viene creato e assegnato alla proprietà value dell'oggetto ShaderParameter quando si crea un oggetto Shader. Dopo che l'array viene assegnato alla proprietà value (specificando anche se si tratta dell'array predefinito), il valore del parametro può essere modificato cambiando il valore dell'elemento dell'array. Non è necessario creare un nuovo array e assegnarlo alla proprietà value .

L'esempio seguente dimostra come impostare il valore di un parametro dello shader in ActionScript. In questo esempio lo shader definisce un parametro chiamato color . Il parametro color viene dichiarato come variabile float4 nel codice sorgente di Pixel Bender; ciò significa che si tratta di un array di quattro numeri a virgola mobile. Nell'esempio, il valore del parametro color viene cambiato continuamente e ogni volta che cambia lo shader viene usato per disegnare un rettangolo colorato sullo schermo. Il risultato è un cambio di colore animato.

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

Il codice ActionScript è incentrato su tre metodi:

  • init() : nel metodo init() il codice carica il codice byte Pixel Bender contenente lo shader. Quando il file viene caricato, viene chiamato il metodo onLoadComplete() .

  • onLoadComplete() : nel metodo onLoadComplete() il codice crea l'oggetto Shader denominato shader e un'istanza di Sprite denominata texture . Nel metodo renderShader() il codice disegna il risultato dello shader in texture una volta per fotogramma.

  • onEnterFrame() : il metodo onEnterFrame() viene chiamato una volta per ogni frame per realizzare l'effetto di animazione. In questo metodo il codice imposta il valore del parametro dello shader su un nuovo colore, quindi chiama il metodo renderShader() per disegnare il risultato dello shader sotto forma di un rettangolo.

  • renderShader() : nel metodo renderShader() il codice chiama il metodo Graphics.beginShaderFill() per specificare un riempimento per lo shader, quindi disegna un rettangolo il cui riempimento è definito dall'output dello shader (il colore generato). Per ulteriori informazioni su questo tipo di uso degli shader, vedete Uso di uno shader come riempimento .

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.net.URLLoader; 
    import flash.net.URLLoaderDataFormat; 
    import flash.net.URLRequest; 
     
    public class ColorFilterExample extends Sprite 
    { 
        private const DELTA_OFFSET:Number = Math.PI * 0.5; 
        private var loader:URLLoader; 
        private var shader:Shader; 
        private var texture:Sprite; 
        private var delta:Number = 0; 
         
        public function ColorFilterExample() 
        { 
            init(); 
        } 
         
        private function init():void 
        { 
            loader = new URLLoader(); 
            loader.dataFormat = URLLoaderDataFormat.BINARY; 
            loader.addEventListener(Event.COMPLETE, onLoadComplete); 
            loader.load(new URLRequest("ColorFilter.pbj")); 
        } 
         
        private function onLoadComplete(event:Event):void 
        { 
            shader = new Shader(loader.data); 
             
            texture = new Sprite(); 
             
            addChild(texture); 
             
            addEventListener(Event.ENTER_FRAME, onEnterFrame); 
        } 
        private function onEnterFrame(event:Event):void 
        { 
            shader.data.color.value[0] = 0.5 + Math.cos(delta - DELTA_OFFSET) * 0.5; 
            shader.data.color.value[1] = 0.5 + Math.cos(delta) * 0.5; 
            shader.data.color.value[2] = 0.5 + Math.cos(delta + DELTA_OFFSET) * 0.5; 
            // The alpha channel value (index 3) is set to 1 by the kernel's default 
            // value. This value doesn't need to change. 
             
            delta += 0.1; 
             
            renderShader(); 
        } 
         
        private function renderShader():void 
        { 
            texture:graphics.clear(); 
            texture.graphics.beginShaderFill(shader); 
            texture.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight); 
            texture.graphics.endFill(); 
        } 
    } 
}

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

<languageVersion : 1.0;> 
kernel ColorFilter 
< 
    namespace : "boostworthy::Example"; 
    vendor : "Ryan Taylor"; 
    version : 1; 
    description : "Creates an image where every pixel has the specified color value."; 
> 
{ 
    output pixel4 result; 
     
    parameter float4 color 
    < 
        minValue:float4(0, 0, 0, 0); 
        maxValue:float4(1, 1, 1, 1); 
        defaultValue:float4(0, 0, 0, 1); 
    >; 
     
    void evaluatePixel() 
    { 
        result = color; 
    } 
}

Se usate uno shader i cui parametri non sono documentati, potete scoprire quanti elementi di quale tipo devono essere inclusi nell'array controllando la proprietà type dell'oggetto ShaderParameter. La proprietà type indica il tipo di dati del parametro così come è definito nello shader. Per un elenco che riporta numeri e tipi degli elementi richiesti da ogni tipo di parametro, vedete la voce della proprietà ShaderParameter.value nella Guida di riferimento di ActionScript 3.0.

Ciascun oggetto ShaderParameter prevede inoltre una proprietà index che indica la posizione in cui si trova il parametro nell'ordine dei parametri dello shader. Oltre a queste proprietà, un oggetto ShaderParameter può avere altre proprietà contenenti i valori dei metadati forniti dall'autore dello shader. Ad esempio, l'autore può specificare valori dei metadati quali i valori minimo, massimo e predefinito per un parametro. Tutti i valori dei metadati specificati da un autore vengono aggiunti all'oggetto ShaderParameter come proprietà dinamiche. Per esaminare queste proprietà, utilizzate un ciclo for..in per scorrere le proprietà dinamiche dell'oggetto ShaderParameter e identificarne i metadati. L'esempio seguente illustra come utilizzare un ciclo for..in per identificare i metadati di un oggetto ShaderParameter. Ogni valore dei metadati viene aggiunto a un'istanza Vector il cui nome è metadata . Si noti che questo esempio presuppone che sia già stata creata l'istanza Shader myShader contenente il parametro brightness :

var brightness:ShaderParameter = myShader.data.brightness; 
var metadata:Vector.<String> = new Vector.<String>(); 
 
for (var prop:String in brightness) 
{ 
    if (brightness[prop] is String) 
    { 
        metadata[metadata.length] = brightness[prop]; 
    } 
} 
 
// do something with the metadata