Degenerate Bevel Weld

examples/degenerate-bevel-weld/

Bevel offset >= half the min box dimension collapses the band into zero-area faces — and they ship: a stdlib GLB re-parse counts the degenerate triangles crossing the export boundary. Two rugged cases whose shells are the check's meshes: flat end panel versus a rolled knife ridge, the collapsed seam traced hot from live mesh data.

Rendered headless by the example itself. Select it to enlarge.

witnesses At offset == min_dimension/2 the bevel band pinches to exactly 12 zero-area faces (4 edges x 3 segments); 32 degenerate triangles cross into the exported GLB, waiting for any merge-by-distance to weld them.

tags bmesh mesh game-pipeline

runs on 4.5 LTS · 5.1 · 5.2 LTS

blender --background --python examples/degenerate-bevel-weld/degenerate_bevel_weld.py --

falsify it Breaks the contract on purpose and must exit 4

blender --background --python examples/degenerate-bevel-weld/degenerate_bevel_weld.py -- --both-safe

A runnable example isolating the half-dimension bevel collapse: author a bevel width against one box and reuse it on a thinner one, and at offset == min_dimension / 2 the bevel band pinches into zero-area faces — and those degenerate triangles cross the export boundary. Re-parsed from the shipped GLB with stdlib only, they are sitting in the file, where an engine-side merge-by-distance welds their loops. Found authoring gltf-export-roundtrip (its count check caught a 36-vertex weld on a thin crate part); this example isolates the threshold.

Pipeline arc neighbors: round-trip fidelity in gltf-export-roundtrip, topology gates in mesh-hygiene-audit, watertight parametric solids in bmesh-gear.

What it witnesses: a 1.6 × 0.4 × 1.0 slab (min dim 0.4, half = 0.2) with every edge beveled at 3 segments. All closed form or independently re-derived:

What each check catches on failure: safe offset pushed to the threshold (exit 3); degenerate offset backed below it (exit 4); coincident closed form corrupted (exit 6); GLB degenerate-tri expectation off (exit 8, e.g. if a future Blender changes triangulation — re-measure and update deliberately).

Version witness: output is byte-identical on Blender 4.5.11 LTS and 5.1.2 — same counts, same min_area values, same GLB triangle census.

Render as proof: two rugged hard-shell equipment cases whose shells are the check's two meshes — beveled_box(DIMS, 0.10) and beveled_box(DIMS, 0.20) — with every fitting (handle, steel draw latches with wire bails, rubber corner guards, molded frame, purge valve, ID plate, feet) kept inside the flat front land that survives both offsets, so the bevel is the only difference. The cases turn their end panels to the camera: the left keeps a flat end framed by clean chamfer bands; on the right the end and top lands are gone and the band rolls into a knife ridge at mid-depth. That collapsed seam is traced as a thin red-orange ink line (low emission, no neon halo) from live mesh data (every edge of every face thinner than 1e-6), with a small amber pin on each of the 12 zero-area faces the check counts — change the offset and the overlay moves or disappears. The clean case is the designed asset and passes the asset-quality floors (exit 11).

Run#

blender --background --python degenerate_bevel_weld.py --
blender --background --python degenerate_bevel_weld.py -- --both-safe
blender --background --python degenerate_bevel_weld.py -- --output bevel.png
blender --background --python degenerate_bevel_weld.py -- --output bevel.png --engine cycles

Exit codes#

Per-script sequential checks. 9 is a valid check code; there is no rule against it. 10 is the shared framing helper, 11 the shared asset-quality helper.

CodeMeaning
0Success
1Uncaught exception (FATAL wrapper)
2argparse / usage
3Safe bevel produced zero-area faces
4Degenerate bevel zero-area count ≠ closed form (--both-safe lands here)
5min_area collapse under 1e5×
6Coincident-position count off the closed form
7Safe GLB carries degenerate triangles
8Degenerate GLB triangle or position count drifted
9--output produced no file
10Gallery framing violation
11Asset-quality floor violation (render path only)

The blender-smoke workflow runs the check on Blender 5.2 LTS and 4.5 LTS (5.1 on the weekly cron, the needs-5.1 PR label, or manual dispatch). Smoke does not pass --output. Its catalog falsifier is --both-safe (expects exit 4).

Source

examples/degenerate-bevel-weld/degenerate_bevel_weld.py View the script on GitHub →
Two blue hard-shell cases with steel latches: the left with clean chamfer bands, the right with its rim collapsed into a ridge traced by a thin red-orange seam and amber pins at the degenerate faces.