SubD10 サンプル

Cc308055.d3d10_sample_SubD10(ja-jp,VS.85).jpg

Path

ソース : SDK ルート\Samples\C++\Direct3D10\SubD10
実行可能ファイル : SDK ルート\Samples\C++\Direct3D10\Bin\x86 または x64\SubD10.exe

サンプルの概要

SubD10 サンプルは、ペーパー "Approximating Catmull-Clark Subdivision Surfaces with Bicubic Patches" by Charles Loop and Scott Schaefer (Microsoft Research の Web サイトへのリンクから入手できます) に記載されているアルゴリズムを実装します。ここでは、この方式を ACC と呼びます。

以下のプロセスを実行します。最初に、サンプルにオブジェクト (.obj) ファイルがロードされます。オブジェクト ファイル形式を使用するのは、それがサーフェスをクワッドとして出力できる一般的な形式であるからです。.obj ファイルが内部表現に変換されます。各フレームの中でこの内部表現がスキニングされ、GPU 上で双三次パッチに変換されます。双三次パッチのコントロール ポイントが、GPU メモリーにストリーム出力されます。2 番目のパスで、双三次パッチのコントロール ポイントが GPU によって読み取られ、それを使用して Catmull-Clark 小分割サーフェスの近似が作成されます。

Catmull-Clark 小分割サーフェスの表現

現在、このサンプルはクワッドによって表現される Catmull-Clark サーフェスでのみ有効です。小分割サーフェス表現から双三次パッチ表現に変換するために、ACC 方式では、小分割サーフェス クワッドの 4 つの頂点と、そのクワッドを囲む頂点の 1 リング隣接が必要です。このサンプルでは、クワッドを含むオブジェクト ファイルをロードし、各クワッドの 1 リング隣接を作成します。小分割クワッドは、2 つのカテゴリに分割されます。最初のタイプは、通常のクワッドです。通常のクワッドの 4 つの頂点はすべて、4 つの隣接頂点を持ちます (価数が 4)。

Cc308055.d3d10_sample_subd10_regular(ja-jp,VS.85).jpg

2 番目のタイプは、特別なクワッドです。特別なクワッドでは、隣接頂点の数が 4 でない頂点が 1 つ以上あります。これらの頂点を特別な頂点と言います。

Cc308055.d3d10_sample_subd10_extraordinary(ja-jp,VS.85).jpg

図では、頂点に内側から外側へ逆時計周りで番号を付けています。この順序は、小分割サーフェスから双三次パッチへの変換の際に、変換プロセスのどの段階にいるかを知る方法として使用されます。SubDMesh.h および SubDMesh.cpp は、オブジェクト ファイルをロードし、それらを ACC の適切な表現に変換するためのすべてのコードを含んでいます。

小分割サーフェスから双三次パッチへの変換

Catmull-Clark 小分割サーフェスから双三次表現への変換に使用される計算は非常に複雑なので、ここでは説明しません。詳細については、上記のリンクされているペーパーを参照してください。ここでは、このペーパーを要約しておきます。各小分割サーフェス クワッドが双三次表現に変換されます。したがって、100 個のクワッドから成るメッシュは、100 個の双三次パッチに変換されます。双三次サーフェスの各コントロール ポイントは、その 1 リング隣接での小分割サーフェス クワッドからの一連のポイントの重み付けされた組み合わせです。この番号付けスキームは、出力双三次パッチの各コントロール ポイントを作成するために、どの入力ポイントおよび重みを使用するかを決めるのに役立ちます。

Cc308055.d3d10_sample_subd10_bicubic(ja-jp,VS.85).jpg

