Skip to content

Commit 418b641

Browse files
TMHSDigitalclaude
andauthored
fix: terrain-scatter and car-mirror-symmetry quality pass (#248)
* fix(showcase): terrain-scatter second quality pass, with three new budgets The tile read as a slice of cake with pebbles dropped on it. - Stones were seated by one dirt sample at their centre, which left daylight under the downhill side: no stone was sealed in more than 6 of 8 azimuth sectors. Each stone now samples the ground under every vertex and sinks until every sector holds a buried vertex (exit 21, --perch-rocks). - All nine stones were within ~20% of one size. STONE_SIZES gives each a factor from 0.55 to 1.45 and the relaxation spaces pairs by their own bounds (footprint ratio 9.81 >= 3.0, exit 22, --uniform-rocks). - The hill met the walls at a knife edge. The rim is bevelled in four segments, bounded by the step in normal elevation (33.5 <= 40 deg, exit 23, --sharp-rim). - Two closed-form micro-relief terms in the GN tree; hill smooth-shaded; stones mid-grey; dirt darkens to subsoil down the walls. Base tris 1758 -> 2398. The collider hulls a coarse unbevelled tile (36). The outer AABB was re-fitted from 0.584 to 0.570 m. Same results on 4.5.11, 5.1.2 and 5.2.1. Includes the asset sheet. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Signed-off-by: TMHSDigital <[email protected]> * docs(showcase): seal seated parts all round, vary scatter size, bound rim tilt Three conventions from the terrain-scatter pass: a seated part is sunk until every azimuth sector holds a buried vertex; scatter carries a size factor and asserts a footprint-ratio floor; a rim over a slope bounds its step in normal elevation (not the dihedral, which misreads rounded corners). Relaxation now spaces each pair by the sum of its own bounds. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Signed-off-by: TMHSDigital <[email protected]> * fix(examples): stand the car-mirror-symmetry camera on the key's side The key light is at -X but the camera stood at +X, so the flank it saw was the one the key cannot reach and the whole visible side rendered near-black: the hero measured luma 0.138, below the 0.151 calibration floor. The car is mirror-symmetric, so mirroring the camera keeps the composition; luma is now 0.169. Render path only. Exit codes unchanged on 4.5.11, 5.1.2 and 5.2.1 (default 0, --no-mirror 5, --output 0), and every measured line matches the baseline. Shared gallery index rides here. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Signed-off-by: TMHSDigital <[email protected]> --------- Signed-off-by: TMHSDigital <[email protected]> Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
1 parent ca285b3 commit 418b641

16 files changed

Lines changed: 672 additions & 138 deletions

File tree

33.8 KB
Loading
5.18 KB
Loading
-1.84 KB
Loading

‎docs/gallery/car-mirror-symmetry/index.html‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ <h1>car-mirror-symmetry</h1>
283283
<ul><li><strong>Original holds the half.</strong> Body datablock is exactly 126 verts / 231 edges / 106 faces (14 × 9, loft closed forms), with exactly 28 centerline verts (probe: modifier applied into data → exit 3, datablock reads <code>(224, 434, 212)</code>).</li><li><strong>Evaluated is the welded whole.</strong> Exactly <code>2n − c = 224</code> verts (probe: <code>use_mirror_merge = False</code> → exit 5, <strong>252</strong> verts — the doubled seam; probe: one centerline vert pulled off the plane → exit 4, <strong>27 ≠ 28</strong> welded; probe: mirror axis off → exit 5, <strong>126</strong> — the half-car). The evaluated shell is watertight (every edge borders 2 faces) with Euler characteristic <strong>2</strong> — the two halves weld into a topological sphere.</li><li><strong>Exact ±X partners.</strong> Every evaluated vertex has a partner at negated X: measured deviation <strong>0.000e+00</strong> (mirror copies exactly; tol 2e-5 guards float32), evaluated bbox symmetric (<code>min.x == −max.x</code>).</li><li><strong>Mirrored parts.</strong> Wheels (96/81 half → 192/162 evaluated) and lamps (8/6 → 16/12) each double across the plane with partner deviation 0.0 — and each object origin reads <code>x == 0</code>.</li></ul>
284284
<p><strong>Why the checks target the modifier, not the base:</strong> mutating a non-plane base vertex cannot break the ±X pairing — the evaluated set is always <code>half ∪ mirror(half)</code>, symmetric by construction. Realistic failures live in the modifier (merge off, axis off, modifier applied into data, origin off the plane), which is what the probes break.</p>
285285
<p><strong>Version witness:</strong> check output is byte-identical on Blender 4.5.11 LTS and 5.1.2. Mirror, <code>evaluated_get</code> / <code>to_mesh</code> / <code>to_mesh_clear</code> (no argument — passing the mesh raises TypeError on both), and <code>TRACK_TO</code> constraint behavior are stable across the pair; only the EEVEE engine id is version-gated.</p>
286-
<p>The render is the proof: hide the mirror and the still is literally half a car — halved windshield and hood at the centerline, one headlamp. Render notes: the loft is faceted by design (flat shading, no bevel modifier — the modifier stack is Mirror only, so counts stay closed-form); the window band is glass by construction class (steepest roof-rise slope is the windshield, steepest drop the rear window, ring segment 5 the side windows), and the glass is dielectric — metallic glass mirrors the key light and renders the windshield as a hot salmon slab.</p>
286+
<p>The render is the proof: hide the mirror and the still is literally half a car — halved windshield and hood at the centerline, one headlamp. Render notes: the loft is faceted by design (flat shading, no bevel modifier — the modifier stack is Mirror only, so counts stay closed-form); the window band is glass by construction class (steepest roof-rise slope is the windshield, steepest drop the rear window, ring segment 5 the side windows), and the glass is dielectric — metallic glass mirrors the key light and renders the windshield as a hot salmon slab. The camera stands on the key light&#x27;s side of the car: from the other side it saw only the flank the key cannot reach, and the whole visible side rendered near-black. The car is mirror-symmetric, so the composition is the same either way. The bright streak along the cowl below the windshield is the key&#x27;s highlight in a crease that faces it.</p>
287287
<h2>Run</h2>
288288
<pre><code># Cheap correctness check (no render) — the CI check:
289289
blender --background --python car_mirror_symmetry.py --
@@ -788,7 +788,10 @@ <h2>Source</h2>
788788
cam_data = bpy.data.cameras.new(<span class="s">&quot;Cam&quot;</span>)
789789
cam_data.lens = <span class="n">52.0</span>
790790
cam = bpy.data.objects.new(<span class="s">&quot;Cam&quot;</span>, cam_data)
791-
cam.location = (<span class="n">4.4</span>, -<span class="n">5.3</span>, <span class="n">2.1</span>)
791+
<span class="c"># On the key&#x27;s side (-X): the car is mirror-symmetric, so this is the</span>
792+
<span class="c"># same composition, but at +X the camera saw the flank the key cannot</span>
793+
<span class="c"># reach and the whole visible side rendered near-black.</span>
794+
cam.location = (-<span class="n">4.4</span>, -<span class="n">5.3</span>, <span class="n">2.1</span>)
792795
scene.collection.objects.link(cam)
793796
track = cam.constraints.new(<span class="s">&#x27;TRACK_TO&#x27;</span>) <span class="c"># data API, not bpy.ops (damped-track-aim)</span>
794797
track.target = aim
9.88 KB
Loading
-748 Bytes
Loading

‎docs/gallery/index.html‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -981,12 +981,12 @@ <h2><a href="treasure-chest/">treasure-chest</a></h2>
981981
</article>
982982
<article class="card" data-tags="mesh export showcase">
983983
<a class="card-media" href="terrain-scatter/" tabindex="-1" aria-hidden="true">
984-
<img src="assets/terrain-scatter-hero.webp" alt="A square tile of dark rolling earth with nine faceted grey rocks seated across the hill, none touching." loading="lazy" decoding="async" />
984+
<img src="assets/terrain-scatter-hero.webp" alt="A square tile of dark rolling earth with a rounded edge, nine faceted grey stones from cobble to boulder sunk into the ground across the hill." loading="lazy" decoding="async" />
985985
</a>
986986
<div class="card-body">
987987
<h2><a href="terrain-scatter/">terrain-scatter</a></h2>
988-
<p class="teaches">A Geometry Nodes hill tile with seated icosphere scatter through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.</p>
989-
<p class="witnesses"><span class="tag">witnesses</span> Recomputed: 1758 tris, two materials with 720 stone faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.800×1.800×0.552 m, grounded zmin, 9 stones of ≥80 faces seated on sampled dirt Z (offset −35 mm, floor zmin 0.113 m), LOD ratios in band, convex collider 81 tris, hygiene zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --poke-rock 17; --float-rocks 18; --box-rocks 19.</p>
988+
<p class="teaches">A Geometry Nodes hill tile with embedded, varied stone scatter through UVs, bake, LOD, collider, and Unity glTF, asserting recomputed budgets rather than an API contract.</p>
989+
<p class="witnesses"><span class="tag">witnesses</span> Recomputed: 2398 tris, two materials with 720 stone faces, UVs in 0..1 with zero AABB overlap, outer AABB 1.800x1.800x0.570 m, grounded zmin, 9 stones of &gt;=80 faces each sealed into the ground in 8/8 sectors, footprint ratio 9.8, rim tilt step 33.5 deg, no stone pairs overlapping, LOD ratios in band, convex collider 36 tris, hygiene zero, non-empty glTF. --skip-decimate exits 9; --stray-vert 15; --lift-z 16; --poke-rock 17; --float-rocks 18; --box-rocks 19; --pile-rocks 20; --perch-rocks 21; --uniform-rocks 22; --sharp-rim 23.</p>
990990
<a class="card-link" href="terrain-scatter/">View showcase piece<span class="sr-only"> terrain-scatter</span> <span aria-hidden="true">&rarr;</span></a>
991991
</div>
992992
</article>

0 commit comments

Comments
 (0)