> ## 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.

# Meshlets

> Meshlets

*meshlet* 就是一个网格（mesh）的子块——固定数量的图元和顶点。一个 *mesh* 可以完全由一组 meshlet 定义，每个 meshlet 由该 mesh 中一组唯一的图元组成。我们把已转换为 meshlet 结构的 mesh 称为已 *meshletized*（网格块化）的 mesh。

用于构建已 meshletized 网格的固定图元与顶点数量在整个 meshlet 列表中保持一致，并定义了每个 meshlet 的最大大小。理想情况下，每个 meshlet 都尽量接近这一大小，但并不一定要填满。传统的索引缓冲区被三种新的数据结构所取代：meshlet 列表、唯一顶点索引列表和图元列表。

**图 1. 一个按 meshlet 着色的已 meshletized 网格（一条龙）的渲染结果。请注意 meshlet 由具备合理空间相关性的图元组成。**

<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="Dragon" width="519" height="500" data-path="images/gdk/features/graphics/ms_dragon_meshlets.png" />

以下代码示例展示了运行时 meshlet 结构的 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;
```

这一 meshlet 结构对于网格着色器渲染有若干好处。每个 meshlet 都有固定的最大大小，非常适合将固定大小的线程组映射到单个 meshlet，同时提供了线程到顶点/图元的直观映射。顶点数和图元数是提前已知的，无需在着色器代码中计算。顶点索引已经去重，消除了冗余的顶点变换和导出。图元索引被局部化到该 meshlet 的顶点列表中。meshlet 还提供了带有空间和方向信息的额外剔除粒度。

前面的代码示例展示了新的 meshlet 缓冲区之间的相互关系。meshlet 列表是运行时 "meshlet" 结构的平面列表，至少包含指向唯一顶点索引列表和图元列表的偏移与计数。唯一顶点索引列表是指向顶点数据缓冲区的去重索引列表。图元列表定义了 mesh 的图元，并由指向唯一顶点索引列表的索引组成，这些索引局部化到该 meshlet 的顶点偏移。

**图 2. 显示 meshlet 缓冲区之间关系的示意图。**

<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="显示 meshlet 缓冲区之间关系的示意图" width="1000" height="283" data-path="images/gdk/features/graphics/ms_meshlet_data.png" />

## 转换为 meshlet

将传统的索引缓冲区网格 meshletized 无需美术工作流的变化——这只是在模型创作后的一个程序化后处理步骤。传统索引缓冲区也可以在运行时快速重新生成，从而无需同时交付传统索引缓冲区和 meshlet 缓冲区。meshletization 的计算量可能不小，因此建议脱机进行预处理。

ATG 在[XBOX 开发者下载页](https://aka.ms/xgddl)上随其他示例一起提供了一个示例 meshlet 转换器项目，包括一个 C++ 库和一个命令行工具，可用于执行此转换。该工具不会修改顶点数据本身，因此建议你在对网格数据进行 meshletization 之前，先对其运行如 Forsyth 算法的顶点缓存优化器。优化器往往会生成比一般创作工具输出的网格更具空间相关性的网格。也可以加入其他启发式规则来平衡顶点复用和最终网格结构的有利剔除特性。

## 使用 meshlet 渲染

meshlet 的结构让使用网格着色器进行渲染变得非常容易。将线程组大小声明为最大 meshlet 大小，并为 mesh 中的每个 meshlet 分派一个线程组。每个线程负责处理并导出一个顶点和图元。

以下展示一个简单的网格着色器代码示例，用于渲染一个已 meshletized 的网格。首先，加载线程组的 meshlet，之后可以立即声明输出计数。最后，PrimitiveCount 个线程负责加载并写入图元索引数据，VertexCount 个线程加载用于访问顶点数据的顶点索引，对其进行着色并写入输出数组。

完整示例可以在 [XBOX 开发者下载页](https://aka.ms/xgddl)上找到。

以下代码示例是一个网格着色器 meshlet 渲染的示例实现。

```
#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)

[Meshlet 剔除](/build/core-features/graphics/newfeatures/ms/ms-meshlet-culling)


## Related topics

- [Meshlet 剔除示例](/zh-CN/build/core-features/graphics/newfeatures/ms/ms-meshlet-culling.md)
- [XBOX Series X|S 上的网格着色器与 Meshlet](/zh-CN/build/core-features/graphics/newfeatures/ms/index.md)
- [为什么使用网格着色器？](/zh-CN/build/core-features/graphics/newfeatures/ms/ms-why.md)
- [XBOX GDK 主机开发 NDA 主题索引](/zh-CN/nda/nda-overview.md)
