mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-14 11:24:19 +00:00
wgpu backend: CPU frustum cull + per-mesh draw compaction
Stage 6 of the wgpu port. Replaces the one-draw-per-(mesh, instance) loop
with a CPU cull pass that survives one drawIndexed per non-empty mesh
with packed instanceCount.
Adds to WgpuModelGpuData:
- visible_buffer: u32[] storage SSBO, pre-sized to instance_count at
applyCachedModel so the bind group reference never invalidates.
Re-uploaded each frame via wgpuQueueWriteBuffer.
- mesh_draws: per-mesh schedule (first_instance, instance_count,
first_index, base_vertex, index_count). instance_count==0 means the
mesh contributed nothing this frame and the draw is elided entirely.
cullModelCpu per-frame:
- Extract 6 frustum planes from the same VP we write into the uniform.
WebGPU clip-space z is [0, 1], so near plane = matrix row 2 (not
row 3 + row 2 as in GL); rest of the derivation is standard.
- Per-instance AABB-vs-frustum test using the p-vertex shortcut
(cheapest correct early-out for AABBs).
- Bucket survivors by mesh_id; flatten into a contiguous u32 list;
upload via wgpuQueueWriteBuffer. Per-mesh slice is [first_instance,
first_instance + instance_count).
WGSL adds @group(1) @binding(3) var<storage, read> visible: array<u32>
and an extra indirection: instance_idx = visible[iid]; the rest of the
shader is unchanged. firstInstance on each drawIndexed offsets into
visible[], so each mesh reads its own slice.
Verified two ways:
1. basic.ifc (3 instances, all on-screen) renders pixel-identically
to pre-stage-6 — proves cull keeps everything it should.
2. basic.ifc + a synthetic instance placed at (100, 100, 100) is
culled cleanly: only the cube renders, the far quad is rejected
by the frustum test. Proves cull actually rejects out-of-frustum
geometry rather than passing everything through.
Contribution culling, HiZ, and LOD selection arrive in stages 7 and 8;
they all hook into the same cullModelCpu seam.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -102,6 +102,12 @@ private:
|
||||
void flushPendingSidecarQueue();
|
||||
bool computeSceneAabb(float mn[3], float mx[3]) const;
|
||||
|
||||
// Cull `m`'s instances against the supplied frustum planes (world-space,
|
||||
// ax+by+cz+d >= 0 means inside), bucket survivors by mesh_id, and write
|
||||
// the flat visible-index list into m.visible_buffer via wgpuQueueWriteBuffer.
|
||||
// After return, m.mesh_draws is the per-mesh draw schedule for the frame.
|
||||
void cullModelCpu(WgpuModelGpuData& m, const float planes[6][4]);
|
||||
|
||||
bool wgpu_initialized_ = false;
|
||||
bool surface_configured_ = false;
|
||||
int configured_w_ = 0;
|
||||
|
||||
Reference in New Issue
Block a user