Określanie wartości danych wejściowych i parametrów modułu cieniującego

Flash Player 10 i nowsze wersje, Adobe AIR 1.5 i nowsze wersje

Definicja wielu modułów cieniujących Pixel Bender zakłada użycie jednego lub wielu obrazów wejściowych używanych w procesie przetwarzania danych. Często moduły cieniujące przyjmują wejściowy obraz źródłowy i zwracają go po zastosowaniu określonego efektu. W zależności od sposobu wykorzystania modułu cieniującego wartość wejściowa może być określana automatycznie lub konieczne jest jawne podanie wartości. Wiele modułów cieniujących przyjmuje także parametry wpływające na wyniki działania modułu. Przed użyciem takiego modułu cieniującego należy jawnie ustawić wartości wszystkich parametrów.

Właściwość data obiektu Shader umożliwia ustawianie danych wejściowych i parametrów modułu cieniującego oraz sprawdzanie, czy dany moduł oczekuje danych wejściowych bądź parametrów. Właściwość data jest wystąpieniem klasy ShaderData.

Rozpoznawanie danych wejściowych i parametrów modułu cieniującego

Pierwszym etapem określania danych wejściowych i wartości parametrów modułu cieniującego jest sprawdzenie, czy dany moduł faktycznie oczekuje określonych obrazów wejściowych lub parametrów. Każde wystąpienie klasy Shader ma właściwość data zawierającą obiekt ShaderData. Jeśli moduł cieniujący definiuje jakiekolwiek dane wejściowe lub parametry, będą one dostępne jako właściwości tego obiektu ShaderData. Nazwy właściwości są identyczne z nazwami danych wejściowych i parametrów określonymi w kodzie źródłowym modułu cieniującego. Jeśli na przykład w module zdefiniowany jest obraz wejściowy o nazwie src , obiekt ShaderData zawiera właściwość o nazwie src reprezentującą ten obraz wejściowy. Każda właściwość reprezentująca dane wejściowe jest instancją klasy ShaderInput, a każda właściwość reprezentująca parametr jest instancją klasy ShaderParameter.

W idealnym przypadku autor modułu cieniującego udostępnia jego dokumentację, w której opisane są obrazy wejściowe i parametry oczekiwane przez moduł, ich znaczenie, zakres wartości itd.

Jeśli jednak moduł cieniujący nie jest udokumentowany (i nie mamy jego kodu źródłowego), możemy odczytywać jego właściwość data w celu rozpoznania danych wejściowych i parametrów. Właściwości reprezentujące obrazy wejściowe i parametry są dodawane dynamicznie do obiektu ShaderData. W rezultacie możliwe jest użycie pętli for..in na obiekcie ShaderData w celu sprawdzenia, czy skojarzony z nim moduł cieniujący definiuje jakiekolwiek dane wejściowe lub parametry. Zgodnie z opisem w sekcji Uzyskiwanie dostępu do metadanych modułu cieniującego wszelkie wartości metadanych zdefiniowane dla modułu są dostępne jako właściwości dynamiczne dodane do właściwości Shader.data . Korzystając z tej techniki rozpoznawania danych wejściowych i parametrów, należy sprawdzać typ danych właściwości dynamicznych. Jeśli właściwość jest instancją klasy ShaderInput, reprezentuje dane wejściowe. Jeśli jest instancją klasy ShaderParameter, reprezentuje parametr. W przeciwnym razie jest wartością metadanych. Poniższy przykład ilustruje użycie pętli for..in do odczytywania właściwości dynamicznych z właściwości data modułu cieniującego. Każdy obraz wejściowy (obiekt ShaderInput) jest dodawany do wystąpienia klasy Vector o nazwie inputs . Każdy parametr (obiekt klasy ShaderParameter) jest dodawany do wystąpienia klasy Vector o nazwie parameters . Wszelkie właściwości metadanych są dodawane do wystąpienia klasy Vector o nazwie metadata . W przykładzie przyjęto założenie, że istnieje już wystąpienie klasy Shader o nazwie 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

Określanie wartości danych wejściowych modułu cieniującego

Wiele modułów cieniujących oczekuje jednego lub kilku obrazów wejściowych używanych w procesie przetwarzania. Jednak w wielu przypadkach dane wejściowe są określane automatycznie, w toku użycia obiektu Shader. Załóżmy na przykład, że moduł cieniujący wymaga jednego obrazu wejściowego i jest używany jako filtr. Gdy zastosujemy filtr do obiektu wyświetlanego lub obiektu BitmapData, obiekt ten automatycznie stanie się obrazem wejściowym. W takim przypadku nie musimy jawnie ustawiać wartości wejściowej.

