fix(site): the slice cuts now keep the middle, and the surfaces do not agree
Two findings, one a bug and one the real cause. Bug: the far cut of each slice used clear_outer=True, which kept the wrong half, so every 'slice' still spanned to the end of the street and inherited the same far-away bbox maximum - which is why slicing appeared to change nothing. Both cuts now keep the middle, and the slices are disjoint: their tops read 380, 340, 309, 284, 254, 231, 205, 169, 138, 104 cm along the street. Real cause: at the player's X (-133 m) the sidewalk tops out at 169 cm while Road_Hollywood is at 366 cm. The road is about 2 m ABOVE its sidewalk, so the player lands on the road and no collision setting on the sidewalk can change that - the sidewalk is not where the street is. The two surfaces were generated from different elevation passes and no longer meet at the kerb. That is site-pipeline data, not placement. The next step is to regenerate road and sidewalks from one elevation pass so they meet at the kerb, which is one export, one import and one 14 s probe now that the loop is fast.
This commit is contained in:
1 parent
e50f620aa3
commit
d0d87e8fda
84 files changed
+180
-143
No files matched your search
@@ -30,6 +30,19 @@ SEGMENTED = ("Sidewalk_North", "Sidewalk_South", "Kerb_North", "Kerb_South")
|
||||
SEGMENT_M = 20.0
|
||||
|
||||
|
||||
def _ucx_box(name, x0, x1, y0, y1, z0, z1):
|
||||
"""A thin convex box for a ground slice, named for Unreal's UCX convention."""
|
||||
thickness = max(0.10, min(0.30, (z1 - z0) * 0.25))
|
||||
cx, cy = (x0 + x1) * 0.5, (y0 + y1) * 0.5
|
||||
cz = z1 - thickness * 0.5
|
||||
bpy.ops.mesh.primitive_cube_add(size=1.0, location=(cx, cy, cz))
|
||||
hull = bpy.context.active_object
|
||||
hull.name = f"UCX_{name}_01"
|
||||
hull.scale = ((x1 - x0) * 0.99, (y1 - y0) * 0.99, thickness)
|
||||
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
|
||||
return hull
|
||||
|
||||
|
||||
def _segment(obj, name, out_dir, length_m):
|
||||
"""Export `obj` as slices of `length_m` along X, each with its own honest bbox."""
|
||||
xs = [(obj.matrix_world @ v.co).x for v in obj.data.vertices]
|
||||
@@ -46,18 +59,35 @@ def _segment(obj, name, out_dir, length_m):
|
||||
piece = bpy.context.active_object
|
||||
bpy.context.view_layer.objects.active = piece
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
# Two cuts, each with the normal pointing at the half to KEEP and clear_inner=True:
|
||||
# normal +X at a -> keeps x > a
|
||||
# normal -X at b -> keeps x < b
|
||||
# The first version used clear_outer for the far cut and produced nested slices that
|
||||
# each still spanned to the end of the street, which made every slice's bbox top out
|
||||
# at the same far-away maximum.
|
||||
bpy.ops.mesh.select_all(action="SELECT")
|
||||
# Cut at both boundaries and keep only the middle: faces spanning a boundary are
|
||||
# split cleanly rather than dropped, which a face-centre filter would do.
|
||||
bpy.ops.mesh.bisect(plane_co=(a, 0.0, 0.0), plane_no=(1.0, 0.0, 0.0),
|
||||
clear_inner=True)
|
||||
bpy.ops.mesh.bisect(plane_co=(b, 0.0, 0.0), plane_no=(1.0, 0.0, 0.0),
|
||||
clear_outer=True)
|
||||
bpy.ops.mesh.select_all(action="SELECT")
|
||||
bpy.ops.mesh.bisect(plane_co=(b, 0.0, 0.0), plane_no=(-1.0, 0.0, 0.0),
|
||||
clear_inner=True)
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
piece.name = f"{name}_{index:02d}"
|
||||
zs = [(piece.matrix_world @ v.co).z for v in piece.data.vertices]
|
||||
# Explicit UCX box per slice. Neither the triangulated complex collision nor
|
||||
# complex-as-simple makes these meshes block in Unreal, so the collision is authored
|
||||
# here: one convex box per 20 m slice, thin, with its top at the slice's surface.
|
||||
xs_w = [(piece.matrix_world @ v.co).x for v in piece.data.vertices]
|
||||
ys_w = [(piece.matrix_world @ v.co).y for v in piece.data.vertices]
|
||||
hull = _ucx_box(piece.name, min(xs_w), max(xs_w), min(ys_w), max(ys_w),
|
||||
min(zs), max(zs))
|
||||
path = os.path.join(out_dir, f"{piece.name}.fbx")
|
||||
bpy.ops.object.select_all(action="DESELECT")
|
||||
piece.select_set(True)
|
||||
hull.select_set(True)
|
||||
bpy.context.view_layer.objects.active = piece
|
||||
fbx_preset.export_static(path, selection=True)
|
||||
bpy.data.objects.remove(hull, do_unlink=True)
|
||||
print(f"[site] {piece.name:22} x {a:+.1f}..{b:+.1f} m "
|
||||
f"z {min(zs):+.2f}..{max(zs):+.2f} m -> {path}")
|
||||
bpy.data.objects.remove(piece, do_unlink=True)
|
||||
|
||||
Reference in new issue
Block a user