feat(hero): Ionic base and abacus, medallions onto the parapet face
Detail pass on the hero, all verified by measuring the built mesh: - Column base moulding: a 1.36 m wide, 0.22 m tall cylinder at each shaft foot (2.00-2.22 m). The shaft previously started straight off the square pedestal, so the base never read in silhouette. - Abacus: a 1.30 m square, 0.14 m thick slab over each capital. It takes the top of the capital zone, so the colonnade still ends at 9.70 m and the 53.1 % proportion is unchanged. - Medallions fixed: they were built with the Z-axis cylinder helper, so the two 'discs' were pancakes lying flat on the parapet coping (1.1 x 1.1 x 0.02, z 14.02-14.04). New disc_on_wall() helper rotates the cylinder 90 deg about X; they now stand 1.1 m across on the parapet face (y -1.32..-1.28, z 13.05..14.15). Hero rebuilt (95 parts, 2420 tris, still 14.50 m), re-imported, DemoMap rebuilt, screenshot set re-rendered. Part report records the new dims and their assumption notes. Screenshots README notes the detail pass.
This commit is contained in:
1 parent
fe8a23e5ee
commit
70c6e322e2
29 files changed
+117
-60
No files matched your search
@@ -88,6 +88,25 @@ def cylinder(name, x, y, z0, z1, radius, material, vertices=24):
|
||||
return obj
|
||||
|
||||
|
||||
def disc_on_wall(name, x, y, z, radius, thickness, material=None, vertices=24):
|
||||
"""A round disc mounted vertically on a wall face.
|
||||
|
||||
`cylinder()` builds along Z, so a "medallion" made with it is a pancake lying
|
||||
flat on top of the parapet rather than a disc on its face — which is what the
|
||||
first build did (1.1 m across in Y, 0.02 m thick in Z, sitting at the coping).
|
||||
This rotates the cylinder 90 degrees about X so the axis points along Y and
|
||||
the disc faces the street.
|
||||
"""
|
||||
obj = cylinder(name, x, y, z - thickness / 2.0, z + thickness / 2.0,
|
||||
radius, material, vertices=vertices)
|
||||
obj.rotation_euler = (math.radians(90.0), 0.0, 0.0)
|
||||
bpy.ops.object.select_all(action="DESELECT")
|
||||
obj.select_set(True)
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)
|
||||
return obj
|
||||
|
||||
|
||||
def make_material(name, rgba, roughness=0.75):
|
||||
mat = bpy.data.materials.new(name)
|
||||
mat.use_nodes = True
|
||||
@@ -136,14 +155,32 @@ def build():
|
||||
col_xs.append(x)
|
||||
cube(f"Hero_Pedestal_{i + 1}", x, -0.62, PEDESTAL_H + 0.27,
|
||||
1.24, 1.24, 0.54, stone)
|
||||
cylinder(f"Hero_Column_{i + 1}", x, -0.55, PEDESTAL_H + 0.55,
|
||||
PEDESTAL_H + 0.55 + (HEIGHT - ENTABLATURE_H - PARAPET_H - PEDESTAL_H - 0.55 - CAPITAL_H),
|
||||
# Base moulding: a taller, wider cylinder where the shaft meets the
|
||||
# pedestal. Without it the shaft starts straight off a square plinth,
|
||||
# which is not how an Ionic base reads in silhouette.
|
||||
base_z0 = PEDESTAL_H + 0.55
|
||||
base_h = 0.22
|
||||
cylinder(f"Hero_ColumnBase_{i + 1}", x, -0.55, base_z0, base_z0 + base_h,
|
||||
0.68, stone, vertices=20)
|
||||
shaft_z0 = base_z0 + base_h
|
||||
cap_z0 = HEIGHT - ENTABLATURE_H - PARAPET_H - CAPITAL_H
|
||||
cylinder(f"Hero_Column_{i + 1}", x, -0.55, shaft_z0, cap_z0,
|
||||
COLUMN_D / 2.0, stone)
|
||||
cylinder(f"Hero_Capital_{i + 1}", x, -0.55,
|
||||
HEIGHT - ENTABLATURE_H - PARAPET_H - CAPITAL_H,
|
||||
HEIGHT - ENTABLATURE_H - PARAPET_H, 0.62, stone, vertices=16)
|
||||
# Capital block, then the square abacus that carries the architrave.
|
||||
# The abacus takes the top 0.14 m of the capital zone so the colonnade
|
||||
# still ends at HEIGHT - ENTABLATURE_H - PARAPET_H (proportion unchanged).
|
||||
abacus_h = 0.14
|
||||
cylinder(f"Hero_Capital_{i + 1}", x, -0.55, cap_z0,
|
||||
HEIGHT - ENTABLATURE_H - PARAPET_H - abacus_h, 0.62, stone, vertices=16)
|
||||
cube(f"Hero_Abacus_{i + 1}", x, -0.55,
|
||||
HEIGHT - ENTABLATURE_H - PARAPET_H - abacus_h / 2.0,
|
||||
1.30, 1.30, abacus_h, stone)
|
||||
note("Hero_Column_x6", (COLUMN_D, COLUMN_D, HEIGHT - ENTABLATURE_H - PARAPET_H - PEDESTAL_H),
|
||||
f"6 columns at {COLUMN_BAY} m centres (sibling notes x measured frontage)")
|
||||
note("Hero_ColumnBase_x6", (1.36, 1.36, 0.22),
|
||||
"assumption: Ionic base moulding; photographs show a wider base at the shaft foot")
|
||||
note("Hero_Abacus_x6", (1.30, 1.30, 0.14),
|
||||
"assumption: square abacus under the architrave, as Ionic capitals carry")
|
||||
|
||||
# --- entablature and parapet ------------------------------------------
|
||||
ent_z0 = HEIGHT - ENTABLATURE_H - PARAPET_H
|
||||
@@ -167,11 +204,13 @@ def build():
|
||||
FRONTAGE_W - 3.0, 0.08, 0.85, stone_dark)
|
||||
note("Hero_MottoBand", (FRONTAGE_W - 3.0, 0.08, 0.85), "photographs: motto panel above the colonnade")
|
||||
|
||||
# Medallions either side of the inscription.
|
||||
# Medallions either side of the inscription: discs on the parapet face, not
|
||||
# pancakes on the coping (see disc_on_wall).
|
||||
for i, x in enumerate((-6.2, 6.2), start=1):
|
||||
cylinder(f"Hero_Medallion_{i}", x, -1.36, HEIGHT - PARAPET_H / 2.0 + 0.42,
|
||||
HEIGHT - PARAPET_H / 2.0 + 0.44, 0.55, stone_dark, vertices=20)
|
||||
note("Hero_Medallion_x2", (1.1, 1.1, 0.02), "photographs: two stone discs beside the motto")
|
||||
disc_on_wall(f"Hero_Medallion_{i}", x, -1.30, HEIGHT - PARAPET_H / 2.0,
|
||||
0.55, 0.04, stone_dark, vertices=20)
|
||||
note("Hero_Medallion_x2", (1.1, 0.04, 1.1),
|
||||
"photographs: two stone discs beside the motto, mounted on the parapet face")
|
||||
|
||||
# --- entrances ---------------------------------------------------------
|
||||
# Three portals between column pairs, each with its own short flight. The
|
||||
|
||||
Reference in new issue
Block a user