このサンプルは、GPU を使用して Catmull-Clark 表現から双三次サーフェス表現に変換します。1 つの小分割サーフェス クワッドのすべての情報は、1 つの頂点に格納されます。これは、実際のクワッドの頂点と 1 リング隣接全体を含みます。通常のパッチでは、実際のデータは頂点に格納されます。通常のパッチでは、格納する必要がある位置は 16 個だけであるので (4 つの内部頂点と 12 個の外部頂点)、それで問題はありません。特別なパッチは、17 個以上の位置を必要とする場合があります。Direct3D 10 では、頂点が 17 個以上の要素を持つことは許可されません。特別なパッチの場合、インデックスを 4 つの内部クワッド頂点と外部の 1 リング隣接に格納します。変換時に、実際の値が頂点バッファーからフェッチされます。

SubDtoBezier.fx は、Catmull-Clark 小分割サーフェスから双三次パッチに変換するためのすべてのテクニックを含んでいます。VSConvertToBezier にはいくつかの異なるバリエーションがあり、異なる変換方法を使用しますが、それらはすべて同じ基本式に従います。最初に、頂点をロードするために LoadVerts が呼び出されます。特別なパッチでは、VS への入力は、どの頂点をフェッチするかを決めるために使用されます。通常のパッチでは、VS への入力は直接に使用されます。また、UI で [スキン メッシュ] が選択されている場合、LoadVerts 内で頂点をスキニングできます。

次に、GenPatchExtra.fxh および GenPatchRegular.fxh の中の関数を使用して、双三次パッチのコントロール ポイントが生成されます。これらの 2 つのファイルは、ACC アルゴリズムの一部を実装する関数を含んでいます。

最後に、双三次パッチすべてのコントロール ポイントが、1 つの頂点に書き込まれます。その頂点は、バッファーにストリーム出力されます。双三次サーフェスでは 17 個以上のコントロール ポイントが存在することはないため、Direct3D 10 で頂点に格納できる要素の数を超える書き込みについて心配する必要はありません。

法線の修正

通常のパッチでは、小分割から双三次パッチへの変換により、そのパッチの Catmull-Clark 限定的サーフェスを正確に表現する、双三次サーフェスが生成されます。しかし、特別なパッチでは、生成される双三次パッチは近似であり、若干のエラーが含まれます。生成されるメッシュは隙間がありませんが、パッチ境界を越える微分は非連続です。そのため、下図に示すように不自然なシェーディングが生成されます。

Cc308055.d3d10_sample_subd10_ballartifact(ja-jp,VS.85).jpg

ACC ではこれを修正するために、各双三次パッチに接線パッチと複接線パッチを作成します。これらの接線および複接線パッチ (または U および V パッチ) は、各双三次パッチの微分の代わりに使用されます。基になるジオメトリは変化しませんが、接線および複接線パッチはシェーディングを修正し、非常に適切な Catmull-Clark サーフェスの近似を生成します。

Cc308055.d3d10_sample_subd10_ballfixed(ja-jp,VS.85).jpg

接線および複接線パッチを生成するためにもう 1 つのパスが必要です。これは、双三次パッチのデータが、既に 16 個の要素を使っているからです。接線および複接線パッチの生成が必要とされるのは、特別なパッチの場合のみです。通常のパッチと特別なパッチを分けることによって、一層の最適化が可能です。これは、通常のパッチの構造は既知であり、その構造に応じて最適化できるからです。

双三次パッチの再作成

双三次パッチ (および、必要に応じて接線/複接線パッチ) のコントロール ポイントのストリーム出力が完了すれば、残っている作業は双三次サーフェスの再作成だけです。このサンプルでは、一連のテッセレーション済みの正方形を使用します。これらの正方形は [0..1] の範囲の UV 座標を含み、また、一部の計算を GPU に保存できるようにするために Bernstein 基底関数の計算済み部分の一部を含みます。このサンプルでは、必要とされるテッセレーションの各レベルについて、1 つのテッセレーション済みの正方形を作成します。

Cc308055.d3d10_sample_subd10_tesssquares(ja-jp,VS.85).jpg

各メッシュについて、どのテッセレーション済み正方形を使用するかは、[パッチ分割] スライダーに基づいて決定されます。たとえば、[パッチ分割] が 8 に設定されている場合、アプリケーションは、 8×8 クワッドにテッセレーションされている正方形を選択します。さらに、[距離減衰] が選択されている場合、カメラへの距離が、使用するパッチ分割の数を増やすために使用されます。

次にこの正方形が、前のパスから出力された各双三次サーフェスについて一度ずつ、メッシュ全体にインスタンス化されます。SubD10.fx の頂点シェーダーでは、双三次サーフェスのコントロール ポイントのどのセットをフェッチするかを決定するために、InstanceID が使用されます。次に、テッセレーション済み正方形の各頂点について、双三次コントロール ポイントと、頂点に格納されている UV [0..1] を使用して、そのポイントの双三次サーフェスが再作成されます。通常のパッチでは、サーフェス法線は、U および V で双三次サーフェスの 2 つの偏微分を使用し、その外積を実行することによって計算されます。特別なパッチでは、接線および複接線 (U および V) パッチを使用して偏微分を再作成し、外積します。また、バンプ マッピングおよびディスプレースメント マッピングもここで行われます (テクニックおよびモデルでサポートされている場合)。

さらに、このサンプルは、テッセレーション済みパッチを使用しないで双三次サーフェスを再作成するもう 1 つの方法をサポートします。この代替方法を示すために、SubD10.cpp の先頭で定義される USE_PRECALC_PATCHES を 0 に設定できます。この代替方法は、NULL 頂点バッファーをバインドし、DrawIndexedInstanced( VerticesToDraw, NumPatches, 0, 0, 0 ) を呼び出します。パイプラインにバインドされる頂点バッファーはありませんが、VS は、InputAssembler から渡される一連の VertexID および InstanceID を取得します。InstanceID はここでも、どの双三次パッチ係数のセットを使用するかを決めるために使用されます。VertexID はそのポイントの UV を決定するために使用され、UV は、前の例と同様に、双三次パッチを再作成するために使用されます。

ジオメトリ シェーダーについて

テッセレーション済み正方形なしで、入力アセンブラーを使用せずに双三次サーフェスを再作成することもできます。ジオメトリ シェーダーを使用して [0..1] UV ドメイン上でテッセレーションを実行し、複数の三角形を出力できます。これによって、テッセレーション済みジオメトリや入力アセンブラーを使用する必要がなくなります。これには 2 つの問題があります。1 つは、ジオメトリ シェーダーの出力が 4096 バイトに制限されていることです。つまり、現在のサンプルでは、サイドあたり 5 分割を超えるテッセレーション レベルはサポートされません。もう 1 つは、パフォーマンスの問題です。現在の Direct3D 10 ハードウェアのジオメトリ シェーダーのパフォーマンスは、ジオメトリ シェーダーからの出力量が増えると低下します。現在、正方形のインスタンス化を使用する方法は、同じメッシュ上で同等のジオメトリ シェーダーを実装する場合よりも格段に高速です。この理由により、ジオメトリ シェーダーの実装をサンプルから除外しています。

パフォーマンスに関する考慮事項

Catmull-Clark から双三次パッチへの変換は、パッチの数については直線的です。通常のパッチのプロパティは既知であるので、それらを独自のパスに分割することによって、特別なパッチには適用しない最適化を通常のパッチに適用することができます。

アルゴリズムのコストの多くの部分は、双三次サーフェスの評価に関連しています。双三次サーフェスの評価は、テッセレーション済みのパッチの各ポイントに対して行う必要があります。通常のパッチでは、この評価には 1 つのバッファーからの 16 回のロードと約 73 件の ALU 操作が必要です。特別なパッチでは、格納される接線および複接線パッチが少ない場合、1 つのバッファーからの最大 24 回のロードと約 120 件の ALU 操作が必要になることがあります。

双三次の評価のコストがあるために、ACC を使用して、どのレンダリング操作を高速化できるかは必ずしも明白ではありません。直感的には、単純な 4 ボーン スキニングがその候補となると考えられます。解像度がはるかに低い Catmull-Clark 表現をスキニングし、その後でそれを双三次パッチに変換すれば、同じメッシュの非常に解像度が高いテッセレーション済みバージョンをスキニングするよりも低コストであるように思われます。しかし、双三次パッチを評価するコストは、スキニングのコストよりも大きな影響をもたらします。この 2 つは同じ頻度で行われます。テッセレーション済みのメッシュをスキニングするには、16 回の定数バッファー アクセス (スケーリングを無視する場合は 12 回) と、スキンニング、法線の回転などの約 38 件の ALU 操作が必要です。テッセレーション済みのメッシュの各頂点についてこれが行われますが、それでも双三次サーフェスを評価するよりも低コストです。両方のオプションを実装した結果、テッセレーション済みのメッシュをスキンニングした場合に、Catmull-Clark 表現をスキンニングしてからそれを双三次パッチに変換した場合よりもパフォーマンスが約 30% 増加することが示されています。

パフォーマンスの観点から考えると、双三次評価よりも高解像度のテッセレーション済みのメッシュでのコストが大きい操作は、ACC を採用する候補となります。これには、アニメーション ブレンディング、モーフ ターゲット、布地のシミュレーションなどの、より高度なスキンニングが含まれます。

各オプションの機能

  • Patch Divisions
    各双三次パッチにテッセレーションを適用するときの、サイドあたりのデフォルトの分割数を決定します。

  • BumpHeight
    メッシュのディスプレースメント高さと、それをサポートするテクニックを変更します。

  • Technique dropdown
    現在のテクニックを変更します。テクニックの説明は、このトピックの次のセクションに示しています。

  • Toggle Wires
    ワイヤフレームのオーバーレイを有効にします。

  • Separate Reg/Extra
    通常のパッチと特別なパッチを、別のパスで変換するかどうかを決定します。一般的には、このオプションを有効にしておく方が効率的です。

  • Convert Every Frame
    フレームごとに小分割から双三次パッチへの変換を実行します。

  • Distance Attenuate
    カメラへの距離に基づき、オブジェクトあたりのパッチ分割数を変更します。オブジェクトがカメラから遠くなるほど、必要なパッチ分割の数が少なくなります。

  • Skin Meshes
    小分割メッシュのスキニングを有効にします。

各テクニックの機能

  • RenderScene
    ACC アプローチを使用してシーンをレンダリングします。シェーディングの修正のための接線および複接線パッチを使用しません。

  • RenderSceneTan
    RenderSceneTan と同じですが、接線および複接線パッチがコンパクトな形式で表されます。これは帯域幅を節約しますが、その代償として双三次の再作成でより多くの ALU 操作が必要になります。

  • RenderSceneBump
    RenderScene と同じですが、 ディスプレースメントおよびバンプ マッピングを有効にします (それをサポートするオブジェクト上で)。

  • RenderSceneBumpTan
    RenderSceneTan_Compact と同じですが、ディスプレースメントおよびバンプ マッピングを有効にします (それをサポートするオブジェクト上で)。

各 #define の用途

  • MAX_BUMP
    これは、ディスプレースメント マッピングの最大バンプ量 (x1000) です。

  • MAX_DIVS
    サイドあたりのパッチ分割の最大数です。

  • NUM_BONES
    オブジェクトのリギングはプログラムによって処理されます。これは、オブジェクトあたり使用するボーンの数を決定します。

  • MAX_POINTS
    小分割パッチによって参照できるポイントの最大数。これは、4 つのクワッド ポイントと 1 リング隣接全体を含みます。

  • NUM_REGULAR_POINTS
    通常のパッチによって参照されるポイントの数。これは変数ではありません。

  • MAX_VALENCE
    これは、小分割サーフェス内のいずれかの頂点から想定される最大の頂点価数 (隣接の数) です。

Artwork

このサンプルでは、モンスターフロッグとビッグガイのモデルを、Valve Software の Bay Raitt のご厚意により使用させていただきました。