sync
This commit is contained in:
1 parent
2a4da34fe9
commit
bf525034e0
10 files changed
+142
-494
No files matched your search
Binary file not shown.
@@ -17,7 +17,7 @@ import os, json, math, random, unreal
|
||||
|
||||
CONFIG_PATH = os.environ.get(
|
||||
"TERRAIN_CONFIG",
|
||||
os.path.join(os.path.dirname(os.path.abspath(__file__)), "terrain_config.json"),
|
||||
os.path.join(os.path.dirname(os.path.abspath(__file__)), "terrain_config_variants_demo.json"),
|
||||
)
|
||||
|
||||
asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
|
||||
@@ -85,7 +85,7 @@ class FractalHeightField:
|
||||
frequency *= self.lacunarity
|
||||
return (total / max_amp) * self.height_scale
|
||||
|
||||
def normal(self, x, y, step=25.0):
|
||||
def normal(self, x, y, step=200.0):
|
||||
h_l = self.height(x - step, y)
|
||||
h_r = self.height(x + step, y)
|
||||
h_d = self.height(x, y - step)
|
||||
@@ -145,17 +145,42 @@ def build_terrain_mesh(cfg, field):
|
||||
return static_mesh, bounds
|
||||
|
||||
|
||||
_mesh_base_z_cache = {}
|
||||
_mesh_bounds_cache = {}
|
||||
|
||||
|
||||
def mesh_base_z(mesh):
|
||||
"""Local-space Z of the mesh's lowest point, so we can plant its base on the
|
||||
ground instead of its (often bounding-box-centered) pivot."""
|
||||
def mesh_local_bounds(mesh):
|
||||
path = mesh.get_path_name()
|
||||
if path not in _mesh_base_z_cache:
|
||||
if path not in _mesh_bounds_cache:
|
||||
box = mesh.get_bounding_box()
|
||||
_mesh_base_z_cache[path] = box.min.z
|
||||
return _mesh_base_z_cache[path]
|
||||
_mesh_bounds_cache[path] = (box.min, box.max)
|
||||
return _mesh_bounds_cache[path]
|
||||
|
||||
|
||||
def ground_offset_for(mesh, quat, scale_vec):
|
||||
"""World-space Z distance from the actor's pivot down to the lowest point of
|
||||
its (scaled, rotated) mesh, so the base can be planted exactly on the ground
|
||||
no matter where the source asset's pivot was authored, or how it's tilted."""
|
||||
box_min, box_max = mesh_local_bounds(mesh)
|
||||
min_z = None
|
||||
for x in (box_min.x, box_max.x):
|
||||
for y in (box_min.y, box_max.y):
|
||||
for z in (box_min.z, box_max.z):
|
||||
corner = unreal.Vector(x * scale_vec.x, y * scale_vec.y, z * scale_vec.z)
|
||||
world_z = quat.rotate_vector(corner).z
|
||||
if min_z is None or world_z < min_z:
|
||||
min_z = world_z
|
||||
return -min_z
|
||||
|
||||
|
||||
def align_and_yaw_quat(normal, yaw_degrees, align_to_normal):
|
||||
"""Random yaw about the object's own up axis, then (optionally) tilt that
|
||||
up axis to match the terrain normal - in that order, since tilting first
|
||||
would rotate the yaw axis out from under the random spin."""
|
||||
yaw_quat = unreal.Rotator(roll=0.0, pitch=0.0, yaw=yaw_degrees).quaternion()
|
||||
if not align_to_normal:
|
||||
return yaw_quat
|
||||
align_quat = unreal.Vector(0.0, 0.0, 1.0).find_quat_between_normals(normal)
|
||||
return align_quat * yaw_quat
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -199,21 +224,17 @@ def scatter_layer(layer_cfg, field, bounds, origin, base_folder):
|
||||
|
||||
mesh = rng.choice(meshes)
|
||||
scale = rng.uniform(layer_cfg["min_scale"], layer_cfg["max_scale"])
|
||||
# Shift up by -min_z*scale so the mesh's lowest vertex sits on the ground,
|
||||
# regardless of where the source asset's pivot was authored.
|
||||
ground_offset = -mesh_base_z(mesh) * scale
|
||||
location = unreal.Vector(origin.x + x, origin.y + y, origin.z + z + ground_offset)
|
||||
scale_vec = unreal.Vector(scale, scale, scale)
|
||||
|
||||
yaw = rng.uniform(0.0, 360.0)
|
||||
if layer_cfg.get("align_to_normal", False):
|
||||
# Approximate tilt from the surface normal; good enough for gentle slopes.
|
||||
pitch = -math.degrees(math.atan2(normal.x, normal.z))
|
||||
roll = math.degrees(math.atan2(normal.y, normal.z))
|
||||
rotation = unreal.Rotator(roll=roll, pitch=pitch, yaw=yaw)
|
||||
else:
|
||||
rotation = unreal.Rotator(roll=0.0, pitch=0.0, yaw=yaw)
|
||||
quat = align_and_yaw_quat(normal, yaw, layer_cfg.get("align_to_normal", False))
|
||||
rotation = quat.rotator()
|
||||
|
||||
ground_offset = ground_offset_for(mesh, quat, scale_vec)
|
||||
location = unreal.Vector(origin.x + x, origin.y + y, origin.z + z + ground_offset)
|
||||
|
||||
actor = actor_subsystem.spawn_actor_from_object(mesh, location, rotation)
|
||||
actor.set_actor_scale3d(unreal.Vector(scale, scale, scale))
|
||||
actor.set_actor_scale3d(scale_vec)
|
||||
actor.set_folder_path(f"{base_folder}/{layer_cfg['name']}")
|
||||
actor.set_actor_label(f"{layer_cfg['name']}_{spawned:04d}")
|
||||
spawned += 1
|
||||
@@ -245,13 +266,15 @@ def place_explicit(entries, field, origin, base_folder):
|
||||
else:
|
||||
scale_vec = unreal.Vector(scale, scale, scale)
|
||||
|
||||
roll, pitch, yaw = entry.get("rotation", [0.0, 0.0, 0.0])
|
||||
rotation = unreal.Rotator(roll=roll, pitch=pitch, yaw=yaw)
|
||||
quat = rotation.quaternion()
|
||||
|
||||
z = z_offset
|
||||
if entry.get("snap_to_terrain", True):
|
||||
z += field.height(x, y) - mesh_base_z(mesh) * scale_vec.z
|
||||
z += field.height(x, y) + ground_offset_for(mesh, quat, scale_vec)
|
||||
|
||||
roll, pitch, yaw = entry.get("rotation", [0.0, 0.0, 0.0])
|
||||
location = unreal.Vector(origin.x + x, origin.y + y, origin.z + z)
|
||||
rotation = unreal.Rotator(roll=roll, pitch=pitch, yaw=yaw)
|
||||
|
||||
actor = actor_subsystem.spawn_actor_from_object(mesh, location, rotation)
|
||||
actor.set_actor_scale3d(scale_vec)
|
||||
|
||||
@@ -37,9 +37,7 @@
|
||||
{
|
||||
"name": "Rocks",
|
||||
"meshes": [
|
||||
"/Game/ImportedAssets/Rocks/SM_rock1",
|
||||
"/Game/ImportedAssets/Rocks/SM_rock2",
|
||||
"/Game/ImportedAssets/Rocks/SM_rock3"
|
||||
"/Game/ImportedAssets/Rocks/SM_rock1"
|
||||
],
|
||||
"count": 150,
|
||||
"min_height": -100.0,
|
||||
@@ -63,7 +61,7 @@
|
||||
},
|
||||
{
|
||||
"name": "RockCairn_Waypoint",
|
||||
"mesh": "/Game/ImportedAssets/Rocks/SM_rock2",
|
||||
"mesh": "/Game/ImportedAssets/Rocks/SM_rock1",
|
||||
"location": [-1500.0, -600.0, 0.0],
|
||||
"snap_to_terrain": true,
|
||||
"rotation": [0.0, 0.0, 0.0],
|
||||
|
||||
Reference in new issue
Block a user