Adopt the realism pass and refresh screenshots/docs
Full build / Import + headless tests (push) Successful in 34s
Full build / Full desktop build + optional release (push) Skipped

- add the v2 runtime picks: per-phase skyline panoramas, brick, sidewalk
  pavers, dry/wet asphalt, awning canvas, and their normal maps
- add the realism tooling and evidence: tools/scene_concepts.py, capture_realism.gd,
  concept frames, reports/sheets, and tests
- retune phase lighting/fog/exposure, add sun yaw, brighten the night glow,
  add the flashlight beam mesh, and rebuild the planter/tree assets
- regenerate all eleven staged screenshots from the current build; compare is
  11 good / 0 bad
- finish the visual-alignment closeout in DONE/TODO, update architecture,
  blender-assets, PLAN, and ignore rules (editable Blender sources untracked)
- keep the judge retry and document the verified default judge model

Verification: headless 227/227; Python tooling 86/86; check_screenshots 11/11.
This commit is contained in:
zwitschi committed 2026-11-01 17:03:05 +01:00
1 parent 26ecb93fd4
commit d7e523f63c
70 files changed
+4042 -101

No files matched your search

+32 -15
View File
@@ -1056,20 +1056,37 @@ def build_gear(name):
# Props (grounded, front = Blender -Y)
# ---------------------------------------------------------------------------
def _shrub(name, center, radii, mat, lumps=7, seed=1):
"""Lumpy foliage cluster from overlapping low-poly spheres."""
def _shrub(name, center, radii, mat, lumps=7, seed=1, lump=0.42):
"""Dense foliage cluster: many small flat-shaded clumps, not one smooth blob.
Reads as leaves at game distance because the silhouette is broken up and the
facets catch the light, which is what the realism-pass foliage note asks for.
"""
parts = []
import random
rng = random.Random(seed)
parts.append(sphere(name, 1.0, center, mat, seg=10, rings=7, scale=radii))
for i in range(lumps):
a = math.tau * i / lumps + rng.uniform(-0.3, 0.3)
r = rng.uniform(0.45, 0.6)
off = (center[0] + math.cos(a) * radii[0] * 0.6,
center[1] + math.sin(a) * radii[1] * 0.6,
center[2] + rng.uniform(-0.1, 0.35) * radii[2])
parts.append(sphere(name, 1.0, center, mat, seg=10, rings=7, scale=radii,
smooth=False))
for i in range(lumps * 2): # inner clumps fill the volume
a = math.tau * i / (lumps * 2) + rng.uniform(-0.25, 0.25)
ring = rng.uniform(0.25, 0.75)
r = rng.uniform(lump * 0.8, lump * 1.25)
off = (center[0] + math.cos(a) * radii[0] * ring,
center[1] + math.sin(a) * radii[1] * ring,
center[2] + rng.uniform(-0.2, 0.55) * radii[2])
parts.append(sphere(name, 1.0, off, mat, seg=8, rings=6,
scale=(radii[0] * r, radii[1] * r, radii[2] * r * 0.9)))
scale=(radii[0] * r, radii[1] * r, radii[2] * r * 0.9),
smooth=False))
for i in range(max(3, lumps // 2)): # outer clumps break the silhouette
a = math.tau * i / max(3, lumps // 2) + rng.uniform(-0.3, 0.3)
r = rng.uniform(lump * 0.6, lump * 0.85)
off = (center[0] + math.cos(a) * radii[0] * rng.uniform(0.85, 1.0),
center[1] + math.sin(a) * radii[1] * rng.uniform(0.85, 1.0),
center[2] + rng.uniform(-0.05, 0.4) * radii[2])
parts.append(sphere(name, 1.0, off, mat, seg=8, rings=6,
scale=(radii[0] * r, radii[1] * r, radii[2] * r * 0.8),
rot=(rng.uniform(0, 1), rng.uniform(0, 1), rng.uniform(0, 3)),
smooth=False))
return parts
@@ -1115,7 +1132,7 @@ def build_prop(name):
bevel=0.025, segs=2))
p.append(box("Lip", (1.0, 1.0, 0.05), (0, 0, 0.515), M("stone_pot"), bevel=0.015))
p.append(box("Soil", (0.86, 0.86, 0.02), (0, 0, 0.535), M("soil")))
p += _shrub("Shrub", (0, 0, 0.78), (0.42, 0.42, 0.30), M("foliage"), lumps=8, seed=3)
p += _shrub("Shrub", (0, 0, 0.78), (0.42, 0.42, 0.30), M("foliage"), lumps=5, seed=3)
elif name == "newspaper_box": # 0.44 x 0.38, h ~0.92
p.append(box("Stand", (0.40, 0.34, 0.10), (0, 0, 0.05), M("news_blue"), bevel=0.01))
p.append(box("Body", (0.42, 0.34, 0.70), (0, 0, 0.45), M("news_blue"), bevel=0.02))
@@ -1159,9 +1176,9 @@ def build_prop(name):
M("bark"), seg=8))
p.append(tube("Branch", [(0, 0, 1.6), (0.35, 0.1, 2.2)], 0.04, M("bark"), seg=6))
p.append(tube("Branch", [(0, 0, 1.7), (-0.3, -0.2, 2.3)], 0.04, M("bark"), seg=6))
p += _shrub("Crown", (0, 0, 2.55), (0.95, 0.95, 0.85), M("foliage"), lumps=9, seed=7)
p += _shrub("CrownTop", (0.05, 0.05, 3.15), (0.6, 0.6, 0.5), M("foliage_dark"),
lumps=5, seed=11)
p += _shrub("Crown", (0, 0, 2.55), (0.95, 0.95, 0.85), M("foliage"), lumps=7, seed=7)
p += _shrub("CrownTop", (0.05, 0.05, 3.1), (0.62, 0.62, 0.52), M("foliage_dark"),
lumps=4, seed=11)
p.append(box("Grate", (1.0, 1.0, 0.02), (0, 0, 0.01), M("dark_metal")))
elif name == "palm_tree": # ~7 m Hollywood palm
prof = []
@@ -1200,7 +1217,7 @@ def build_prop(name):
p.append(lathe("Pot", [(0.0, 0.0), (0.22, 0.0), (0.26, 0.05), (0.33, 0.50),
(0.36, 0.52), (0.36, 0.58), (0.31, 0.58), (0.0, 0.56)],
M("stone_pot"), seg=20, sharp=30))
p += _shrub("Topiary", (0, 0, 0.82), (0.34, 0.34, 0.30), M("foliage"), lumps=7, seed=5)
p += _shrub("Topiary", (0, 0, 0.82), (0.34, 0.34, 0.30), M("foliage"), lumps=4, seed=5)
elif name == "a_frame_sign": # chalkboard sidewalk sign
for s in (-1.0, 1.0):
tilt = math.radians(14) * s