Upgrade Ground Zero terrain material
This commit is contained in:
@@ -48,6 +48,10 @@ ENVIRONMENT_MATERIALS = {
|
||||
"terrain": {
|
||||
"path": f"{MATERIAL_FOLDER}/M_AGR_GZ_Terrain_CoastalScrub",
|
||||
"color": unreal.LinearColor(0.16, 0.23, 0.12, 1.0),
|
||||
"dry_soil_color": unreal.LinearColor(0.28, 0.24, 0.16, 1.0),
|
||||
"scrub_green_color": unreal.LinearColor(0.12, 0.22, 0.10, 1.0),
|
||||
"sandy_path_color": unreal.LinearColor(0.42, 0.36, 0.23, 1.0),
|
||||
"noise_scale": 42.0,
|
||||
"roughness": 0.92,
|
||||
},
|
||||
"tree": {
|
||||
@@ -837,11 +841,102 @@ def ensure_environment_materials():
|
||||
material.set_editor_property("used_with_instanced_static_meshes", True)
|
||||
unreal.MaterialEditingLibrary.recompile_material(material)
|
||||
unreal.EditorAssetLibrary.save_asset(spec["path"], only_if_is_dirty=False)
|
||||
if key == "terrain":
|
||||
rebuild_ground_zero_terrain_material(material, spec)
|
||||
created_or_loaded[key] = material
|
||||
|
||||
return created_or_loaded
|
||||
|
||||
|
||||
def set_expression_property(expression, property_name, value):
|
||||
try:
|
||||
expression.set_editor_property(property_name, value)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def connect_expression(source, source_output, target, target_input):
|
||||
try:
|
||||
unreal.MaterialEditingLibrary.connect_material_expressions(source, source_output, target, target_input)
|
||||
return True
|
||||
except Exception as exc:
|
||||
unreal.log_warning(f"Could not connect material expression input {target_input}: {exc}")
|
||||
return False
|
||||
|
||||
|
||||
def create_constant_color(material, color, x, y):
|
||||
expression = unreal.MaterialEditingLibrary.create_material_expression(
|
||||
material, unreal.MaterialExpressionConstant3Vector, x, y
|
||||
)
|
||||
expression.set_editor_property("constant", color)
|
||||
return expression
|
||||
|
||||
|
||||
def create_constant_scalar(material, value, x, y):
|
||||
expression = unreal.MaterialEditingLibrary.create_material_expression(
|
||||
material, unreal.MaterialExpressionConstant, x, y
|
||||
)
|
||||
expression.set_editor_property("r", value)
|
||||
return expression
|
||||
|
||||
|
||||
def rebuild_ground_zero_terrain_material(material, spec):
|
||||
"""Build a simple procedural material so the landscape no longer reads as a flat color."""
|
||||
if hasattr(unreal.MaterialEditingLibrary, "delete_all_material_expressions"):
|
||||
unreal.MaterialEditingLibrary.delete_all_material_expressions(material)
|
||||
|
||||
dry_soil = create_constant_color(material, spec["dry_soil_color"], -900, -260)
|
||||
scrub_green = create_constant_color(material, spec["scrub_green_color"], -900, -80)
|
||||
sandy_path = create_constant_color(material, spec["sandy_path_color"], -900, 100)
|
||||
|
||||
broad_noise = unreal.MaterialEditingLibrary.create_material_expression(
|
||||
material, unreal.MaterialExpressionNoise, -560, -160
|
||||
)
|
||||
set_expression_property(broad_noise, "scale", spec.get("noise_scale", 42.0))
|
||||
set_expression_property(broad_noise, "quality", 3)
|
||||
set_expression_property(broad_noise, "levels", 5)
|
||||
|
||||
fine_noise = unreal.MaterialEditingLibrary.create_material_expression(
|
||||
material, unreal.MaterialExpressionNoise, -560, 100
|
||||
)
|
||||
set_expression_property(fine_noise, "scale", 145.0)
|
||||
set_expression_property(fine_noise, "quality", 2)
|
||||
set_expression_property(fine_noise, "levels", 3)
|
||||
|
||||
scrub_blend = unreal.MaterialEditingLibrary.create_material_expression(
|
||||
material, unreal.MaterialExpressionLinearInterpolate, -260, -180
|
||||
)
|
||||
connect_expression(dry_soil, "", scrub_blend, "A")
|
||||
connect_expression(scrub_green, "", scrub_blend, "B")
|
||||
connect_expression(broad_noise, "", scrub_blend, "Alpha")
|
||||
|
||||
final_blend = unreal.MaterialEditingLibrary.create_material_expression(
|
||||
material, unreal.MaterialExpressionLinearInterpolate, 40, -70
|
||||
)
|
||||
connect_expression(scrub_blend, "", final_blend, "A")
|
||||
connect_expression(sandy_path, "", final_blend, "B")
|
||||
connect_expression(fine_noise, "", final_blend, "Alpha")
|
||||
unreal.MaterialEditingLibrary.connect_material_property(
|
||||
final_blend, "", unreal.MaterialProperty.MP_BASE_COLOR
|
||||
)
|
||||
|
||||
roughness = create_constant_scalar(material, spec["roughness"], -260, 160)
|
||||
unreal.MaterialEditingLibrary.connect_material_property(
|
||||
roughness, "", unreal.MaterialProperty.MP_ROUGHNESS
|
||||
)
|
||||
|
||||
specular = create_constant_scalar(material, 0.18, -260, 260)
|
||||
unreal.MaterialEditingLibrary.connect_material_property(
|
||||
specular, "", unreal.MaterialProperty.MP_SPECULAR
|
||||
)
|
||||
|
||||
material.set_editor_property("use_material_attributes", False)
|
||||
unreal.MaterialEditingLibrary.recompile_material(material)
|
||||
unreal.EditorAssetLibrary.save_asset(spec["path"], only_if_is_dirty=False)
|
||||
unreal.log("Rebuilt Ground Zero terrain material with coastal scrub color variation and procedural noise.")
|
||||
|
||||
|
||||
def apply_material_to_actor_meshes(actor, material):
|
||||
applied_count = 0
|
||||
for component in actor.get_components_by_class(unreal.StaticMeshComponent):
|
||||
|
||||
@@ -82,6 +82,28 @@ def assert_asset(path):
|
||||
return asset
|
||||
|
||||
|
||||
def verify_terrain_material_is_not_flat(material, failures):
|
||||
project_root = unreal.Paths.convert_relative_path_to_full(unreal.Paths.project_dir())
|
||||
material_package = project_root + "Content/Agrarian/Materials/M_AGR_GZ_Terrain_CoastalScrub.uasset"
|
||||
try:
|
||||
with open(material_package, "rb") as handle:
|
||||
package_bytes = handle.read()
|
||||
except Exception as exc:
|
||||
failures.append(f"could not inspect terrain material package: {exc}")
|
||||
return
|
||||
|
||||
noise_count = package_bytes.count(b"MaterialExpressionNoise")
|
||||
lerp_count = package_bytes.count(b"MaterialExpressionLinearInterpolate")
|
||||
color_count = package_bytes.count(b"MaterialExpressionConstant3Vector")
|
||||
|
||||
if noise_count < 1:
|
||||
failures.append("terrain material should include a noise expression for color breakup")
|
||||
if lerp_count < 1:
|
||||
failures.append("terrain material should include a blend expression instead of a flat base color")
|
||||
if color_count < 1:
|
||||
failures.append("terrain material should include coastal scrub color vector expressions")
|
||||
|
||||
|
||||
def main():
|
||||
if not unreal.EditorLevelLibrary.load_level(MAP_PATH):
|
||||
raise RuntimeError(f"Could not load map: {MAP_PATH}")
|
||||
@@ -98,6 +120,7 @@ def main():
|
||||
expected = MATERIALS["terrain"]
|
||||
if assigned != expected:
|
||||
failures.append(f"landscape material expected {expected}, got {assigned}")
|
||||
verify_terrain_material_is_not_flat(materials["terrain"], failures)
|
||||
|
||||
foliage_actors = [actor for actor in actors if get_actor_label(actor) == FOLIAGE_LABEL]
|
||||
if len(foliage_actors) != 1:
|
||||
@@ -187,8 +210,10 @@ def main():
|
||||
roadmap = unreal.Paths.convert_relative_path_to_full(unreal.Paths.project_dir()) + "AGRARIAN_DEVELOPMENT_ROADMAP.md"
|
||||
for path, snippet in [
|
||||
(docs, "asset variation"),
|
||||
(docs, "procedural coastal scrub terrain material"),
|
||||
(roadmap, "[x] Replace grey-box environment presentation with an MVP natural environment pass"),
|
||||
(roadmap, "[x] Add first-pass environment asset variation"),
|
||||
(roadmap, "[x] Replace or upgrade the terrain material first so Ground Zero no longer reads as flat tan placeholder ground."),
|
||||
]:
|
||||
with open(path, "r", encoding="utf-8") as handle:
|
||||
text = handle.read()
|
||||
|
||||
Reference in New Issue
Block a user