@@ -8,23 +8,62 @@ Inverse of [`degenerate-bevel-weld`](../degenerate-bevel-weld/)
88solid). Neighbor of [ ` gltf-export-roundtrip ` ] ( ../gltf-export-roundtrip/ )
99(kit-bash face-plane welds on export).
1010
11- ** Why this pathology:** coincident shells are still manifold (every
12- edge borders 2 faces). Hygiene can pass. The engine trap is extra
13- triangles on disk.
11+ ## The contract
12+
13+ A mesh holding two coincident shells is still ** manifold** : every edge
14+ borders exactly two faces, because each shell is closed on its own. A
15+ hygiene check that only counts non-manifold edges reports 0 and passes.
16+ The glTF exporter then writes both shells: nothing in
17+ ` bpy.ops.export_scene.gltf ` welds coincident vertices, so the file
18+ carries twice the triangles of the visible solid.
19+
20+ ** Who hits this:** kit-bash and boolean-cleanup pipelines, duplicated
21+ objects joined back onto themselves, and generators that emit a part
22+ twice. The asset looks like one cube in Blender and in the engine: the
23+ two shells are identical triangles, so the depth test hides the second
24+ without flicker. The cost is invisible in the viewport and real on disk
25+ and at runtime: double the draw triangles, a collider built from the mesh
26+ twice as heavy, and overlapping lightmap UVs if the shells were unwrapped.
27+
28+ ** What catches it:** a coincident-vertex check, not a manifold check.
29+ ` bmesh.ops.find_doubles(dist=1e-5) ` reports ** 8** doubles on this mesh
30+ while the non-manifold count stays ** 0** . That is why the showcase
31+ hygiene budgets count doubles separately from non-manifold edges. The
32+ fix is ` bmesh.ops.remove_doubles ` before export.
33+
34+ ## What the check asserts
1435
1536** Pre-assertion (pathology exists):** ** 16** verts, ** 8** unique
16- positions, ** 12** faces, ** 24** edges, valence all 2. ` --no-duplicate `
17- exits 3.
37+ positions, ** 12** faces, ** 24** edges, valence 2 on every edge.
38+ ` --no-duplicate ` builds a single cube and exits 3. Vert count 16 alone is
39+ not enough, since any 16-vert mesh has it. Unique positions = 8 is the
40+ construction witness.
41+
42+ ** Handling (second axis):** read back from the written ` .gltf ` and its
43+ ` .bin ` : ** 48** loop-split positions, ** 24** triangles, ** 8** unique
44+ positions. ` --weld ` runs ` remove_doubles ` after the pre-assertion, the
45+ file then carries 24 positions and 12 triangles, and the check exits 4.
46+
47+ ` remove_doubles ` collapses the pair to one cube: 8 verts, 12 edges,
48+ 6 faces, valence 2. That is identical in every count to a cube built
49+ once. It does not leave a 4-faces-per-edge mesh.
50+
51+ ## Versions
52+
53+ Re-verified on Blender 4.5.11 LTS, 5.1.2 and 5.2.1 LTS. Every count
54+ above is the same on all three, including the ` find_doubles ` and
55+ non-manifold figures and both falsifier exits. Not a version split.
1856
19- ** Handling (second axis):** glTF ships ** 48** loop-split positions,
20- ** 24** tris, ** 8** unique. Vert count 16 is not enough; unique=8 is
21- the construction axis; 24 tris vs 12 after ` remove_doubles ` is the
22- export axis. ` --weld ` after the pre-assert exits 4.
57+ No gallery still. Two coincident cubes look like one cube; the defect
58+ is only in the counts.
2359
24- ` remove_doubles ` collapses to one cube (8/12/6), still manifold — not
25- a 4-face-per-edge mesh. Same on 4.5 LTS and 5.2 LTS.
60+ ## API reference
2661
27- No gallery still. Two coincident cubes look like one cube.
62+ - [ ` bmesh.ops.find_doubles ` ] ( https://docs.blender.org/api/current/bmesh.ops.html#bmesh.ops.find_doubles )
63+ and [ ` bmesh.ops.remove_doubles ` ] ( https://docs.blender.org/api/current/bmesh.ops.html#bmesh.ops.remove_doubles )
64+ ([ 4.5 LTS] ( https://docs.blender.org/api/4.5/bmesh.ops.html#bmesh.ops.remove_doubles ) )
65+ - [ ` bpy.ops.export_scene.gltf ` ] ( https://docs.blender.org/api/current/bpy.ops.export_scene.html#bpy.ops.export_scene.gltf )
66+ ([ 4.5 LTS] ( https://docs.blender.org/api/4.5/bpy.ops.export_scene.html#bpy.ops.export_scene.gltf ) )
2867
2968## Run
3069
0 commit comments