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

    Interface ProjectedMeshData

    Everything the geometry builder needs for one projection epoch.

    interface ProjectedMeshData {
        position: Float32Array;
        indices: Uint32Array;
        visibleFaceCount: number;
        visibleVertexCount: number;
        side: MeshSide;
        storedNormalsUsable: boolean;
        usedFastPath: boolean;
        positionChanged: boolean;
        positionKey: string;
        bounds: MeshProjectionBounds | null;
        undecidableReason?: string;
    }
    Index
    position: Float32Array

    Display-space positions (vertexCount * 3)

    indices: Uint32Array

    Vertex indices of the visible triangles (visibleFaceCount * 3), in the ORIGINAL (un-remapped) vertex numbering.

    visibleFaceCount: number

    Triangles that survived the cull

    visibleVertexCount: number

    Vertices that passed the slab test (diagnostic; not a draw bound)

    side: MeshSide

    The material side this epoch requires.

    'front' only when the node asked for single-sided AND projected winding is decidable (see resolveWinding); 'double' otherwise.

    storedNormalsUsable: boolean

    Whether this epoch's displayed axes are the frame the stored normals were authored in — see storedNormalsUsable.

    Sits next to side because it is the same kind of quantity: a per-epoch consequence of displayDims that the material must be told about, not a property of the node. side decides which faces draw; this decides which normal the shade term reads.

    false on a node with no stored normals at all, so a consumer needs only this one flag (plus the view-independent shading) to pick the shader variant.

    usedFastPath: boolean

    True when the cull was skipped because there are no hidden dimensions

    positionChanged: boolean

    True when position was (re)extracted this epoch — i.e. displayDims changed, or this is the first projection.

    Reported explicitly because the position buffer is REUSED across epochs (LoadedMeshData.projection), so its array identity can no longer signal a change. Consumers must gate the re-upload and the bounds recompute on this rather than on identity; using identity with a reused buffer silently stops re-uploading after an axis permutation, and using it with a freshly allocated buffer re-uploads the whole mesh on every slice move (#1245).

    positionKey: string

    The displayDims.join() these positions were extracted for. The commit stamps it on the geometry and re-uploads whenever it differs from the geometry's last-uploaded key — so an aborted commit (which advanced the loader's displayDimsKey but never uploaded) is still repaired by the next commit at that displayDims. positionChanged alone cannot: it is a projection-time signal and reads false on the epoch after a superseded re-extraction.

    bounds: MeshProjectionBounds | null

    Display-space AABB over the vertices the emitted index references, or null when nothing is drawn.

    Same role as LinesProjectionBounds / GSplatsProjectionBounds: the projection computes it and computeMeshBounds sets the geometry's box and sphere from it. Bounding the INDEXED vertices rather than the whole position buffer is the point — under no-compaction position holds every vertex of the whole nD mesh, so a 4D surface that translates over time would otherwise frame its entire trajectory (#1252).

    undecidableReason?: string

    Set when the node asked for single-sided rendering but winding could not be decided, carrying the reason. Threaded out to the caller rather than logged here so resolveWinding and projectMeshTo3D stay free of side effects — the projection runs on every slice move, so a warning emitted at this depth would flood the console during a scrub.