Completes "Materials and look development for all exported assets". Every exported surface previously carried a flat Constant3Vector fill, which read as plastic. ensure_material() in Tools/ue_build_demo_map.py now builds a procedural material per surface: - base colour blended between two shades by world-space noise (WorldPosition -> Multiply -> Noise -> Lerp -> BaseColor) for large-scale variation, - an explicit roughness and specular so the surface type is readable. M_Asphalt 0.92, M_Concrete 0.88, M_KerbConcrete 0.85, M_Ground 0.98, M_RoadPaint 0.62, M_FacadeStone 0.72, M_Stucco 0.86 Site meshes take their material by mesh name; the hero facade and the two north-side buildings take theirs by actor label, so they are covered even though other scripts stage them. Materials are deleted and rebuilt on every run, so a look change cannot be masked by a stale asset. Result: the facade reads as warm stone with surface variation, asphalt as dark asphalt with grain, concrete and kerbs lighter and matte, and the north buildings in stucco instead of flat grey. Screenshots re-rendered and approved by the owner. The richer texture-based pass (baked/procedural brick_facade, seamless_concrete, glass, material instances) stays in the 0.1.4 facade patch. Squash of branch materials-lookdev-0.1.0 (PR #5).
Tools
Repeatable helpers that drive Blender, Unreal, and the reference/asset sources. Nothing here is hand-run twice: every step that produced committed content has a script.
Geographic tools live in Geo/tools/ and the Blender-side builders live next to their output in Art/blender/*/; this folder holds everything that talks to Unreal, the network, or the repository.
Conventions
- One script, one job. Every input is an argument; no interactive prompts.
- Absolute paths where a tool crosses into a sandbox (Blender Flatpak, the Unreal commandlet). Those processes do not share the repo's working directory.
- Unreal commandlets swallow
print(), so each writes a result file under/tmp/gigline/. Read the file; do not trust the exit code alone. - No credentials, no writes outside the project by default.
Repository and assets
| Tool | Purpose |
|---|---|
check-lfs.sh |
Fails if the lfs filter is missing or an LFS-tracked file was committed as a plain blob |
sibling_asset_audit.py |
Reads the sibling project's prop library from GLB headers into Art/props/reuse-manifest.json; copies nothing |
scale_test_export.py / ue_scale_test_import.py |
The 1 m = 100 uu scale test; the named presets ue_metric_v1 live in these two files |
Reference gathering
| Tool | Purpose |
|---|---|
commons_fetch.py |
Wikimedia Commons: search, exact File: titles, or a whole category; writes a provenance sidecar.json |
page_image_fetch.py |
Resolves a web page's og:image and downloads it (Flickr, Commons file pages, photo blogs) |
addon_compat_probe.py |
Verifies MPFB/Blosm can load and generate headless on the pinned Blender |
Blender content
| Tool | Purpose |
|---|---|
hero_facade_build.py |
Parametric hero façade; emits a JSON report naming the evidence behind every part |
mpfb_character_export.py |
MPFB human, standard rig, baked skin, FBX export |
Unreal import and level building
| Tool | Purpose |
|---|---|
ue_import_site.py |
Imports the six site FBXs into /Game/Hollywood/Site, setting collision complexity per mesh |
ue_hero_facade_import.py |
Imports the façade and places it on the measured building line |
ue_build_demo_map.py |
Builds /Game/Hollywood/DemoMap: lighting, façade, site meshes, player start |
ue_build_review_map.py |
Rebuilds Test/ReviewMap, stages the shot camera list, and stages the demo-map views |
ue_create_input_assets.py |
Creates /Game/Input actions and the mapping context headlessly |
ue_character_import.py |
Skeletal import plus the material/texture chain Interchange skips |
Visual review
| Tool | Purpose |
|---|---|
render_screenshots.py / render_screenshots.sh |
Rebuilds the review map, runs the game, captures the shot list into Screenshots/ |
judge_screenshot.py |
Vision-model pre-check: judges a screenshot against an expected-scene description (--image + --expect, or --shots for every shot in the README). Reads OPENROUTER_API_KEY from .env (ignored). Optional helper — a human must still approve. |