連載
.NET&Windows Vistaへ広がるDirectXの世界

第2回 DirectXマスターを目指すあなたが持つべき視点

NyaRuRu
Microsoft MVP Windows - DirectX(Jan 2004 - Dec 2006)
2006/07/22
Page1 Page2 Page3

3. DirectX開発の未来

 前章では、DirectX APIが反復型開発プロセスによって定期的に改良されてきた歴史を見てきた。本章では、さらに速い変化に対する取り組みと、今後のDirectX開発の方向性について見ていこう。

アジャイル開発

 前述したように、現在DirectX SDKは典型的なアジャイル開発が行われている。更新される内容は、DirectXのコアAPIではなく、SDKに付属するユーティリティ・ライブラリやドキュメント、サンプル・コードである。

 これらについて、メーリング・リストやWeb上のフォーラムを通じたフィードバックが募集され、それを反映する形で2カ月に1度の定期リリースが行われる。この体制はもうかれこれ2年余り続いており、この間にリリースされたSDKは11を数える。具体的には次のリストのように更新されてきた。

  • DirectX 9.0 SDK Update - (Summer 2004)
  • DirectX 9.0 SDK Update - (October 2004)
  • DirectX 9.0 SDK Update - (December 2004)
  • DirectX 9.0 SDK Update - (February 2005)
  • DirectX 9.0 SDK Update - (April 2005)
  • DirectX 9.0 SDK Update - (June 2005)
  • DirectX 9.0 SDK Update - (August 2005)
  • DirectX 9.0 SDK Update - (October 2005)
  • DirectX SDK - (December 2005)
  • DirectX SDK - (April 2006)
  • DirectX SDK - (June 2006)
DirectX 9.0cになってからリリースされたDirectX SDKの一覧
Direct3DのコアAPIはこの間変化していない。

 開発者向けのメーリング・リストを眺めていると、あるライブラリについてパフォーマンスに関する議論が起き、その数カ月後のSDKで改良が行われるというケースをたびたび見かける。また、最新の3D表現を実現するためのユーティリティ関数がサンプル・デモ付きで多数追加されることも多い。

 このような活発なSDKの更新が、最新技術のいち早い導入や、短期間でのバグ・フィックスという恩恵をもたらす一方で、既存ソース・コードの互換性をたびたび失わせる原因になってしまっているのは残念な話である。

 COMによって厳密にインターフェイス・バージョンが管理されているDirectX APIとは異なり、これらのユーティリティ・ライブラリは、モノリシックな構成を取りつつ、ヘッダ・ファイルを上書きする形で更新されてきたため、コンパイル段階で一括して更新せざるを得ないためだ。変化速度を基準にパッケージを分割するだけでも大きく状況が改善されるはずで、今後の改良が期待されるところである。

.NETへの展開

 他方、現在マイクロソフトのコンポーネント開発の本流はCOMの後継たる.NET Framework(以降、.NET)に移っており、実際にDirectXにはManaged DirectXやXNA Framework(=Xbox 360などで動作するゲームを作成するためのフレームワーク)といった.NETプラットフォームへのポーティングも存在する。

 しかし.NET技術についてもある程度見てきた筆者には、初期のDirectXがCOMをもてあましていたのと同様、これらのポーティングも.NETが目指すプログラミング・モデルを100%消化し切れているとはいえないように見える。

 初期のDirectXがCOMを消化し、インターフェイス・セットの安定化のめどがたったタイミングを筆者はDirectX 8だと見ているが、登場から5年の歳月を要していることになる。.NETへの展開についても、ミスマッチを解消するにはやはり同程度の時間がかかるのではなかろうか。必要な可変性を確保しつつ、プログラミング・モデルとして支持される仕組みを作り上げていくことは、一朝一夕にできるものではない。なお、.NET環境からのDirectX開発の現状については、次回以降掘り下げて見ていく予定である。

 そもそも、.NET化のみが新しいプログラミング・モデルを導入する手段というわけではない。例えば.NETが掲げるメタデータの活用といったテーマを、最近のDirectXは専用言語の併用という形で取り込み始めている。

3Dプログラミングと言語

 ハードウェアの性能を引き出すためにわざわざ専用言語まで持ち出すというのは、DirectX開発の特色の1つといえるかもしれない。現在、プログラマブル・シェーダという特殊なデバイスを操作するには、次の3通りの方法がある。

