Upgrade Ground Zero terrain material
This commit is contained in:
@@ -946,7 +946,7 @@ looks intentional, grounded, and investor-readable.
|
||||
|
||||
Required order:
|
||||
|
||||
- [ ] Replace or upgrade the terrain material first so Ground Zero no longer reads as flat tan placeholder ground.
|
||||
- [x] Replace or upgrade the terrain material first so Ground Zero no longer reads as flat tan placeholder ground. Rebuilt `M_AGR_GZ_Terrain_CoastalScrub` as a procedural coastal scrub material that blends dry soil, scrub green, and sandy path color families with broad and fine noise, documented the visual baseline, and extended the natural-environment verifier so flat constant-color terrain fails.
|
||||
- [ ] Replace or upgrade grasses, shrubs, and trees with believable coastal-scrub vegetation assets, density, color variation, scale variation, and LOD/performance limits.
|
||||
- [ ] Replace or upgrade freshwater visuals with readable water surface, edge treatment, bank dressing, reflection/roughness tuning, and collectability cues.
|
||||
- [ ] Replace or upgrade character bodies and clothing so selected characters read as realistic near-future post-collapse frontier people rather than template mannequins or proxy stacks.
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6,7 +6,9 @@ space.
|
||||
|
||||
## Scope
|
||||
|
||||
- Terrain receives a warm coastal scrub ground material.
|
||||
- Terrain receives a procedural coastal scrub terrain material that blends
|
||||
dry soil, scrub green, and sandy path color families with broad and fine
|
||||
noise so Ground Zero does not read as flat tan placeholder ground.
|
||||
- Foliage patch instances keep the current prototype meshes but use distinct
|
||||
tree, shrub, and dry grass materials.
|
||||
- Wood, fiber, stone, and freshwater actors receive distinct first-pass
|
||||
@@ -48,7 +50,10 @@ space.
|
||||
`Scripts/verify_ground_zero_natural_environment_pass.py` checks that the
|
||||
materials exist, the landscape uses the terrain material, the foliage actor has
|
||||
the expected investor-facing instance counts and material assignments, and
|
||||
resource/water actors are visually dressed. It also checks the asset variation
|
||||
resource/water actors are visually dressed. It also checks that the terrain
|
||||
material contains procedural color breakup rather than a flat constant color:
|
||||
noise, blend, and coastal-scrub color-vector expression families must be present
|
||||
in the saved material package. It also checks the asset variation
|
||||
layer: twenty-three labeled variation actors, at least four mesh silhouettes,
|
||||
unique scale profiles, and coverage across tree, bush, grass, rock, and water
|
||||
visual families. `Scripts/verify_native_placeholder_meshes.py` checks that playable
|
||||
|
||||
@@ -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