Skip to content

Fix inverted-exterior duplicate triangles in Corset model#279

Open
bghgary wants to merge 1 commit into
KhronosGroup:mainfrom
bghgary:fix-corset-inverted-exterior-dups
Open

Fix inverted-exterior duplicate triangles in Corset model#279
bghgary wants to merge 1 commit into
KhronosGroup:mainfrom
bghgary:fix-corset-inverted-exterior-dups

Conversation

@bghgary
Copy link
Copy Markdown
Contributor

@bghgary bghgary commented May 5, 2026

Context

The Corset model contains a large number of "inverted-exterior duplicate" triangles — triangles whose vertex positions lie on the model's outer surface, but whose face normals point inward (toward the model's central axis), coincident with properly outward-facing triangles right next to them. Most rasterizing viewers hide these via backface culling and z-fight resolution, so they have been invisible in tools like the Babylon Sandbox, model-viewer, and the Khronos Sample Viewer's rasterizer mode.

Path tracers don't cull during BVH traversal, and they fire shadow rays directly through the BVH. The phantom interior surfaces win the BVH-traversal coin flip on some pixels (corrupting shading, since the surface gets classified as back-facing) and intercept shadow rays cast from properly-lit points (producing phantom shadows). Issue #278 reported one example of the latter: a hard dark patch on the upper-right chest in vk_gltf_renderer's path tracer.

Root cause

For a representative example, glTF triangles 7520 and 7521 form a single source-FBX quad (Models/Corset/sourceModels/Corset.fbx polygon #3798, vertices [3956, 3860, 3864, 3955]). Both triangles' positions sit on the proper outer surface, but their face normals point inward and their vertex normals were authored to match (so winding-only checks don't flag them). They duplicate the exterior surface tri-for-tri, just with the winding reversed.

Surveying the whole mesh, 3,490 triangles match this pattern (face normal points radially inward, and a properly-oriented outward-facing triangle exists at the same radius within ≤2 mm). That's roughly 19% of the mesh's 18,324 triangles. The remaining inward-facing triangles (~30) sit at smaller radius than the outer shell and are legitimate inner-liner geometry; they were preserved.

Fix

Removed the 3,490 inverted-exterior duplicate triangles from the index buffer. The proper outward-facing triangles already cover the model surface, so removal does not leave holes. All three variants were regenerated:

Variant Before After Notes
Corset/glTF/Corset.bin 662,184 B 641,244 B indices bufferView + accessor count updated
Corset/glTF/Corset.gltf 18,324 tris 14,834 tris accessor count 54972 → 44502, bufferView byteLength 109944 → 89004, buffer byteLength 662184 → 641244
Corset/glTF-Binary/Corset.glb 13,491,364 B 13,471,000 B regenerated from fixed glTF with gltf-pipeline
Corset/glTF-Draco/Corset.bin 230,116 B 215,792 B regenerated from fixed glTF with gltf-pipeline -d --separate

The glTF-Binary and glTF-Draco variants were regenerated using gltf-pipeline — the same tool the upstream Corset Draco file was originally encoded with (see KhronosGroup/glTF-Sample-Models@7f3cd41). The Draco bitstream version (2.2) and encoder method (edgebreaker) are byte-identical between the upstream and regenerated files; only the compressed payload differs.

Verification

  • Khronos glTF Validator (2.0.0-dev.3.10): all three variants pass (Errors: 0, Warnings: 0).
  • vk_gltf_renderer path tracer: rendered the fixed asset from a camera matching the issue's reported angle. The dark diamond on the upper-right chest is gone. Diff vs the original at the same camera shows changes only in the affected region (and faint AO tightening elsewhere where shadow rays no longer punch through the duplicate shell).
  • Default-camera path tracer render: no missing geometry, no new artifacts.
  • Rasterizer comparison (Babylon Sandbox): the rasterized image is unchanged before vs after the fix. This is expected — backface culling was hiding these triangles all along — and confirms no rasterization regression.

Source FBX

The same inverted-exterior duplicates exist in glTF-Sample-Models/sourceModels/Corset/Corset.fbx. Updating the source FBX is outside the scope of this PR; this fix only touches the glTF-format derivatives.

Closes #278

[Created by Copilot on behalf of @bghgary]

The Corset mesh contained 3,490 triangles whose face normals pointed
radially inward, coincident with properly outward-facing triangles at the
same outer-surface position. Rasterizers hid these via backface culling,
but path tracers (which don't cull during BVH traversal and fire shadow
rays directly) produced phantom shadow patches and shading artifacts —
e.g., the dark diamond on the upper-right chest reported in KhronosGroup#278.

Removed the offending triangles from glTF/Corset.bin (indices accessor
count and bufferView byteLength updated accordingly) and regenerated the
glTF-Binary and glTF-Draco variants from the fixed glTF using
gltf-pipeline. All three variants pass the Khronos glTF Validator.

Closes KhronosGroup#278

[Created by Copilot on behalf of @bghgary]

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

Corset Model Contains a Flipped Polygon in Front of the Surface

1 participant