mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
126d2d4c06
WGPU_SPATIAL_BUCKETS=1 swaps the applyCachedModelStreaming planner from mesh-keyed Morton+greedy to octree-style instance bucketing. Default behaviour unchanged (env var unset → mesh-keyed planner runs). Phase 1 of #55 / #56. The mesh-keyed planner produces chunks whose AABBs are the union of all instances of the chunk's meshes — for heavily-deduplicated IFC meshes (a "standard floor tile" used 800 times across a federation) the mesh's "centroid" is a mean of scattered instance positions and the chunk's AABB ends up spanning the entire model. Symptom: chunk-level frustum cull rarely fires (AABB always intersects view), and the screen-area priority metric under-rates big-AABB chunks because their corners straddle the near plane. Visible objects pop in/out as the camera tilts, even though they're fully on screen. The spatial planner bucketises INSTANCES directly. Each leaf bucket contains its instance list + the unique mesh data those instances reference. A mesh whose instances scatter into multiple buckets gets its vertex/index data uploaded into multiple pool slices — duplication is the cost for tight bucket AABBs. For IFC this is acceptable: heavily-shared meshes tend to be small (fittings, fasteners), so per-bucket duplication adds tens-of-MB not GB. Octree implementation (planSpatialChunks): - work-stack subdivision: for each (instance subset, AABB), split into 8 octants around centre and recurse - stop conditions: bucket fits WGPU_CHUNK_VERTEX_BYTES_LIMIT for union vertex bytes AND ≤ spatial_max_instances_ instances; OR single instance left; OR every instance falls into the same octant (pathological — emit as leaf rather than infinite recurse) - spatial_max_instances_ default 5000, overridable via WGPU_SPATIAL_BUCKET_MAX_INSTS env var so the prototype can be swept without rebuilding Data-model adjustment beyond what dc2927997 prepared: - Per-chunk per-mesh chunk-local offset table (chunk_mesh_offsets) built during the chunk-construction loop. The mesh-keyed per-mesh global arrays (mesh_chunk_idx etc.) still get populated for legacy reads, but under spatial bucketing they're overwritten when the same mesh appears in multiple chunks — harmless because cull reads the per-instance arrays exclusively (per dc2927997). - Post-construction, per-instance arrays are populated from chunk_mesh_offsets via (instance_to_chunk[i], inst.mesh_id) lookup. Mesh-keyed planner derives identical values to before (pixel-identical); spatial planner now writes the correct per-bucket offsets even when the mesh appears in multiple chunks. basic.ifc parity on all three paths confirmed (non-streaming mesh-keyed, streaming mesh-keyed, streaming spatial all produce 0 pixel diff vs the reference). Spatial planner produced 1 bucket on basic.ifc (3 instances, well under thresholds) as expected. Non-streaming applyCachedModel left unchanged — the prototype targets the streaming path which is where the federation-scale missing-objects issue lives. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>