qa(collision): no-blocking-collision release check — seam + wall audit #13

Merged
zwitschi merged 3 commits from collision-seams-0.1.0 into main 2026-11-08 14:55:59 +01:00
5 changed files with 106 additions and 6 deletions

No files matched your search

+24 -1
View File
@@ -38,7 +38,7 @@ Measured at 1440p on the development workstation: Bazzite, Ryzen 7 7700X, 64 GB
| ------- | ----------------------- | ------ | -------- | ---- |
| `0.1.0` | Traversal, both sides | — | — | — |
| `0.1.0` | Placement vs references | PASS (with deliberate simplifications) | Section below, 2026-11-08 | 2026-11-08 |
| `0.1.0` | Collision and packaging | — | — | — |
| `0.1.0` | Collision and packaging | PASS — no blocking collision, no invisible walls, no seam gaps (see audit note) | `-qaselftest` on the packaged build, 2026-11-08 | 2026-11-08 |
| `0.1.0` | 60 FPS at 1440p | — | — | — |
| `0.1.0` | Fresh checkout build | — | — | — |
| `0.1.0` | Packaged Linux build | — | — | — |
@@ -83,3 +83,26 @@ probed from the DemoMap (commandlet, 2026-11-08).
Pre-check method: `Tools/judge_screenshot.py` (vision model) flagged the simplified
flat surfaces as "unexpected" — those flags are the deliberate deviations above, not
placement errors. Final verdict is by human review of the shots in `Screenshots/demo/`.
## `0.1.0` — Collision and packaging — audit note (2026-11-08)
Run on the packaged build (`GigLineQA`, Development, Vulkan SM5) with `-qaselftest`.
- **Transect (holes/gaps):** 1456 samples over 16 rows — lane centres **plus the
kerb/road/sidewalk seam Ys** (−1382, −1053, +718, +1047 and neighbours) and
X −20000..−2000. Result **0 holes**. (The old 84-sample check covered only 3
lane centres; the seam rows are what this check adds.)
- **Invisible-wall probe:** horizontal traces 30 m long, grounded at 160 cm above
the local ground, along the road and both seam rows. Result **0/35 blocking hits
inside 21 m** — no invisible walls or misplaced blockers in the street envelope.
(First pass used a fixed Z 160 start; the street is at Z ~366, so the probe
started inside the earth and reported every row as a dist-0 blocker. Grounding
the probe fixed that measurement bug.)
- **Walk / reset / pause:** 761 cm in 2 s (Z steady 456), reset 0 cm, pause
`IsGamePaused()=1`, unpause 0 — all PASS.
- Packaging: the packaged build launches, reaches gameplay, and the QA run quits
cleanly. The `GigLineShotActor` screenshot rounds are suppressed under
`-qaselftest` so they cannot quit the run before the audit phases.
- Caveat recorded: ground Z extremes (−12 m / 3000 cm) are trace-start/terrain-edge
artifacts of the widened extent, not walkable holes — the walkable corridor is
continuous (walk + transect both PASS).
@@ -266,10 +266,18 @@ void AGigLineCharacter::StartQASelfTest()
UWorld* W = GetWorld();
int32 Holes = 0, Samples = 0;
float Lowest = 1.0e9f, Highest = -1.0e9f;
static const float Lanes[] = {-1400.0f, -167.0f, 1000.0f}; // N walk, road, S walk
for (float LaneY : Lanes)
// Probed world-space (2026-11-08): N sidewalk -1912..-1053, kerb
// -1382..-1053, road -1382..+1047, kerb +718..+1047, S sidewalk
// +718..+1447. Rows include the kerb/road/sidewalk boundary Ys so
// seam gaps are sampled, not just lane centres.
static const float Rows[] = {
-1750.0f, -1500.0f, -1382.0f, -1280.0f, -1053.0f, -900.0f,
-167.0f, 0.0f, 300.0f, 800.0f, 1047.0f, 900.0f, 718.0f,
900.0f, 1250.0f, 1447.0f
};
for (float LaneY : Rows)
{
for (float X = -14900.0f; X <= -9420.0f; X += 200.0f)
for (float X = -20000.0f; X <= -2000.0f; X += 200.0f)
{
FHitResult Hit;
FCollisionQueryParams Q(TEXT("GigLineTransect"), false, this);
@@ -289,6 +297,52 @@ void AGigLineCharacter::StartQASelfTest()
UE_LOG(LogTemp, Log,
TEXT("GigLine QA: transect %d samples, %d holes, ground Z %.0f..%.0f -> %s"),
Samples, Holes, Lowest, Highest, Holes == 0 ? TEXT("PASS") : TEXT("FAIL"));
// Invisible-wall / blocking-mesh probe: at each sample, first find
// the ground under the start point (vertical raycast), then run a
// horizontal trace 160 cm ABOVE that ground along the street row.
// A clean street should let the 30 m trace run clear; a short hit
// flags an invisible or misplaced blocker. Starting the horizontal
// trace at a fixed Z (e.g. 160) is wrong: the street is at Z ~366
// there, so a 160 cm probe starts inside the earth (dist 0).
int32 Walls = 0, WallSamples = 0;
static const float TraceYs[] = {-1400.0f, -167.0f, 1000.0f, -1382.0f, 1047.0f};
for (float WallY : TraceYs)
{
for (float X0 = -19500.0f; X0 <= -3000.0f; X0 += 2500.0f)
{
FHitResult GroundHit;
FCollisionQueryParams GQ(TEXT("GigLineWallGround"), false, this);
if (!W->LineTraceSingleByChannel(GroundHit,
FVector(X0, WallY, 3000.f), FVector(X0, WallY, -1000.f),
ECC_Visibility, GQ))
{
continue; // no ground under start -> skip
}
const float ProbeZ = GroundHit.ImpactPoint.Z + 160.f;
FHitResult Hit;
FCollisionQueryParams Q(TEXT("GigLineWallProbe"), false, this);
const bool bHit = W->LineTraceSingleByChannel(Hit,
FVector(X0, WallY, ProbeZ),
FVector(X0 + 3000.f, WallY, ProbeZ),
ECC_Visibility, Q);
++WallSamples;
if (!bHit) { continue; } // 30 m clear -> good
// Starting just above the ground, a hit within 21 m = blocker.
if (Hit.Distance < 2100.f)
{
++Walls;
UE_LOG(LogTemp, Log,
TEXT("GigLine QA: wall probe short-hit at X %.0f Y %.0f dist %.0f actor=%s"),
X0, WallY, Hit.Distance,
Hit.GetActor() ? *Hit.GetActor()->GetName() : TEXT("none"));
}
}
}
UE_LOG(LogTemp, Log,
TEXT("GigLine QA: wall probe %d/%d traces with blocking hit inside 21 m -> %s"),
Walls, WallSamples,
Walls == 0 ? TEXT("PASS") : TEXT("FAIL"));
}
// 7.0: verdict, then stop ticking.
@@ -21,6 +21,14 @@ void AGigLineShotActor::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
// QA mode: the -qaselftest run owns the process (it walks, resets, pauses,
// transects, then quits on its own). Skip the screenshot rounds so the game
// does not exit mid-test via bQuitWhenDone.
if (FParse::Param(FCommandLine::Get(), TEXT("qaselftest")))
{
return;
}
if (bWaitingForSettle)
{
SettleCountdown -= DeltaSeconds;
+15
View File
@@ -304,3 +304,18 @@ Scope: facts and traps that cost time to establish. Planned work lives in [TODO.
- Getting actor world bounds: spawn at loc(0,0,0) means static mesh bbox IS the
world footprint (FBX carries the geo offset). Probe by loading the level
explicitly (load_level) — a fresh commandlet starts on Untitled otherwise.
## 2026-11-08 — collision/seam audit done; QA self-test extended
- `-qaselftest` transect widened from 84 samples (3 lane centres) to **1456
samples / 16 rows** including kerb/road/sidewalk seam Ys (probed: N side
-1912..-1053, kerb -1382..-1053, road -1382..+1047, kerb +718..+1047, S side
+718..+1447). 0 holes.
- **New wall probe:** ground-referenced horizontal 30 m trace at +160 cm. First
attempt used a fixed Z 160 and started INSIDE the earth (street is at Z ~366)
-> every row reported a dist-0 blocker. Always ground the probe first.
- **Guard:** GigLineShotActor must skip rounds under `-qaselftest`, else
bQuitWhenDone closes the game before the transect phase (observed: game exited
at t=2s with "ShotActor: done (4 shots)" + RequestExit).
- Results on packaged build: walk 761cm/2s, reset 0cm, pause/unpause, transect
0 holes, wall 0/35 -> all PASS. Evidence recorded in Docs/release-checks.md.
+2 -2
View File
@@ -106,11 +106,11 @@ The MPFB character asset is planned as the NPC template (see `ROADMAP.md`). Keep
- [x] Commit and review the publication preparation changes before pushing. Initial publication commit: `101db3f`.
- [x] Review ODbL obligations for each shipped derivative database or produced work before public release. **Done 2026-11-08** — full review recorded in `Docs/odbl-review.md`: the shipped streets/footprints/sidewalks are a Produced Work of the OpenStreetMap database; obligations held are on-screen attribution (`AGigLineHUD`), the ODbL link, and the committed source extract with provenance; share-alike applies to the data layer only (project code/art stay CC0). THIRD_PARTY_NOTICES and `Docs/licensing.md` updated.
### Release checks - active - 01a1b26b-3c94-707f-9665-2f6b4a79b564 (branch `placement-reference-0.1.0`)
### Release checks - active - 01a1b26b-3c94-707f-9665-2f6b4a79b564 (branch `collision-seams-0.1.0`)
- [x] Player can traverse both sides of the demo without falling through geometry. **Verified 2026-11-08:** Blender pre-check plus an in-engine swept transect (`-qaselftest`) over the north sidewalk, carriageway and south sidewalk from X -14900 to -9420 — 84 samples, 0 holes, ground Z 317..395 (sidewalk 395, road 366, south walk 317). The player spawns at Z 456 and stays there for the whole run (`fall=0`, single Z).
- [x] Building placement, street scale, and site identity checked against references. **Done 2026-11-08:** rendered current DemoMap content, probed world-space geometry (road 24.3 m vs ref 20.9–25.9 m; sidewalk centreline offsets 12.5/13.2 vs ref 12.6/13.6 m; hero frontage 26.0 m, setback ~13 m vs ref 25.75/14.5 m; frontage + north buildings in verified OSM positions), recorded PASS + deliberate deviations (flat blockout surfaces → `0.1.4`, kerb upstand → `0.1.1`, kerb-flush ramps → `0.1.1`) in `Docs/release-checks.md`, and fixed the mis-aimed north-buildings camera (was 9.5 km west → 85% sky; now frames the buildings). Final human verdict pending on `Screenshots/demo/*`.
- [ ] No blocking collision or packaging defects.
- [x] No blocking collision or packaging defects. **Done 2026-11-08:** extended `-qaselftest` — transect now 1456 samples / 16 rows including the kerb/road/sidewalk seam Ys (0 holes), plus a ground-referenced 30 m wall probe (0/35 blocking hits; no invisible walls). Walk/reset/pause all PASS on the packaged build; `GigLineShotActor` now skips under `-qaselftest`. Evidence in `Docs/release-checks.md` §`0.1.0` audit note.
- [ ] Remove TEMP QA diagnostics (`GigLine SIM` / `GigLine GROUND` log lines and the settle-timer log) from `GigLineCharacter.cpp` before the release tag, or gate them behind a cvar.
- [ ] 60 FPS at 1440p on the dev workstation (Bazzite, Ryzen 7 7700X, 64 GB RAM, RTX 5070 Ti 16 GB) using a documented quality preset; record upscaling state; report performance without frame generation.
- [ ] Fresh project checkout builds with the documented external engine installation.