Especificação de valores de entrada e de parâmetro de sombreador

Flash Player 10 e posterior, Adobe AIR 1.5 e posterior

Muitos sombreadores Pixel Bender são definidos para usar uma ou mais imagens de entrada que são usadas no processamento do sombreador. Por exemplo, é comum um sombreador aceitar uma imagem de origem e produzi-la com um efeito específico aplicado a ela. Dependendo de como o sombreador é usado, o valor de entrada pode ser especificado automaticamente ou você pode precisar fornecer um valor explicitamente. De modo semelhante, muitos sombreadores especificam parâmetros que são usados para personalizar a saída do sombreador. Você também deve definir explicitamente um valor para cada parâmetro antes de usar o sombreador.

Você usa a propriedade data do objeto Shader para definir entradas e parâmetros do sombreador e para determinar se um sombreador específico espera entradas ou parâmetros. A propriedade data é uma ocorrência de ShaderData.

Identificação de entradas e parâmetros de sombreador

A primeira etapa da especificação de valores de entrada e de parâmetro de sombreador é descobrir se o sombreador específico que você está usando espera qualquer imagem ou parâmetro de entrada. Cada ocorrência de Shader tem uma propriedade data que contém um objeto ShaderData. Se o sombreador definir quaisquer entradas ou parâmetros, eles serão acessados como propriedades desse objeto ShaderData. Os nomes de propriedades correspondem aos nomes especificados para as entradas e parâmetros no código fonte do sombreador. Por exemplo, se um sombreador definir uma entrada denominada src , o objeto ShaderData terá uma propriedade denominada src que representa essa entrada. Cada propriedade que representa uma entrada é uma ocorrência de ShaderInput, e cada propriedade que representa um parâmetro é uma ocorrência de ShaderParameter.

O ideal é que o autor do sombreador forneça documentação do sombreador, indicando quais valores de imagens de entrada e de parâmetros o sombreador espera, o que eles representam, os valores apropriados, e assim por diante.

No entanto, se o sombreador não estiver documentado (e você não tiver seu código fonte), você poderá inspecionar os dados do sombreador para identificar as entradas e parâmetros. As propriedades que representam entradas e parâmetros são adicionadas dinamicamente ao objeto ShaderData. Consequentemente, você pode usar um loop for..in para examinar o objeto ShaderData para descobrir se o sombreador associado define quaisquer entradas ou parâmetros. Conforme descrito em Acesso aos metadados de sombreador , qualquer valor de metadados definido para um sombreador também é acessado como uma propriedade dinâmica adicionada à propriedade Shader.data . Ao usar essa técnica para identificar entradas e parâmetros de sombreador, verifique o tipo de dados das propriedades dinâmicas. Se uma propriedade for uma ocorrência de ShaderInput, ela representará uma entrada. Se ela for uma ocorrência de ShaderParameter, ela representará um parâmetro. Caso contrário, ela será um valor de metadados. O exemplo a seguir mostra como usar um loop for..in para examinar as propriedades dinâmicas da propriedade data de um sombreador. Cada entrada (objeto ShaderInput) é adicionada a uma ocorrência de Vector denominada inputs . Cada parâmetro (objeto ShaderParameter) é adicionado a uma ocorrência de Vector denominada parameters . Finalmente, quaisquer propriedades de metadados são adicionadas a uma ocorrência de Vector denominada metadata . Observe que este exemplo pressupõe que uma ocorrência de Shader denominada myShader já foi criada:

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

Especificação de valores de entrada de sombreador

Muitos sombreadores esperam uma ou mais imagens de entrada que são usadas no processamento do sombreador. No entanto, em muitos casos, uma entrada é especificada automaticamente quando o objeto Shader é usado. Por exemplo, suponha que um sombreador exija uma entrada e seja usado como um filtro. Quando o filtro é aplicado a um objeto de exibição ou a um objeto BitmapData, esse objeto é definido automaticamente como a entrada. Nesse caso você não define explicitamente um valor de entrada.

No entanto, em alguns casos, especialmente se um sombreador definir várias entradas, você definirá explicitamente um valor para uma entrada. Cada entrada definida em um sombreador é representada no ActionScript por um objeto ShaderInput. O objeto ShaderInput é uma propriedade da ocorrência de ShaderData na propriedade data do objeto Shader, conforme descrito em Identificação de entradas e parâmetros de sombreador . Por exemplo, suponha que um sombreador defina uma entrada denominada src e que o sombreador esteja vinculado a um objeto Shader denominado myShader . Nesse caso, você acessa o objeto ShaderInput que corresponde à entrada src usando o seguinte identificador:

myShader.data.src

Cada objeto ShaderInput tem uma propriedade input usada para definir o valor da entrada. Você define a propriedade input como uma ocorrência de BitmapData para especificar dados da imagem. Também pode definir a propriedade input como uma ocorrência de BitmapData ou Vector.<Number> para especificar dados binários ou numéricos. Para obter detalhes e restrições sobre o uso de uma instância de BitmapData ou Vector.<Number> como entrada, consulte a lista ShaderInput.input em Referência do ActionScript® 3.0 para Adobe® Flash® Platform .

Além da propriedade input , um objeto ShaderInput tem propriedades que podem ser usadas para determinar qual tipo de imagem a entrada espera. Essas propriedades incluem as propriedades width , height e channels . Cada objeto ShaderInput também tem uma propriedade index que é útil para determinar se um valor explícito deve ser fornecido para a entrada. Se um sombreador esperar mais entradas do que o número definido automaticamente, defina valores para essas entradas. Para obter detalhes sobre as diferentes maneiras de uso de um sombreador, e se os valores de entrada são definidos automaticamente, consulte Uso de um sombreador .

