Skip to content

Commit 285b935

Browse files
authored
fix: polish hygiene backlight and origin accessory heroes
Squash of HoleCard removal / out-of-frame backlight and prop-origin accessory+socket rebuild.
1 parent e273630 commit 285b935

12 files changed

Lines changed: 161 additions & 159 deletions

File tree

-855 KB
Loading
-914 KB
Loading
-20.6 KB
Loading
-17.5 KB
Loading

docs/gallery/mesh-hygiene-audit/index.html

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ <h1>mesh-hygiene-audit</h1>
190190
<ul><li><strong>No ngons.</strong> <code>len(poly.vertices) &lt;= 4</code> for every face.</li><li><strong>No loose vertices.</strong> Every vert has degree ≥ 1.</li><li><strong>Manifold edges.</strong> Every edge borders exactly 2 faces (closed solid).</li><li><strong>No zero-area faces.</strong> Face area &gt; 1e-10; prints measured <code>min_area</code>.</li><li><strong>Outward winding.</strong> Positive signed volume (divergence theorem).</li><li><strong>Euler sphere.</strong> <code>V − E + F == 2</code> for the clean closed manifold (measured: verts=66 edges=136 faces=72, volume≈0.652001, min_area≈1.146e-02).</li></ul>
191191
<p><strong>What each check catches on failure:</strong> loose vert injected (exit 4); face deleted → boundary edges (exit 5); edge dissolved → ngon (exit 3); all faces flipped → signed volume negated (exit 7); face collapsed → zero-area (exit 6).</p>
192192
<p><strong>Version witness:</strong> output is byte-identical on Blender 4.5.11 LTS and 5.1.2 — same counts, same volume, same <code>min_area</code>.</p>
193-
<p><strong>Render as proof:</strong> dual panel, same brass on both. DIRTY stages a camera-facing through-hole (boundary edges) plus a loose vert; emissive beads/edge tubes are built from the live mesh incidence the check uses — not decorative paint. CLEAN is the intact manifold. A warm card behind the hole makes the void readable against the backdrop.</p>
193+
<p><strong>Render as proof:</strong> dual panel, same brass on both. DIRTY stages a camera-facing through-hole (boundary edges) plus a loose vert; emissive beads/edge tubes are built from the live mesh incidence the check uses — not decorative paint. CLEAN is the intact manifold. An out-of-frame AREA light rakes through the hole from behind so the aperture reads warm without a visible light panel in frame.</p>
194194
<p><strong>Not depicted in the still (check-proven only):</strong> ngon dissolve, zero-area collapse, and full-mesh winding invert — they do not read as geometry at thumbnail scale without faking annotation.</p>
195195
<h2>Run</h2>
196196
<pre><code>blender --background --python mesh_hygiene_audit.py --
@@ -605,8 +605,8 @@ <h2>Source</h2>
605605
ob.data.materials.append(brass)
606606

607607
bead_mat = make_material(
608-
<span class="s">&quot;LooseBead&quot;</span>, (<span class="n">1.0</span>, <span class="n">0.85</span>, <span class="n">0.15</span>), rough=<span class="n">0.3</span>, metallic=<span class="n">0.0</span>,
609-
emit=(<span class="n">1.0</span>, <span class="n">0.9</span>, <span class="n">0.2</span>), estr=<span class="n">3.0</span>,
608+
<span class="s">&quot;LooseBead&quot;</span>, (<span class="n">0.95</span>, <span class="n">0.75</span>, <span class="n">0.2</span>), rough=<span class="n">0.35</span>, metallic=<span class="n">0.1</span>,
609+
emit=(<span class="n">1.0</span>, <span class="n">0.85</span>, <span class="n">0.25</span>), estr=<span class="n">0.85</span>,
610610
)
611611
<span class="k">for</span> i, co <span class="k">in</span> enumerate(loose):
612612
sme = bpy.data.meshes.new(<span class="s">f&quot;</span><span class="s">LooseBead</span>{i}<span class="s">&quot;</span>)
@@ -622,8 +622,8 @@ <h2>Source</h2>
622622
sc.collection.objects.link(sob)
623623

