シェーダーの入力およびパラメーターの値の指定

Flash Player 10 以降、Adobe AIR 1.5 以降

多くの場合、Pixel Bender シェーダーは、シェーダー処理過程で 1 つまたは複数の入力イメージを使用するように定義されています。例えば、シェーダーがソースイメージを取得し、特定のエフェクトを適用してそのイメージを出力する場合などがあります。シェーダーの使用方法に応じて、入力値が自動的に指定される場合と、値を明示的に指定する必要がある場合があります。同様に、多くのシェーダーでは、シェーダーの出力をカスタマイズするためのパラメーターを指定します。シェーダーを使用する前に、個々のパラメーターの値も明示的に指定する必要があります。

Shader オブジェクトの data プロパティは、シェーダーの入力およびパラメーターの設定と、そのシェーダーに入力またはパラメーターが必要かどうかの特定に使用されます。data プロパティは ShaderData インスタンスです。

シェーダーの入力およびパラメーターの識別

シェーダーの入力値とパラメーター値を指定するには、まず、そのシェーダーに入力イメージとパラメーターが必要かどうかを確認します。各 Shader インスタンスには ShaderData オブジェクトを含む data プロパティがあります。シェーダーに定義されている入力やパラメーターには、ShaderData オブジェクトのプロパティとしてアクセスします。プロパティの名前は、シェーダーソースコードで指定されている入力やパラメーターの名前と一致します。例えば、シェーダーに src という入力が定義されている場合、ShaderData オブジェクトは src という名前のプロパティでその入力を表します。入力を表す個々のプロパティは ShaderInput インスタンスで、パラメーターを表す個々のプロパティは ShaderParameter インスタンスです。

理想的には、シェーダーの作者が、シェーダーに必要な入力イメージの値やパラメーター、それらが表す内容、適切な値など、シェーダーに関する説明を提供します。

ただし、シェーダーに説明がない場合やソースコードがない場合、シェーダーデータを調べて入力やパラメーターを確認できます。入力やパラメーターを表すプロパティは ShaderData オブジェクトに動的に追加されます。したがって、for..in ループを使用して ShaderData オブジェクトを調べ、関連付けられているシェーダーで入力やパラメーターが定義されているかどうかを確認できます。シェーダーメタデータへのアクセスで説明しているように、シェーダーに定義されているメタデータ値には、Shader.data プロパティに追加されたダイナミックプロパティとしてもアクセスできます。この方法でシェーダーの入力とパラメーターを識別する場合は、ダイナミックプロパティのデータ型を調べます。ShaderInput インスタンスであるプロパティは、入力を表し、ShaderParameter インスタンスであるプロパティは、パラメーターを表します。どちらでもなければ、メタデータ値です。次の例では、for..in ループを使用してシェーダーの data プロパティのダイナミックプロパティを調べる方法を示します。各入力(ShaderInput オブジェクト)は inputs という名前の Vector インスタンスに追加されます。各パラメーター(ShaderParameter オブジェクト)は parameters という名前の Vector インスタンスに追加されます。最後に、メタデータプロパティは metadata という名前の Vector インスタンスに追加されます。この例では、myShader という名前の Shader インスタンスが既に作成されているとします。

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

シェーダー入力値の指定

多くのシェーダーは、シェーダー処理過程で使用する 1 つまたは複数の入力イメージを必要とします。ただし、多くの場合、Shader オブジェクトの使用時に入力は自動的に指定されます。例えば、1 つの入力を使用するシェーダーがあり、そのシェーダーがフィルターとして使用される場合を考えてみましょう。そのフィルターが表示オブジェクトまたは BitmapData オブジェクトに適用されるとき、オブジェクトは自動的に入力として設定されます。この場合は入力値を明示的に設定しません。

ただし、場合によっては、特にシェーダーに複数の入力が定義されている場合は、入力値を明示的に設定します。シェーダー内に定義されている各入力は ActionScript 内では ShaderInput オブジェクトで表されます。シェーダーの入力およびパラメーターの識別で説明しているように、ShaderInput オブジェクトは Shader オブジェクトの data プロパティにおける ShaderData インスタンスのプロパティです。例えば、シェーダーに src という名前の入力が定義されていて、そのシェーダーが myShader という名前の Shader オブジェクトにリンクしているとします。この場合、src 入力に対応する ShaderInput オブジェクトには次の識別子を使用してアクセスします。

myShader.data.src

各 ShaderInput オブジェクトには、入力の値を設定するために使用される input プロパティがあります。イメージデータを指定するには、input プロパティを BitmapData インスタンスに設定します。また、バイナリデータや数値データを指定するには、input プロパティを BitmapData または Vector.<Number> インスタンスに設定します。BitmapData または Vector.<Number> インスタンスの input プロパティとしての使用や制限について詳しくは、『Adobe Flash Platform 用 ActionScript 3.0 リファレンスガイド』の ShaderInput.input を参照してください。

input プロパティのほか、ShaderInput オブジェクトには、入力に必要なイメージの種類を特定するために使用するプロパティもあります。これらのプロパティには widthheight および channels プロパティが含まれます。各 ShaderInput オブジェクトには、明示的に入力値を指定する必要があるかどうかの判断に役立つ index プロパティもあります。シェーダーに必要な入力が自動的に設定された数より多い場合は、これらの入力の値を設定します。シェーダーの様々な使用方法や、入力値が自動的に設定されるかどうかについて詳しくは、シェーダーの使用を参照してください。

シェーダーパラメーター値の指定

