- TCL Chinese Theatre (6925) and Madame Tussaud's (6933) exported from the verified OSM blockout with ue_metric_v1 (export_north_buildings.py), with a Y-mirror so they land north of the road, across from the hero facade. - ue_import_north_buildings.py imports + stages them in the DemoMap as North_TCL_Chinese / North_Madame_Tussauds (TCL Y 1802..9431, Tussaud's 1888..7586; hero at Y -1450, road centreline ~0). - render_screenshots.sh now also runs the DemoMap capture pass; added a demo-north-buildings camera, so the new buildings get a review shot. - README/roadmap updated; flat facade materials pending the 0.1.4 patch.
91 lines
3.4 KiB
Python
91 lines
3.4 KiB
Python
# Export the two in-scope north-side background buildings from the OSM blockout.
|
|
#
|
|
# blender -b --factory-startup Art/blender/blockout/blockout-2026-11-06.blend \
|
|
# --python Tools/export_north_buildings.py -- --out /tmp/gigline/north
|
|
#
|
|
# The blockout is already in the shared project frame (metres, X east / Y north /
|
|
# Z up, origin Hollywood x Highland), so exporting each object at its own world
|
|
# position preserves the offset from the hero facade. The site export preset
|
|
# (`ue_metric_v1`) is reused verbatim so the metre->centimetre mapping matches.
|
|
|
|
import argparse
|
|
import os
|
|
import sys
|
|
|
|
import bpy
|
|
|
|
BUILDINGS = ("TCL Chinese Theatre", "Madame Tussaud's")
|
|
|
|
|
|
def main():
|
|
argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--out", default="/tmp/gigline/north")
|
|
args = ap.parse_args(argv)
|
|
os.makedirs(args.out, exist_ok=True)
|
|
|
|
print(f"[north] scene objects: {len(bpy.data.objects)}")
|
|
for name in BUILDINGS:
|
|
obj = bpy.data.objects.get(name)
|
|
if obj is None or obj.type != "MESH":
|
|
print(f"[north] MISSING {name}")
|
|
continue
|
|
bpy.ops.object.select_all(action="DESELECT")
|
|
obj.select_set(True)
|
|
bpy.context.view_layer.objects.active = obj
|
|
mesh = obj.data
|
|
if not mesh.materials:
|
|
mat = bpy.data.materials.new(f"M_{name.replace(' ', '_')}")
|
|
mat.diffuse_color = (0.75, 0.72, 0.68, 1.0)
|
|
mat.use_nodes = False
|
|
mesh.materials.append(mat)
|
|
|
|
# The blockout sits with the hero (6840, south side) at negative Y. The two
|
|
# in-scope north buildings must land ACROSS Hollywood Blvd at positive Y in
|
|
# Unreal. Mirror the exported geometry across the road centreline (Y=0) and
|
|
# reverse winding; the FBX exporter does not do this for us.
|
|
new_mesh = mesh.copy()
|
|
new_obj = obj.copy()
|
|
new_obj.data = new_mesh
|
|
new_obj.matrix_world = obj.matrix_world.copy()
|
|
bpy.context.collection.objects.link(new_obj)
|
|
import mathutils as mu
|
|
world = new_obj.matrix_world
|
|
inv = world.inverted()
|
|
for v in new_mesh.vertices:
|
|
wp = world @ v.co
|
|
wp.y = -wp.y
|
|
v.co = inv @ wp
|
|
for poly in new_mesh.polygons:
|
|
verts = list(poly.vertices)
|
|
verts.reverse()
|
|
poly.vertices = verts
|
|
new_mesh.update()
|
|
bpy.ops.object.select_all(action="DESELECT")
|
|
new_obj.select_set(True)
|
|
bpy.context.view_layer.objects.active = new_obj
|
|
|
|
path = os.path.join(args.out, name.replace(" ", "_").replace("'", "") + ".fbx")
|
|
bpy.ops.export_scene.fbx(
|
|
filepath=path,
|
|
use_selection=True,
|
|
object_types={"MESH"},
|
|
apply_unit_scale=True,
|
|
apply_scale_options="FBX_SCALE_NONE",
|
|
axis_forward="-Y",
|
|
axis_up="Z",
|
|
use_space_transform=True,
|
|
use_mesh_modifiers=True,
|
|
mesh_smooth_type="OFF",
|
|
path_mode="AUTO",
|
|
bake_space_transform=False,
|
|
)
|
|
zs = [(world @ v.co).z for v in new_mesh.vertices]
|
|
print(f"[north] {name:22} verts {len(new_mesh.vertices):5} z {min(zs):+.2f}..{max(zs):+.2f} m "
|
|
f"-> {path}")
|
|
bpy.data.objects.remove(new_obj, do_unlink=True)
|
|
|
|
print(f"[north] done")
|
|
|
|
|
|
main() |