Skip to content

EdgeProjector.get returns empty geometry for small item subsets — deterministic, set-content-dependent (3.4.6) #763

Description

@Cmillkon

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions