Describe the bug
EdgeProjector.get(modelIdMap, world) returns empty visible/hidden line geometries when called with a small subset of a model's items, while the same local ids included in a larger set produce full linework. The effect is deterministic (independent of call order / warm-up) and depends on the content of the requested set, not just its size.
Measured directly against projector.get (components 3.4.6, fragments 3.4.6, chromium headless with real GPU via ANGLE/gl-egl; same results through TechnicalDrawing.addProjectionFromItems):
Requested set (localIds from getItemsOfCategories) |
visible position count |
| 4 walls |
0 |
| 1 slab |
0 |
| walls + slab (5 items) |
24 |
| walls + windows (6 items) |
48 |
| slab + roof + door + windows (5 items, no walls) |
146 |
| 8 geometric items (all minus one wall) |
268 |
| all 9 geometric items |
330 |
| 9 + 1 non-geometric id |
330 |
Note the two different 5-item sets yielding 24 vs 146 — neither pure set size nor a single "bad item" explains it. Yield grows superlinearly with set content until the full set is requested.
What I ruled out
- All 9 element ids pass the
getItemsIdsWithGeometry() filter (each id is present).
model.getItemsGeometry(subset) returns complete positions/indices/transform/representationId for every requested item (e.g. the 4 walls alone: 144/144/144/72 positions, distinct representationIds) — so the data reaching the mesh-building loop in EdgeProjector.get looks healthy. The loss happens downstream (generator / VisibilityCuller stage).
- Call order and repetition don't matter: walls-only → 0 whether it's the first call after load or after a successful full-set call.
- Adding a non-geometric id to the full set changes nothing (filter works as intended).
Reproduction
Model (15 kB IFC4X3, imports cleanly via IfcImporter, renders fine in 3D):
https://gist.github.com/Cmillkon/ff579f1080bf05abc720f730f8ac1b02
const model = fragments.list.get(modelId);
const walls = (await model.getItemsOfCategories([/^IFCWALL$/]))['IFCWALL']; // 4 ids
const projector = components.get(OBC.EdgeProjector);
const sub = await projector.get({ [modelId]: new Set(walls) }, world, {});
console.log(sub.visible.getAttribute('position').count); // 0 ← bug
const all = Object.values(await model.getItemsOfCategories([/.*/])).flat();
const full = await projector.get({ [modelId]: new Set(all) }, world, {});
console.log(full.visible.getAttribute('position').count); // 330 ✓
Our other test model (the tutorials' school-style IFC exported from Revit-class tools) does not exhibit this — per-category projection works there. The affected model is written by our own IFC4X3 writer (web-ifc CreateModel/SaveModel, one IfcExtrudedAreaSolid per element), so geometry is simple prisms; if the generator has a minimum-feature/pixel threshold interacting with small groups, that would be consistent with the gradient above.
Happy to provide more measurements. Downstream we work around it by re-projecting the full set into one layer whenever a per-category pass comes back empty.
Describe the bug
EdgeProjector.get(modelIdMap, world)returns empty visible/hidden line geometries when called with a small subset of a model's items, while the same local ids included in a larger set produce full linework. The effect is deterministic (independent of call order / warm-up) and depends on the content of the requested set, not just its size.Measured directly against
projector.get(components 3.4.6, fragments 3.4.6, chromium headless with real GPU via ANGLE/gl-egl; same results throughTechnicalDrawing.addProjectionFromItems):getItemsOfCategories)Note the two different 5-item sets yielding 24 vs 146 — neither pure set size nor a single "bad item" explains it. Yield grows superlinearly with set content until the full set is requested.
What I ruled out
getItemsIdsWithGeometry()filter (each id is present).model.getItemsGeometry(subset)returns completepositions/indices/transform/representationIdfor every requested item (e.g. the 4 walls alone: 144/144/144/72 positions, distinct representationIds) — so the data reaching the mesh-building loop inEdgeProjector.getlooks healthy. The loss happens downstream (generator / VisibilityCuller stage).Reproduction
Model (15 kB IFC4X3, imports cleanly via
IfcImporter, renders fine in 3D):https://gist.github.com/Cmillkon/ff579f1080bf05abc720f730f8ac1b02
Our other test model (the tutorials' school-style IFC exported from Revit-class tools) does not exhibit this — per-category projection works there. The affected model is written by our own IFC4X3 writer (web-ifc
CreateModel/SaveModel, oneIfcExtrudedAreaSolidper element), so geometry is simple prisms; if the generator has a minimum-feature/pixel threshold interacting with small groups, that would be consistent with the gradient above.Happy to provide more measurements. Downstream we work around it by re-projecting the full set into one layer whenever a per-category pass comes back empty.