Skip to content

Commit 16678c5

Browse files
committed
feat: remodel modular-kit-snap panels and palette under the gate
Three defects fixed: flat grey wall panels are now assemblies (backing plate + inset panel + four bolt heads each), the palette shifted teal-slate so the card no longer twins with lightmap-uv-channel's warm cart, and mean luminance was brought into the calibration range (82.7 -> 66.1, ceiling 77.7) by dimming fixtures/spill/rim - the interior run no longer reads as a fourth over-bright card, so only the documented framing deviation remains. Detail parts 12 -> 20 (hygiene 13 -> 21), boundary contract untouched (16 verts/edges, probes still exit 3/4 with measured errors), materials now cached per design key instead of duplicated per part per segment. Signed-off-by: fOuttaMyPaint <TMhospitalitystrategies@gmail.com>
1 parent a3f0250 commit 16678c5

2 files changed

Lines changed: 73 additions & 17 deletions

File tree

‎examples/modular-kit-snap/README.md‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ positions with no gap and no overlap. Interior geometry is free-form
88
deliberate authoring pass, and the check is what catches you skipping it.
99

1010
**The asset, for reuse:** a 4 × 3 × 3 m corridor segment (hollow-rectangle
11-
shell plus twelve detail parts — frame rib, walkway plate, wall panels,
12-
trim rails, emissive light strips). Origin at the connection pivot
11+
shell plus twenty detail parts — frame rib, walkway plate, wall panel
12+
assemblies (backing plate + inset panel + four bolt heads each), trim
13+
rails, emissive light strips). Origin at the connection pivot
1314
(floor-center of the start edge, so instance *n* places at `x = n·4`),
1415
identity transforms by construction, datablocks under
1516
`Kit.CorridorSeg.*`, manifold everywhere except the two intentional open
@@ -57,7 +58,15 @@ and 5.1.2 — same counts, same zero measured deviations.
5758
falsification variant (`--falsify`) accumulates a 120 mm gap, 50 mm lateral
5859
jogs, and 40 mm floor steps at each joint: floor plates split with dark
5960
seams and the trim rails visibly break. The check measures the same failure
60-
class at 3 mm; the render exaggerates it to read at frame scale.
61+
class at 3 mm; the render exaggerates it to read at frame scale. The render
62+
path also gates the asset through `examples/gallery_asset_quality.py`
63+
(naming, material variation, edge treatment — exit 11). An earlier revision
64+
shipped flat grey wall panels and was remodeled under that gate: each panel
65+
is now an assembly (backing plate + inset panel + four bolt heads), the
66+
palette shifted teal-slate so the card does not twin with
67+
`lightmap-uv-channel`'s warm cart, and mean luminance was brought into the
68+
calibration range (82.7 → 66.1, ceiling 77.7) — no luminance deviation
69+
needed.
6170

6271
**Framing deviation:** the still is an interior corridor run — the envelope
6372
surrounds the camera on five sides and the tiling joints are the proof, so

‎examples/modular-kit-snap/modular_kit_snap.py‎

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir))
4747
sys.dont_write_bytecode = True # keep examples/__pycache__ out of the repo tree
4848
import gallery_framing
49+
import gallery_asset_quality
4950

