feat(fuse): "Check mirrored parts" — an option for files that store mirrored parts already facing outward - #67
Conversation
…heir mirrored parts already facing outward
User, on the Confederate frigate: "there is an issue with Group A, it's
partly transparent despite having all parts", then "make it an option".
glTF says a negative-determinant node renders with its winding
reversed, and the fuse gather applies that to every mirrored part —
which is what the Teutonic needed. The frigate's file stores its
mirrored hull half ALREADY facing outward, so the same reversal turned
that whole side inward. Measured (rays along the beam, 0.05 cells):
fused, as today 94.8 % back-facing from one side, 0.2 % the other
same 60 parts unfused 0.1 % / 0.1 %
Welded to the correct half in one island, the halves cancelled every
direction signal (volume +0.00, inside-out +0.00, twins 3605 / 3514),
the island was "not judged", and the fuse kept it as it stood.
Step 3b, after welding: a PLAIN part's winding is never in doubt, so it
is the reference. A mirrored part whose shared two-face seams run the
same way as its plain neighbours' is inside-out relative to them;
verdicts spread ring by ring to mirrored parts that touch only
mirrored ones. The reversal is undone only on a CLEAR verdict: at least
three parts judged and nine in ten agreeing the file is pre-flipped.
Then every mirrored part follows (parts with no plain neighbour
included, the frigate's Object_961 carried 2,443 of the 2,462 cells a
per-part rule left behind), except a part whose own seams disagree.
Mixed evidence changes nothing: the Romanic's group H judged 1 against
2, and acting on the one made it worse (2,667 -> 2,955 cells).
OFF BY DEFAULT: with it off the output is byte-identical to master
(checked on the frigate); the fuse warns when a group would need it.
With it on, measured with the real fuse on the real files:
frigate group A 94.8 % -> 0.0 % (unfused source 0.1 %)
Romanic group A, hull 108 / 9 -> 8 / 5 back-facing cells from the
beam, same bug, earlier taken as authored
Romanic group D, deck 161 -> 29 from above
Romanic group H byte-identical (mixed evidence)
Teutonic hull, 8 other Romanic groups byte-identical
Developed and drilled in a separate worktree the Unity project does not
compile. Four tests: a pre-flipped file fixed only with the option, a
standard file byte-identical, mixed evidence unchanged, a lone mirrored
part following the file's convention (its failure reproduced with the
option off). A Model Fuser checkbox under the weld slider; changelog
and tools page. 861 tests pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…lying on their plates are not inside-out Review of PR #67 (76de8e3), P2, reproduced and fixed. A lap strip lies ON its plate, stitched along one edge and facing the same way, so both faces walk the shared edge the SAME way on purpose. The consistency pass has handled that since 2026-09-15 (the Teutonic's Object_8, 671 strips): same traversal with surfaces already facing the same way (normalised dot > 0.9) is consistent as authored. Step 3b counted it as a conflict, so three mirrored lap strips over plain plates drew a unanimous "already facing outward" verdict and 18 correct faces were turned inward. 3b now applies that same rule before it counts a conflict, a decided part about to be undone judged as it will be written. One rule for laps in both places, not a second one. Test: the reviewer's case, three mirrored lap strips on plain plates: every face +Z with the option off (premise), the output byte-identical with it on, no verdict, no warning. It failed before the fix. Re-drilled on the real ships, in a worktree the Unity project does not compile: the frigate's group A byte-identical to the result that measured 0.0 % back-facing; the Teutonic hull identical to off; all eleven Romanic groups identical to the previous on-run, so the hull (108 -> 8) and deck (161 -> 29) gains stand. 862 tests pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Confirmed and fixed in 516995e — thank you, it reproduced exactly as described. A lap strip lies on its plate, stitched along one edge and facing the same way, so both faces walk the shared edge the same way on purpose. The consistency pass has handled that since 09-15 (the Teutonic's Object_8, 671 strips): same traversal with surfaces already facing the same way (normalised dot > 0.9) is consistent as authored. Step 3b counted it as a conflict. It now applies that same rule before counting — one lap rule in both places, not a second one — with a decided part about to be undone judged as it will be written. Your case is the new regression test: three mirrored lap strips on plain plates — every face +Z with the option off, output byte-identical with it on, no verdict, no warning. It failed before the fix. On the caveat that the real ships were not exercised: I re-drilled them, in a worktree the Unity project does not compile.
862 tests pass; gate passed on the push. 🤖 Generated with Claude Code |
Summary
"There is an issue with Group A, it's partly transparent despite having all parts" (the Confederate frigate), then "make it an option".
glTF says a mirrored part (a negative-scale node, one side of a symmetric hull) renders with its winding reversed, and the fuse applies that to every mirrored part, which is exactly what the Teutonic needed. The frigate's file stores its mirrored hull half already facing outward, so the same reversal turned that whole side inward. Welded to the correct half in one island, the two cancelled every direction signal and the fuse left the island as it stood.
The option, "Check mirrored parts", in the Model Fuser under the weld slider. Off by default. After welding, a plain part's winding is the reference, since no rule touched it. A mirrored part whose shared seams run the same way as its plain neighbours' is inside-out relative to them. The reversal is undone only on a clear verdict: at least three mirrored parts judged and nine in ten agreeing. Then every mirrored part follows, except one whose own seams disagree. Mixed evidence changes nothing. With the option off the fuse warns when a group would need it.
Measured with the real fuse on the real files
The Romanic's 108 hull cells, taken this morning as authored in the source, turn out to be the same bug.
Two rules came out of the drills rather than the design:
Object_961, which touches no plain part, on the reversal. It carried 2,443 of the 2,462 back-facing cells that remained. How mirrored parts are stored is a property of the exporter, so a clear verdict from the judged parts decides the rest.Developed and drilled in a separate worktree that the Unity project does not compile.
Test plan
bash tools/check.sh(861 tests). New: a pre-flipped file fixed only with the option; a standard file byte-identical; mixed evidence unchanged; a lone mirrored part following the file's convention, its failure reproduced with the option off.🤖 Generated with Claude Code