Jednak w niektórych przypadkach, zwłaszcza gdy moduł cieniujący oczekuje wielu obrazów wejściowych, konieczne jest jawne określenie wartości danych wejściowych. Każdy obraz wejściowy zdefiniowany w module cieniującym jest reprezentowany w kodzie ActionScript przez obiekt ShaderInput. Obiekt ShaderInput jest właściwością wystąpienia klasy ShaderData we właściwości data obiektu Shader, tak jak opisano to w sekcji Rozpoznawanie danych wejściowych i parametrów modułu cieniującego . Załóżmy na przykład, że w module cieniującym zdefiniowano obraz wejściowy o nazwie src i że moduł cieniujący jest powiązany z obiektem Shader o nazwie myShader . W tym przypadku w celu uzyskania dostępu do obiektu ShaderInput odpowiadającego obrazowi src należy użyć następującego identyfikatora:

myShader.data.src

Każdy obiekt ShaderInput ma właściwość input służącą do ustawiania wartości danych wejściowych. Aby określić dane obrazu, należy przypisać do właściwości input wystąpienie klasy BitmapData. Można również przypisać do właściwości input obiekt BitmapData lub Vector.<Number>, aby określić dane binarne lub liczbowe. Szczegółowe informacje i ograniczenia dotyczące używania instancji BitmapData lub Vector.Sposób wykorzystania instancji <Number> jako danych wejściowych zawiera opis właściwości ShaderInput.input w Skorowidzu języka ActionScript 3.0 dla platformy Adobe Flash .

Oprócz właściwości input obiekt ShaderInput ma właściwości umożliwiające ustalenie typu obrazu oczekiwanego w charakterze danych wejściowych. Są to właściwości width , height i channels . Każdy obiekt ShaderInput ma również właściwość index przydatną do sprawdzania, czy dla konkretnych danych wejściowych należy podać jawną wartość. Jeśli moduł cieniujący oczekuje większej liczby obrazów niż przekazywana automatycznie, to należy określić wartości dla tych dodatkowych obrazów. Szczegółowe informacje na temat różnych sposobów korzystania z modułu cieniującego i sprawdzania, czy obrazy wejściowe są ustawiane automatycznie, zawiera sekcja Korzystanie z modułu cieniującego .

Określanie parametrów modułu cieniującego

Definicje niektórych modułów cieniujących zawierają wartości parametrów, na podstawie których moduł cieniujący tworzy wynik. Na przykład moduł cieniujący, który zmienia jasność obrazu, może mieć parametr brigthness określający wielkość oczekiwanej zmiany. Dla jednego parametru zdefiniowanego w module cieniującym może być oczekiwana jedna wartość lub wiele wartości, w zależności od definicji tego parametru w module. Każdy parametr zdefiniowany w module cieniującym jest reprezentowany w kodzie ActionScript przez obiekt ShaderParameter. Obiekt ShaderParameter jest właściwością instancji ShaderData właściwości Rozpoznawanie danych wejściowych i parametrów modułu cieniującego obiektu Shader, tak jak opisano to w sekcji Rozpoznawanie danych wejściowych i parametrów modułu cieniującego. Załóżmy na przykład, że w module cieniującym zdefiniowano parametr o nazwie brightness i że moduł cieniujący jest reprezentowany przez obiekt Shader o nazwie myShader . W tym przypadku w celu uzyskania dostępu do obiektu ShaderParameter odpowiadającego parametrowi brightness należy użyć następującego identyfikatora:

myShader.data.brightness

Aby określić wartość lub wartości dla parametru modułu cieniującego, należy utworzyć w kodzie ActionScript tablicę zawierającą wartość lub wartości, a następnie przypisać ją do właściwości value obiektu ShaderParameter. Właściwość value jest zdefiniowana jako wystąpienie klasy Array, ponieważ jeden parametr modułu cieniującego może wymagać podania wielu wartości. Nawet jeśli parametr modułu cieniującego oczekuje jednej wartości, należy tę wartość umieścić w obiekcie Array, aby możliwe było przypisanie jej do właściwości ShaderParameter.value . Poniższy kod ilustruje ustawianie jednej wartości jako właściwości value .

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

