飴屋

Flash3D/プログラマブルシェーダー

シェーダーの実装方法

実際にプログラマブルシェーダーを実装する場合、以下のような感じになるらしいそうです。

var vertexShaderAssembler:AGALMiniAssembler = new AGALMiniAssembler();
vertexShaderAssembler.assemble( Context3DProgramType.VERTEX,
"m44 op, va0, vc0\n" +
"mov v0, va1"
);
var fragmentShaderAssembler:AGALMiniAssembler= new AGALMiniAssembler();
fragmentShaderAssembler.assemble( Context3DProgramType.FRAGMENT,
"tex ft1, v0, fs0 <2d,linear, nomip>;\n" +
"mov oc, ft1"
);

var program:Program3D = context3D.createProgram();
program.upload( vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode);

AGALMiniAssemblerとかいうクラスになにやら呪文のようなアセンブラにも似たオペレーションコードを渡して、シェーダのバイトコードを作成しているようです。この呪文のようなものはAGALというAdobeの開発したグラフィック処理用の言語で、その仕様はオープンにされています。2D版が前からあったと思いましたが、3D版ははたしてどんな内容なのでしょうか?モチベーションの問題だと思いますが、ここはもうちょっととっつきやすい方法でAGALコードを作成してみましょう。

Pixel Bender 3D

Adobeから公開されているPixel Bender 3Dというソフトを使えば、もうちょっと人間に近い感覚でシェーダープログラムが組めるようです。

Date: 2011/6/15

Pixel Bender 3Dの使い方を調べてみましょう。

専用のプログラム記法で書けるのは、Vertex kernelとMaterial kernelという二つで、頂点と見た目に関するGPUの計算をそれぞれ定義します。Vertex kernelは「.pbvk」、Material kernelは「.pbmk」という拡張子のテキストファイルとしましょう。

Vertex kernel

Vertex kernelの資料よりシンプルなVertext kernelの書き方を抜粋します。

<languageVersion : 1.0;>
vertex kernel SimplestVertexKernel
<
namespace : "AIF Test";
vendor : "Adobe";
version : 1;
>
{
parameter float4x4 objectToClipSpaceTransform
<
id : "PB3D_CLIP_TRANSFORM";
>;
input vertex float3 vertexPosition
<
id : "PB3D_POSITION";
>;
output float4 vertexClipPosition;
void evaluateVertex()
{
vertexClipPosition = float4(
vertexPosition.x, vertexPosition.y,
vertexPosition.z, 1.0 ) * objectToClipSpaceTransform;
}
}

入力に頂点の座標を、操作パラメータに変換行列を、出力に変換後の頂点座標を持っているのがなんとなくわかるでしょうか。evaluateVertexという関数の中で実際に変換処理がかかれてます。「vertexPosition.y」を「-vertexPosition.y」なんて書くときっと頂点座標が上下さかさまになるんでしょうね。

Material kernel

同様にMaterial kernelのサンプルをみてみます。

<languageVersion : 1.0;>
material kernel SimpleMaterialKernel
<
namespace : "AIF Test";
vendor : "Adobe";
version : 1;
>
{
input vertex float3 vertexPosition
<
id : "PB3D_POSITION";
>;
input vertex float3 vertexColor
<
id : "PB3D_COLOR";
>;
interpolated float3 interpolatedColor;
output float4 fragmentColor;
void evaluateVertex()
{
interpolatedColor = vertexColor;
// Tweak the red channel depending on the Z coordinate
if( vertexPosition.z > 4.0 )
interpolatedColor.r /= 2.0;
}
void evaluateFragment()
{
fragmentColor.rgb = interpolatedColor;
fragmentColor.a = 1.0;
}
}

こちらは入力に頂点位置と頂点色をとり、表面色を出力するようになっています。頂点ごとの計算部分(evaluateVertex関数)をみてみると頂点座標の位置に応じて色の赤成分をそのまま出力したり、半減させて出力したりしているようです。z座標が閾値を超えた途端に質感から赤みが減るのでしょうね。

サンプルに出てきた入力値は頂点の座標位置や色ばかりでしたが、法線やテクスチャなどのその他に与えられた情報を処理することもできます。変数や関数のお作法なども合わせてPixel Bender 3Dをダウンロードして中のドキュメントを読めば詳しくわかると思います。なお、これを書いている現時点で読んでいるドキュメントは2番目のプレビュー版でした。大きく「Draft(下書き)」とあるので、変更が入る可能性がありそうです。1番目のプレビュー版と比べたら内容が増えてました。

PB-ASM

Pixel Bender 3Dを使ってVertex kernelとMaterial kernelを次の中間ファイルに変換する場合は、ついてくるコマンドを以下のように叩きます。

pb3dutil vertexKernel.pbvk vertexProgram.pbasm
pb3dutil materialKernel.pbmk matVertProg.pbasm fragProgram.pbasm

前述のVertex kernelがVertex programに、Material kernelがMaterial vertex programとFragment programの二つに変換されて出力されます。この中間ファイルの名前はPB-ASMと書いてあったのですが、中身を見た感じの印象だとこの後バイナリコードを生成するためにテキスト処理をしやすい形式に書きなおしているだけのファイルのように思えます。Material kernelを二つに分けてバーテックスシェーダーとフラグメントシェーダーに変換しやすくもしているのかもしれません。

これを一緒についてきた「pb3dlib.swc」というライブラリを使ってActionScriptでパッケージ化しておくと後々使い勝手がよさそうです。PBASMProgramというクラスで先ほどのPB-ASMというテキストファイルを読み込みます。続いて、PBASMCompiler.compileというメソッドで3つのPBASMProgramをコンパイルするとAGALProgramPairというバーテックスシェーダーとフラグメントシェーダーのセットを表すクラスのインスタンスが出来上がります。ここまでできたらProgram3D.uploadメソッドに両シェーダーのバイナリコードを渡してあげるだけです。オペレーションコードの塊をAGALMiniAssemblerでアセンブルしたときと同等のことがこれで行われました。

Date: 2011/9/13

Flash3D