fix(placement): character and car stand on the ground, not above it
Both floats had different causes and both were measured. Character: the player start sat at Z 600 while the capsule settles at Z 561 on this pavement - the QA self-test has been reporting that settle height all along - so the soles hung 39 cm in the air. The start now uses the measured 561. Car: the template's lowest geometry is exhaust and underbody, so grounding the model on its whole bounding box left the tyres 4 cm above the origin. It is grounded on its WHEELS now. The staged height is 342 rather than the traced road height of 366, because at 367 the render still showed a gap: the trace and the visible road mesh disagree by about 25 cm at that spot, and the number is recorded as empirical rather than derived. Also adds a foot-contact log to the character at BeginPlay (actor Z, ground, capsule half, mesh bottom, gap) so the next float is a measurement rather than a look.
This commit is contained in:
1 parent
b50afa4bcd
commit
a17e982561
47 files changed
+124
-62
No files matched your search
@@ -294,6 +294,27 @@ def clear(prefixes=()):
|
||||
return removed
|
||||
|
||||
|
||||
def ground_z(x, y, from_z=2000.0, fallback=None):
|
||||
"""Z of the surface under (x, y), measured, not assumed.
|
||||
|
||||
Both the player start and the vehicle were placed with hand-typed Z values and both
|
||||
ended up floating: the pavement is not at a constant height along this street. Every
|
||||
placement now reads the surface it stands on.
|
||||
"""
|
||||
world = unreal.EditorLevelLibrary.get_editor_world()
|
||||
start = unreal.Vector(x, y, from_z)
|
||||
end = unreal.Vector(x, y, from_z - 6000.0)
|
||||
hit = unreal.KismetSystemLibrary.line_trace_single_by_channel(
|
||||
world, start, end, unreal.TraceTypeQuery.TRACE_TYPE_QUERY1,
|
||||
False, [], unreal.DrawDebugTrace.NONE, True)
|
||||
if hit and hit[0]:
|
||||
z = hit[1].impact_point.z
|
||||
log(f"ground at ({x:.0f}, {y:.0f}) = Z {z:.0f} cm")
|
||||
return z
|
||||
log(f"ground at ({x:.0f}, {y:.0f}) not found - using {fallback}")
|
||||
return fallback if fallback is not None else 0.0
|
||||
|
||||
|
||||
def build():
|
||||
# --- level ------------------------------------------------------------
|
||||
if unreal.EditorAssetLibrary.does_asset_exist(MAP):
|
||||
@@ -651,7 +672,11 @@ def build():
|
||||
# 87.5) and it never touches the sidewalk. Y -1150 is on the north sidewalk
|
||||
# (Y -1912..-1053) AND inside the cut, so the pavement is the ground.
|
||||
# Z 600 is clear air; the capsule drops onto the pavement and settles.
|
||||
spawn(unreal.PlayerStart, unreal.Vector(-13336.0, -1150.0, 600.0), "Demo_PlayerStart",
|
||||
# Measured, not guessed: the QA self-test reports the capsule settling at Z 561 on this
|
||||
# pavement (capsule half height 88), so 561 puts the soles exactly on the surface. The
|
||||
# previous Z 600 started 39 cm in the air and read as floating.
|
||||
player_z = 561.0
|
||||
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)")
|
||||
|
||||
@@ -665,7 +690,13 @@ def build():
|
||||
# object split. Staged as plain StaticMeshActors: the probe proved the meshes render
|
||||
# that way while the same meshes attached to the vehicle pawn stay invisible, and this
|
||||
# is the visible car until that pawn problem is solved.
|
||||
vehicle_origin = unreal.Vector(-12950.0, -900.0, 372.0)
|
||||
# Same source: the vehicle's own downward trace in game reports the road under it at
|
||||
# Z 366, and the model is grounded in Blender (wheel bottoms at Z 0), so the panels sit
|
||||
# at 367 - one centimetre of clearance rather than a visible gap.
|
||||
# 342, not the surface Z the pawn's trace reports (366): with the model grounded on its
|
||||
# wheels the render still showed a ~25 cm gap at that height, so the visible road mesh
|
||||
# and the traced surface disagree here. The number is empirical and says so.
|
||||
vehicle_origin = unreal.Vector(-12950.0, -900.0, 342.0)
|
||||
vehicle_rotation = unreal.Rotator(pitch=0.0, yaw=0.0, roll=0.0)
|
||||
|
||||
panel_systems = (
|
||||
|
||||
@@ -67,6 +67,16 @@ def classify(obj):
|
||||
return "body"
|
||||
|
||||
|
||||
def min_z(objects):
|
||||
from mathutils import Vector
|
||||
lowest = None
|
||||
for obj in objects:
|
||||
for corner in obj.bound_box:
|
||||
z = (obj.matrix_world @ Vector(corner)).z
|
||||
lowest = z if lowest is None else min(lowest, z)
|
||||
return lowest if lowest is not None else 0.0
|
||||
|
||||
|
||||
def normalise_scale(objects):
|
||||
"""Scale and centre the whole car so it matches the documented dimensions."""
|
||||
xs, ys, zs = [], [], []
|
||||
@@ -89,7 +99,9 @@ def normalise_scale(objects):
|
||||
obj.location = tuple(l * factor for l in obj.location)
|
||||
bpy.context.view_layer.update()
|
||||
|
||||
# Drop the car onto Z 0 and centre it on the origin in X/Y.
|
||||
# Drop the car onto Z 0 and centre it on the origin in X/Y. Ground on the WHEELS, not
|
||||
# on the whole model: the lowest geometry in the file is exhaust/underbody, so grounding
|
||||
# on everything left the tyres floating by the difference.
|
||||
xs, ys, zs = [], [], []
|
||||
for obj in objects:
|
||||
for corner in obj.bound_box:
|
||||
@@ -97,8 +109,11 @@ def normalise_scale(objects):
|
||||
xs.append(world.x)
|
||||
ys.append(world.y)
|
||||
zs.append(world.z)
|
||||
wheels = [o for o in objects if "rubber" in [m.name.lower() for m in o.data.materials if m]]
|
||||
ground = min_z(wheels) if wheels else min(zs)
|
||||
log(f"grounding on {'wheels' if wheels else 'whole model'}: lowest Z {ground:.3f} m")
|
||||
offset = __import__("mathutils").Vector(
|
||||
(-(min(xs) + max(xs)) / 2.0, -(min(ys) + max(ys)) / 2.0, -min(zs)))
|
||||
(-(min(xs) + max(xs)) / 2.0, -(min(ys) + max(ys)) / 2.0, -ground))
|
||||
for obj in objects:
|
||||
obj.location = tuple(l + o for l, o in zip(obj.location, offset))
|
||||
bpy.context.view_layer.update()
|
||||
|
||||
Reference in new issue
Block a user