プログラマブル・シェーダのバイト・コード

 DirectX 8/9 APIでは、プログラマブル・シェーダの実体はバイト・コードとして定義されている。そのバイト・コード仕様はひっそりとDirectXのヘッダ・ファイルに定義されているのだが、DirectX APIの公式ヘルプにすら仕様が記述されておらず、事実上ドライバ開発者向けという性格が強い。APIレベルでのプログラマブル・シェーダは、初代Direct3Dと同じくバッファにバイト・コードを書き込むというものなのだが、初代Direct 3Dとの違いは、ユーティリティ・ライブラリと外部ツールでうまくこの部分を隠蔽したことにある。

 DirectX 8 SDKには、アセンブリ言語からシェーダ・バイト・コードを出力するコンパイラと実行時ライブラリが、はじめからに同梱されていたおかげで、ほとんどのプログラマはコンパイル後のバイト・コードを意識することなく、シェーダ・アセンブリ言語での開発を行うことができた。一方、DirectX 2 SDK時代には、このようなツールが存在しなかったため、多くのプログラマはまずC/C++でバイト・コードの生成を行おうとしたと考えられる。専用言語との記述性・生産性の違いは明白であろう。

プログラマブル・シェーダ・アセンブリ

 このように、プログラマブル・シェーダの登場時に、マイクロソフトが主戦場に選んだのがプログラマブル・シェーダ・アセンブリによるシェーダ・プログラミングであった。そのコンパイラはDirectX SDKに付属するユーティリティ・ライブラリの一種に位置付けられている。従来、描画技法を議論するうえでC/C++のソース・コードを提示していたのが、記述性の高い専用言語のみを示して議論できるようになったのは画期的なことである。

 また、コンパイル処理を実行時に行うことができるようになったのも大きな一歩である。プログラマブル・シェーダのバイト・コードを直接操作することに比べれば、シェーダ・アセンブリ・コードの自動生成はずっと容易であり、文字列から動的にコンパイルを行う実行時コンパイラが標準で付属したことで、開発者は強力なカスタマイズ性を手に入れたといえるだろう。

上位シェーダ言語(HLSL:High Level Shader Language)

 プログラマブル・シェーダ対応ハードウェアの普及とともに、プログラマブル・シェーダ・アセンブリによるコードの可読性や再利用性の低さに対する不満が高まると、C言語に類似した記法を用いるいくつかの高級シェーダ言語が登場することとなった。

 NVIDIAが提唱したCg(C for graphics)、DirectX用に開発されたHLSL(High Level Shader Language)、OpenGL用に標準化されたGLSL(OpenGL Shading Language)などである。

 HLSLはDirectX SDKに付属するユーティリティ・ライブラリによって実装され、現在DirectX開発で広く用いられている。ただし、前述したようにDirectX APIレベルでのプログラマブル・シェーダはバイト・コードであるため、CgをDirectX互換のバイト・コード・ジェネレータとして用いるといったことももちろん可能である。

 この状況はDirect3D 10で大きく変わり、HLSLはユーティリティ・ライブラリが解釈するシェーダ言語という立場からDirect3D 10 APIが直接受け取る言語仕様に格上げされる。この変更は、自社の製品に最適化されたバイト・コードを出力したいと望んでいるハードウェア・ベンダの思惑と合致しており、Direct3D 10ではHLSLのコンパイルにドライバが介入できるようになるのだ。

 パフォーマンスと表現力向上のために、使い慣れた汎用言語ではなく、新しい特殊な言語で開発を行わなければならないということは、一見大きな手間であるようにも見える。しかし他分野に目を向けても、Webアプリケーション開発など、1つの製品を作り上げるのに複数の言語、複数の視点が入り交じることは何も珍しい話ではない。

 むしろ近年盛んに議論されているのは、問題や関心事をどのように分離するか、そしてどのように組み合わせるかといった分割と統合の枠組みと、さらに分割・統合の実現手段としてのメタデータやAOP(=Aspect-Oriented Programming。アスペクト指向プログラミング)といった複合化技術ではなかろうか。そのような視点では、シェーダ言語を使用すること自体はそれほど大きな問題ではなく、「シェーダ言語を使用した共同開発をどのように行うか」こそが問題となる。