5051
TILE = 4.0 # tile length along X, metres
5152
WIDTH = 3.0 # corridor width along Y ( +/- 1.5 )
@@ -141,26 +142,56 @@ def detail_layout():
141142
("Rib.Beam", (0.24, 2 * inner_y - 0.30, 0.34), (0.18, 0.0, HEIGHT - WALL - 0.17), 0.02),
142143
# walkway floor plate
143144
("FloorPlate", (3.4, 1.8, 0.05), (TILE / 2, 0.0, WALL + 0.025), 0.015),
144-
# wall panels, two per side, recessed-look slabs on the bore face
145-
("Panel.L.1", (1.15, 0.05, 1.15), (1.2, inner_y - 0.025, 1.55), 0.02),
146-
("Panel.L.2", (1.15, 0.05, 1.15), (2.8, inner_y - 0.025, 1.55), 0.02),
147-
("Panel.R.1", (1.15, 0.05, 1.15), (1.2, -(inner_y - 0.025), 1.55), 0.02),
148-
("Panel.R.2", (1.15, 0.05, 1.15), (2.8, -(inner_y - 0.025), 1.55), 0.02),
149145
# orange trim rails — the lines that jog visibly when a joint steps
150146
("Trim.L", (3.7, 0.06, 0.09), (TILE / 2, inner_y - 0.03, 0.78), 0.015),
151147
("Trim.R", (3.7, 0.06, 0.09), (TILE / 2, -(inner_y - 0.03), 0.78), 0.015),
152148
# emissive light strips along the wall/ceiling join
153149
("Light.L", (3.0, 0.05, 0.07), (TILE / 2, inner_y - 0.025, HEIGHT - WALL - 0.09), 0.01),
154150
("Light.R", (3.0, 0.05, 0.07), (TILE / 2, -(inner_y - 0.025), HEIGHT - WALL - 0.09), 0.01),
155151
]
152+
# wall panel assemblies: backing plate proud of the bore face, a lighter
153+
# inset panel — depth, not flat grey rectangles. Bolt heads are spheres,
154+
# built by _bolts_mesh in build_kit_meshes rather than as boxes.
155+
for side, sy in (("L", 1.0), ("R", -1.0)):
156+
for idx, px in ((1, 1.2), (2, 2.8)):
157+
parts.append((f"PanelBack.{side}.{idx}", (1.35, 0.04, 1.35),
158+
(px, sy * (inner_y - 0.02), 1.55), 0.015))
159+
parts.append((f"Panel.{side}.{idx}", (1.15, 0.05, 1.15),
160+
(px, sy * (inner_y - 0.045), 1.55), 0.02))
156161
return parts
157162

158163

164+
def _bolts_mesh(name, positions, radius):
165+
"""Bolt head spheres at positions — one mesh, disconnected islands."""
166+
me = bpy.data.meshes.new(name)
167+
bm = bmesh.new()
168+
try:
169+
for px, py, pz in positions:
170+
before_v = set(bm.verts)
171+
bmesh.ops.create_uvsphere(bm, u_segments=8, v_segments=6, radius=radius)
172+
for v in set(bm.verts) - before_v:
173+
v.co.x += px
174+
v.co.y += py
175+
v.co.z += pz
176+
bm.to_mesh(me)
177+
finally:
178+
bm.free()
179+
return me
180+
181+
159182
def build_kit_meshes(skew=0.0, nudge=0.0):
160183
"""All kit meshes, keyed by part suffix. Skew/nudge touch the shell only."""
161184
meshes = {"Shell": build_shell("Kit.CorridorSeg.Shell", skew, nudge)}
162185
for suffix, dims, center, bevel in detail_layout():
163186
meshes[suffix] = build_detail(f"Kit.CorridorSeg.{suffix}", dims, center, bevel)
187+
# panel fixings: four bolt heads per panel, proud of the inset panel
188+
inner_y = WIDTH / 2 - WALL
189+
for side, sy in (("L", 1.0), ("R", -1.0)):
190+
for idx, px in ((1, 1.2), (2, 2.8)):
191+
positions = [(px + dx, sy * (inner_y - 0.07), 1.55 + dz)
192+
for dx in (-0.5, 0.5) for dz in (-0.5, 0.5)]
193+
meshes[f"PanelBolts.{side}.{idx}"] = _bolts_mesh(
194+
f"Kit.CorridorSeg.PanelBolts.{side}.{idx}", positions, 0.022)
164195
return meshes
165196

166197

@@ -368,19 +399,28 @@ def make_material(name, rgb, rough=0.45, metallic=0.6, emit=None, estr=0.0):
368399

369400

370401
SEGMENT_MATS = {
371-
"Shell": ("Shell", (0.10, 0.11, 0.13), 0.5, 0.8, None, 0.0),
402+
"Shell": ("Shell", (0.075, 0.095, 0.115), 0.5, 0.8, None, 0.0),
372403
"Rib": ("Rib", (0.05, 0.05, 0.06), 0.45, 0.85, None, 0.0),
373-
"FloorPlate": ("FloorPlate", (0.07, 0.08, 0.09), 0.6, 0.7, None, 0.0),
374-
"Panel": ("Panel", (0.19, 0.25, 0.33), 0.4, 0.6, None, 0.0),
404+
"FloorPlate": ("FloorPlate", (0.06, 0.075, 0.09), 0.6, 0.7, None, 0.0),
405+
"Panel": ("Panel", (0.10, 0.21, 0.26), 0.42, 0.6, None, 0.0),
406+
"PanelBack": ("PanelBack", (0.06, 0.10, 0.13), 0.5, 0.75, None, 0.0),
407+
"PanelBolts": ("PanelBolts", (0.35, 0.38, 0.42), 0.3, 0.9, None, 0.0),
375408
"Trim": ("Trim", (0.85, 0.35, 0.08), 0.35, 0.3, None, 0.0),
376409
"Light": ("LightStrip", (0.30, 0.25, 0.18), 0.5, 0.2, (1.0, 0.75, 0.4), 8.0),
377410
}
378411