624624
edge_mat = make_material(
625-
<span class="s">&quot;BoundaryEdge&quot;</span>, (<span class="n">1.0</span>, <span class="n">0.25</span>, <span class="n">0.05</span>), rough=<span class="n">0.35</span>, metallic=<span class="n">0.0</span>,
626-
emit=(<span class="n">1.0</span>, <span class="n">0.35</span>, <span class="n">0.05</span>), estr=<span class="n">2.8</span>,
625+
<span class="s">&quot;BoundaryEdge&quot;</span>, (<span class="n">0.95</span>, <span class="n">0.35</span>, <span class="n">0.1</span>), rough=<span class="n">0.4</span>, metallic=<span class="n">0.15</span>,
626+
emit=(<span class="n">1.0</span>, <span class="n">0.4</span>, <span class="n">0.1</span>), estr=<span class="n">0.7</span>,
627627
)
628628
<span class="k">for</span> i, (a, b) <span class="k">in</span> enumerate(boundary):
629629
mid = (a + b) * <span class="n">0.5</span>
@@ -678,55 +678,52 @@ <h2>Source</h2>
678678
clean_ob.hide_render = <span class="k">True</span>
679679
clean_ob.hide_viewport = <span class="k">True</span>
680680

681-
left = _duplicate_mesh_obj(sc, clean_ob, <span class="s">&quot;Dirty&quot;</span>, (-<span class="n">1.15</span>, <span class="n">0.0</span>, <span class="n">0.0</span>))
682-
left.rotation_euler.z = math.radians(<span class="n">22.5</span>)
681+
left = _duplicate_mesh_obj(sc, clean_ob, <span class="s">&quot;Dirty&quot;</span>, (-<span class="n">0.88</span>, <span class="n">0.0</span>, <span class="n">0.0</span>))
682+
left.rotation_euler.z = math.radians(<span class="n">20</span>)
683683
bpy.context.view_layer.update()
684684
_inject_through_hole(left.data)
685685
inject_defect(left.data, <span class="s">&quot;loose&quot;</span>)
686686
mark_defects_from_audit(left)
687687

688-
right = _duplicate_mesh_obj(sc, clean_ob, <span class="s">&quot;Clean&quot;</span>, (<span class="n">1.15</span>, <span class="n">0.0</span>, <span class="n">0.0</span>))
689-
right.rotation_euler.z = math.radians(-<span class="n">12</span>)
688+
right = _duplicate_mesh_obj(sc, clean_ob, <span class="s">&quot;Clean&quot;</span>, (<span class="n">0.88</span>, <span class="n">0.0</span>, <span class="n">0.0</span>))
689+
right.rotation_euler.z = math.radians(-<span class="n">10</span>)
690690
right.data.materials.clear()
691691
right.data.materials.append(
692692
make_material(<span class="s">&quot;CleanBrass&quot;</span>, (<span class="n">0.55</span>, <span class="n">0.38</span>, <span class="n">0.14</span>), rough=<span class="n">0.38</span>, metallic=<span class="n">0.85</span>)
693693
)
694694
<span class="k">for</span> p <span class="k">in</span> right.data.polygons:
695695
p.use_smooth = abs(p.normal.z) &lt; <span class="n">0.85</span>
696696

697-
placard(sc, <span class="s">&quot;DIRTY&quot;</span>, (-<span class="n">1.15</span>, -<span class="n">1.0</span>, <span class="n">0.02</span>), size=<span class="n">0.15</span>)
698-
placard(sc, <span class="s">&quot;CLEAN&quot;</span>, (<span class="n">1.15</span>, -<span class="n">1.0</span>, <span class="n">0.02</span>), size=<span class="n">0.15</span>)
697+
placard(sc, <span class="s">&quot;DIRTY&quot;</span>, (-<span class="n">0.88</span>, -<span class="n">1.15</span>, <span class="n">0.02</span>), size=<span class="n">0.11</span>)
698+
placard(sc, <span class="s">&quot;CLEAN&quot;</span>, (<span class="n">0.88</span>, -<span class="n">1.15</span>, <span class="n">0.02</span>), size=<span class="n">0.11</span>)
699699