フレームワークとドメイン特化言語(DSL)

 巨大なステート・マシンであるDirectXにとって、新しい描画技法の導入は設定すべきステート・セットの変更として表面化する。CGアーティストとアプリケーション開発者が共同作業を行うためには、この描画にかかわる要素をアプリケーション本体から分離することが必要になる。

 DirectX 8で登場したエフェクト・フレームワークは、DirectXが描画時に必要とする数百のステート設定や、プログラマブル・シェーダの定義などを記述するための専用フォーマットを定義している。アプリケーション本体は常にエフェクト・フレームワークを通じて描画設定の適用を行うことで、アプリケーション開発を描画技法という視点で分離・統合することができる。

 エフェクト・フレームワークでは、次のような記述形式で描画設定を外部データ化する。

int alphaRef = 0x08;

TECHNIQUE MyTechnique
{
  PASS MyPass1
  {
    AlphaBlendEnable = false;
    PixelShader      = null;
    PixelShader      = asm
    {
       ps.1.1
       tex t0
       tex t1
       mul_x2 r0, t1, t0;
    };
  }

  PASS MyPass2
  {
    AlphaBlendEnable = true;
    AlphaFunc        = GreaterEqual;
    AlphaRef         = <alphaRef>;
    AlphaTestEnable  = true;
    BlendOp          = Add;
    SrcBlend         = One;
    DestBlend        = InvSrcAlpha;
    PixelShader      = asm
    {
       ps.1.1
       tex t0
       tex t1
       mul_x2 r0, t1, t0;
    };
  }
}
エフェクト・フレームワークにおいて描画設定を外部データ化するコード例
描画技法はテクニック(TECHNIQUE)として分類され、重ね描きをサポートするために各テクニックは複数のパス(PASS)で構成される。1回の描画で完結する描画技法は、1つのパスのみを含むことになる。各パスではそれぞれ、ステート設定とプログラマブル・シェーダを記述することができる。ステート設定には変数を使うことができ、この変数はエフェクト・フレームワーク経由でアプリケーション本体から取得・設定が可能である。変数、テクニック、パスはそれぞれエフェクト・フレームワークのリフレクションAPIを通じてアプリケーション本体から列挙することができる。設定ファイルはエフェクト・ファイルと呼ばれ、実行時にエフェクト・フレームワークによって評価されるため、エフェクト・ファイルを修正してもアプリケーション本体は再コンパイルの必要はない。

 DirectX 9でエフェクト・フレームワークはさらに進化し、エフェクト・ファイルの列挙可能要素に.NETでいうところの属性(Attribute)を付加できるようになった。ただし、記法はC#風の“[属性名]”ではなくVisual Basic風の“<属性名>”を用い、呼び名も属性ではなくアノテーションというあたりが面白い*5

 また、前述したHLSLはエフェクト・ファイルのサブセットになっており、基本的にHLSLで書けることは全てエフェクト・ファイルに記述可能である。プログラマは、エフェクト・フレームワークを使う限り、対象であるかエフェクト・ファイルであるかを意識することなく使用できる。

*5 「アノテーション」は、.NETの属性(Attribute)に相当する機能に対して、Javaで用いられている名称である。ちなみにDirectXでは、アノテーションというメタデータのほかに、セマンティクスと呼ばれる別形式のメタデータも付与できる。

 さて、アノテーションの導入による最大のメリットは、エフェクト・ファイルの文法を独自に拡張し、エフェクト・フレームワークの上に自前のフレームワークを構築することが容易になったことだ。

 例えば2次元テクスチャは、エフェクト・ファイル(HLSL)で通常次のように宣言される。

texture2D MyTexture;

 これに、次のようなメタデータを設定してみよう。

