Direct3D 9 でのシェーダーの使用

  • 特定のハードウェアに対するシェーダーのコンパイル
  • シェーダー定数の初期化
  • シェーダー パラメーターを特定のレジスタにバインド
  • プログラム可能なシェーダーのレンダリング
  • シェーダーのデバッグ

特定のハードウェアに対するシェーダーのコンパイル

シェーダーは、まず Microsoft DirectX in DirectX 8.0 に追加されました。その当時、いくつかの仮想シェーダー マシンが定義され、それぞれ大手 3D グラフィック ベンダーが生成する特定のグラフィック プロセッサにほぼ対応していました。これらの仮想シェーダー マシンそれぞれに、アセンブリ言語が設計されていました。シェーダー モデル (vs_1_1 およびps_1_1 ~ ps_1_4) に書き込まれたプログラムは比較的短く、一般的には開発者によって適切なアセンブリ言語に直接書き込まれていました。アプリケーションは D3DXAssembleShader を使用して、人間が判読可能なこのアセンブリ言語コードを D3DX ライブラリに渡し、バイナリ表現に変換して返されたシェーダーを取得します。このバイナリ表現シェーダーを、CreateVertexShader または CreatePixelShader を使用して渡します。詳細については、ソフトウェア開発キット (SDK) を参照してください。

Direct3D 9 でのシミュレーションはこれと似ています。アプリケーションは D3DXCompileShader を使用して HLSL シェーダーを D3DX に渡し、バイナリ表現にコンパイルして返されたシェーダーを取得します。このバイナリ表現シェーダーを、CreatePixelShader または CreateVertexShader を使用して Microsoft Direct3D に渡します。ランタイムはバイナリ アセンブリ シェーダーのモデルのみ認識し、HLSL については何も認識しません。これは、HLSL コンパイラが Direct3D ランタイムとは独立して更新できることを意味するため、好都合です。また、fxc を使用してシェーダーをオフラインでコンパイルすることもできます。

HLSL コンパイラの開発に加えて、Direct3D 9 はアセンブリ レベルのシェーダーも導入し、最新世代のグラフィック ハードウェアの機能を公開しています。アプリケーションの開発者は、これらの新しいモデル (vs_2_0, vs_3_0, ps_2_0, ps_3_0) のアセンブリで作業できますが、シェーダー開発については、ほとんどの開発者が HLSL に移行すると予測されます。

もちろん、HLSL プログラムを記述して特定のシェーダー アルゴリズムを表現する能力は、どんなハードウェアでも自動的に実現可能というわけではありません。アプリケーションは D3DX を呼び出し、D3DXCompileShader を使用してシェーダーをバイナリ アセンブリにコンパイルします。このエントリ ポイントの制約の 1 つは、HLSL コンパイラが最終的なシェーダー コードを表現するために、どのアセンブリレベルのモデル (またはコンパイル ターゲット) を使用するかを定義するパラメーターです。アプリケーションが HLSL シェーダー のコンパイルを (コンパイル時間やオフライン時ではなく) 実行時に実行する場合、アプリケーションは Direct3D デバイスの能力を調べて、一致するコンパイル ターゲットを選択できます。HLSL シェーダーで表現されたアルゴリズムが、選択されたコンパイル ターゲットでは複雑すぎて実行できない場合、コンパイルは異常終了します。これは、HLSL がシェーダー開発にはかなりの利点がある一方で、開発者は常にさまざまな機能のグラフィック デバイスを持つ対象利用者にゲームを出荷するという現実から逃れることができないことを意味します。ゲーム開発者として、それぞれのビジュアルに対する段階的なアプローチを管理しなければなりません。つまり、最新のグラフィック カードには優れたシェーダーを記述し、古いグラフィック カードにはよりベーシックなバージョンを記述することを意味します。ただし、うまく記述された HLSL があれば、この負担を大幅に軽減できます。

アプリケーションのロード時、またはアプリケーションを最初に使用するときに、ユーザーのマシンの D3DX を使用して HLSL シェーダーをコンパイルするのではなく、出荷前にシェーダーを HLSL からバイナリ アセンブリ コードにコンパイルすることを多くの開発者が選択しています。これによって、開発者の HLSL ソース コードがのぞき見されることがなく、アプリケーションのすべてのシェーダーが社内の品質保証プロセスを通じて動作することを確認できます。シェーダーをオフラインでコンパイルする便利なユーティリティは、fxc です。このツールには、指定されたコンパイル ターゲットに対するコードをコンパイルできる多数のオプションが用意されています。シェーダーを最適化したい場合や、単に仮想シェーダー マシンの能力についてもっとよく知りたい場合には、開発中に逆アセンブルされた出力を調べるとかなり役に立ちます。以下に、これらのオプションをまとめます。

シェーダー定数の初期化

シェーダー定数は、定数テーブルに含まれています。定数テーブルには、ID3DXConstantTable インターフェイスを使用してアクセスできます。グローバル シェーダー変数はシェーダー コードで初期化できます。これの変数は、SetDefaults を呼び出すことで実行時に初期化されます。

シェーダー パラメーターを特定のレジスタにバインド

グローバル変数には、コンパイラによって自動的にレジスタが割り当てられます。この 3 つのグローバル変数に対して、コンパイラは Environment をサンプラー レジスタ s0 に、SparkleNoise をサンプラー レジスタ s1 に、k_s を定数レジスタ c0 に割り当てます (既に割り当てられているサンプラー レジスタや定数レジスタがないものとします)。

 sampler Environment; sampler SparkleNoise; float4 k_s; 

変数を特定のレジスタにバインドすることもできます。コンパイラが特定のレジスタに値を割り当てるようにするには、以下の構文を使います。

 register(RegisterName) 

RegisterName は特定のレジスタ名です。以下の例は、特定のレジスタ割り当て構文を示しています。この場合、サンプラー Environment はサンプラー レジスタ s1 に、SparkleNoise はサンプラー レジスタ s0 に、k_s は定数レジスタ c12 にバインドされます。

 sampler Environment : register(s1); sampler SparkleNoise : register(s0); float4 k_s : register(c12); 

プログラム可能なシェーダーのレンダリング

シェーダーは、現在のシェーダーをデバイスに設定し、シェーダー定数を初期化し、デバイスにさまざまな入力データの発生元を伝え、最後にプリミティブをレンダリングすることでレンダリングされます。これらはそれぞれ、以下のメソッドを呼び出すことで実行できます。

シェーダーのデバッグ

Microsoft Visual Studio .NET の DirectX 拡張機能は、Visual Studio .NET 統合開発環境 (IDE) 内に完全統合された HLSL デバッガーを提供します。シェーダー デバッグを準備するには、マシンに適切なツールをインストールする必要があります (「Visual Studio でのシェーダーのデバッグ (Direct3D 9)」を参照)。