meshopt_buildMeshlets vs meshopt_buildMeshletsSpatial for Ray Tracing: Key Differences Explained

Use meshopt_buildMeshlets for rasterization pipelines that prioritize vertex cache efficiency, and meshopt_buildMeshletsSpatial when generating clusters for hardware ray tracing where spatial locality and BVH traversal performance dominate.

The meshoptimizer library provides two distinct algorithms for partitioning triangle meshes into GPU-friendly meshlets. While both meshopt_buildMeshlets and meshopt_buildMeshletsSpatial generate clusters suitable for modern graphics pipelines, they differ fundamentally in their optimization goals and are designed for different rendering workloads, particularly when targeting ray tracing acceleration structures.

Core Differences Between the Two Builders

Optimization Goals

  • meshopt_buildMeshlets balances topological efficiency (maximizing vertex reuse) with culling efficiency (minimizing meshlet radius and cone divergence). It greedily groups triangles to keep the GPU vertex cache warm while respecting cone culling constraints.

  • meshopt_buildMeshletsSpatial optimizes for spatial locality using a Surface Area Heuristic (SAH) to create BVH-friendly clusters. It may sacrifice vertex reuse to ensure triangles that are spatially close remain in the same meshlet, reducing ray tracing traversal cost.

API Parameters and Bounds

The functions expose different parameters that reflect their distinct strategies:

Function Key Parameters Bounds Calculation
meshopt_buildMeshlets max_vertices, max_triangles, cone_weight meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles)
meshopt_buildMeshletsSpatial max_vertices, min_triangles, max_triangles, fill_weight meshopt_buildMeshletsBound(index_count, max_vertices, min_triangles)

Critical distinction: When using meshopt_buildMeshletsSpatial, you must compute the output buffer size using min_triangles rather than max_triangles because the spatial builder may produce more meshlets by partially filling clusters to preserve spatial coherence.

Algorithmic Implementation Details

meshopt_buildMeshlets: Topological Clustering

According to the source in src/meshoptimizer.h (lines 727–740), this algorithm starts from a vertex-cache-optimized index buffer and greedily accumulates triangles into meshlets. It attempts to keep meshlets "complete"—merging disconnected regions if necessary—to maximize vertex reuse. This approach is implemented in src/meshletutils.cpp and is ideal for rasterization pipelines where vertex cache hit rates directly impact performance.

meshopt_buildMeshletsSpatial: SAH-Based Spatial Clustering

As defined in src/meshoptimizer.h (lines 741–757), this builder recursively subdivides the triangle set using a Surface Area Heuristic similar to BVH construction. It may leave meshlets partially filled to preserve spatial coherence, trading some vertex reuse for better ray tracing performance. The fill_weight parameter (0.0 to 1.0) controls how aggressively the algorithm fills partially empty meshlets versus maintaining strict spatial locality.

Code Examples

Standard Meshlet Generation (Rasterization)

#include "meshoptimizer.h"
#include <vector>

// Assume indices, vertex_positions, and vertex_count are defined
const size_t max_vertices = 64;
const size_t max_triangles = 124;
const float cone_weight = 0.0f;

// Calculate maximum possible meshlets
const size_t max_meshlets = meshopt_buildMeshletsBound(
    indices.size(), max_vertices, max_triangles);

std::vector<meshopt_Meshlet> meshlets(max_meshlets);
std::vector<unsigned int> meshlet_vertices(max_meshlets * max_vertices);
std::vector<unsigned char> meshlet_triangles(max_meshlets * max_triangles * 3);

// Build meshlets optimized for vertex reuse
const size_t meshlet_count = meshopt_buildMeshlets(
    meshlets.data(),
    meshlet_vertices.data(),
    meshlet_triangles.data(),
    indices.data(),
    indices.size(),
    reinterpret_cast<const float*>(vertex_positions),
    vertex_count,
    sizeof(float) * 3,
    max_vertices,
    max_triangles,
    cone_weight);

Ray Tracing Optimized Meshlets (Spatial)

