diff --git a/Art/blender/street/street-2026-11-06.blend b/Art/blender/street/street-2026-11-06.blend index 47871e3..f186e53 100644 --- a/Art/blender/street/street-2026-11-06.blend +++ b/Art/blender/street/street-2026-11-06.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b675a61e3f6d2d97d77383ff2edc522886bbee9fbb84a3ebccdce2e69ba1ba08 -size 510663 +oid sha256:8ae571a174d7c07f01ebd90d60ef4c3ffaacc11d0fc8476c6d85eb00acb8fbbd +size 512324 diff --git a/Art/blender/street/street_mesh.py b/Art/blender/street/street_mesh.py index db900e1..cdd99e9 100644 --- a/Art/blender/street/street_mesh.py +++ b/Art/blender/street/street_mesh.py @@ -18,6 +18,10 @@ Geometry follows the measured profile rather than a guess: kerb (see `Geo/verification/2026-11-06-cross-sections.md`); * kerbs are flushed to 0.02 m within ±2.5 m of each signalised crossing, with a 1.5 m blend, so the crossings are actually usable on foot; +* each signalised crossing gets continental zebra markings — 0.5 m white bars + with 0.5 m gaps across a 3 m band, laid 1 cm above the road surface — so the + mid-block crossing (OSM way 385648319, s ≈ 130 m) reads as a designated + crossing in game; * sidewalk widths 4.0 m south and 5.3 m north, from the DEM-derived setback arithmetic; * the DEM supplies every elevation, so the 3.4 m fall and the ~2 % crown come @@ -247,6 +251,44 @@ def main(): kerb_faces(SOUTH_GUTTER, "Kerb_South") kerb_faces(NORTH_GUTTER, "Kerb_North") + # Continental zebra markings: one band per signalised crossing. Bars run + # along the road (traffic direction), side by side across the carriageway; + # a pedestrian crosses perpendicular to them. Lifted 1 cm above the road + # surface (which is itself 2 cm above the DEM) to avoid z-fighting. + paint = bpy.data.materials.new("Road_Paint_White") + paint.diffuse_color = (0.85, 0.85, 0.85, 1.0) + + def crossing_band(s_c): + 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)) + for k in range(n): + s0 = s_c - zone / 2 + k * (w + g) + corners = [] + 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))) + # 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])) + mesh = bpy.data.meshes.new("Crossing_Markings") + mesh.from_pydata(verts, [], faces) + mesh.update() + mesh.materials.append(paint) + obj = bpy.data.objects.new("Crossing_Markings", mesh) + bpy.context.scene.collection.objects.link(obj) + return obj + + for s_c in CROSSINGS: + band = crossing_band(s_c) + print(f"crossing band at s={s_c:.1f}: {len(band.data.polygons)} stripes") + for obj in (road, sw_s, sw_n): print(f"{obj.name:16} verts {len(obj.data.vertices):5} faces {len(obj.data.polygons):5}")