Luxar Viewer API Documentation - v2026.9.22
    Preparing search index...

    Module data/mesh/mesh-progressive-loader

    Progressive Mesh loader for reveal-ladder (multi-additive-LOD) nodes.

    Wraps N MeshWholeNodeLoader instances — one per additive_<i> subgroup — behind the single MeshDataLoader interface, so the scene loader, the commit path and the Layers panel see one mesh node that gains triangles over time. The fourth member of the progressive-loader family (points- / lines- / gsplats-progressive-loader.ts).

    A prefix of an arbitrary index buffer is a surface full of holes, not a coarser one — which is why mesh has no level-of-detail additive ladder and never will (docs/specs/MESH_NODE_SPEC.md §9). What it has is a REVEAL: the writer orders faces by best-first growth through face adjacency keyed on radius, so every prefix is ONE connected patch. The renderer does nothing special; each level is just more triangles. That is the whole design — MESH_ADDITIVE_METHODS on the Python side admits radial and nothing else for exactly this reason.

    Connectivity is the guarantee; "grows outward from the centre" is what it LOOKS like only where the radius actually varies over the surface — an isosurface with depth structure, the target case. On a shell at near-constant radius (a sphere, a membrane) the radius carries almost no information, the frontier admits a whole radius class at once, and the half-revealed surface reads as a sieve filling in rather than a cap spreading. Observed on an icosphere, not inferred. Still one connected patch, still far better than an arbitrary order — but worth knowing before promising a user a growing cap.

    They are per-slice STREAMING ladders: their sub-loaders answer a spatial range query, so a slice move genuinely changes what each level holds. That forces the whole apparatus this file does not have — a view-state equality check, a reset generation, a departure-store/restore against the SliceCache, and a per-view concat.

    A mesh is whole-node resident (spec §7): every level fetches its faces ONCE and serves every later updateView from that decode, so the ladder is view-independent. What is loaded depends only on how many levels have arrived; what is drawn depends on the slice, and that is decided downstream in projection.ts exactly as it is for an unladdered mesh.

    Two consequences worth stating, because both are load-bearing:

    1. No SliceCache. Each sub-loader's own cached decode is the cache, and it lasts the node's lifetime. A whole-ladder S-cache entry keyed by slice would store the same bytes under every key.
    2. The concat memo is keyed on level count alone, so a slice move returns the SAME object — and with it the same loader-owned projection scratch (#1245). Had the ladder reset per view like its siblings, every scrub frame would have reallocated and re-uploaded the whole vertex buffer, which is precisely the regression that scratch exists to prevent.
    MeshProgressiveLoader
    concatenateMeshData