Swanman's Horizon

性欲をもてあましつつなんらかの話をするよ。

FMX3Dで任意のシェーダを使う

シェーダってなに?

google:シェーダ

FireMonkeyでのシェーダ

FireMonkeyでは基本的にTCustomMaterial(の派生クラス)とシェーダが1:1で対応します。そしてTCustomMaterialはTMaterialSource(の派生クラス)が保持します。つまり、3DオブジェクトにTMaterialSourceを割り当てることは、3Dオブジェクトにシェーダを割り当てることと同義です。
上記のような関係により、FireMonkeyで任意のシェーダを使う場合は、TCustomMaterialとTMaterialSourceを実装すればいいことになります。

サンプル

説明より実際のコードを見た方が早いと思うので、最低限の実装を用意してみました(今回はWindows向けなのでDX9とDX10用)。XE4での実装なのでそれ以外の環境では修正が必要かもしれません。
ダウンロード

使い方

インストールして普通のMaterialSourceと同じように割り当てるか、動的に割り当てる場合は以下のようなコードを書きます。

var
  mat: TCheapMaterialSource;
begin
  mat := TCheapMaterialSource.Create(Self);
  Sphere1.MaterialSource := mat;
end;

シェーダを動的に読み込むようになっているので、同梱のシェーダはexeと同じ階層に置くか、あるいはCheapMaterial.pas内のファイル名指定部分を修正して下さい。

注意点

TContextShaderSource.Createの最後の引数であるSizeは、TContextShaderArchによって扱いが異なります。DX9の場合、ここはfloat*4を1つと数えた場合のデータの数で、DX10は単純にバイト数になります。なので例えば4x4行列を渡す場合、DX9は4、DX10は64を指定することになります。DX11やGLSLは未調査ですが、TContext3Dの各実装を見ればたぶん分かると思います。

シェーダはDirectX SDKWindows SDK(こっちに入ってる方が最新)に含まれるfxc.exeでコンパイルできます。compile_shaders.batを実行するとDX9とDX10用の頂点シェーダとピクセルシェーダがコンパイルされるようになっていますが、各環境に合わせて一行目のパスを書き換えて使ってください。

その他

かなりざっくりと書いたので、不明点等あれば @lynatan までお願いします。

追記(10/19 13:00)

頂点シェーダで使われる変数名等はFMX.Context.XXX内で指定されている場合があります。DX9では特にないんですが、DX10だとセマンティクスが任意に名付けられるので、FMX.Context.DX10.pas内のTDX10Context.DoDrawPrimitivesを参照して同じ名前を使う必要があります。GLSL(Mac)だとFMX.Context.Mac.pasのTContextOpenGL.FindProgramに変数名の記述があります。