gameplay: designated street crossing — zebra markings, corridor cut, up-facing street
- street_mesh.py: continental zebra markings (0.5 m bars, 0.5 m gaps, 3 m band) at all three signalised crossings, triangles not quads (FBX SDK refuses to triangulate the crown-twisted quads), stripes +6 cm above the DEM so they stay above the road surface; winding flipped so every street surface faces up (road/sidewalks/markings were 100% down-facing and invisible in engine once the terrain stopped covering them). - terrain_from_dem.py: cut a 10.7 m corridor around the Hollywood Blvd centreline so road, kerbs and sidewalks are not buried under the terrain; sidewalks themselves cover the transition band, walk-check stays at 0 holes. - Blender builders save with a writability guard + fatal failure: *.blend is LFS-lockable and checks out read-only; a failed save previously left downstream steps building from stale files. - ue_import_site.py: Crossing_Markings imports with no collision (paint on the road); ue_build_demo_map.py stages it and chmods the lockable .umap before saving (save_map silently returned False on read-only maps). - ue_build_review_map.py: demo-crossing camera moved to the real crossing (s=130.1 m -> UE -24291,-1340) and fixed the ensure_writable path (was missing the .umap suffix, so the chmod never fired).
This commit is contained in:
1 parent
985dfcbac7
commit
bc2e421d33
20 files changed
+133
-36
No files matched your search
Binary file not shown.
@@ -148,7 +148,10 @@ def strip(rows, offsets, z_at, name, material):
|
||||
for r in range(len(rows) - 1):
|
||||
for c in range(cols - 1):
|
||||
i = r * cols + c
|
||||
faces.append((i, i + 1, i + cols + 1, i + cols))
|
||||
# Winding faces up: the natural (i, i+1, i+cols+1, i+cols) order
|
||||
# produces downward normals (every surface faced the ground and was
|
||||
# invisible in engine until the terrain corridor cut exposed it).
|
||||
faces.append((i, i + cols, i + cols + 1, i + 1))
|
||||
mesh = bpy.data.meshes.new(name)
|
||||
mesh.from_pydata(verts, [], faces)
|
||||
mesh.update()
|
||||
@@ -239,7 +242,7 @@ def main():
|
||||
verts.extend([(x, y, z_road), (x, y, z_walk)])
|
||||
for idx in range(len(rows) - 1):
|
||||
i = idx * 2
|
||||
faces.append((i, i + 2, i + 3, i + 1))
|
||||
faces.append((i, i + 1, i + 3, i + 2))
|
||||
mesh = bpy.data.meshes.new(name)
|
||||
mesh.from_pydata(verts, [], faces)
|
||||
mesh.update()
|
||||
@@ -259,24 +262,34 @@ def main():
|
||||
paint.diffuse_color = (0.85, 0.85, 0.85, 1.0)
|
||||
|
||||
def crossing_band(s_c):
|
||||
# Stripes are emitted as two triangles each: the road crown makes the
|
||||
# quad non-planar and the FBX SDK refuses to triangulate it on import
|
||||
# ("unable to triangulate mesh" — the mesh is omitted entirely).
|
||||
zone = 3.0 # band length along the road, m
|
||||
w, g = 0.5, 0.5 # stripe width / gap, m
|
||||
span = (SOUTH_GUTTER + 0.2, NORTH_GUTTER - 0.2)
|
||||
verts, faces = [], []
|
||||
n = int(zone // (w + g))
|
||||
covered = n * w + (n - 1) * g # actual stripe coverage, centred on s_c
|
||||
for k in range(n):
|
||||
s0 = s_c - zone / 2 + k * (w + g)
|
||||
s0 = s_c - covered / 2 + k * (w + g)
|
||||
corners = []
|
||||
base_idx = len(verts) # verts grows only after the stripe is sampled
|
||||
for s_edge in (s0, s0 + w):
|
||||
base, normal, _ = at(s_edge)
|
||||
for off in span:
|
||||
x = base[0] + off * normal[0]
|
||||
y = base[1] + off * normal[1]
|
||||
corners.append((len(verts), (x, y, (dem_z(x, y) or 0.0) + 0.03)))
|
||||
# +6 cm above the DEM = 4 cm above the road surface: the road
|
||||
# interpolates the DEM along 1 m rows while the markings sample
|
||||
# only their own corners, so a 1 cm lift left parts of the
|
||||
# stripes sunk under the road and invisible in game.
|
||||
corners.append((base_idx + len(corners), (x, y, (dem_z(x, y) or 0.0) + 0.06)))
|
||||
# corners order: (s0,off_s), (s0,off_n), (s1,off_s), (s1,off_n)
|
||||
idx = [c[0] for c in corners]
|
||||
verts.extend(c[1] for c in corners)
|
||||
faces.append((idx[0], idx[1], idx[3], idx[2]))
|
||||
faces.append((idx[0], idx[3], idx[1]))
|
||||
faces.append((idx[0], idx[2], idx[3]))
|
||||
mesh = bpy.data.meshes.new("Crossing_Markings")
|
||||
mesh.from_pydata(verts, [], faces)
|
||||
mesh.update()
|
||||
@@ -303,7 +316,14 @@ def main():
|
||||
|
||||
out = os.path.abspath(args.out)
|
||||
os.makedirs(os.path.dirname(out), exist_ok=True)
|
||||
bpy.ops.wm.save_as_mainfile(filepath=out)
|
||||
# *.blend is LFS-lockable, so a fresh checkout marks it read-only. Make it
|
||||
# writable again or the save fails and downstream steps build from a stale
|
||||
# file — which is worse than failing here.
|
||||
if os.path.exists(out) and not os.access(out, os.W_OK):
|
||||
os.chmod(out, 0o644)
|
||||
result = bpy.ops.wm.save_as_mainfile(filepath=out)
|
||||
if result != {"FINISHED"}:
|
||||
raise RuntimeError(f"could not save {out}: {result}")
|
||||
print(f"saved {out}")
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user