Jeśli w kodzie źródłowym modułu cieniującego Pixel Bender zdefiniowana jest wartość domyślna parametru, tworzona jest tablica zawierająca wartość lub wartości domyślne. Tablica ta jest przypisywana do właściwości value obiektu ShaderParameter podczas tworzenia obiektu Shader. Po przypisaniu tablicy do właściwości value (również jeśli jest to tablica domyślna) możliwe jest zmienianie wartości parametru value przez modyfikowanie wartości elementów tablicy. Nie trzeba tworzyć nowej tablicy i przypisywać jej do właściwości value .

Poniższy przykład demonstruje nadawanie wartości parametrowi modułu cieniującego w kodzie ActionScript. Moduł użyty w przykładzie ma parametr o nazwie color . Parametr color jest zadeklarowany w kodzie źródłowym Pixel Bender jako zmienna typu float4 , co oznacza, że jest tablicą czterech liczb zmiennopozycyjnych. W przykładzie wartość parametru color jest stale zmieniana, a po każdej zmianie moduł cieniujący jest wywoływany w celu narysowania kolorowego prostokąta. W rezultacie uzyskuje się animację koloru.

Uwaga: Autorem kodu tego przykładu jest Ryan Taylor. Dziękujemy Ryanowi za udostępnienie tego przykładu. Portfolio Ryana oraz jego artykuły są dostępne na stronie www.boostworthy.com .

Kod ActionScript jest skupiony wokół trzech metod:

  • init() : W metodzie init() kod wczytuje plik kodu bajtowego Pixel Bender zawierający moduł cieniujący. Podczas wczytywania pliku wywoływana jest metoda onLoadComplete() .

  • onLoadComplete() : W metodzie onLoadComplete() kod tworzy obiekt Shader o nazwie shader . Tworzy również wystąpienie klasy Sprite o nazwie texture . W metodzie renderShader() kod rysuje wynik działania modułu cieniującego na obiekcie texture jeden raz na klatkę.

  • onEnterFrame() : Metoda onEnterFrame() jest wywoływana raz w każdej klatce, co prowadzi do uzyskania efektu animacji. W tej metodzie kod przypisuje parametrowi modułu cieniującego nowy kolor, a potem wywołuje metodę renderShader() w celu narysowania wyniku działania modułu jako prostokąta.

  • renderShader() : W metodzie renderShader() kod wywołuje metodę Graphics.beginShaderFill() określającą wypełnienie w postaci wyniku modułu cieniującego. Następnie rysowany jest prostokąt, którego wypełnieniem jest wynik działania modułu (wygenerowany kolor). Więcej informacji o użyciu modułu cieniującego w ten sposób zawiera sekcja Użycie modułu cieniującego jako wypełnienia .

Oto kod tego przykładu w języku ActionScript. Ta aplikacja może być używana jako główna klasa aplikacji dla projektu zawierającego tylko kod ActionScript w programie Flash Builder lub jako klasa document dla pliku FLA w programie 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(); 
        } 
    } 
}

Poniżej przedstawiono kod źródłowy jądra modułu cieniującego ColorFilter, na podstawie którego utworzono kod bajtowy Pixel Bender w pliku „ColorFilter.pbj”:

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

Jeśli używany jest moduł cieniujący, którego parametry nie są udokumentowane, można sprawdzić liczbę i typy wartości, jakie należy umieścić w tablicy, odczytując właściwość type obiektu ShaderParameter. Właściwość type wskazuje na typ danych parametru zdefiniowany w module cieniującym. Listę liczb i typów elementów oczekiwanych dla poszczególnych typów parametrów zawiera opis właściwości ShaderParameter.value w Skorowidzu języka ActionScript 3.0.

Każdy obiekt ShaderParameter ma także właściwość index , która określa położenie danego parametru na liście parametrów modułu cieniującego. Obok tych właściwości obiekt ShaderParameter może mieć dodatkowe właściwości zawierające wartości metadanych określone przez autora modułu. Autor może na przykład określić dla parametru takie metadane, jak minimum, maksimum i wartość domyślna. Wszelkie wartości metadanych określone przez autora są dodawane do obiektu ShaderParameter jako właściwości dynamiczne. Aby odczytać te właściwości, należy użyć pętli for..in i przeglądnąć dynamiczne właściwości obiektu ShaderParameter w celu rozpoznania jego metadanych. Poniższy przykład ilustruje użycie pętli for..in do rozpoznania metadanych obiektu ShaderParameter. Każda wartość metadanych jest dodawana do wystąpienia klasy Vector o nazwie metadata . W przykładzie przyjęto założenie, że istnieje już wystąpienie klasy Shader o nazwie myShader i że ma ono parametr o nazwie 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