#include "meshoptimizer.h"
#include <vector>

// Parameters for ray-tracing-friendly meshlets
const size_t max_vertices = 64;
const size_t min_triangles = 32;   // Enforce minimum to avoid tiny clusters
const size_t max_triangles = 124;
const float fill_weight = 0.0f;    // Prefer spatial coherence over density

// Note: Use min_triangles for bound calculation, not max_triangles
const size_t max_meshlets = meshopt_buildMeshletsBound(
    indices.size(), max_vertices, min_triangles);

std::vector<meshopt_Meshlet> meshlets(max_meshlets);
std::vector<unsigned int> meshlet_vertices(max_meshlets * max_vertices);
std::vector<unsigned char> meshlet_triangles(max_meshlets * max_triangles * 3);

// Build meshlets optimized for spatial locality and BVH traversal
const size_t meshlet_count = meshopt_buildMeshletsSpatial(
    meshlets.data(),
    meshlet_vertices.data(),
    meshlet_triangles.data(),
    indices.data(),
    indices.size(),
    reinterpret_cast<const float*>(vertex_positions),
    vertex_count,
    sizeof(float) * 3,
    max_vertices,
    min_triangles,
    max_triangles,
    fill_weight);

When to Use Which for Ray Tracing

Choose meshopt_buildMeshletsSpatial when:

  • Targeting Vulkan Ray Tracing or DirectX Raytracing pipelines
  • Building acceleration structures on-the-fly or preprocessing assets for RT cores
  • Ray traversal cost dominates over vertex shading performance
  • You need clusters that map efficiently to BVH leaf nodes

Choose meshopt_buildMeshlets when:

  • Working with traditional rasterization pipelines
  • Vertex cache efficiency is the primary bottleneck
  • Using meshlets for visibility buffer rendering or GPU culling systems where cone culling is beneficial

Key Source Files

The implementations and declarations for both functions are located in:

  • src/meshoptimizer.h: Public API declarations for both builders (lines 727–757)
  • src/meshletutils.cpp: Core algorithm implementation including SAH-based clustering
  • demo/main.cpp: Working examples demonstrating both meshlet generation paths around line 907
  • README.md: High-level documentation describing the spatial builder's purpose (around line 282)

Summary

  • meshopt_buildMeshlets optimizes for vertex reuse and cone culling, making it ideal for rasterization pipelines.

  • meshopt_buildMeshletsSpatial uses SAH-based recursive subdivision to prioritize spatial locality, producing meshlets that reduce BVH traversal cost in ray tracing applications.

  • Always calculate buffer bounds using min_triangles (not max_triangles) when calling meshopt_buildMeshletsSpatial to account for partially filled clusters.

  • The fill_weight parameter controls the trade-off between meshlet density and spatial coherence in the spatial builder.

Frequently Asked Questions

Can I use meshopt_buildMeshlets for ray tracing workloads?

While functional, meshopt_buildMeshlets prioritizes vertex reuse over spatial locality, which can produce irregularly shaped clusters that hurt BVH traversal performance. For dedicated ray tracing pipelines, meshopt_buildMeshletsSpatial is strongly recommended as it generates clusters that behave similarly to BVH leaves, reducing traversal cost.

Why does meshopt_buildMeshletsSpatial require min_triangles for the bounds calculation?

Because the spatial builder uses SAH-based recursive subdivision to preserve locality, it may split clusters before they reach max_triangles, creating partially filled meshlets. This can result in more total meshlets than the worst-case calculation with max_triangles would suggest. Using min_triangles ensures you allocate sufficient buffer space for these additional sparse clusters.

What is the optimal fill_weight value for ray tracing?

A fill_weight of 0.0f prioritizes spatial coherence over meshlet density, which is typically best for ray tracing as it maintains the SAH-friendly distribution. Values closer to 1.0f aggressively fill partial meshlets, increasing vertex reuse but potentially degrading BVH traversal efficiency. For pure ray tracing assets, start with 0.0f and profile traversal cost.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →