Skip to content

Fix cap vertex normals of oblique IfcExtrudedAreaSolid#2054

Open
cvillagrasa wants to merge 1 commit into
ThatOpen:mainfrom
cvillagrasa:oblique-extrusion-cap-normals
Open

Fix cap vertex normals of oblique IfcExtrudedAreaSolid#2054
cvillagrasa wants to merge 1 commit into
ThatOpen:mainfrom
cvillagrasa:oblique-extrusion-cap-normals

Conversation

@cvillagrasa

@cvillagrasa cvillagrasa commented Jul 12, 2026

Copy link
Copy Markdown

I noticed the roof of the IfcOpenHouse model shading not correct at the vertical eave faces. The roof there is an IfcExtrudedAreaSolid with an ExtrudedDirection not perpendicular to the profile plane. I see that it happens both with the original file by Thomas Krijnen, already bundled in this repo in tests/ifcfiles/public/IfcOpenHouse_IFC4.ifc, and with another version I did with the ifcopenshell API.

IfcOpenHouse_roof_bug

It seems that the cause is that the extrusion tessellator stores the extrusion direction as the vertex normal of both cap faces. The caps of an extrusion lie in planes parallel to the profile plane regardless of the direction, so this is only correct when the extrusion is perpendicular, not for a 45° oblique roof.

The following lines reproduce the issue:

#26=IFCDIRECTION((0.,0.70710678118654757,0.70710678118654757));
#25=IFCRECTANGLEPROFILEDEF(.AREA.,$,$,2.,1.);
#27=IFCEXTRUDEDAREASOLID(#25,$,#26,3.);

Bisecting the npm releases: up to 0.0.51 render correctly, 0.0.52 onwards do not. The tessellator has always written dir as the cap normal, but until 0.0.52 every mesh was round-tripped through fuzzybools::Geometry::Normalize, which rebuilt vertex normals from triangle positions and silently corrected the caps. Commit 97714b4 removed that round-trip while fixing #664 and #597, and the raw tessellator cap normals became visible.

In this PR, in bimGeometry::Extrude (src/cpp/web-ifc/geometry/operations/bim-geometry/utils.h):

  • The stored cap normal is the profile-plane normal, computed with Newell's method over the outer profile contour and oriented outward (top cap along the extrusion direction, bottom cap against it). For perpendicular extrusions this is identical to the previous behaviour.
  • When the bottom cap is projected onto a cutting plane (cuttingPlaneNormal provided), that plane's normal is used instead, also oriented against the extrusion direction.

Side faces are unaffected, since they already compute geometric normals via AddFace(a, b, c). Vertex positions, indices and transformations are untouched.

tests/functional/ExtrusionCapNormals.spec.ts loads the fixture (one perpendicular box, one oblique box) and asserts that every stored vertex normal matches the geometric triangle normal. The oblique case fails before this change (minDot = 0.7071) and passes after (minDot = 1.0). The perpendicular case passes before and after. IfcOpenHouse roofs also come out exact (dot = 1.0 on all triangles) with the fix.

Cap faces always lie in planes parallel to the profile plane, but the
extrusion tessellator stored the extrusion direction as their vertex
normal, which is only correct for perpendicular extrusions. Oblique
extrusions (schema-legal per ValidExtrusionDirection) rendered with
mis-shaded caps since 0.0.52, when the fuzzybools normalization
round-trip that used to rebuild normals from positions was removed.

Compute the cap normal from the outer profile contour with Newell's
method, oriented along the extrusion direction for the top cap and
against it for the bottom cap; a cutting-plane-projected bottom cap
uses the cutting plane's normal.

Adds a spec with an inline two-box model (perpendicular and oblique)
asserting stored vertex normals match geometric triangle normals.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant