Pixel Bender をちょっとやってみた。

メモ的です。
#ああ、まだ全然分かんないから丸のみにしないで。
そろそろFlash10も出そうなのでちょっくらPixel Bender をインストールしてみたら普通にGPUに対応しているんだね。
ってことで、簡易ベンチしてみました。
CPUのみで処理(←プロパティで設定できるよ)

GPU処理

#100倍も違うとは。
参考にさせていただいているページ

んで、早速クールなフィルターが作りたくて勉強しているのですが、なんか書きづらい。
↓ちょびっと勉強してて感じたことを書いてます。

float4

float4 は 4つの値がいっぺんに格納できる値(配列)って思うと簡単かも。
float3 は3個。float2は2個。floatは1個。
宣言は float4( 1 , 1 , 1 , 1 );
でもまとめて計算もできるっぽい。

float4( 1.0 - 0.5 ) ⇒
                      float( 1.0 - 0.5 )
                      float( 1.0 - 0.5 )
                      float( 1.0 - 0.5 )
                      float( 1.0 - 0.5 )

まとめて書けるのがとにかく便利。
float4を使う理由は画像のRGBAがまとめて設定できるからだと思う。

出力について

src は読み込み画像
dst は出力画像
srcはいきなり float4に変換されるのであまりフィルター部分では最初だけでそれ以降はあんま見ない。

float4 inputColor;
inputColor = sampleNearest( src , outCoord() ); //outCoord()分かんない

どっちかというと dst で遊ぶ。

dst = sampleNearest( src , outCoord() ); //outCoord()分かんない
dst.a = dst.a * 0.5;

普通のプログラムと違うところ

rgbaのセットでまとめて計算できる。

//RGBA値を全部半分
dst.rgba = dst.rgba * 0.5;
//こっちでもOK
dst = dst * 0.5;

もちろん、個別に計算したい時は dst.r とかで取り出して計算できる。

パラメーター設定

パラメーターはメインプログラムの上に書きます。
Pixel Bender上ではパラメーターがインターフェイスになるのでデバッグが簡単。

//パラメーター作成
parameter float4 ColorRatio
<
    defaultValue:float4(1,1,1,1);
>;
//メイン部分
input image4 src;
output pixel4 dst;
void
evaluatePixel()
{
    //フィルター部分
}

実際にみんなに使ってもらう

FlashFlexからはshader.data.paramで設定できるっぽいです(←まだやってない)

shader.data.ColorRatio.value[0]=0.5;
shader.data.ColorRatio.value[1]=0.6;
shader.data.ColorRatio.value[2]=0.7;
shader.data.ColorRatio.value[3]=0.8;

以下は現在勉強中のプログラムのネタです。

RGBA色を変更

<languageVersion:1.0;>
kernel NewFilter
<
    namespace:"myname";
    vendor:"myname";
    version:1;
    description:"my description";
>
{
    parameter float4 ColorRatio
    <
        defaultValue:float4(1,1,1,1);
    >;
    input  image4 src;
    output pixel4 dst;
    void evaluatePixel(){
        float4 inputColor;
        inputColor = sampleNearest( src , outCoord() );
        dst        = inputColor * ColorRatio;
    }
}

レベルフィルター

<languageVersion : 1.0;>
kernel NewFilter
<   nameSpace : "anttikupila";
    vendor : "Antti Kupila";
    version : 1;
    description : "Levels filter";
>
{
    //parameter setting
    parameter float2 red<
        minValue    :float2( 0 , 0 );
        maxValue    :float2( 1 , 1 );
        defaultValue:float2( 0 , 1 );
    >;
    parameter float2 green<
        minValue    :float2( 0 , 0 );
        maxValue    :float2( 1 , 1 );
        defaultValue:float2( 0 , 1 );
    >;
    parameter float2 blue<
        minValue    :float2( 0 , 0 );
        maxValue    :float2( 1 , 1 );
        defaultValue:float2( 0 , 1 );
    >;
    parameter float2 RGB<
        minValue    :float2( 0 , 0 );
        maxValue    :float2( 1 , 1 );
        defaultValue:float2( 0.1 , 0.9 );
    >;
    //input output image
    input  image4 src;
    output pixel4 dst;
    //main program
    void evaluatePixel(){
        //input image
        pixel4 p;
        p = sampleNearest( src , outCoord() );
        //param RGB Diff
        float rgbdiff = RGB[1] - RGB[0];
        p.r = ( ( p.r - red[0] )  / ( red[1] - red[0] )     - RGB[0] ) / rgbdiff;
        p.g = ( ( p.g - green[0] )/ ( green[1] - green[0] ) - RGB[0] ) / rgbdiff;
        p.b = ( ( p.b - blue[0] ) / ( blue[1] - blue[0] ) / - RGB[0] ) / rgbdiff;
        //output
        dst = p;
    }
}

セピア

kernel Sepia
<
    namespace:          "popforge::ImageProcessing";
    vendor:             "Joa Ebert";
    version:            1;
    description:        "A good looking sepia filter using Y transform";
>
{
    input image4 src;
    output pixel4 dst;
    void
    evaluatePixel()
    {
        pixel4 color = sampleLinear( src, outCoord() );
        float y = 0.299 * color.r + 0.587 * color.g + 0.114 * color.b;
        // use min/max instead of if's
        float r = min(1.0, y + 0.19);
        float g = max(0.0, y - 0.055);
        float b = max(0.0, y - 0.22);
        dst = pixel4(r,g,b,1.0);
    }
}

ピクセレート(モザイク)

<languageVersion : 1.0;>
kernel NewFilter
<   namespace : "Your Namespace";
    vendor : "Your Vendor";
    version : 1;
    description : "your description";
>
{
    parameter float2 strength<
        minValue:       float2(1.0);
        maxValue:       float2(64.0);
        defaultValue:   float2(2.0);
        description:    "The strength or square-size.";
    >;
    input image4 src;
    output pixel4 dst;
    void
    evaluatePixel()
    {
        float2 pos = outCoord();
        pos -= mod( pos, strength );
        dst = sampleNearest( src, pos );
    }
}

おそらく outCoord() で現在のx,y座標を取得で sampleNearest( src , pos ) で ActionScript における .draw( src , matrix ) みたいなのをしているもんだと思う。
基本畳み込み。