texture2D MyTexture <string ResourceAddress = "flower.png";>;

 エフェクト・フレームワークのリフレクションAPIを通じて、アプリケーション本体はMyTextureという変数にResourceAddressという名前の文字列型のアノテーションが設定されていることを知ることができる。

 標準のエフェクト・フレームワークはResourceAddressというアノテーションを関知しないが、アプリケーション本体とエフェクト・ファイル作成者の間で、ResourceAddressをリソースのファイル名を表すことにするという約束事を作ってしまうのだ。こうすることによって、エフェクト・ファイル編集者の責務でテクスチャのファイル名を管理できるようになる。

 メタデータによる拡張の可能性は実にさまざまだ。アノテーションの文法に従う限り、構文解析はエフェクト・フレームワークに任せることができ、簡単に言語拡張を行うことができる。使用例としては、ハードウェアの能力による描画技法の使い分けの記述や、特定条件で指定された名前の描画技法をオーバーライドするといった仕組みが考えられる。このような柔軟性と記述性を兼ね備えたエフェクト・ファイルは、まさにドメイン特化言語(DSL:Domain Specific Language)と呼ぶにふさわしい。

 例えば、NVIDIAのエフェクト開発ツール「FX Composer」は、変数の有効範囲や編集方式を記述するのにアノテーションを用いている。FX ComposerによってCGアーティストは描画技法のパラメータをGUIツール上で調整することができるが、そのための補助的な設定をもエフェクト・ファイルに記述してしまったというのがポイントである。

NVIDIAのエフェクト開発ツール「FX Composer」による描画技法のパラメータ設定の例
FX Composerはアノテーションによって値の取り得る範囲やGUIでの編集方法を記述する。
  エフェクト内で使用する変数としてSceneIntensityが定義されている。<>記号内がアノテーションである。
  プロパティ・ウィンドウに表示されている“Scene intensity”というプロパティ項目は、アノテーションによって制御されている。この例では、プロパティに表示される名前(=「string UIName="Scene intensity";」)、値調整用のウィジット・タイプとしてスライドバーを使うこと(=「string UIWidget="slider";」)、値の上限と下限(=「float UIMin=0.0f;」と「float UIMax=2.0f;」)、および変更時の刻み幅(=「float UIStep=0.1f;」)が設定されている。

 とはいえ、このようなツール間連携を意図したアノテーションは、ある程度の共通規格があった方が都合がよい。そこでマイクロソフトは、DirectX Standard Annotations and Semantics(DXSAS)と呼ばれる「アノテーションとセマンティクスのガイドライン」を提唱し、ツール間の相互運用を図ろうとしている。

 DXSASがスタンダードとなるかどうかは未知数ではあるが、このような描画技法の外部ファイル化と、メタデータによる拡張性は、今後3Dアプリケーション開発で大きなトレンドになっていくと考えられる。

DirectXの未来

 上に述べたように、Direct3D 10ではエフェクト・ファイルという強力なDSLが標準APIに格上げさる。これにより、ハードウェアの新機能とインターフェイス・セットの整理という中程度の変化をAPIでカバーしつつ、開発現場での速い変化をエフェクト・ファイルで対応するというすみ分けが公式に推進されることとなる。

 Direct3D 10世代の開発ではますますエフェクト・ファイルが多用されると予想され、その複合化に現在Javaや.NETで盛んなDI(Dependency Injection:依存性注入)コンテナ系のAOPフレームワーク*6技術が応用できるのではないかと期待している。エフェクト・ファイルによって属性による宣言型プログラミングを可能とし、フレームワーク側で実装をダイナミックに折り合わせていくことで、変化の激しい3Dアプリケーション開発に一定の可変性を導入することができるのではなかろうか。

*6 S2Container.NETSpring.NETなど。

4. まとめ

 今回は、DirectXの世界をソフトウェア開発の視点から紹介するという試みにあえて挑戦してみた。DirectXの解説書はそれなりの数存在するのだが、初学者を意識してかHow-To的な紹介のされ方が多く、「なぜ、そういう仕組みなのか」「過去・現在・未来の変化に規則性はあるか」といった視点でふかんした記事があってもよいのではないかと思ってのことである。これからどのように開発を始めるかの、最初の一歩の紹介を期待されていた方にはご容赦いただきたい。

 次回からは、C# 2.0を使用して実際にManaged DirectX開発を行い、開発に当たって知っておくべき背景事情を中心に紹介していくつもりである。これを機会にC#でDirectX開発を初めてみたいという方はご期待いただきたい。End of Article


 INDEX
  .NET&Windows Vistaへ広がるDirectXの世界
  第2回 DirectXマスターを目指すあなたが持つべき視点
    1.安定性に基づく分類
    2.COMと反復型開発
  3.DirectX開発の未来
 
インデックス・ページヘ  「.NET&Windows Vistaへ広がるDirectXの世界」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間