fix(hero): seat the façade detail on the wall, so it renders at all
The three hero captures showed a plain block with six columns because every applied detail sat BEHIND the wall's front face, inside the solid mass: Hero_Banner_1 y -1.08..-1.02 (55 cm inside) Hero_Portal_1 y -2.35..-1.15 (2 m inside) Hero_Window_1_1 y -0.60..-0.52 (2 cm inside) The colonnade, cornice and dentils happened to protrude, which is exactly what the shots showed. The depth is now stated once, in hero_facade_build.py: FRONT_Y is the wall's front face and seat_on_front() moves every applied part until its street-facing face sits at FRONT_Y + offset - 8 cm for banners and jambs, 5 cm for entablature and cornice, 3 cm for window panes, 4 cm for mullions, 10 cm for portal signs. It reports what it moved, 99 parts. After re-export, re-import and re-render the front elevation now shows the three red banners, the two window bands, the dentil course and the portals. What is still missing against the reference: rusticated banding on the stone, lettering on the motto band, grilles in the windows, a balustrade on the parapet, and the blank lintel band across the portals that the reference does not have. Rows 4, 5 and 6 are back to pending for review because the images changed.
This commit is contained in:
1 parent
01e49ff889
commit
7b9a7a3867
110 files changed
+183
-137
No files matched your search
@@ -147,6 +147,14 @@ def build():
|
||||
# Inset so the entablature (1.5 m deep) and parapet (1.2 m deep) sit inside the
|
||||
# measured 25.75 m frontage instead of overhanging it.
|
||||
inset = 0.75
|
||||
# The wall's front face, and the only Y that matters for what is visible.
|
||||
# +Y is the street side: anything with y < FRONT_Y is inside the solid mass and never renders.
|
||||
# Hand-typed negative Y values throughout this file put the banners 55 cm, the portals 2 m and
|
||||
# the windows 6 cm behind this plane, which is why the captures showed a plain block with six
|
||||
# columns. `seat_on_front()` below re-seats every applied detail relative to FRONT_Y, so the
|
||||
# depth is stated once instead of guessed at each call site.
|
||||
global FRONT_Y
|
||||
FRONT_Y = -BODY_D / 2.0 - 0.5 + BODY_D / 2.0 # = -0.5 with the current BODY_D
|
||||
cube("Hero_Mass", 0.0, -BODY_D / 2.0 - 0.5, HEIGHT / 2.0, FRONTAGE_W - 2 * inset, BODY_D, HEIGHT, stone_dark)
|
||||
note("Hero_Mass", (FRONTAGE_W - 2 * inset, BODY_D, HEIGHT),
|
||||
"measured frontage x assumption depth x measured height, inset behind the cornice")
|
||||
@@ -350,9 +358,47 @@ def build():
|
||||
cube(f"Hero_Window_{rank}_{i}", wx, WINDOW_Y, z, 2.0, 0.08, 1.9, glass)
|
||||
note("Hero_Window_x10", (2.0, 0.08, 1.9), "photographs: window bands behind the colonnade")
|
||||
|
||||
# --- seat the applied detail on the wall ---------------------------------
|
||||
# Depth is a property of the façade, not of each call site: state it once here. Parts whose
|
||||
# front face is behind the wall plane are moved until it sits at FRONT_Y + offset.
|
||||
seat_on_front((
|
||||
("Hero_Architrave", 0.05), ("Hero_Cornice", 0.05), ("Hero_Dentil", 0.05),
|
||||
("Hero_Entablature", 0.03), ("Hero_MottoBand", 0.06), ("Hero_MottoSurround", 0.06),
|
||||
("Hero_Medallion", 0.08), ("Hero_Banner", 0.08), ("Hero_Window", 0.03),
|
||||
("Hero_Portal", 0.05), ("Hero_PortalJamb", 0.08), ("Hero_PortalLintel", 0.08),
|
||||
("Hero_PortalMullion", 0.04), ("Hero_PortalSign", 0.10),
|
||||
))
|
||||
|
||||
return parts, lines
|
||||
|
||||
|
||||
def seat_on_front(table):
|
||||
"""Move each named part so its street-facing face sits `offset` metres proud of FRONT_Y.
|
||||
|
||||
`table` is (name_prefix, offset_m) pairs. Parts that name no prefix - the mass, the colonnade,
|
||||
the steps and the stylobate - are left where the geometry put them, because they define the
|
||||
plane rather than hang on it.
|
||||
"""
|
||||
moved = 0
|
||||
for obj in bpy.data.objects:
|
||||
if obj.type != "MESH":
|
||||
continue
|
||||
for prefix, offset in table:
|
||||
if not obj.name.startswith(prefix):
|
||||
continue
|
||||
world_ys = [(obj.matrix_world @ v.co).y for v in obj.data.vertices]
|
||||
front = max(world_ys)
|
||||
delta = (FRONT_Y + offset) - front
|
||||
if abs(delta) < 1e-4:
|
||||
moved += 1
|
||||
else:
|
||||
obj.location.y += delta
|
||||
print(f"[hero] seat {obj.name:22} y {front:+.2f} -> {front + delta:+.2f} (offset {offset:+.2f})")
|
||||
moved += 1
|
||||
break
|
||||
print(f"[hero] seated {moved} parts on the wall plane at Y {FRONT_Y:+.2f}")
|
||||
|
||||
|
||||
def export_fbx(path):
|
||||
# Preset lives in Tools/fbx_export_preset.py (ue_metric_v1).
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
|
||||
Reference in new issue
Block a user