fix(hero): the albedo renders - two blockers, both at the map level
The generated ashlar albedo never showed for two reasons that had nothing to do with the material graph,
which was verified correct the whole time (TextureSampleParameter2D -> Multiply -> Base Color, colour sampler,
texture set, 6x UV tiling):
1. **The map overrode every hero slot.** The generic per-slot material pass in ue_build_demo_map.py assigned
the facade KIT's flat stone to every actor whose slot names looked like stone, banner, glass - including
Hero_Facade. Whatever the import authored was replaced at map build time. The hero is now excluded and gets
its own materials.
2. **Mesh slot assignment does not persist.** Assigning to mesh.get_editor_property('static_materials') returns a
copy; after a reload the mesh still pointed at the original imported materials (measured twice). Component
level overrides do persist in the saved map, so apply_hero_materials() sets them in both builders.
The elevation now renders as coursed, grainy warm limestone with banners, window bays and recessed portals.
Rows 4-6 re-rendered and pending review; the comparison plate is regenerated. Still missing against the
reference: carved inscription, medallion relief, banner lettering, crimson banner tone. The two-model judge
returns no/no (0.90/0.95) - it wants the text and detail that are still absent, which is at least the right
complaint this time.
This commit is contained in:
1 parent
0189ff00fe
commit
ff9eb0a4ad
118 files changed
+242
-189
No files matched your search
@@ -84,69 +84,55 @@ def import_albedo():
|
||||
|
||||
|
||||
def tint_imported_materials():
|
||||
"""Author plain facade materials for the imported slots.
|
||||
"""Rebuild each imported facade material in place with the reference colour and the stone albedo.
|
||||
|
||||
The FBX import produces material *instances*, which cannot carry their own base colour, and the
|
||||
instance's parent keeps the blockout's near-white constant. Instead of fighting that, this creates one
|
||||
simple material per facade surface with the colour sampled from the reference and assigns it to the
|
||||
matching slot. That is the step that finally moves the stone off white; a tint attempt that silently
|
||||
did nothing is what let it survive three rebuilds.
|
||||
Assigning new material assets to the mesh's slots does NOT persist: the slot list returned by
|
||||
`get_editor_property("static_materials")` is a copy, and after a reload the mesh still points at the
|
||||
originals - measured, twice. Editing the imported material assets themselves is what sticks, because the
|
||||
mesh already references them by name. This is also the step that finally moves the stone off a flat tint.
|
||||
|
||||
Albedo is multiplied by a tint rather than used raw, so the generated texture's brightness stays inside the
|
||||
reference's range.
|
||||
"""
|
||||
mesh = unreal.EditorAssetLibrary.load_asset(f"{DEST}/SM_HeroFacade")
|
||||
if mesh is None:
|
||||
log("no SM_HeroFacade to tint")
|
||||
return
|
||||
library = unreal.MaterialEditingLibrary
|
||||
albedo = import_albedo()
|
||||
slots = mesh.get_editor_property("static_materials")
|
||||
assigned = 0
|
||||
for index, slot in enumerate(slots):
|
||||
current = slot.get_editor_property("material_interface")
|
||||
name = current.get_name() if current else ""
|
||||
base = name.split(".")[0].replace("_T", "")
|
||||
rgb = FACADE_TINTS.get(base)
|
||||
if rgb is None:
|
||||
rebuilt = 0
|
||||
for base, rgb in FACADE_TINTS.items():
|
||||
path = f"{DEST}/{base}"
|
||||
if not unreal.EditorAssetLibrary.does_asset_exist(path):
|
||||
log(f"{base}: missing, not rebuilt")
|
||||
continue
|
||||
path = f"{DEST}/{base}_Ref"
|
||||
if unreal.EditorAssetLibrary.does_asset_exist(path):
|
||||
unreal.EditorAssetLibrary.delete_asset(path)
|
||||
material = unreal.AssetToolsHelpers.get_asset_tools().create_asset(
|
||||
base + "_Ref", DEST, unreal.Material, unreal.MaterialFactoryNew())
|
||||
material = unreal.EditorAssetLibrary.load_asset(path)
|
||||
if material is None:
|
||||
log(f"{base}: could not load")
|
||||
continue
|
||||
library.delete_all_material_expressions(material)
|
||||
colour = library.create_material_expression(
|
||||
material, unreal.MaterialExpressionConstant3Vector, -400, 0)
|
||||
material, unreal.MaterialExpressionConstant3Vector, -600, 200)
|
||||
colour.set_editor_property("constant", unreal.LinearColor(rgb[0], rgb[1], rgb[2], 1.0))
|
||||
source = colour
|
||||
if albedo is not None and base in ("M_Facade_Stone", "M_Facade_StoneShadow"):
|
||||
# Texture sample multiplied by the tint: the map carries the coursing and grain, the tint keeps
|
||||
# the value in the reference's range instead of the generator's brighter one.
|
||||
sample = library.create_material_expression(
|
||||
material, unreal.MaterialExpressionTextureSampleParameter2D, -700, 0)
|
||||
material, unreal.MaterialExpressionTextureSampleParameter2D, -900, -100)
|
||||
sample.set_editor_property("parameter_name", f"Albedo_{base}")
|
||||
sample.set_editor_property("texture", albedo)
|
||||
if hasattr(unreal, "MaterialExpressionTextureCoordinate"):
|
||||
uvs = library.create_material_expression(
|
||||
material, unreal.MaterialExpressionTextureCoordinate, -950, 0)
|
||||
uvs.set_editor_property("u_tiling", 6.0)
|
||||
uvs.set_editor_property("v_tiling", 6.0)
|
||||
library.connect_material_expressions(uvs, "", sample, "UVs")
|
||||
sample.set_editor_property("sampler_type", unreal.MaterialSamplerType.SAMPLERTYPE_COLOR)
|
||||
uvs = library.create_material_expression(
|
||||
material, unreal.MaterialExpressionTextureCoordinate, -1150, -100)
|
||||
uvs.set_editor_property("u_tiling", 6.0)
|
||||
uvs.set_editor_property("v_tiling", 6.0)
|
||||
library.connect_material_expressions(uvs, "", sample, "UVs")
|
||||
multiply = library.create_material_expression(
|
||||
material, unreal.MaterialExpressionMultiply, -250, 0)
|
||||
material, unreal.MaterialExpressionMultiply, -300, 0)
|
||||
library.connect_material_expressions(sample, "RGB", multiply, "A")
|
||||
library.connect_material_expressions(colour, "", multiply, "B")
|
||||
source = multiply
|
||||
library.connect_material_property(source, "", unreal.MaterialProperty.MP_BASE_COLOR)
|
||||
library.recompile_material(material)
|
||||
# Save the material itself. Saving only the mesh left these assets unsaved, so after a reload the
|
||||
# slots pointed at nothing and the whole elevation rendered in one default colour.
|
||||
saved = unreal.EditorAssetLibrary.save_loaded_asset(material)
|
||||
log(f"{base}_Ref saved: {saved}")
|
||||
slot.set_editor_property("material_interface", material)
|
||||
assigned += 1
|
||||
log(f"slot {index} {base}: {material.get_name()} {rgb}")
|
||||
if assigned:
|
||||
mesh.set_editor_property("static_materials", slots)
|
||||
unreal.EditorAssetLibrary.save_loaded_asset(mesh)
|
||||
log(f"assigned {assigned} facade materials")
|
||||
log(f"{base}: rebuilt (albedo {'yes' if source is not colour else 'no'}), saved {saved}")
|
||||
rebuilt += 1
|
||||
log(f"rebuilt {rebuilt} facade materials")
|
||||
|
||||
|
||||
def drop_stale_mesh():
|
||||
|
||||
Reference in new issue
Block a user