> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# メッシュレット

> メッシュレット

*メッシュレット* とは、単純にメッシュのサブチャンク、つまり固定数のプリミティブと頂点の集合です。*メッシュ* はメッシュレットのセットで完全に定義することができ、各メッシュレットはメッシュから取り出された一意なプリミティブ集合で構成されます。メッシュレット構造に変換されたメッシュを *メッシュレット化* されたと呼びます。

メッシュレット化されたメッシュを構築するために使用する固定のプリミティブ数と頂点数は、メッシュレットのリスト全体で一貫しており、各メッシュレットの最大サイズを定義します。理想的には、各メッシュレットはこのサイズにできる限り近いことが望まれますが、必ずしもそれを埋め尽くす必要はありません。従来のインデックス バッファーは、メッシュレット リスト、一意な頂点インデックス リスト、プリミティブ リストの 3 つの新しいデータ構造に置き換わります。

**図 1. メッシュレット単位で色付けされた、メッシュレット化メッシュのレンダリング (ドラゴン)。メッシュレットが妥当な空間的一貫性を持つプリミティブで構成されていることに注目してください。**

<img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/ms_dragon_meshlets.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=dc30dfff622025378255edbf728ba775" alt="ドラゴン" width="519" height="500" data-path="images/gdk/features/graphics/ms_dragon_meshlets.png" />

以下のコード例は、実行時のメッシュレット構造の C++ 実装です。このデータは、レンダリング可能なメッシュを完全に記述します。

```
struct Meshlet
{
    // Meshlet data.
    uint VertexOffset;
    uint VertexCount;
    uint PrimitiveOffset;
    uint PrimitiveCount;

    // Culling data.
    ...
};

std::vector<MyVertex> Vertices;
std::vector<Meshlet>  Meshlets;
std::vector<uint16_t> UniqueVertexIndices;
std::vector<uint8_t>  PrimitiveIndices;
```

このメッシュレット構造には、メッシュ シェーダー レンダリングに対していくつかの利点があります。各メッシュレットは固定の最大サイズを持ち、固定サイズのスレッドグループを 1 つのメッシュレットにマッピングするのに理想的であり、スレッドから頂点/プリミティブへの直感的なマッピングを提供します。頂点数とプリミティブ数は事前に判明しているため、シェーダー コード内でそれらを計算する必要がありません。頂点インデックスは既に重複排除されており、冗長な頂点変換とエクスポートを排除します。プリミティブ インデックスはメッシュレットの頂点リストに対してローカル化されます。メッシュレットはまた、空間および方向情報を用いたカリングのための追加の粒度も提供します。

前のコード例は、新しいメッシュレット バッファー間の相互関係を示しています。メッシュレット リストは実行時 "meshlet" 構造体のフラットなリストであり、少なくとも一意な頂点インデックス リストとプリミティブ リストへのオフセットとカウントを含みます。一意な頂点インデックス リストは、頂点データ バッファーへのインデックスの重複排除されたリストです。プリミティブ リストはメッシュのプリミティブを定義し、メッシュレットの頂点オフセットに対してローカル化された、一意な頂点インデックス リストへのインデックスで構成されます。

**図 2. メッシュレット バッファー間の関係を示す図。**

<img src="https://mintcdn.com/microsoft-4404708b/6hkHc7s12mHcTMCE/images/gdk/features/graphics/ms_meshlet_data.png?fit=max&auto=format&n=6hkHc7s12mHcTMCE&q=85&s=e8e9587e2ed7cde69d6bb91adb78971f" alt="メッシュレット バッファー間の関係を示す図" width="1000" height="283" data-path="images/gdk/features/graphics/ms_meshlet_data.png" />

## メッシュレットへの変換

従来のインデックス バッファー メッシュをメッシュレット化する処理は、アーティストのワークフローに変更を必要としません。これはモデル作成後の手続き的な後処理ステップです。従来のインデックス バッファーは実行時にも素早く再生成できるため、従来のインデックス バッファーとメッシュレット バッファーの両方を出荷する必要はありません。メッシュレット化は計算量的に決して些細ではないため、オフラインで前処理することをお勧めします。

