wip(assembler): M2 round 1 -- sharp-mesher spike: hybrid MC+DC keeps edges, borders and LOD seams not solved yet

Standalone only. Hybrid/DC cut sharp residual 16.7 -> 6.25 cm and split creases ~100%, organic wall
unchanged under hybrid, +4.4% mesh cost, W1/W8/W16 identical. Gate failed: hybrid open edges on 500/625
tagged tile borders; every method fails LOD0/LOD1 (no transition templates yet). Binaries and OBJ meshes not committed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-10 01:32:27 +02:00
1 parent 61633cb492
commit 6953254349
31 files changed
+5627

No files matched your search

@@ -0,0 +1,125 @@
# World assembler M2 round 1: sharp-mesher decision spike
Date: 2026-10-10
Status: **Gate failed; no production mesher selected.** Hybrid is the leading candidate for an in-game follow-up, but it does not pass independent tile seams. Every candidate fails the tested LOD0/LOD1 seam.
## Decision
At 25 cm, feature-aware DC substantially reduces sharp-feature field residual and preserves hard normal splits. The hybrid also leaves the smooth cave-chamber wall on the MC path, where its measured residual matches MC. Its 8-worker mesh cost is about 4.4% above MC.
Those gains are not enough to choose it: hybrid fails all 500 tagged-shape independent tile-border cases, and DC everywhere fails all 625. MC passes all 625 same-LOD tile-border cases but retains large sharp-feature bevel residual and also fails every LOD transition case. No candidate passes both border gates. Hold architectural recipes until a real border/transition implementation passes.
Round 2 should take MC and hybrid into Unreal as opt-in, versioned recipe candidates. Hybrid is the primary quality candidate; MC is the baseline and organic fallback. Bring neighbor halo/ownership rules, a 2:1 transition template or equivalent, and actual collision cooking. Compare the five fixtures in-game with matched cameras, including same-LOD and LOD0/LOD1 borders. Keep DC-everywhere as a reference unless its organic quality and border results improve.
## Test setup
The standalone C++20 harness uses the plugin’s canonical marching-cubes lookup table and 25 cm cells. It builds a 32³-cell, 8 m tile for each fixture. The lattice phase sweep translates each analytic field by 0, 5, 10, 15, and 20 cm on each axis: 125 phases per fixture and method, 1,875 phase meshes total.
The fixtures are a union-of-boxes 90° corner, a box doorway with an analytic void, a one-metre riser, a cliff ledge/overhang, and a smooth spherical cave-chamber cavity. The chamber has negative density in solid rock and positive density in its air cavity, following the plugin sign convention. It is an analytic curved proxy, not a sampled native cave or SurfaceWorld patch.
The candidates are:
- **MC:** table-driven marching cubes with linear edge roots and interpolated central-difference field normals. This preserves MC geometry while giving it a fair smooth-normal path.
- **Hybrid:** untagged connected surface components use MC. Components connected to analytic sharp-plane feature tags use dual contouring.
- **DC:** dual contouring on every surface component, including the cave-chamber wall.
DC uses Hermite roots, a fixed-order 3×3 QEF solve, a small center penalty for rank-deficient constraints, cell-bound clamping, deterministic feature selection, and position quantization at 1/65,536 voxel. All candidates share a 0.01 mm positive bias for exact-zero lattice samples. No LOD transition template is implemented in this spike; independent fine/coarse half meshes are compared directly to expose that gate.
Phase and same-resolution seam sweeps use the five phase offsets above. Same-LOD borders compare independently generated 8 m tiles on either side of x=0. LOD borders compare an independently generated 25 cm half tile against an independently generated 50 cm half tile. Border contours are compared in both directions at five points per segment. A missing contour is recorded as unmatched; the topological audit counts geometric boundary and nonmanifold edges after merging the independent meshes.
## Surface residual and crease normals
The residual is the absolute analytic field value, in metres, sampled at each triangle’s three vertices, three edge midpoints, and centroid. The table shows the equal-weight mean of the 125 phase means and the maximum sample over all phases. Repeated vertex samples count repeatedly. This is a useful analytic-field residual, not a symmetric Hausdorff distance.
| Fixture | MC mean / max (cm) | Hybrid mean / max (cm) | DC mean / max (cm) |
|---|---:|---:|---:|
| 90° corner | 0.51 / 16.67 | 0.17 / 6.25 | 0.17 / 6.25 |
| Doorway | 0.99 / 16.67 | 0.41 / 12.50 | 0.41 / 12.50 |
| One-metre riser | 0.46 / 16.67 | 0.15 / 6.25 | 0.15 / 6.25 |
| Cliff ledge / overhang | 0.49 / 16.67 | 0.16 / 6.25 | 0.16 / 6.25 |
| Cave-chamber wall | 0.39 / 1.17 | 0.39 / 1.17 | 0.50 / 4.75 |
MC’s worst sharp residual is 16.67 cm at this phase sample, close to the expected 17.68 cm half-diagonal bevel bound. Hybrid/DC reduce the sharp residual while DC-everywhere is rougher on the smooth chamber than either MC path.
Crease split rate counts adjacent triangles with distinct analytic feature labels and face-normal angle above 30°. A split is counted when their average interpolated/vertex normals also differ by more than 30°.
| Fixture | MC split rate | Hybrid split rate | DC split rate |
|---|---:|---:|---:|
| 90° corner | 11.83% | 99.93% | 99.93% |
| Doorway | 24.31% | 100.00% | 100.00% |
| One-metre riser | 12.98% | 99.99% | 99.99% |
| Cliff ledge / overhang | 15.18% | 99.89% | 99.89% |
| Cave-chamber wall | no tagged crease | no tagged crease | no tagged crease |
## Topology and independent borders
The phase meshes themselves have no nonmanifold edges. MC has 0 open-edge meshes in 625 fixture/phase cases. Hybrid and DC each have 36 open-edge meshes in 625, summing to 116 open edges across those cases.
Independent-border results aggregate 625 fixture/phase cases per method. “Bad” means unmatched seam probes, boundary edges, or nonmanifold edges. No nonmanifold edges were found.
| Method | Same-LOD bad cases / 625 | Same-LOD open edges | Same-LOD unmatched probes | LOD0/LOD1 bad cases / 625 | LOD0/LOD1 open edges | LOD0/LOD1 unmatched probes |
|---|---:|---:|---:|---:|---:|---:|
| MC | 0 | 0 | 0 | 625 | 75,494 | 0 |
| Hybrid | 500 | 85,632 | 3,484 | 625 | 75,794 | 5,819 |
| DC | 625 | 101,440 | 3,609 | 625 | 75,790 | 6,128 |
MC’s same-LOD contour match is exact in all cases: zero measured contour distance and zero merged open edges. Hybrid passes only the 125 smooth chamber cases; its 500 tagged-shape cases have open edges. DC also fails the chamber border.
Every LOD0/LOD1 case has open boundary edges. For MC, the per-case maximum sampled contour distance has an 18.57 cm median, 26.41 cm 95th percentile, and 31.82 cm worst case; 39 of 625 cases exceed 25 cm. Hybrid has complete contour comparisons in only 130 cases; five of those exceed 25 cm, with a 560.47 cm worst finite comparison. DC has complete contour comparisons in only five cases, with a 560.47 cm worst finite comparison. The large finite outliers and unmatched probes are direct failures, not a pass hidden by averages. The spike has no transition templates, so these results are a transition gate, not a claim that any candidate’s final transition design has been tuned.
## Cost, determinism, and collision proxy
Each timing uses an already sampled 32³-cell field grid, three mesh builds, and the median build time. Field sampling, Unreal scheduling, upload, collision cooking, and rendering are excluded. All values below average the five fixtures.
| Worker count | MC mean ms/tile | Hybrid mean ms/tile | DC mean ms/tile |
|---:|---:|---:|---:|
| 1 | 16.308 | 17.375 | 16.269 |
| 8 | 14.275 | 14.907 | 13.996 |
| 16 | 14.555 | 15.291 | 14.129 |
At W8, hybrid is 4.4% slower and DC is 2.0% faster than MC. Mean triangle counts are 3,454.4 / 3,456.8 / 3,457.6 for MC / Hybrid / DC. Mean vertex counts are 1,728.8 / 3,469.2 / 1,985.6. Hybrid’s feature-split path therefore roughly doubles output vertices for negligible triangle change.
All 45 determinism rows (five fixtures × three methods × three worker counts) match the W1 reference for that fixture and method: zero cross-worker hash mismatches. W16 is a 16-worker software pool running with process affinity limited to eight logical CPUs.
The standalone collision proxy is the same emitted vertex/triangle mesh. All 45 proxy hashes match the visual mesh hash and report 0 m geometry delta. This verifies the candidate mesh handoff only; there is no independent collision simplification, Unreal physics cook, or contact test in round 1.
## Captures
The [contact sheet](results/captures/contact_sheet.jpg) is an offline orthographic rasterization of matched MC, Hybrid, and DC meshes for all five fixtures, plus one LOD seam view per method. It is 864 × 1,476 pixels. The 18 individual captures are 288 × 246 pixels. There are 19 JPEGs including the sheet; all are under 300 KB, and the largest is the 128,260-byte contact sheet. No viewer was launched.
Capture files:
- [90° corner — MC](results/captures/corner90_MC.jpg), [Hybrid](results/captures/corner90_Hybrid.jpg), [DC](results/captures/corner90_DC.jpg)
- [Doorway — MC](results/captures/doorway_MC.jpg), [Hybrid](results/captures/doorway_Hybrid.jpg), [DC](results/captures/doorway_DC.jpg)
- [One-metre riser — MC](results/captures/riser1m_MC.jpg), [Hybrid](results/captures/riser1m_Hybrid.jpg), [DC](results/captures/riser1m_DC.jpg)
- [Cliff ledge — MC](results/captures/cliff_overhang_MC.jpg), [Hybrid](results/captures/cliff_overhang_Hybrid.jpg), [DC](results/captures/cliff_overhang_DC.jpg)
- [Cave chamber — MC](results/captures/organic_cave_chamber_MC.jpg), [Hybrid](results/captures/organic_cave_chamber_Hybrid.jpg), [DC](results/captures/organic_cave_chamber_DC.jpg)
- [LOD seam — MC](results/captures/lodseam_MC.jpg), [Hybrid](results/captures/lodseam_Hybrid.jpg), [DC](results/captures/lodseam_DC.jpg)
## Run ledger and constraints
| Run/check | Result |
|---|---|
| Final MSVC C++20 build | Passed in 4.42 s, BelowNormal, affinity 0xFF00. |
| Final phase/cost/determinism/seam run | Passed in 114.208 s; 1,875 phase meshes and 1,875 independent seam cases, BelowNormal, affinity 0xFF00. |
| Final capture renderer | Passed in 2.61 s, BelowNormal, affinity 0xFF00; 19 files under the 300 KB cap. |
| Earlier phase run 1 | Exited normally in 31.14 s; exact-zero lattice degeneracies exposed topology defects. |
| Earlier phase run 2 | Exited normally in 31.11 s after adding the deterministic exact-zero bias; DC still had boundary defects. |
| Earlier phase run 3 | Exited normally in 35.07 s after splitting disconnected cell patches; remaining boundary defects kept it from acceptance. |
| Earlier phase run 4 | Exited normally in 36.55 s after making MC endpoint-gradient interpolation explicit; used for normal-split comparison. |
| Earlier seam run | Exited normally in 74.21 s, but clipped a shared mesh and did not test independently generated borders. It was superseded by the final independent-neighbor seam run. |
| Tool validation | One early PowerShell parser check used an invalid reference argument. Two later analysis-only PowerShell aggregation commands had syntax errors. All were corrected; none launched a mesher process. One early MSVC environment setup printed a nonfatal vswhere helper warning; compilation succeeded, and the final build emitted no warning. |
Every final build/test/render process used BelowNormal priority and affinity 0xFF00, limiting it to eight of the 16 logical processors. The build/test/render scripts enforce an 8 GB private-memory guard and 15-minute timeout. No process hit either limit, crashed, or needed a 0xC0000142 retry. The earlier phase runs above exited normally; their topology/seam measurements failed or were superseded as noted. No viewer or owner editor was opened. No owner project was built and no .uasset was touched.
## Files added for the spike
New implementation and launch files:
- [SharpMesherSpike.cpp](SharpMesherSpike.cpp)
- [BuildSharpMesherSpike.ps1](BuildSharpMesherSpike.ps1)
- [RunSharpMesherSpike.ps1](RunSharpMesherSpike.ps1)
- [RenderSharpMesherCaptures.ps1](RenderSharpMesherCaptures.ps1)
- [RenderSharpMesherCaptures.py](RenderSharpMesherCaptures.py)
The report, CSV measurements, exported OBJ meshes, offline captures, executable/object build outputs, and run logs are also in this WorldAssemblerM2 directory. No files under Source were changed.