379412

413+
_mat_cache = {}
414+
415+
380416
def mat_for(suffix):
417+
"""One material per design key, shared across segments (an earlier
418+
revision instantiated a duplicate material per part per segment)."""
381419
key = suffix.split(".")[0]
382-
name, rgb, rough, metal, emit, estr = SEGMENT_MATS[key]
383-
return make_material(name, rgb, rough, metal, emit, estr)
420+
if key not in _mat_cache:
421+
name, rgb, rough, metal, emit, estr = SEGMENT_MATS[key]
422+
_mat_cache[key] = make_material(name, rgb, rough, metal, emit, estr)
423+
return _mat_cache[key]
384424

385425

386426
def build_kit_objects(sc, x_offset, skew=0.0, nudge=0.0, y_jog=0.0, z_jog=0.0):
@@ -443,7 +483,7 @@ def light(name, loc, energy, size, col, rot):
443483
# the kit's own lighting language, designed with the asset
444484
for i in range(4):
445485
ld = bpy.data.lights.new(f"Fixture{i}", "AREA")
446-
ld.energy = 130.0
486+
ld.energy = 85.0
447487
ld.size = 3.2
448488
ld.color = (1.0, 0.8, 0.55)
449489
ob = bpy.data.objects.new(f"Fixture{i}", ld)
@@ -458,7 +498,7 @@ def build_bulkhead(sc):
458498
Not part of the kit — the corridor's destination for this still."""
459499
frame_mat = make_material("Bulkhead", (0.06, 0.06, 0.07), rough=0.4, metallic=0.85)
460500
door_mat = make_material("BulkheadDoor", (0.30, 0.16, 0.07), rough=0.5,
461-
metallic=0.3, emit=(1.0, 0.42, 0.12), estr=0.6)
501+
metallic=0.3, emit=(1.0, 0.42, 0.12), estr=0.5)
462502
inner_y = WIDTH / 2 - WALL
463503
end_x = TILE * 4
464504
parts = []
@@ -479,7 +519,7 @@ def build_bulkhead(sc):
479519
parts.append(door_ob)
480520
# warm spill into the corridor, toward the camera
481521
ld = bpy.data.lights.new("BulkheadSpill", "AREA")
482-
ld.energy = 140.0
522+
ld.energy = 90.0
483523
ld.size = 1.8
484524
ld.color = (1.0, 0.62, 0.3)
485525
ob = bpy.data.objects.new("BulkheadSpill", ld)
@@ -489,7 +529,7 @@ def build_bulkhead(sc):
489529
# cool rim from the mouth behind the camera: lifts the near right wall and
490530
# the ceiling edge out of dead black without touching the warm pools
491531
rd = bpy.data.lights.new("MouthRim", "AREA")
492-
rd.energy = 65.0
532+
rd.energy = 45.0
493533
rd.size = 2.0
494534
rd.color = (0.62, 0.76, 1.0)
495535
rob = bpy.data.objects.new("MouthRim", rd)
@@ -508,6 +548,7 @@ def render_still(path, engine, falsify=False):
508548
sc = bpy.context.scene
509549

510550
all_parts = []
551+
aq_hero = None
511552
for i in range(4):
512553
if falsify:
513554
obs = build_kit_objects(
@@ -516,6 +557,8 @@ def render_still(path, engine, falsify=False):
516557
z_jog=(0.04 if i % 2 else 0.0))
517558
else:
518559
obs = build_kit_objects(sc, TILE * i)
560+
if aq_hero is None:
561+
aq_hero = obs[1:] # the asset-quality gate scores one segment
519562
all_parts.extend(obs[1:]) # mesh parts only, not the root empties
520563
floor, wall = build_studio(sc)
521564
bulkhead = build_bulkhead(sc)
@@ -563,6 +606,10 @@ def render_still(path, engine, falsify=False):
563606
)
564607
if fcode:
565608
return fcode
609+
aqcode = gallery_asset_quality.check_asset_quality(
610+
sc, cam, hero=aq_hero, stage=[floor, wall])
611+
if aqcode:
612+
return aqcode
566613
bpy.ops.render.render(write_still=True)
567614
if not (os.path.exists(path) and os.path.getsize(path) > 0):
568615
print("ERROR: render produced no file", file=sys.stderr)

0 commit comments

Comments
 (0)