ifcviewer: fix pick-pass cull corruption and cached-model ID collisions

Two stability bugs:

1. Clicking an object left the scene with wrong shading until the camera
   moved.  The pick pass re-culls every model with its own parameters
   (min_pixel_radius=0, no HiZ) and overwrites each model's visible_ssbo
   and indirect buffer.  The next render() saw an unchanged camera,
   skipped the cull via the have_cached_cull_ shortcut, and drew the
   stale pick-pass buffers.  Fix: invalidate have_cached_cull_ at the
   end of pickObjectAt().

2. Loading two sidecar-cached models made the second model's picked
   properties resolve to the first model's elements.  Sidecars store raw
   object_id / model_id values from the session that wrote them, and
   both files start at object_id=1, so element_map_ entries collided.
   Fix: on load, rebase every PackedElementInfo and InstanceCpu by
   (next_object_id_ - min_id_in_sidecar) and overwrite model_id with
   the freshly-assigned handle before the elements hit element_map_.

Also document both in the README — the pick-pass note under 3A
contribution culling, the sidecar rebase under the sidecar format
section.
This commit is contained in:
Dion Moult
2026-04-15 18:30:03 +10:00
parent 99f409280a
commit 03662d2016
3 changed files with 44 additions and 5 deletions
+22 -5
View File
@@ -248,11 +248,28 @@ void MainWindow::applySidecarData(ModelId mid, SidecarData data) {
QElapsedTimer t;
t.start();
// Update next_object_id_ past all objects in this model before the
// extracted `elements` is moved out of `data`.
for (const auto& elem : data.elements) {
if (elem.object_id >= next_object_id_)
next_object_id_ = elem.object_id + 1;
// Sidecars store raw object_ids and model_ids from the session that wrote
// them. On load we must rebase both onto the current session's ID space,
// or two cached models collide (both starting at object_id=1, both
// claiming the original model_id). Offset by (next_object_id_ - min_id)
// so the first cached object takes the next free slot.
uint32_t min_oid = UINT32_MAX;
for (const auto& pe : data.elements) {
if (pe.object_id < min_oid) min_oid = pe.object_id;
}
uint32_t oid_offset = 0;
if (!data.elements.empty() && min_oid < UINT32_MAX) {
oid_offset = next_object_id_ - min_oid;
}
for (auto& pe : data.elements) {
pe.object_id += oid_offset;
pe.model_id = mid;
if (pe.object_id >= next_object_id_)
next_object_id_ = pe.object_id + 1;
}
for (auto& inst : data.instances) {
inst.object_id += oid_offset;
inst.model_id = mid;
}
// Hand off geometry to GPU in a single call.