export interface VirtualMeshSource { /** xyz per vertex */ positions: Float32Array; /** xyz per vertex */ normals: Float32Array; /** Optional rgb per vertex, multiplied with the material color. */ colors?: Float32Array; /** Optional uv per vertex (texture coordinates). Vertices on a UV seam must be separate vertices. */ uvs?: Float32Array; indices: Uint32Array; } export interface VirtualMeshBuildOptions { /** Meshlets per group before simplification. */ groupSize?: number; maxLodLevels?: number; /** A group that keeps more than this fraction of its triangles stops refining (its meshlets become roots). */ maxGroupKeepRatio?: number; /** Fraction of a group's triangles kept by its simplification (the per-level reduction factor). */ simplifyRatio?: number; /** Stop when a whole level removed less than this fraction of triangles. */ minLevelReduction?: number; /** Remove small disconnected components while simplifying (good for foliage). */ prune?: boolean; /** * Keep simplifying below a single meshlet once the remaining roots form the whole mesh, so distant * instances can draw a handful of triangles (or nothing, with `prune`) instead of a full meshlet. */ tailSimplify?: boolean; /** Stop the tail at this many triangles. */ minRootTriangles?: number; /** * Let coarse LODs switch to voxel proxies when those are more accurate than simplified triangles * (foliage and other aggregate geometry; solid meshes keep their triangles). Default true. */ voxelLods?: boolean; /** * Finest voxel grid for those proxies, in cells along the longest side. Default 64. A finer grid (128) lowers the * smallest error a voxel level can have, so foliage made of many separate pieces (palm fronds, leaves) switches to * its cheap coarse levels closer to the camera. Builds take longer and use more memory. */ voxelResolution?: number; /** * Keep simplifying groups of separate small pieces (leaf cards, grass blades) when edge collapses stall: each piece * is simplified on its own, then neighbouring pieces are thinned in pairs, the kept piece widened to cover both * (see aggregate.ts). Without it such groups keep every piece up to the voxel levels. Default true. */ aggregateLods?: boolean; onProgress?: (fraction: number) => void | Promise; } export interface VirtualMeshData { positions: Float32Array; normals: Float32Array; colors: Float32Array | null; /** uv per vertex, or null when the source had none. */ uvs: Float32Array | null; /** Concatenated meshlet triangle lists, indexing `positions`. */ indices: Uint32Array; meshletCount: number; /** * 4 x vec4 per meshlet: * [0] LOD sphere (center, radius) - shared by all meshlets created from the same group * [1] parent LOD sphere (center, radius) * [2] (error, parentError, 0, 0) - object-space; parentError = ERROR_INFINITY for roots * [3] culling sphere (center, radius) - the meshlet's own geometry */ meshletBounds: Float32Array; /** * uvec4 per meshlet: (triangleCount, firstIndex, lodLevel, vertexOffset). * `firstIndex / 3` is also the meshlet's first entry in `meshletTriangles`. */ meshletInfo: Uint32Array; /** Global vertex ids, per meshlet, in meshlet-local order (`vertexOffset` indexes this). */ meshletVertices: Uint32Array; /** One packed triangle per entry: three meshlet-local vertex ids in bits 0-7, 8-15, 16-23. */ meshletTriangles: Uint32Array; /** Meshlets are sorted by LOD level. Per level: [firstMeshlet, meshletCount]. */ levelRanges: Uint32Array; /** Per level: [smallest own error, largest parent error] in object space (parent may be ERROR_INFINITY). */ levelErrors: Float32Array; /** * Per level: [largest own error, smallest parent error] in object space. Used by the fast path: if every * meshlet of a level passes the LOD test at the nearest distance (largest own error) and at the farthest * (smallest parent error), the level needs no per-meshlet test. */ levelGuardErrors: Float32Array; /** Sphere enclosing every LOD and parent sphere: bounds the distances the LOD test can see. */ lodBoundsSphere: [number, number, number, number]; /** Sphere enclosing every meshlet's culling sphere (all LODs): if an instance sphere is inside the frustum, so are they. */ cullBoundsSphere: [number, number, number, number]; /** * DAG links (CPU only, for `verifyCutCoverage`; not stored in .vgeo files). Meshlet i belongs to the group that * `replacementGroup[i]` names (-1 for the coarsest meshlets), and that group is replaced by the coarser meshlets * `replacementIndices[replacementStart[g] .. replacementStart[g + 1]]`. Every meshlet of a group shares one list, so * the size stays linear even when a simplification step merges thousands of meshlets at once. */ replacementGroup: Int32Array; replacementStart: Uint32Array; replacementIndices: Uint32Array; /** Whole-object bounding sphere (center xyz, radius). */ boundingSphere: [number, number, number, number]; stats: { leafTriangles: number; leafMeshlets: number; rootTriangles: number; rootMeshlets: number; lodLevels: number; /** Coarse levels built from voxel proxies (see voxelProxy.ts). */ voxelLevels: number; /** Groups simplified piece by piece (see aggregate.ts; absent in files baked before it). */ aggregateGroups?: number; buildMs: number; }; } export declare function buildVirtualMesh(src: VirtualMeshSource, options?: VirtualMeshBuildOptions): Promise; /** * How far the simplified mesh's bounding box retreats from the original's, per side (max over the 6 * sides). An empty result counts as losing the whole extent. Used as a floor for the LOD error so a * version that lost its silhouette is only drawn once that loss is below the pixel threshold. */ export declare function extentShrink(before: Uint32Array, after: Uint32Array, positions: Float32Array): number; /** Order-independent edge id. Safe while vertex ids stay below 2^26. */ export declare const edgeKey: (a: number, b: number) => number;