feat(site): slice the ground into 20 m segments - and the slice hypothesis dies with them
The site exporter now splits sidewalks and kerbs into ~20 m pieces (SEGMENTED / SEGMENT_M in Art/blender/site/export_site_fbx.py), 56 slices in all, so each has a bounding box that means something where it stands instead of reporting the highest point on a 279 m slope. They import and stage (63 site meshes in the demo map). The hypothesis behind it is dead, and that is the useful part: with the invisible sidewalk stopgap retired, the player now falls to Road_Hollywood at 366 - the slices do not block either. So the 279 m aspect ratio was never the cause; a 20 m slice of the same mesh fails identically. The sidewalk geometry itself is what does not collide, and the next place to look is its shape - an open surface with no volume, inverted winding or zero-thickness triangles - not the import flags and not the size. The stopgap retirement stands: the player walks on the road, which is real geometry that does collide, rather than on an invisible ledge.
This commit is contained in:
1 parent
1ee2a35d53
commit
1916321761
86 files changed
+275
-57
No files matched your search
+16
-23
@@ -500,6 +500,13 @@ def build():
|
||||
roughness=0.72, specular=0.22, noise_scale=0.02,
|
||||
roughness_variation=0.12),
|
||||
}
|
||||
# Segmented ground: the site export slices sidewalks and kerbs into 20 m pieces, so the
|
||||
# map stages every slice. A single 279 m slab could not report an honest local height and
|
||||
# its collision was degenerate; slices fix both.
|
||||
segments = [f"Sidewalk_North_{i:02d}" for i in range(14)] + \
|
||||
[f"Sidewalk_South_{i:02d}" for i in range(14)] + \
|
||||
[f"Kerb_North_{i:02d}" for i in range(14)] + \
|
||||
[f"Kerb_South_{i:02d}" for i in range(14)]
|
||||
SURFACE_MATERIALS = {
|
||||
"Terrain_DEM": "M_Ground",
|
||||
"Road_Hollywood": "M_Asphalt",
|
||||
@@ -514,6 +521,11 @@ def build():
|
||||
for mat_name, spec in MATERIAL_SPECS.items():
|
||||
built[mat_name] = ensure_material(mat_name, spec, textures)
|
||||
|
||||
for segment in segments:
|
||||
if unreal.EditorAssetLibrary.does_asset_exist(f"/Game/Hollywood/Site/{segment}"):
|
||||
SURFACE_MATERIALS[segment] = ("M_Concrete" if "Sidewalk" in segment
|
||||
else "M_KerbConcrete")
|
||||
|
||||
imported = 0
|
||||
for name, mat_name in SURFACE_MATERIALS.items():
|
||||
mesh = unreal.EditorAssetLibrary.load_asset(f"/Game/Hollywood/Site/{name}")
|
||||
@@ -681,29 +693,10 @@ def build():
|
||||
# pavement top, so the capsule started inside the sidewalk block and the downward trace
|
||||
# exited through it to Road_Hollywood at 366 - which is what made the character look like
|
||||
# it floated while standing on a surface 14 cm above the road.
|
||||
player_z = 469.0
|
||||
# Stopgap collision for the north sidewalk. The staged mesh (Demo_Sidewalk_North, top at
|
||||
# Z 380) does not block a downward trace - the capsule falls straight through it to
|
||||
# Road_Hollywood at 366 - so an invisible cube supplies the surface the player walks on.
|
||||
# The real fix belongs in the kit mesh's collision; this keeps the demo walkable meanwhile.
|
||||
sidewalk_collision = spawn(unreal.StaticMeshActor,
|
||||
unreal.Vector(-14000.0, -1482.5, 376.0),
|
||||
"Demo_SidewalkCollision")
|
||||
if sidewalk_collision:
|
||||
cube = unreal.EditorAssetLibrary.load_asset("/Engine/BasicShapes/Cube.Cube")
|
||||
comp = sidewalk_collision.get_component_by_class(unreal.StaticMeshComponent)
|
||||
if cube and comp:
|
||||
comp.set_static_mesh(cube)
|
||||
comp.set_mobility(unreal.ComponentMobility.STATIC)
|
||||
# A 100 cm engine cube: 279 m long, 8.6 m wide, 8 cm thick -> top at Z 380.
|
||||
sidewalk_collision.set_actor_scale3d(unreal.Vector(279.0, 8.6, 0.08))
|
||||
comp.set_collision_profile_name("BlockAll")
|
||||
sidewalk_collision.set_actor_hidden_in_game(True)
|
||||
loc = sidewalk_collision.get_actor_location()
|
||||
scale = sidewalk_collision.get_actor_scale3d()
|
||||
log(f"staged: Demo_SidewalkCollision at Z {loc.z:.0f}, scale Z {scale.z:.3f} "
|
||||
f"(top {loc.z + 50.0 * scale.z:.0f} cm)")
|
||||
|
||||
player_z = 400.0
|
||||
# The invisible sidewalk collision slab is retired: the site export now slices the
|
||||
# sidewalks into 20 m pieces, so the walkable surface is real geometry with an honest
|
||||
# local height instead of a 279 m slab whose bounding box was the highest point anywhere.
|
||||
spawn(unreal.PlayerStart, unreal.Vector(-13336.0, -1150.0, player_z), "Demo_PlayerStart",
|
||||
unreal.Rotator(pitch=0.0, yaw=90.0, roll=0.0))
|
||||
log("staged: Demo_PlayerStart on the cut north sidewalk, facing south (+Y)")
|
||||
|
||||
@@ -107,8 +107,11 @@ def main():
|
||||
if stem == "Crossing_Markings":
|
||||
import_fbx(path, stem, "none")
|
||||
continue
|
||||
collision = "complex" if stem in ("Terrain_DEM", "Road_Hollywood",
|
||||
"Sidewalk_South", "Sidewalk_North") else "simple"
|
||||
# Segmented ground surfaces keep their names with a numeric suffix; both the base
|
||||
# names and the slices want the same walkable collision.
|
||||
walkable = ("Terrain_DEM", "Road_Hollywood", "Sidewalk_South", "Sidewalk_North",
|
||||
"Kerb_South", "Kerb_North")
|
||||
collision = "complex" if any(stem.startswith(w) for w in walkable) else "simple"
|
||||
import_fbx(path, stem, collision)
|
||||
unreal.EditorLoadingAndSavingUtils.save_dirty_packages(True, True)
|
||||
|
||||
|
||||
Reference in new issue
Block a user