22 APR 2026

rahulmnavneeth

meshlet clusters

homedocs

Location

include/mop/core/meshlet.h   — Cluster types + builder API
src/core/meshlet.c           — Greedy builder + normal cones

What Meshlets Are

Geometry clusters of bounded size (up to 64 vertices, 124 triangles) with per-cluster bounding sphere and normal cone. GPU-friendly for:

MOP builds meshlets offline; the runtime uses them for Hi-Z + frustum culling on the Vulkan backend. CPU backend currently ignores meshlets.

Limits

#define MOP_MESHLET_MAX_VERTICES   64
#define MOP_MESHLET_MAX_TRIANGLES  124
#define MOP_MESHLET_MAX_INDICES    (MOP_MESHLET_MAX_TRIANGLES * 3)

These match VK_EXT_mesh_shader recommendations.

Types

MopMeshlet (32 bytes, std430 layout)

typedef struct MopMeshlet {
    uint32_t vertex_offset;      /* into MopMeshletData.vertex_indices   */
    uint32_t vertex_count;       /* unique vertex count (≤ 64)           */
    uint32_t triangle_offset;    /* into MopMeshletData.prim_indices     */
    uint32_t triangle_count;     /* triangle count (≤ 124)               */
    float    center[3];          /* bounding sphere center, object space */
    float    radius;
} MopMeshlet;

MopMeshletCone (32 bytes)

typedef struct MopMeshletCone {
    float axis[3];     /* average normal direction (unit) */
    float cutoff;      /* cos(half-angle); negative = wide */
    float apex[3];     /* cone apex, object space          */
    float _pad;
} MopMeshletCone;

Culling test: if dot(normalize(view_dir), cone.axis) < cone.cutoff, the entire cluster is back-facing and can be skipped.

MopMeshletData

typedef struct MopMeshletData {
    MopMeshlet     *meshlets;              uint32_t meshlet_count;
    MopMeshletCone *cones;                 /* parallel array, same count */
    uint32_t       *vertex_indices;        /* local → global vertex map  */
    uint32_t        vertex_index_count;
    uint8_t        *prim_indices;          /* packed triangles (3 × u8)  */
    uint32_t        prim_index_count;      /* total u8 count             */
} MopMeshletData;

Functions

bool     mop_meshlet_build         (const MopVertex *vertices, uint32_t vc,
                                    const uint32_t *indices,   uint32_t ic,
                                    MopMeshletData *out);
void     mop_meshlet_free          (MopMeshletData *data);
uint32_t mop_meshlet_count_estimate(uint32_t triangle_count);

Usage

MopMeshletData md;
if (mop_meshlet_build(vertices, vc, indices, ic, &md)) {
    /* upload md.meshlets / cones / vertex_indices / prim_indices
     * as SSBOs for your GPU culling compute shader. */
    mop_meshlet_free(&md);
}

The runtime integration (upload + GPU cull compute shader) lives in the Vulkan backend; at the public API level you typically never need to build meshlets yourself — MOP will do it internally when gpu_culling_enabled is set on the device.

See Also