🎮

Mesh Shader による四角ポリゴンベースのメッシュ描画

2020/09/28に公開

はじめに

MeshShader で三角ポリゴンベースではなく四角ポリゴンベースでメッシュ描画する実装例です。

Mesh Shader の全体図

Apmlification Shader/Mesh Shader のデータフローもろもろを図にまとめました。
Mesh Shader はシェーダープロセッサ内でローカルな頂点/インデックスバッファを持っており、ここに処理結果を格納しまとめてラスタライザに渡すことで処理の効率化しています。

Mesh Shader の全体図

  • 頂点属性バッファ
    出力頂点データを格納するバッファで Vertex Shader の出力頂点データの配列そのものです。
  • インデックスバッファ
    頂点属性バッファに対するローカルなインデックスを格納するバッファ。
  • プリミティブ属性バッファ
    ポリゴン単位の属性を格納するためにバッファで面ベクトルなど格納します。
    また SV_CullPrimitive を使うことでポリゴン単位のカリングも可能です。
  • ペイロードデータ
    Amplification Shader から Mesh Shader へカリング結果やインスタンス情報を渡すためのバッファです。このバッファは 16KiB 以内にする必要があります。
  • 頂点バッファ
    今までの頂点バッファと同じですが Input Layout の制限を受けないので自由にフォーマット定義できます。
  • 頂点インデックス
    Mesh Shader が処理する頂点位置を格納したバッファです。
  • プリミティブインデックス
    インデックスバッファで説明した通り Mesh Shader ローカルなインデックスを格納します。
  • Meshlet
    頂点インデックス/プリミティブインデックスの開始位置と件数を格納します
    Meshlet 単位のカリングを行う場合、境界ボックス等のカリングに必要な情報も格納します。

四角ポリゴン単位で処理するには?

Mesh Shader の最大出力頂点数は256頂点なのでインデックスに必要なビット数は8ビットです。
32ビット整数に4つのインデックスをパッキングしてプリミティブインデックスに格納すれば 1スレッドで 1四角ポリゴン(=2トライアングル)の処理が可能になります。

最大値
最大スレッド数 128
最大出力頂点数 256
最大三角ポリゴン数 256

三角ポリゴンの対応

メッシュに三角ポリゴンが含まれている場合は縮退ポリゴンで対応します。
Mesh Shader で四角形ポリゴンを三角形ポリゴンに分割するので四つ目のインデックス値を一つ目のインデックス値と同じ値にすれば面積0の縮退ポリゴンとなりラスタライザで破棄されます。

{i0, i1, i2, i3 } -> { i0, i1, i2 } { i0, i2, i3 }
{ 0, 1, 2, 0 } -> { 0, 1, 2 } { 0, 2, 0 }

シェーダーコード

シェーダはいたってシンプルで32bit整数のインデックスからビット演算で4つのインデックスを取り出しインデックスバッファへ書き込むだけです。

if (threadId < faceCount) {
  uint index = PrimitiveIndices[faceOffset + threadId];
  uint i0 = (index >> 0) & 0xFF;
  uint i1 = (index >> 8) & 0xFF;
  uint i2 = (index >> 16) & 0xFF;
  uint i3 = (index >> 24) & 0xFF;

  tris[threadId * 2 + 0] = uint3(i0, i1, i2);
  tris[threadId * 2 + 1] = uint3(i0, i2, i3);
}

レンダリング結果

Meshlet 毎に色分けしスレッドID毎にグラデーションをつけています。
1スレッド単位で四角ポリゴンが描画されているのがわかります。

レンダリング結果

サンプルコード

今回のサンプルコードはこちら

参考資料

Mesh Shader | DirectX-Specs
microsoft/DirectX-Graphics-Samples
もんしょの巣穴 DirectXの話 第171回

Discussion