Especificación de valores de entrada y parámetro de sombreado

Flash Player 10 y posterior, Adobe AIR 1.5 y posterior

Un gran número de sombreados de Pixel Bender se definen para utilizar una o varias imágenes de entrada que se utilizan en el procesamiento de sombreado. Por ejemplo, es habitual que un sombreado acepte una imagen fuente y dar lugar a dicha imagen con un efecto determinado aplicado en la misma. En función de cómo se utilice el sombreado, el valor de entrada se podrá especificar automáticamente o quizá será necesario proporcionar un valor de forma explícita. Asimismo, numerosos sombreados especifican parámetros que se utilizan para personalizar la salida del sombreado. Para poder utilizar el sombreado, también debe establecer explícitamente un valor para cada parámetro.

La propiedad data del objeto Shader se utiliza para establecer entradas y parámetros de sombreado y para determinar si un sombreado específico espera entradas o parámetros. La propiedad data es una instancia de ShaderData.

Identificación de entradas y parámetros de sombreado

El primer paso para especificar los valores de entrada y parámetro de sombreado es determinar si el sombreado que se utiliza espera imágenes o parámetros de entrada. Cada instancia de Shader tiene una propiedad data que contiene un objeto ShaderData. Si el sombreado define entradas o parámetros, a estos se accede como propiedades de dicho objeto ShaderData. Los nombres de las propiedades coinciden con los nombres especificados para las entradas y los parámetros del código fuente del sombreado. Por ejemplo, si un sombreado define una entrada src , el objeto ShaderData tiene una propiedad src que representa dicha entrada. Cada propiedad que representa una entrada es una instancia de ShaderInput, y cada propiedad que representa un parámetro es una instancia de ShaderParameter.

Lo ideal es que el autor del sombreado proporcione la documentación para dicho sombreado, indicando los valores de imagen de entrada y los parámetros que espera el sombrado, lo que representan, los valores adecuados, etc.

Sin embargo, si el sombreado no está documentado (y no se dispone de su código fuente), se pueden examinar los datos del sombreado para identificar las entradas y los parámetros. Las propiedades que representan las entradas y los parámetros se añaden de forma dinámica al objeto ShaderData. En consecuencia, se puede utilizar un bucle for..in para examinar el objeto ShaderData y determinar si su sombreado asociado define entradas o parámetros. Como se describe en Acceso a los metadatos de sombreado , a los valores de metadatos definidos para un sombrado también se accede como una propiedad dinámica añadida a la propiedad Shader.data . Al utilizar esta técnica para identificar las entradas y los parámetros de sombreado, compruebe los tipos de datos de las propiedades dinámicas. Si una propiedad es una instancia de ShaderInput dicha propiedad representa una entrada. Si es una instancia de ShaderParameter, representa un parámetro. De lo contrario, es un valor de metadatos. El ejemplo siguiente muestra cómo utilizar un bucle for..in para examinar las propiedades dinámicas de la propiedad data de un sombreado. Cada entrada (objeto ShaderInput) se añade a la instancia de Vector inputs . Cada parámetro (objeto ShaderParameter) se añade a la instancia de Vector parameters . Por último, las propiedades de metadatos se añaden a la instancia de Vector metadata . Es necesario tener en cuenta que en este ejemplo se asume que ya se ha creado una instancia de Shader denominada 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

Especificación de valores de entrada de sombreado

Un gran número de sombreados esperan una o varias imágenes de entrada que se utilizan en el procesamiento de sombreados. Sin embargo, en un gran número de casos se especifica una entrada automáticamente al utilizar el objeto Shader. Por ejemplo, si un sombreado requiere una entrada, y dicho sombreado se utiliza como filtro. Cuando el filtro se aplica a un objeto de visualización o un objeto BitmapData, dicho objeto se establece automáticamente con la entrada. En este caso no se establece explícitamente un valor de entrada.

No obstante, en algunos casos, en especial si un sombreado define varias entradas, el valor para la entrada se establece explícitamente. Cada entrada que se define en un sombreado viene representada en ActionScript por un objeto ShaderInput. El objeto ShaderInput es una propiedad de la instancia de ShaderData de la propiedad data del objeto Shader, como se describe en Identificación de entradas y parámetros de sombreado . Por ejemplo, si un sombreado define una entrada denominada src y dicho sombreado está vinculado a un objeto Shader denominado myShader . En este caso, se accede al objeto ShaderInput correspondiente a la entrada src a través del identificador siguiente:

myShader.data.src

Cada objeto ShaderInput tiene una propiedad input que se utiliza para establecer el valor de la entrada. La propiedad input se establece como una instancia de BitmapData para especificar datos de imagen. La propiedad input también se puede establecer como BitmapData o Vector.<Number> instancia para especificar datos binarios o numéricos. Para obtener información detallada y conocer las restricciones relativas a la utilización de una instancia de BitmapData o Vector.<Number> como entrada, consulte el listado ShaderInput.input en Referencia de ActionScript 3.0 para la plataforma de Adobe Flash .

Además de la propiedad input , el objeto ShaderInput presenta propiedades que se pueden utilizar para determinar el tipo de imagen que espera la entrada. Entre estas propiedades se incluyen width , height y channels . Cada objeto ShaderInput también tiene una propiedad index que resulta útil para determinar si se debe proporcionar un valor explícito para la entrada. Si un sombreado espera más entradas de las establecidas automáticamente, se deberán establecer valores para dichas entradas. Para obtener información detallada sobre las diferentes formas de utilizar un sombreado, y si los valores de entrada se establecen automáticamente, consulte Uso de un sombreado .

