2 Commits
Author SHA1 Message Date
zwitschi 6a778dbc63 release: v0.1.1 — changelog entry, TODO pruning (#22)
Merged PR #22: v0.1.1 release prep

Co-authored-by: Zwitschi <zwitschi82@gmail.com>
2026-11-08 16:19:30 +01:00
zwitschi e75e5500a7 fix(street): 0.1.1 collision patch — flush sidewalk edge, graded crossing ramps (#21)
Merged PR #21: 0.1.1 collision patch (flush sidewalk edge, graded ramps)

Co-authored-by: Zwitschi <zwitschi82@gmail.com>
2026-11-08 16:19:11 +01:00
40 changed files with 222 additions and 92 deletions

No files matched your search

+25 -6
View File
@@ -80,7 +80,10 @@ LD_LIBRARY_PATH="$B/blender/lib" "$B/blender/blender" -b --factory-startup \
``` ```
- `Road_Hollywood`: 8 120 verts, 7 812 faces, carriageway −10.5…+10.5 m, DEM elevations plus a 2 cm lift so it does not z-fight the terrain. - `Road_Hollywood`: 8 120 verts, 7 812 faces, carriageway −10.5…+10.5 m, DEM elevations plus a 2 cm lift so it does not z-fight the terrain.
- `Sidewalk_South` 4.0 m wide, `Sidewalk_North` 5.3 m wide, both raised by the kerb height. - `Sidewalk_South` 4.0 m wide, `Sidewalk_North` 5.3 m wide. The kerb upstand is
**full at the road-side edge and tapers to zero at the building-side edge**, so
the walk surface meets the terrain flush (before `0.1.1` the outer lip stood the
full kerb height above the DEM — a 15.8 cm ledge).
- `Kerb_South`, `Kerb_North`: vertical faces, mostly **0.13 m** — the 0.15 m assumption minus nothing on the road side — and flushed to 0 within ±2.5 m of each signalised crossing with a 1.5 m blend. Measured from the built mesh: 256 steps at 0.13 m, 15 flush, a few in transition. - `Kerb_South`, `Kerb_North`: vertical faces, mostly **0.13 m** — the 0.15 m assumption minus nothing on the road side — and flushed to 0 within ±2.5 m of each signalised crossing with a 1.5 m blend. Measured from the built mesh: 256 steps at 0.13 m, 15 flush, a few in transition.
Crown check on the built mesh at mid-block: gutter −10.5 m → +0.99, −5 m → +1.38, centre → +1.52, +5 m → +1.58, +10.5 m → +1.52. The crown sits just north of the centreline, as the cross-sections said. Crown check on the built mesh at mid-block: gutter −10.5 m → +0.99, −5 m → +1.38, centre → +1.52, +5 m → +1.58, +10.5 m → +1.52. The crown sits just north of the centreline, as the cross-sections said.
@@ -105,14 +108,30 @@ A downward raycast on a 1 m grid along both sidewalks and the designated crossin
| Route | Samples | Holes | Z range | Worst step | | Route | Samples | Holes | Z range | Worst step |
| ----------------- | ------: | ----: | ------------- | ---------: | | ----------------- | ------: | ----: | ------------- | ---------: |
| South sidewalk | 279 | 0 | −0.45 … +3.13 | 20.5 cm | | South sidewalk | 279 | 0 | −0.48 … +3.06 | 13.4 cm (s=198) |
| North sidewalk | 279 | 0 | +0.07 … +3.83 | 15.1 cm | | North sidewalk | 279 | 0 | +0.06 … +3.76 | 6.9 cm (s=33) |
| Crossing at 130 m | 26 | 0 | +1.16 … +1.80 | 8.6 cm | | Crossing at 130 m | 26 | 0 | +1.14 … +1.80 | 9.0 cm (off −8.5) |
At `--sample 0.25` the same routes measure 11.6 cm / 8.0 cm / 3.4 cm. The
pre-check now prints the grade and the **location** of the worst step, and its
coverage no longer shrinks with `--sample`.
No holes anywhere, so nothing drops the player on either side. The two flagged steps: No holes anywhere, so nothing drops the player on either side. The two flagged steps:
- **15.8 cm at s≈207**, where a sample crosses from `Terrain_DEM` onto `Sidewalk_South` — that is the sidewalk's outer edge, the 0.15 m kerb height minus the terrain. Mostly hidden by buildings, but it is a real edge and it will be visible anywhere a building is missing. - ~~15.8 cm at s≈207, the sidewalk's outer edge~~ — **fixed in `0.1.1`**: the
- **10–13 cm steps at s≈33, 39 and 126**, inside the sidewalk mesh: the kerb-flush transition at the crossings. That is a ~10 % ramp over 1.5 m, steeper than a real crossing ramp (8 % max). Worth grading properly when the crossings are detailed. sidewalk upstand now tapers to zero at the building side, so the outer edge is
flush with the terrain (north route 15.1 → 6.9 cm).
- ~~10–13 cm steps at the crossings, ~10 % ramp over 1.5 m~~ — **fixed in `0.1.1`**:
the ramp run is now derived from a target grade (`--max-ramp-grade`, default 8 %),
giving 1.63 m instead of the fixed 1.5 m (8.7 %). Measured at 0.25 m sampling the
crossing now steps 3.4 cm (~1.4 % of the route) at the kerb line.
**Remaining finding (not a crossing, not the outer edge):** the south route still
measures a **13.4 cm step at s≈198 m** (11.6 cm at 0.25 m sampling) and the north
route 8.0 cm at s≈251 m. Neither is at a crossing and neither is the outer lip, so
this is a local discontinuity in the sidewalk strip — most likely the DEM sampling
or a centreline vertex near the block ends. Tracked under the `0.1.1` "audit any
collision gaps" item rather than left undocumented.
This is a pre-check, not the `0.1.0` release check: the release check is traversal in the engine. This is a pre-check, not the `0.1.0` release check: the release check is traversal in the engine.
Binary file not shown.
+20 -6
View File
@@ -165,10 +165,16 @@ def main():
def lat_lon(s, offset): def lat_lon(s, offset):
return oc.point_at(line, _lengths, s, offset, lat0, lon0) return oc.point_at(line, _lengths, s, offset, lat0, lon0)
# Sample spacing is independent of coverage: walk the whole block at
# `--sample` metres, so a finer spacing measures the gradient instead of
# accidentally shortening the route (previously range(int(block_len)) with a
# 0.25 m spacing only covered a quarter of the block).
along = int(block_len / args.sample)
across = int(26.0 / args.sample)
route_specs = { route_specs = {
"south sidewalk": [(s, -12.5) for s in [i * args.sample for i in range(int(block_len))]], "south sidewalk": [(i * args.sample, -12.5) for i in range(along)],
"north sidewalk": [(s, 13.0) for s in [i * args.sample for i in range(int(block_len))]], "north sidewalk": [(i * args.sample, 13.0) for i in range(along)],
"crossing at 130 m": [(130.0, o) for o in [i * args.sample - 12.5 for i in range(26)]], "crossing at 130 m": [(130.0, i * args.sample - 12.5) for i in range(across)],
} }
flat = [(spec, lat_lon(s, off)) for spec, samples in route_specs.items() for s, off in samples] flat = [(spec, lat_lon(s, off)) for spec, samples in route_specs.items() for s, off in samples]
local = project_to_local([ll for _spec, ll in flat], find_proj()) local = project_to_local([ll for _spec, ll in flat], find_proj())
@@ -185,12 +191,20 @@ def main():
heights.append(None) heights.append(None)
else: else:
heights.append(z) heights.append(z)
deltas = [abs(b - a) for a, b in zip(heights, heights[1:]) deltas = [(i, abs(b - a)) for i, (a, b) in enumerate(zip(heights, heights[1:]))
if a is not None and b is not None] if a is not None and b is not None]
max_step = max(deltas) if deltas else float("nan") worst_i, max_step = (max(deltas, key=lambda t: t[1]) if deltas else (0, float("nan")))
known = [h for h in heights if h is not None] known = [h for h in heights if h is not None]
grade = (max_step / args.sample) * 100 if deltas else float("nan")
# Position of the worst step, as arc length / cross offset, so the cause
# can be located instead of guessed.
if label == "crossing at 130 m":
where = f"s=130 off={(worst_i * args.sample - 12.5):+.2f} m"
else:
where = f"s={worst_i * args.sample:.1f} m"
print(f" {label:18} samples {len(heights):3} holes {holes} " print(f" {label:18} samples {len(heights):3} holes {holes} "
f"Z {min(known):+.2f}..{max(known):+.2f} max step {max_step*100:.1f} cm") f"Z {min(known):+.2f}..{max(known):+.2f} max step {max_step*100:.1f} cm "
f"({grade:.1f} % grade) at {where}")
out = os.path.abspath(args.out) out = os.path.abspath(args.out)
os.makedirs(os.path.dirname(out), exist_ok=True) os.makedirs(os.path.dirname(out), exist_ok=True)
Binary file not shown.
+51 -6
View File
@@ -68,8 +68,13 @@ def parse_args():
ap.add_argument("--cross", type=float, default=0.75) ap.add_argument("--cross", type=float, default=0.75)
ap.add_argument("--kerb", type=float, default=0.15) ap.add_argument("--kerb", type=float, default=0.15)
ap.add_argument("--ramp-half-width", type=float, default=2.5) ap.add_argument("--ramp-half-width", type=float, default=2.5)
ap.add_argument("--ramp-blend", type=float, default=1.5) ap.add_argument("--ramp-blend", type=float, default=None,
return ap.parse_args(argv) help="override the ramp run; default derives it from --max-ramp-grade")
ap.add_argument("--max-ramp-grade", type=float, default=0.08,
help="maximum crossing-ramp slope (0.08 = 8%%)")
args = ap.parse_args(argv)
args.ramp_blend = ramp_blend(args.kerb, args.max_ramp_grade, args.ramp_blend)
return args
def find_proj(): def find_proj():
@@ -125,7 +130,13 @@ class Dem:
def kerb_height(s, base, half_width, blend): def kerb_height(s, base, half_width, blend):
"""Full kerb, except flushed near a crossing so people can step off.""" """Full kerb, except flushed near a crossing so people can step off.
`blend` is the horizontal run over which the kerb drops from `base` to the
0.02 m flush height. It is derived from a target maximum grade (see
`ramp_blend`) so the crossing ramps stay within a real ramp's slope instead
of the ~8.7 % the old fixed 1.5 m run produced.
"""
for crossing in CROSSINGS: for crossing in CROSSINGS:
d = abs(s - crossing) d = abs(s - crossing)
if d <= half_width: if d <= half_width:
@@ -136,6 +147,22 @@ def kerb_height(s, base, half_width, blend):
return base return base
def ramp_blend(kerb, max_grade, override=None):
"""Horizontal run needed for the kerb ramp to stay at or under max_grade.
0.15 m kerb at an 8 % grade needs 1.63 m of run; the previous fixed 1.5 m
gave 8.7 %, and the walk pre-check measured the transition as a 10-13 cm
step over 1.5 m. When `override` is given it wins (kept for reproducing old
meshes), otherwise the run is computed from the live kerb height so it stays
correct if the kerb height assumption changes.
"""
if override is not None:
return max(0.0, override)
if max_grade <= 0.0:
return 0.0
return max(0.0, (kerb - 0.02)) / max_grade
def strip(rows, offsets, z_at, name, material): def strip(rows, offsets, z_at, name, material):
"""Build a quad grid from per-row sampled vertices.""" """Build a quad grid from per-row sampled vertices."""
verts, faces = [], [] verts, faces = [], []
@@ -218,13 +245,31 @@ def main():
z = dem_z(x, y) z = dem_z(x, y)
return (z if z is not None else 0.0) + 0.02 return (z if z is not None else 0.0) + 0.02
def south_z(r, off, x, y): def sidewalk_z(r, off, inner, outer, x, y):
"""Sidewalk surface: full kerb upstand at the road-side (inner) edge,
tapering to zero at the building-side (outer) edge so the walk surface
meets the terrain flush.
Before this taper the outer lip stood the full kerb height above the DEM,
which the walkability pre-check measured as a 15.8 cm step where a sample
crosses from Terrain_DEM onto Sidewalk_South (with a matching lip on the
north side). A 0.15 m lip over a 4.0 m / 5.3 m strip is a ~3-4 % ramp:
walkable and visually negligible, and it removes the ledge entirely.
"""
z = dem_z(x, y) z = dem_z(x, y)
base = z if z is not None else 0.0 base = z if z is not None else 0.0
return base + kerb_height(rows[r][0], args.kerb, args.ramp_half_width, args.ramp_blend) h = kerb_height(rows[r][0], args.kerb, args.ramp_half_width, args.ramp_blend)
span = inner - outer
if abs(span) < 1e-9:
return base + h
t = min(1.0, max(0.0, (off - outer) / span))
return base + h * t
def south_z(r, off, x, y):
return sidewalk_z(r, off, SOUTH_GUTTER, SOUTH_SIDEWALK, x, y)
def north_z(r, off, x, y): def north_z(r, off, x, y):
return south_z(r, off, x, y) return sidewalk_z(r, off, NORTH_GUTTER, NORTH_SIDEWALK, x, y)
road = strip(rows, road_offsets, road_z, "Road_Hollywood", asphalt) road = strip(rows, road_offsets, road_z, "Road_Hollywood", asphalt)
sw_s = strip(rows, south_offsets, south_z, "Sidewalk_South", concrete) sw_s = strip(rows, south_offsets, south_z, "Sidewalk_South", concrete)
+53 -1
View File
@@ -8,6 +8,57 @@ Format: [Keep a Changelog](https://keepachangelog.com/) style, versions follow [
Nothing yet. Nothing yet.
## [0.1.1] — 2026-11-08
Collision-fidelity patch. No new scope: street geometry corrections and the QA
tooling that measures them.
### Fixed
- **Sidewalk outer edge ledge.** The sidewalk stood the full 0.15 m kerb height
above the DEM at both edges, leaving a 15.8 cm lip where the walk route crossed
from terrain onto the south sidewalk. The upstand now tapers from full at the
road-side edge to zero at the building-side edge; the north route's worst step
fell from 15.1 cm to 6.9 cm.
- **Crossing ramps too steep.** The kerb-flush run was a fixed 1.5 m, giving
~8.7 % (measured 10–13 cm over 1.5 m). The run is now derived from a target
grade (`--max-ramp-grade`, default 8 % ⇒ 1.63 m); the crossing steps 3.4 cm at
0.25 m sampling.
### Added
- **Walk pre-check improvements** (`Art/blender/site/site_assembly.py`): sampling
coverage is independent of `--sample` (it previously shrank the route), and the
report now prints the grade and the arc-length/offset **location** of the worst
step, so a step can be located rather than guessed.
### Changed
- **Kerb height recorded as final** at 0.15 m modelled / 0.13 m as built — a
standard 6 in LA kerb; neither the 3DEP DEM nor the reference photography can
resolve it further (±2 cm), which is far below the character's 45 cm step
height.
### Verified
- Site meshes rebuilt and re-imported (7/7, collision flags intact), DemoMap
rebuilt, packaged Development build `EXIT=0`.
- `-qaselftest` on the packaged build: walk 761 cm in 2 s at steady Z 456, reset
0 cm, pause/unpause, transect 1456 samples across 16 rows / **0 holes**, wall
probe **0/35** blocking hits.
### Known limitations
- One residual **13.4 cm surface step at s≈198 m** on the south sidewalk (8.0 cm
at s≈251 m north). It is not a gap and is below the 45 cm `MaxStepHeight`, so it
does not block traversal; the cause is a sidewalk-strip discontinuity near a
centreline vertex, recorded in `Art/blender/README.md` as a smoothness
refinement.
- Kerb radii at junctions, driveway aprons, drainage inlets and pavement joints
remain unmodelled (unchanged from `0.1.0`).
Nothing yet.
## [0.1.0] — 2026-11-08 ## [0.1.0] — 2026-11-08
The first playable release: a walkable exterior demo of the **6840 Hollywood Blvd** The first playable release: a walkable exterior demo of the **6840 Hollywood Blvd**
@@ -78,5 +129,6 @@ frontage staged on a walkable street.
graded crossing ramps are deferred to `0.1.1`; crossing ramps are kerb flushes. graded crossing ramps are deferred to `0.1.1`; crossing ramps are kerb flushes.
- One block only; no vehicles, NPCs, audio, or settings UI yet. - One block only; no vehicles, NPCs, audio, or settings UI yet.
[Unreleased]: https://git.allucanget.biz/zwitschi/gig-line/compare/v0.1.0...main [Unreleased]: https://git.allucanget.biz/zwitschi/gig-line/compare/v0.1.1...main
[0.1.1]: https://git.allucanget.biz/zwitschi/gig-line/releases/tag/v0.1.1
[0.1.0]: https://git.allucanget.biz/zwitschi/gig-line/releases/tag/v0.1.0 [0.1.0]: https://git.allucanget.biz/zwitschi/gig-line/releases/tag/v0.1.0
+6 -5
View File
@@ -1,8 +1,9 @@
# Gig Line Architecture Documentation ---
title: Gig Line Architecture Documentation
> Linux-first walking/driving demo around 6840 Hollywood Blvd description: Architecture documentation for the Gig Line Linux-first Unreal Engine 5 demo around 6840 Hollywood Blvd.
status: v0.1.0
Version 0.1.0 — 2026-11-08 — initial architecture documentation date: 2026-11-08
---
# Introduction and Goals # Introduction and Goals
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+14
View File
@@ -345,3 +345,17 @@ Scope: facts and traps that cost time to establish. Planned work lives in [TODO.
incl. Blosm, QGIS and Git LFS are now verified as tool-only. incl. Blosm, QGIS and Git LFS are now verified as tool-only.
- Next work: the `0.1.1` collision-detail patch (sidewalk outer edge 15.8 cm step, - Next work: the `0.1.1` collision-detail patch (sidewalk outer edge 15.8 cm step,
crossing ramp gradient 10 %, kerb height assumption, traversal regression). crossing ramp gradient 10 %, kerb height assumption, traversal regression).
## 2026-11-08 — v0.1.1 released (collision patch)
- Sidewalk upstand now tapers full-at-kerb → zero at the building edge (removes the
15.8 cm outer ledge). Crossing ramp run derives from `--max-ramp-grade` (8 % ⇒
1.63 m) instead of a fixed 1.5 m/8.7 %. Street + site rebuilt, site re-imported,
DemoMap rebuilt, packaged build verified.
- Pre-check tool fixes: coverage no longer shrinks with `--sample` (it used
`range(int(block_len))`), and it reports grade + location of the worst step.
- Residual, documented not hidden: 13.4 cm surface step at s≈198 (south) / 8.0 cm
at s≈251 (north) — a strip discontinuity near a centreline vertex, below the
45 cm MaxStepHeight, so not blocking.
- Kerb height finalised at 0.15 m modelled / 0.13 m built (6 in LA standard; DEM
and photos can't resolve finer).
+1 -1
View File
@@ -16,7 +16,7 @@ Rebuilds `Game/GigLine/Content/Test/ReviewMap.umap` from current content, runs t
All shots ☑ approved 2026-11-07, including the block frontage pass that added the neighbouring buildings and corrected the hero and north-building placement. All shots ☑ approved 2026-11-07, including the block frontage pass that added the neighbouring buildings and corrected the hero and north-building placement.
**2026-11-08 — regenerated set.** Re-rendered via `Tools/render_screenshots.sh` after the placement release check. The `demo-north-buildings` camera was re-pointed (it previously sat 9.5 km west and framed 85 % sky); that shot now shows both north buildings, and all maps carry the re-staged shot cameras. **Approved 2026-11-08** (owner review of the regenerated set). **2026-11-08 — regenerated set (v0.1.1 geometry).** Re-rendered again after the `0.1.1` street change (sidewalk upstand tapered to the building edge, crossing ramps graded to ≤8 %). Re-rendered via `Tools/render_screenshots.sh` after the placement release check. The `demo-north-buildings` camera was re-pointed (it previously sat 9.5 km west and framed 85 % sky); that shot now shows both north buildings, and all maps carry the re-staged shot cameras. **Approved 2026-11-08** (owner review of the regenerated set).
| # | File | Preview | Map | View | What it shows | | # | File | Preview | Map | View | What it shows |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-15
View File
@@ -9,21 +9,6 @@ Actionable task list for this project. This file is the single, central place fo
- When all steps in a version section are done: write a `CHANGELOG.md` entry, then remove the version section from this file. - When all steps in a version section are done: write a `CHANGELOG.md` entry, then remove the version section from this file.
- Release gate: a version is tagged only on the owner's explicit go-ahead once its release checks pass, not automatically when the checkboxes close. - Release gate: a version is tagged only on the owner's explicit go-ahead once its release checks pass, not automatically when the checkboxes close.
## 0.1.1 — Collision fixes (patch)
Suggested blender skills: **collision-proxy** (UCX/UHX naming, convex hulls, simple collider meshes — the core of the authoring pass), **qa-review** (validation checklists, viewport screenshots, ship/no-ship verdicts for the audit), **asset-optimization** (pre-export validation of every collider). Note: these skills assume MCP-driven Blender; use them as method guides for the headless scripts.
### Patch tasks
- [ ] **Sidewalk outer edge against terrain.** The pre-check measured a **15.8 cm** step where a walk sample crosses from `Terrain_DEM` onto `Sidewalk_South` (`Art/blender/README.md`, s≈207 m). Mostly hidden by buildings; visible wherever the frontage is missing. Fix by extending the sidewalk mesh to meet the terrain, or by lowering the outer lip.
- [ ] **Crossing ramp gradient.** The kerb-flush transitions measure **10–13 cm over 1.5 m ≈ 10 %**, steeper than the 8 % a real ramp uses (`Geo/tools/street_section.py` output, s≈33, 39, 126 m). Grade the three ramp openings properly.
- [x] **Collision authoring pass.** Terrain and site meshes use complex-as-simple / `BlockAll` (forced by `UGigLineAssetTools`, verified 2026-11-08 with 84-sample transect). Remaining: simple convex hulls per building (currently using default collision). Record the final settings in `Docs/build.md`.
- [ ] **Kerb height is an assumption.** 0.15 m modelled, 0.13 m as built, and the 3DEP DEM cannot resolve a kerb at all. Check against the photographs and record the final figure.
- [ ] Audit and fix any collision gaps or fall-through geometry found in `0.1.0` in the engine.
- [ ] Regression-test traversal on both sides of the demo.
- [ ] Verify no new packaging defects.
- [ ] Tag `v0.1.1` and write `CHANGELOG.md` entry; then remove this section.
## 0.1.2 — Scale and façade corrections (patch) ## 0.1.2 — Scale and façade corrections (patch)
Suggested blender skills: **references** (reference-image-match and visual-match-checklist templates — measure the guessed heights and colonnade proportions against the photographs), **archviz** (real-world scale and façade composition discipline), **camera-cinematography** (reproduce the reference camera angles when comparing renders to photos). Suggested blender skills: **references** (reference-image-match and visual-match-checklist templates — measure the guessed heights and colonnade proportions against the photographs), **archviz** (real-world scale and façade composition discipline), **camera-cinematography** (reproduce the reference camera angles when comparing renders to photos).