700700
build_studio(sc)
701-
<span class="c"># Lit card behind DIRTY so the through-hole voids read against warm light</span>
702-
card_me = bpy.data.meshes.new(<span class="s">&quot;HoleCard&quot;</span>)
703-
cbm = bmesh.new()
701+
<span class="c"># Out-of-frame POINT behind DIRTY — aperture glow without a rectangular AREA</span>
702+
<span class="c"># footprint on the floor (Layer 1: no visible light shapes).</span>
703+
hole_ld = bpy.data.lights.new(<span class="s">&quot;HoleBack&quot;</span>, <span class="s">&quot;POINT&quot;</span>)
704+
hole_ld.energy = <span class="n">95.0</span>
705+
hole_ld.color = (<span class="n">1.0</span>, <span class="n">0.70</span>, <span class="n">0.40</span>)
704706
<span class="k">try</span>:
705-
bmesh.ops.create_grid(cbm, x_segments=<span class="n">1</span>, y_segments=<span class="n">1</span>, size=<span class="n">1.2</span>)
706-
cbm.to_mesh(card_me)
707-
<span class="k">finally</span>:
708-
cbm.free()
709-
card_mat = make_material(
710-
<span class="s">&quot;HoleCard&quot;</span>, (<span class="n">1.0</span>, <span class="n">0.55</span>, <span class="n">0.25</span>), rough=<span class="n">0.9</span>, metallic=<span class="n">0.0</span>,
711-
emit=(<span class="n">1.0</span>, <span class="n">0.55</span>, <span class="n">0.2</span>), estr=<span class="n">1.8</span>,
712-
)
713-
card_me.materials.append(card_mat)
714-
card = bpy.data.objects.new(<span class="s">&quot;HoleCard&quot;</span>, card_me)
715-
card.location = (-<span class="n">1.15</span>, <span class="n">1.4</span>, <span class="n">0.65</span>)
716-
card.rotation_euler = (math.radians(<span class="n">90</span>), <span class="n">0.0</span>, <span class="n">0.0</span>)
717-
sc.collection.objects.link(card)
707+
hole_ld.shadow_soft_size = <span class="n">1.6</span>
708+
<span class="k">except</span> AttributeError:
709+
<span class="k">pass</span>
710+
hole_back = bpy.data.objects.new(<span class="s">&quot;HoleBack&quot;</span>, hole_ld)
711+
hole_back.location = (-<span class="n">0.88</span>, <span class="n">4.6</span>, <span class="n">0.75</span>)
712+
sc.collection.objects.link(hole_back)
713+
<span class="c"># Pull key slightly so brass highlights don&#x27;t clip with the hole glow</span>
718714
<span class="k">for</span> ob <span class="k">in</span> sc.objects:
719-
<span class="k">if</span> ob.type == <span class="s">&quot;LIGHT&quot;</span> <span class="k">and</span> ob.name == <span class="s">&quot;Wedge&quot;</span>:
720-
ob.data.energy = <span class="n">580.0</span>
721-
ob.location = (<span class="n">0.0</span>, <span class="n">6.5</span>, <span class="n">3.5</span>)
715+
<span class="k">if</span> ob.type == <span class="s">&quot;LIGHT&quot;</span> <span class="k">and</span> ob.name == <span class="s">&quot;Key&quot;</span>:
716+
ob.data.energy = <span class="n">380.0</span>
717+
<span class="k">if</span> ob.type == <span class="s">&quot;LIGHT&quot;</span> <span class="k">and</span> ob.name == <span class="s">&quot;Glint&quot;</span>:
718+
ob.data.energy = <span class="n">140.0</span>
722719

723720
cam_data = bpy.data.cameras.new(<span class="s">&quot;Cam&quot;</span>)
724-
cam_data.lens = <span class="n">50.0</span>
721+
cam_data.lens = <span class="n">38.0</span>
725722
cam = bpy.data.objects.new(<span class="s">&quot;Cam&quot;</span>, cam_data)
726-
cam.location = (<span class="n">0.1</span>, -<span class="n">5.6</span>, <span class="n">1.5</span>)
723+
cam.location = (<span class="n">0.0</span>, -<span class="n">7.8</span>, <span class="n">1.9</span>)
727724
sc.collection.objects.link(cam)
728725
aim = bpy.data.objects.new(<span class="s">&quot;Aim&quot;</span>, <span class="k">None</span>)
729-
aim.location = (<span class="n">0.0</span>, <span class="n">0.0</span>, <span class="n">0.62</span>)
726+
aim.location = (<span class="n">0.0</span>, <span class="n">0.0</span>, <span class="n">0.48</span>)
730727
sc.collection.objects.link(aim)
731728
tr = cam.constraints.new(<span class="s">&quot;TRACK_TO&quot;</span>)
732729
tr.target = aim

0 commit comments

Comments
 (0)