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

# Meshlet 剔除示例

> Meshlet 剔除示例

建议你先阅读 [Meshlets](/build/core-features/graphics/newfeatures/ms/ms-meshlet-render) 主题。

Meshlet 剔除示例主题介绍了一种称为 *meshlet 剔除* 的技术在放大着色器（Amplification Shader）中实现的伪代码。由于一个 meshlet 的图元在理想情况下具备空间和方向的相关性，因此我们可以按 meshlet 存储高效的剔除数据。这些数据可用于在放大着色器中对 meshlet 列表相对视图进行快速剔除，仅为存活下来的 meshlet 分派网格着色器实例。

该技术从一个放大着色器开始，每个线程处理一个 meshlet。这意味着我们必须在命令列表上分派 ceil(MeshletCount / GROUP\_SIZE) 个线程组。

然后，每个放大着色器线程组负责处理 GROUP\_SIZE 个 meshlet。每个线程对其 meshlet 相对视锥体进行剔除，确定其导出槽，然后将其索引写入载荷数据。它接着使用 [DispatchMesh](https://microsoft.github.io/DirectX-Specs/d3d/MeshShader.html#dispatchmesh-intrinsic) 为每个存活下来待渲染的 meshlet 分派一个网格着色器线程组。每个网格着色器线程组随后从载荷数据加载其 meshlet 并导出其几何数据。

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

## 放大着色器

放大着色器的结构与计算着色器完全相同，但结尾最多有一次 'DispatchMesh(…)' 调用。首先，每个线程加载其 meshlet 并对其进行视图剔除。接下来执行紧凑（compaction）流程，以确定每个线程的最终写入位置。这也为该线程组提供了未被剔除的 meshlet 的最终计数。最后，将 meshlet 索引写入到 groupshared 载荷数据，并使用存活下来的 meshlet 数量和载荷数据调用 DispatchMesh。

以下示例以伪代码展示实现 meshlet 剔除的放大着色器。

```
#define GROUP_SIZE 128

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

    // Local Culling data.
    float4 BoundingSphere;
    float4 NormalCone;
};

StructuredBuffer<Meshlet> Meshlets : register(t0);

cbuffer ViewProps : register(b0)
{
    float4x4 ViewMat;
    float4x4 ViewProjMat;
    float3   ViewPosition;
};

struct MyPayload 
{ 
    uint MeshletIndices[GROUP_SIZE]; 
};

groupshared MyPayload payload;

bool CullTests(Meshlet m) { ... }
void CalcPayloadIndexAndCount(bool isCulled, out index, out count) { ... }

[NumThreads(GROUP_SIZE, 1, 1)] 
void main(
    uint dispatchThreadId : SV_DispatchThreadID,
    uint groupThreadId : SV_GroupThreadID
)
{
    Meshlet meshlet = Meshlets[dispatchThreadId];
    bool isCulled = CullTests(meshlet);
    
    uint index, count;
    CalcPayloadIndexAndCount(groupThreadId, isCulled, index, count);
    
    if (!isCulled)
    {
        payload.MeshletIndices[index] = dispatchThreadId;
    }

    DispatchMesh(count, 1, 1, payload);
}
```

## 网格着色器

该管线中的网格着色器与仅使用网格着色器管线的 meshlet 渲染非常相似，区别在于我们从载荷数据中读取线程组的 meshlet 索引。载荷数据即由前置放大着色器构建并导出的数据。GroupID 和 DispatchThreadID 会被局部化到由调用它的放大着色器线程组分派出的网格着色器集群，它们全部共享相同的载荷数据。

以下代码示例展示了紧随前面放大着色器之后的网格着色器。

```
#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,
    in payload MyPayload payload,
    out vertices VertexOut verts[MAX_MESHLET_SIZE],
    out indices uint3 tris[MAX_MESHLET_SIZE])
{
    uint meshletIndex = payload.MeshletIndices[groupId];
    Meshlet m = Meshlets[meshletIndex];

    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)

[为什么使用网格着色器？](/build/core-features/graphics/newfeatures/ms/ms-why)

[网格着色器 API 概述](/build/core-features/graphics/newfeatures/ms/ms-api-design)

[Meshlets](/build/core-features/graphics/newfeatures/ms/ms-meshlet-render)


## Related topics

- [XBOX Series X|S 上的网格着色器与 Meshlet](/zh-CN/build/core-features/graphics/newfeatures/ms/index.md)
- [Meshlets](/zh-CN/build/core-features/graphics/newfeatures/ms/ms-meshlet-render.md)
- [为什么使用网格着色器？](/zh-CN/build/core-features/graphics/newfeatures/ms/ms-why.md)
- [XBOX 游戏能效基础要点](/zh-CN/build/game-principles/sustainability/energy-efficiency-essentials.md)
- [示例](/zh-CN/build/core-features/common/game-streaming/building-touch-layouts/samples/index.md)