Especificação de valores de parâmetros de sombreador

Alguns sombreadores definem valores de parâmetros que o sombreador usa para criar seu resultado. Por exemplo, um sombreador que altera o brilho de uma imagem pode especificar um parâmetro de brilho que determina o quanto a operação afeta o brilho. Um único parâmetro definido em um sombreador pode esperar um único valor ou vários valores, de acordo com a definição do parâmetro no sombreador. Cada parâmetro definido em um sombreador é representado no ActionScript por um objeto ShaderParameter. O objeto ShaderParameter é uma propriedade da ocorrência de ShaderData na propriedade de dados do objeto Shader, conforme descrito em Identificação de entradas e parâmetros de sombreador . Por exemplo, suponha que um sombreador defina um parâmetro denominado brightness e que o sombreador esteja representado por um objeto Shader denominado myShader . Nesse caso, você acessa o ShaderParameter que corresponde ao parâmetro brightness usando o seguinte identificador:

myShader.data.brightness

Para definir um ou mais valores para o parâmetro, crie uma matriz do ActionScript que contenha o valor ou valores e atribua essa matriz à propriedade value do objeto ShaderParameter. A propriedade value é definida como uma ocorrência de Array porque é possível que um único parâmetro do sombreador exija vários valores. Mesmo que o parâmetro do sombreador espere um único valor, você deve delimitar o valor em um objeto Array para atribuí-lo à propriedade ShaderParameter.value . A listagem a seguir demonstra como definir um único valor como a propriedade value :

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

Se o código-fonte de Pixel Bender do sombreador definir um valor padrão para o parâmetro, uma matriz que contém o valor ou valores padrão será criada e atribuída à propriedade value do objeto ShaderParameter quando o objeto Shader for criado. Depois que a matriz for atribuída à propriedade value (inclusive se ela for a matriz padrão), o valor do parâmetro poderá ser alterado com a alteração do valor do elemento de matriz. Você não precisa criar uma nova matriz e atribuí-la à propriedade value .

O exemplo a seguir demonstra a configuração de um valor do parâmetro do sombreador no ActionScript. Neste exemplo o sombreador define um parâmetro denominado color . O parâmetro color é declarado como uma variável float4 no código-fonte do Pixel Bender, o que significa que ela é uma matriz de quatro números de ponto flutuante. No exemplo, o valor do parâmetro color é alterado continuamente e, cada vez que ele é alterado, o sombreador é usado para desenhar um retângulo colorido na tela. O resultado é uma alteração de cor animada.

Nota: O código para este exemplo foi escrito por Ryan Taylor. Obrigado por compartilhar este exemplo, Ryan. Para ver o portfólio de Ryan e ler seus artigos, acesse www.boostworthy.com/ .

O código ActionScript está centralizado em torno de três métodos:

  • init() : no método init() , o código carrega o arquivo de código de bytes do Pixel Bender que contém o sombreador. Quando o arquivo é carregado, o método onLoadComplete() é chamado.

  • onLoadComplete() : no método onLoadComplete() , o código cria o objeto Shader chamado shader . Ele também cria uma ocorrência de Sprite chamada texture . No método renderShader() , o código desenha o resultado do sombreador em texture uma vez por quadro.

  • onEnterFrame() : o método onEnterFrame() é chamado uma vez por quadro, o que cria o efeito de animação. Nesse método, o código define o valor do parâmetro do sombreador como a nova cor e, em seguida, chama o método renderShader() para desenhar o resultado do sombreador como um retângulo.

  • renderShader() : no método renderShader() , o código chama o método Graphics.beginShaderFill() para especificar um preenchimento do sombreador. Em seguida, ele desenha um retângulo cujo preenchimento é definido pela saída do sombreador (a cor gerada). Para obter mais informações sobre como usar um sombreador desta maneira, consulte Uso de um sombreador como um preenchimento de desenho .

Veja abaixo o código ActionScript para este exemplo. Use esta classe com a classe de aplicativo principal em um projeto somente ActionScript no Flash Builder ou como a classe do documento para o arquivo FLA no 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(); 
        } 
    } 
}

Este é o código-fonte para o kernel de sombreador ColorFilter, usado para criar o arquivo de código de bytes do Pixel Bender “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; 
    } 
}

Se você estiver usando um sombreador cujos parâmetros não estão documentados, poderá calcular quantos elementos de qual tipo devem ser incluídos na matriz, marcando a propriedade type do objeto ShaderParameter. A propriedade type indica o tipo de dado do parâmetro, conforme definido no próprio sombreador. Para obter uma lista de números e tipos de elementos esperados por cada tipo de parâmetro, consulte a listagem da propriedade ShaderParameter.value na Referência do ActionScript 3.0.

Cada objeto ShaderParameter também tem uma propriedade index que indica onde o parâmetro se ajusta na ordem dos parâmetros do sombreador. Além dessas propriedades, um objeto ShaderParameter pode ter propriedades adicionais que contêm valores de metadados fornecidos pelo autor do sombreador. Por exemplo, o autor pode especificar valores de metadados, como valores mínimos, máximos e padrão para um parâmetro. Todos os valores de metadados especificados pelo autor são adicionados ao objeto ShaderParameter como propriedades dinâmicas. Para examinar essas propriedades, use um loop for..in para executar um loop nas propriedades dinâmicas do objeto ShaderParameter para identificar seus metadados. O exemplo a seguir mostra como usar um loop for..in para identificar metadados de um objeto ShaderParameter. Cada valor de metadados é adicionado a uma ocorrência de Vector denominada metadata . Observe que este exemplo pressupõe que uma ocorrência de Shader denominada myShader já foi criada, e que é conhecida como tendo um parâmetro denominado 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