Gamedev Hub

Mesh Shaders

The traditional “Vertex $\rightarrow$ Geometry $\rightarrow$ Rasterizer” pipeline is 20 years old and increasingly a bottleneck. Mesh Shaders (introduced with DirectX 12 Ultimate and Vulkan) replace this with a compute-like pipeline that gives the developer total control over geometry.

1. The Two-Stage Pipeline

Stage 1: The Task Shader (Amplification)

The Task Shader operates on Meshlets (small groups of ~64-128 triangles).

Stage 2: The Mesh Shader

The Mesh Shader takes the visible meshlets and generates the final vertices and triangles.

2. Why it’s a Revolution

3. Implementation Concept (HLSL)

struct Meshlet {
    uint vertexCount;
    uint triangleCount;
    // ... data ...
};

[NumThreads(128, 1, 1)]
[OutputTopology("triangle")]
void main(uint gtid : SV_GroupThreadID, out vertices Vertex v[64], out indices uint3 tri[126]) {
    // Direct control over the geometry buffer
    SetMeshOutputs(64, 126);
    
    // Process vertices in parallel
    v[gtid] = FetchAndTransformVertex(gtid);
    
    // Assemble triangles in parallel
    if(gtid < 126) {
        tri[gtid] = GetTriangleIndices(gtid);
    }
}

4. Part 2: GPU Culling Masterclass

Traditional engines cull entire objects. Mesh shaders allow you to cull individual groups of 64 triangles.

Cluster Culling

We break a mesh into Meshlets. In the Task Shader, we calculate the bounding sphere of the meshlet.

Occlusion Culling (Hi-Z)

This is the “Black Magic” of modern rendering.

  1. The GPU generates a low-res version of the previous frame’s depth buffer (a Hi-Z Pyramid).
  2. The Task Shader checks the meshlet’s depth against the Hi-Z pyramid.
  3. If the meshlet is “deeper” than the wall already rendered there, it is culled.

5. Why it wins

This happens entirely on the GPU. The CPU can send “One Billion Triangles” to the GPU, and the Task Shader will discard 99.9% of them in microseconds, leaving only the visible ones for the Mesh Shader to process.

6. Summary