mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-13 06:53:36 +00:00
Phase 3B: per-instance LOD via meshoptimizer simplifySloppy
Decimate each unique mesh once at sidecar-build time and swap to the reduced index slice per-instance per-frame when projected sphere radius drops below IFC_LOD1_PX (default 30). Same VBO, same SSBO, just a different firstIndex/count in the indirect command. Extends MeshInfo (48→56 B) with lod1_ebo_byte_offset + lod1_index_count and bumps the sidecar to v5. buildLods() runs inside onStreamingFinished, appends decimated indices to sd.indices, applyLodExtension pushes the EBO suffix to the live GPU state, and the sidecar is written with LOD1 baked in. simplifySloppy (voxel clustering) is used instead of the default edge-collapse meshopt_simplify because BIM brep output is per-triangle- unwelded and non-manifold after welding — simplify returned the input unchanged for every mesh tested. Sloppy ignores topology. Knobs (IFC_LOD_SLOPPY, IFC_LOD_ERROR, IFC_LOD_RATIO, IFC_LOD_MIN_SAVINGS, IFC_LOD_LOCK_BORDER, IFC_LOD_DEBUG) are available for A/B tuning. Result on the 128M-tri 10-model test scene (GTX 1650, 2px contribution cull): 20.2 → 43.2 fps, 40M → 14M visible triangles, no change in object count. LOD build adds 100–600 ms per model on first open, cached thereafter. README Phase 3B section is now a full writeup of pipeline, selection, decimator-choice rationale, env vars, and measured numbers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -127,6 +127,13 @@ public:
|
||||
// any existing state for model_id and marks it drawable.
|
||||
void applyCachedModel(uint32_t model_id, SidecarData data);
|
||||
|
||||
// After buildLods() has extended sd.indices + populated lod1_* fields,
|
||||
// push just the appended index slice + the refreshed mesh metadata onto
|
||||
// the live GPU state for model_id. VBO / SSBO / instance array are left
|
||||
// alone; only the EBO grows and m.meshes is replaced. No-op if the
|
||||
// model isn't finalised on the viewport.
|
||||
void applyLodExtension(uint32_t model_id, const SidecarData& sd);
|
||||
|
||||
void hideModel(uint32_t model_id);
|
||||
void showModel(uint32_t model_id);
|
||||
void removeModel(uint32_t model_id);
|
||||
@@ -223,8 +230,13 @@ private:
|
||||
// per-frame allocation. indirect_scratch_ is the matching array of
|
||||
// DrawElementsIndirectCommand records — forward-declared as bytes so
|
||||
// the header doesn't need the struct definition.
|
||||
std::vector<std::vector<uint32_t>> visible_by_mesh_fwd_;
|
||||
std::vector<std::vector<uint32_t>> visible_by_mesh_rev_;
|
||||
// Four buckets = {fwd, rev} × {LOD0, LOD1}. LOD1 buckets are only
|
||||
// populated when the mesh has lod1_index_count > 0 and the projected
|
||||
// pixel radius is below the LOD switch threshold.
|
||||
std::vector<std::vector<uint32_t>> visible_by_mesh_fwd_lod0_;
|
||||
std::vector<std::vector<uint32_t>> visible_by_mesh_fwd_lod1_;
|
||||
std::vector<std::vector<uint32_t>> visible_by_mesh_rev_lod0_;
|
||||
std::vector<std::vector<uint32_t>> visible_by_mesh_rev_lod1_;
|
||||
std::vector<uint32_t> visible_flat_;
|
||||
std::vector<DrawElementsIndirectCommand> indirect_scratch_;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user