一部のシェーダーは、結果出力の作成時に使用するパラメーター値を定義します。例えば、イメージの輝度を変更するシェーダーは、操作が輝度に与える影響を決定する brightness パラメーターを指定します。シェーダーのパラメーター定義に応じて、シェーダーで定義されている 1 つのパラメーターに必要な値が 1 つである場合も複数である場合もあります。シェーダーで定義されている各パラメーターは、ActionScript 内では ShaderParameter オブジェクトで表されます。シェーダーの入力およびパラメーターの識別で説明しているように、ShaderParameter オブジェクトは Shader オブジェクトの data プロパティにおける ShaderData インスタンスのプロパティです。例えば、シェーダーに brightness という名前のパラメーターが定義されていて、そのシェーダーが myShader という名前の Shader オブジェクトで表されているとします。この場合、brightness パラメーターに対応する ShaderParameter には次の識別子を使用してアクセスします。

myShader.data.brightness

パラメーターの値(1 つまたは複数)を設定するには、その値を含む ActionScript 配列を作成し、配列を ShaderParameter オブジェクトの value プロパティに割り当てます。1 つのシェーダーパラメーターに複数の値が必要な場合があるので、value プロパティは Array インスタンスとして定義されます。シェーダーパラメーターに必要な値が 1 つでも、値を ShaderParameter.value プロパティに割り当てるには、値を Array オブジェクトに含める必要があります。次の例は、value プロパティとして 1 つの値を設定する方法を示します。

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

シェーダーの Pixel Bender ソースコードがパラメーターのデフォルト値を定義している場合、Shader オブジェクトの作成時に、そのデフォルト値を含む配列が作成され、ShaderParameter オブジェクトの value プロパティに割り当てられます。value プロパティに配列(デフォルト配列である場合も含む)を割り当てた後は、配列要素の値を変更することによってパラメーター値を変更できます。新しい配列を作成して value プロパティに割り当てる必要はありません。

次の例は、ActionScript 内でシェーダーのパラメーター値を設定する方法を示します。この例ではシェーダーは color という名前のパラメーターを定義します。color パラメーターは Pixel Bender ソースコードで float4 変数として宣言されています。つまり、4 つの浮動小数点数を持つ配列です。この例では、color パラメーター値が繰り返し変更され、変更のたびに画面に色付きの矩形を描画するシェーダーが使用されます。結果は色が変化するアニメーションになります。

注意: このコード例は Ryan Taylor 氏が作成したものです。この例の掲載を許可してくれた Ryan 氏に感謝いたします。Ryan 氏の著述は www.boostworthy.com/ で読むことができます。

ActionScript コードには重要な 3 つのメソッドがあります。

  • init()init() メソッドで、シェーダーが含まれる Pixel Bender バイトコードファイルがロードされます。ファイルがロードされると、onLoadComplete() メソッドが呼び出されます。

  • onLoadComplete()onLoadComplete() メソッドで、shader という名前の Shader オブジェクトが作成されます。また、texture という名前の Sprite インスタンスも作成されます。renderShader() メソッドで、1 フレームに 1 回、シェーダーの結果が texture に描画されます。

  • onEnterFrame()onEnterFrame() メソッドは 1 フレームに 1 回呼び出され、アニメーションエフェクトを作成します。このメソッドで、シェーダーパラメーター値が新しい色に設定され、renderShader() メソッドが呼び出されてシェーダーの結果が矩形として描画されます。

  • renderShader()renderShader() メソッドで、シェーダーの塗りを指定するために Graphics.beginShaderFill() メソッドが呼び出されます。それによって、シェーダー出力が定義する塗り(生成された色)で矩形が描画されます。この方法でシェーダーを使用する方法について詳しくは、描画の塗りでのシェーダーの使用を参照してください。

この例の ActionScript コードは次のようになります。Flash Builder の ActionScript のみのプロジェクトでは、このクラスをメインアプリケーションクラスとして使用します。または、Flash Professional の FLA ファイルでは、ドキュメントクラスとして使用します。

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

次の例は、「ColorFilter.pbj」という Pixel Bender バイトコードファイルの作成に使用された ColorFilter シェーダーカーネルのソースコードです。

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

パラメーターの説明がないシェーダーを使用する場合、ShaderParameter オブジェクトの type プロパティを調べることによって、配列に含まれている要素のデータ型と個数を知ることができます。type プロパティはシェーダー自体で定義されているパラメーターのデータ型を示します。各パラメーター型に必要な要素の個数と型については、『ActionScript 3.0 リファレンスガイド』の ShaderParameter.value プロパティの説明を参照してください。

各 ShaderParameter オブジェクトには、一連のシェーダーパラメーターの中でのそのパラメーターの順番を示す index プロパティもあります。これらのプロパティのほか、ShaderParameter オブジェクトには、シェーダーの作者が指定したメタデータ値を保持するプロパティを追加できます。例えば、作者はパラメーターの最小、最大、デフォルトなどの値をメタデータ値として指定できます。作者が指定したメタデータ値は、ShaderParameter オブジェクトにダイナミックプロパティとして追加されます。そのようなプロパティを調べるには、for..in ループを使用して ShaderParameter オブジェクトのダイナミックプロパティをループ処理し、そのメタデータを識別します。次の例では、for..in ループを使用して ShaderParameter オブジェクトのメタデータを識別する方法を示します。各メタデータ値が metadata という名前の Vector インスタンスに追加されます。この例では、myShader という名前の Shader インスタンスが既に作成され、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