Especificación de valores de parámetro de sombreado

Algunos sombreados definen valores de parámetro que el sombreado utiliza al crear su resultado. Por ejemplo, un sombreado que modifica el brillo de una imagen podría especificar un parámetro de brillo que determine el grado en que la operación afecta el brillo. Un solo parámetro definido en un sombreado puede esperar uno o varios valores, en función de la definición de parámetro en el sombreado. Cada parámetro que se define en un sombreado está representado en ActionScript por un objeto ShaderParameter. El objeto ShaderParameter es una propiedad de la instancia de ShaderData de la propiedad data del objeto Shader, como se describe en Identificación de entradas y parámetros de sombreado . Por ejemplo, si un sombreado define un parámetro denominado brightness , y dicho sombreado está representado por un objeto Shader denominado myShader . En este caso se accede al objeto ShaderParameter correspondiente al parámetro brightness a través del identificador siguiente:

myShader.data.brightness

Para establecer un valor (o varios valores) para el parámetro, cree un conjunto ActionScript que contenga el valor o los valores y asígnela a la propiedad value del objeto ShaderParameter. La propiedad value se define como una instancia de Array porque es posible que un solo parámetro de sombreado requiera varios valores. Incluso si el parámetro de sombreado espera únicamente un solo valor, este valor se debe incluir en un objeto Array para asignarlo a la propiedad ShaderParameter.value . El listado siguiente muestra cómo establecer un solo valor con la propiedad value :

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

Si el código fuente de Pixel Bender del sombreado define un valor predeterminado para el parámetro, se creará un conjunto que contendrá el valor o los valores predeterminados y se asignará a la propiedad value del ShaderParameter al crear el objeto Shader. Una vez que se ha asignado un conjunto a la propiedad value (incluso si se trata del conjunto predeterminado), se podrá modificar el valor de parámetro cambiando el valor del elemento de conjunto. No es necesario crear un conjunto nuevo y asignarlo a la propiedad value .

En el ejemplo siguiente se muestra cómo establecer un valor de parámetro de sombreado en ActionScript. En este ejemplo el sombrado define el parámetro color . El parámetro color se declara como una variable float4 en el código fuente de Pixel Bender, por lo que se trata de un conjunto de cuatro números de coma flotante. En el ejemplo, el valor del parámetro color cambia continuamente, y cada vez que cambia el sombreado se utiliza para dibujar un rectángulo de color en la pantalla. El resultado es un cambio de color animado.

Nota: el código de este ejemplo fue escrito por Ryan Taylor. Gracias Ryan por compartir este ejemplo. Para obtener información sobre el trabajo de Ryan, consulte www.boostworthy.com/ .

El código ActionScript se centra en tres métodos:

  • init() : en el método init() el código carga el archivo de código de bytes de Pixel Bender que contiene el sombreado. Cuando se carga el archivo, se llama al método onLoadComplete() .

  • onLoadComplete() : en el método onLoadComplete() el código crea el objeto Shader denominado shader . También se crea una instancia de Sprite denominada texture . En el método renderShader() , el código dibuja el resultado del sombreado en texture una sola vez por fotograma.

  • onEnterFrame() : el método onEnterFrame() se llama una vez en cada fotograma, lo que crea el efecto de animación. En este método, el código establece el valor del parámetro del sombreado en el color nuevo y, a continuación, llama al método renderShader() para dibujar el resultado del sombreado como un rectángulo.

  • renderShader() : en el método renderShader() , el código llama al método Graphics.beginShaderFill() para especificar un relleno de sombreado. A continuación, dibuja un rectángulo cuyo relleno viene definido por la salida del sombreado (el color generado). Para obtener más información sobre la utilización de un sombreado de este modo, consulte Uso de un sombreado como relleno de dibujo .

Este es el código de ActionScript de este ejemplo. Utilice esta clase como clase principal de aplicación para un proyecto solo ActionScript en Flex, o bien, como la clase de documento para el archivo FLA en 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(); 
        } 
    } 
}

A continuación se incluye el código fuente del núcleo del sombreado ColorFilter, que se utiliza para crear el archivo de código de bytes “ColorFilter.pbj” de 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; 
    } 
}

Si utiliza un sombreado cuyos parámetros no están documentados, podrá determinar cuántos elementos y de qué tipo se deben incluir en el conjunto si comprueba la propiedad type del objeto ShaderParameter. La propiedad type indica el tipo de datos del parámetro como se define en el propio sombreado. Para obtener una lista del número y tipo de elementos que espera cada tipo de parámetro, consulte el listado de la propiedad ShaderParameter.value en la referencia del lenguaje.

Cada objeto ShaderParameter también tiene una propiedad index que indica la ubicación adecuada del parámetro en el orden de los parámetros del sombreado. Además de estas propiedades, los objetos ShaderParameter pueden presentar propiedades adicionales que contienen valores de metadatos proporcionados por el autor del sombreado. Por ejemplo, el autor puede especificar los valores de metadatos mínimo, máximo y predeterminado para un parámetro determinado. Los valores de metadatos que el autor especifica se añaden al objeto ShaderParameter como propiedades dinámicas. Para examinar estas propiedades, utilice el bucle for..in para recorrer las propiedades dinámicas del objeto ShaderParameter e identificar sus metadatos. El ejemplo siguiente muestra cómo utilizar un bucle for..in para identificar los metadatos de un objeto ShaderParameter. Cada valor de metadatos se añade a una instancia de Vector denominada metadata . Tenga en cuenta que este ejemplo asume que las instancias de Shader myShader ya están creadas, y que tienen un parámetro 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