サンプルのメッシュレット変換プロジェクト (C++ ライブラリとコマンド ライン ツールの両方) は、他のサンプルと共に ATG によって [XBOX Developer Downloads ページ](https://aka.ms/xgddl)で提供されており、この変換を実施できます。このツールは頂点データ自体を変更しないため、メッシュレット化の前に Forsyth アルゴリズムなどの頂点キャッシュ最適化ツールをメッシュ データに対して実行することをお勧めします。最適化ツールは、コンテンツ作成ツールから普遍的に期待できるものよりも空間的に一貫性のあるメッシュを生成する傾向があります。頂点の再利用と、結果として得られるメッシュ構造のカリング特性の利点をバランス良く両立させるため、追加のヒューリスティックを加えることも可能です。

## メッシュレットを使用したレンダリング

メッシュレットの構造は、メッシュ シェーダーによるレンダリングを非常に容易にします。スレッドグループ サイズをメッシュレットの最大サイズとして宣言し、メッシュ内の各メッシュレットに対して 1 つのスレッドグループをディスパッチします。各スレッドは、1 つの頂点と 1 つのプリミティブの処理およびエクスポートを担当します。

以下は、メッシュレット化されたメッシュをレンダリングするシンプルなメッシュ シェーダーのコード サンプルです。まず、スレッドグループのメッシュレットが読み込まれ、直ちに出力カウントを宣言できます。最後に、PrimitiveCount 個のスレッドがプリミティブ インデックス データの読み込みと書き込みを担当し、VertexCount 個のスレッドが頂点データへのアクセスに使用する頂点インデックスを読み込み、シェーディングを行い、出力配列に書き込みます。

完全なサンプルは、[XBOX Developer Downloads ページ](https://aka.ms/xgddl)で入手できます。

以下のコード例は、メッシュ シェーダーをレンダリングするメッシュレットのサンプル実装です。

```
#define MAX_MESHLET_SIZE 128

StructureBuffer<MyVertex>   Vertices;
StructureBuffer<Meshlet>    Meshlets;
StructuredBuffer<uint>      UniqueVertexIndices;
StructureBuffer<uint3>      PrimitiveIndices;

VertexOut TransformVertex(MyVertex v) { ... }

[NumThreads(MAX_MESHLET_SIZE, 1, 1)]
[OutputTopology("triangle")]
void main(
    uint groupThreadId : SV_GroupIndex,
    uint groupId : SV_GroupID,
    out vertices VertexOut verts[MAX_MESHLET_SIZE],
    out indices uint3 tris[MAX_MESHLET_SIZE])
{
    Meshlet m = Meshlets[groupId];

    SetMeshOutputCounts(m.VertCount, m.PrimCount);

    if (groupThreadId < m.PrimCount) 
    {
        tris[groupThreadId] = PrimitiveIndices[m.PrimOffset + groupThreadId];
    }

    if (groupThreadId < m.VertCount) 
    {
        uint index = UniqueVertexIndices[m.VertOffset + groupThreadId];
        MyVertex vin = Vertices[index];

        verts[groupThreadId] = TransformVertex(vin);
    }
}
```

## 関連項目

[メッシュ シェーダー パイプラインの概要](/build/core-features/graphics/newfeatures/ms/ms-overview)

[メッシュ シェーダー API の概要](/build/core-features/graphics/newfeatures/ms/ms-api-design)

[メッシュ シェーダーの使用方法](/build/core-features/graphics/newfeatures/ms/ms-usage)

[メッシュレット カリング](/build/core-features/graphics/newfeatures/ms/ms-meshlet-culling)


## Related topics

- [メッシュレット カリングの例](/ja-jp/build/core-features/graphics/newfeatures/ms/ms-meshlet-culling.md)
- [XBOX Series X|S のメッシュ シェーダーとメッシュレット](/ja-jp/build/core-features/graphics/newfeatures/ms/index.md)
- [なぜメッシュ シェーダーなのか?](/ja-jp/build/core-features/graphics/newfeatures/ms/ms-why.md)
- [XBOX タイトル向けのゲーム メッシュ ネットワーク](/ja-jp/build/console-features/networking/game-mesh/index.md)
- [メッシュ シェーダー パイプラインの概要](/ja-jp/build/core-features/graphics/newfeatures/ms/ms-overview.md)
