株式会社antsのホームページへようこそ。

Pixel Bender Toolkitを試してみた

0
Posted in Lab. By kiyokazk

こんにちは、kiyokazkです。
先日Flash Player 10のベータ版が公開されましたが(Adobe Labs – Flash Player 10)、そのFlash Player 10でサポートされるカスタムフィルタ(ピクセルシェーダ)を作成できるツールPixel Bender ToolkitAdobe Labs – Pixel Bender Toolkit)もプレビューリリース 3が公開されたので試してみました。


■環境を作成する
Adobe Labs – Pixel Bender Toolkitからダウンロードしてインストールすれば準備はおしまいです。同サイトにチュートリアルのPDFも置いてあります(英語)。
インストールに成功して起動すると、(僕の環境では)GPUのテストに失敗したからCPUを使ってフィルタリングするね、みたいなダイアログが表示されましたがツール自体は問題なく使えます。次回起動時にこのメッセージを出さないようにするには(毎回CPUを使用するようにするには)、メニューの”Edit – Preferences”でオプションメニューを開いてAdvancedタグにある”Force filters to run on the CPU”にチェックを入れればOKです。

pixel_bender_ss.jpg

3つに区切られたエリアは、左上がイメージを表示する部分、左下がソースエディタ部分、右がフィルタパラメータ用UI部分です。

■基本的なフィルタ
メニューから”File – New Pixel Kernel Filter”を選択すると、ソースエディタ部分に基本的なソースが自動生成されます。これはピクセル座標から元画像の色をサンプリングして出力するだけのフィルタです。元の色を読み込んでそのまま出力するだけなので何も変化しません(フィルタと呼んでいいものか)。

■何か作ってみる
このフィルタを改造して何か作ってみます。ありがちですが画像の一部にモザイクをかけるようなフィルタにしましょう。指定のポイントから半径Rのエリアだけにモザイクがかかるようにしてみます。

実際に行うピクセル処理はevaluatePixel()の中に書いていきます。(ここでは便宜上日本語のコメントを書いていますが、現在のToolkitでは日本語コメントは表示できないようです)

[as3]
void
evaluatePixel()
{
float2 coord = outCoord();
int2 srcCoord = int2(coord);
//intは16ビットしか保証されていないのでfloatで計算
float x_sqr = float(srcCoord.x-position.x) * float(srcCoord.x-position.x);
float y_sqr = float(srcCoord.y-position.y) * float(srcCoord.y-position.y);
float size_sqr = float(areaSize) * float(areaSize);
if( x_sqr + y_sqr < size_sqr ){
//モザイク処理
int2 useCoord = srcCoord;
useCoord /= mosaicSize;
useCoord *= mosaicSize;
useCoord += mosaicSize/2;
pixel4 useCol = sampleNearest(src,float2(useCoord));
dst = useCol;
}
else{
//そのまま出力
pixel4 useCol = sampleNearest(src,coord);
dst = useCol;
}
}
[/as3]

positionの点からareaSize以内の距離にある点をモザイク処理、それ以外をそのまま出力としてあります。モザイク処理の部分はmosaicSizeの定数倍ピクセルごとの正方形の中心の点の色でその正方形の中を全部塗りつぶすことにしました。
また距離比較の計算部分は、int型は16ビットしか保証されないようなのでfloatにキャストして計算しています(実際、intで計算した場合にはToolkit上ではうまく動作しましたが、後述のAdobeデモサイトに読み込ませた場合は正しく動作しませんでした)。

この処理の中でモザイクのブロックサイズ(mosaicSize)、モザイクをかける範囲(areaSize)、モザイクをかける位置(position)を変数として使うので、パラメータとして変更できるようにこれより前で定義しておきます。

[as3]
//パラメータ定義
parameter int mosaicSize
<
minValue:int(1);
maxValue:int(64);
defaultValue:int(8);
>;
parameter int areaSize
<
minValue:int(10);
maxValue:int(300);
defaultValue:int(50);
>;
parameter int2 position
<
minValue:int2(0,0);
maxValue:int2(500,500);
defaultValue:int2(100,100);
>;
[/as3]

パラメータとして定義すると、実行したときにツールの右側エリアに自動的にスライダーが表示されて動的に変更できるようになります。

■実行する
このフィルタを実行してみるには、まず何か画像を読み込んでおく必要があります。メニューの”File – Load Image 1″から何かの画像を選択すると読み込まれて左上のイメージエリアに表示されます。
これで実行準備が整ったのでソースエディタの右下にある「run」ボタンを押せば実行されます。(コンパイルに失敗すると実行されずに右エリアにエラーメッセージが表示されます。)

mosaic_run_ss.jpg
クリックで拡大

右エリアにあるパラメータ変更スライダーで、モザイクのかかる範囲(areaSize)、モザイクのブロックサイズ(mosaicSize)、モザイクの中心位置(position)を変更するとイメージエリアのモザイクが動的に変化します。

■保存と書き出し
作成したフィルタは”File – Save Pixel Bender Kernel Filter”を選択すると*.pbkという拡張子のテキストファイルで保存することができます(Windows版。Macはわからないですごめんなさい)。

Flash用のバイトコードとして書き出したい場合は、”File – “Export Pixel Bender Byte Code Filter for Flash”を選択することで*.pbjファイルとして書き出すことができます。書き出したpbjファイルはFlash Player 10用に追加されたクラスflash.display.Shaderとしてロードしてswfから使用できるようです。

AdobeのPixel Benderデモページ(要Flash Player 10)でもコンパイル済みのフィルタ(pbjファイル)を試すことができます。今回のフィルタも以下に置いておくので、動作を見てみたい方はファイルをダウンロードした上でデモサイトで試してみてください。

■今回使用したソースとフィルタ
今回使用したソースとフィルタを置いておきます。
sample1.pbk (ソースファイル)
sample1.pbj (バイトコード)

[as3]
<languageVersion : 1.0;>
kernel AreaMosaicFilter
< namespace : "kiyokazk";
vendor : "kiyokazk";
version : 1;
description : "area mosaic";
>
{
input image4 src;
output pixel4 dst;
parameter int mosaicSize
<
minValue:int(1);
maxValue:int(64);
defaultValue:int(8);
>;
parameter int areaSize
<
minValue:int(10);
maxValue:int(300);
defaultValue:int(50);
>;
parameter int2 position
<
minValue:int2(0,0);
maxValue:int2(500,500);
defaultValue:int2(100,100);
>;
void
evaluatePixel()
{
float2 coord = outCoord();
int2 srcCoord = int2(coord);
float x_sqr = float(srcCoord.x-position.x) * float(srcCoord.x-position.x);
float y_sqr = float(srcCoord.y-position.y) * float(srcCoord.y-position.y);
float size_sqr = float(areaSize) * float(areaSize);
if( x_sqr + y_sqr < size_sqr ){
int2 useCoord = srcCoord;
useCoord /= mosaicSize;
useCoord *= mosaicSize;
useCoord += mosaicSize/2;
pixel4 useCol = sampleNearest(src,float2(useCoord));
dst = useCol;
}
else{
pixel4 useCol = sampleNearest(src,coord);
dst = useCol;
}
}
}
[/as3]