Dynamic Compilation - WPF Shader Effects
Shader Effects BuildTask and Project Templates
.NET Framework 3.5 SP1 では PixelShader 2.0 を用いてポストエフェクトがかけられるようになりましたが,ユーザ定義エフェクトの作成は少しややこしい準備が必要です.この作業を簡略化するカスタムビルドタスクとプロジェクトテンプレートが,.NET Framework 3.5 SP1 のリリースに合わせて CodePlex にて公開されました.作者は Microsoft WPF team の Greg Schechter & Gerhard Schneider コンビです.
- A VisualStudio BuildTask and project and item templates for writing ShaderEffects - Greg Schechter's Blog
- WPF Futures - CodePlex
このカスタムビルドタスクを用いると,プロジェクトをビルド時にエフェクトファイルのコンパイルも一緒に行われます.XNA Game Studio の Content Pipeline の簡易版とも言えます.
このコンパイル部分ですが,C++/CLI で実装されています.実は出所の怪しい D3DX の静的リンクライブラリが同梱されていて*1,d3dx9_xx.dll が見つからない場合でも単独動作可能という特徴があるようです.
ID3DXEffectCompiler
さて,d3dx9_xx.dll の存在を前提にできるなら*2,アンマネージコードとの相互運用を C# だけで完結させることが可能です.
d3dx9_xx.dll がエクスポートする D3DXCreateEffectCompiler に注目します.このエクスポート関数が返す ID3DXEffectCompiler インターフェイスは,動作に IDirect3DDevice9 を必要とせず,バックグラウンドでエフェクトファイルを取り扱うのに便利です.
ID3DXEffectCompiler を基点として,エフェクトファイルに含まれるシェーダコードをコンパイルしたり,エフェクトファイルに含まれる要素に対するリフレクションを行うことができます.
エフェクトファイルの実行時コンパイルサンプル
ちょうど手元に書きかけの ID3DXEffectCompiler ラッパーライブラリがあったので,少し書き足してそこそこ使える形にまとめてみました.それを使って出来たのが以下のサンプルです.このサンプルは,実行時にエフェクトファイルのコンパイルを行い,動的に WPF のシェーダエフェクトを生成します.
- Binary and source code
- 実行方法
- .NET Framework 3.5 SP1 以降が必要です.
- 起動したら,"Open Movie" ボタンを押して適当に動画ファイルを選択して下さい.
- 左の Compile ボタンを押すと,表示されている HLSL をコンパイル・実行します.
- 適用される PixelShader の関数名は main にハードコードしてあります.
- WPF の仕様で,PixelShader 2.0 に固定されています.
- elapsedSeconds 変数には,動画ファイル先頭からの経過時間がバインドされます.
ID3DXEffectCompiler ラッパーライブラリの使い方
上記サンプルコードに含まれる ID3DXEffectCompiler ラッパーライブラリの使い方をごく簡単に紹介しておきます.
文字列型のエフェクトファイルソースコードから,シェーダのバイトコードを得るには次のようにします.
//D3DX Effect Format const string SourceCode = @"sampler2D implicitInput : register(s0); float elapsedSeconds : register(c0); float4 main(float2 uv : TEXCOORD) : COLOR { float phase = 10.0f*(uv.y + elapsedSeconds); float2 offset = 0.1f * float2(cos(phase), 0.0f); return tex2D(implicitInput, uv + offset); } "; var effect = CompiledEffect.FromString(SourceCode, CompilerOptions.None); if(effect.CompileSucceeded) { var shader = effect.CompileShader("main", "ps_2_0", CompilerOptions.None); if(shader.CompileSucceeded) { var shader = new PixelShader(); shader.SetStreamSource(new MemoryStream(shader.Data)); .......
ラッパーの本体は EffectCompiler.cs にまとめてあります.コピー・改変等ご自由にお使い下さい.
更新履歴
- 2008年8月15日
- EffectCompiler.cs: PreserveSig 属性が設定されていなかった COM 呼び出し全てに PreserveSig 属性を付けた.
- 2010年10月2日
*1:WPF や Windows Vista 用のカスタムビルドの可能性があります
*2:一般的には [http://www.microsoft.com/downloads/details.aspx?displaylang=ja&FamilyID=2da43d38-db71-4c1b-bc6a-9b6652cd92a3:title=DirectX の Web Installer] を使ってもらうことになるでしょう
CoreCLR 一区切り
MSDN Magazine August 2008 の CoreCLR 記事を読む限り,次の 3 年後がそろそろ始まるみたいな感じですな.
CoreCLR エンジンの秘密
CoreCLR の設計は、2005 年 10 月に CLR の Version 2.0 をリリースした直後から開始され、サイズと互換性の 2 つの設計目標が設定されました。プログラマの立場から考えると CLR に関するコーディングは常に同じであるべきですが、ユーザーの立場から考えるとダウンロードするサイズを大幅に小さくする必要がありました。
なんとなく 3 年というタイムスパンは普遍的な気がする.C# 3.0 にしてもそうだけど.実際に手を動かし始めてから 3 年はかかると思ってもいいのかも.
クロス プラットフォームの実現
(略)
私たちは、CoreCLR の設計と開発の全体を通じて、開発者が今までに習得したスキルとツールを再利用して、サイズが小さく安全なランタイムに対応するリッチ コンテンツを開発できる環境を提供することに力を入れました。リッチなインターネット アプリケーションのシナリオを減らしたことによって下すことができた決断がほとんどですが、設計の中には過去の作業の中で得た経験が活かされているものもあります。CoreCLR に関して下した決断の中には、最終的にデスクトップに還元できるものもあります。たとえば、次のバージョンのデスクトップ CLR は、プロセス内で別のバージョンの CLR と同時に実行できるようになるでしょう。また、透過的セキュリティ モデルの改善点のほとんども、次の CLR に活かせるはずです。
つくづく世界はインクリメンタルだよなぁ.急に世界は変わらない.でも決して1箇所にとどまらない.