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

Merged PR #13: no-blocking-collision release check

Co-authored-by: Zwitschi <zwitschi82@gmail.com>
This commit was merged in pull request #13.
This commit is contained in:
zwitschi authored and zwitschi committed 2026-11-08 14:55:58 +01:00
1 parent 82a408bc33
commit 71acffec12
5 files changed
+106 -6

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` | Traversal, both sides | — | — | — |
| `0.1.0` | Placement vs references | PASS (with deliberate simplifications) | Section below, 2026-11-08 | 2026-11-08 | | `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` | 60 FPS at 1440p | — | — | — |
| `0.1.0` | Fresh checkout build | — | — | — | | `0.1.0` | Fresh checkout build | — | — | — |
| `0.1.0` | Packaged Linux 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 Pre-check method: `Tools/judge_screenshot.py` (vision model) flagged the simplified
flat surfaces as "unexpected" — those flags are the deliberate deviations above, not 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/`. 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(); UWorld* W = GetWorld();
int32 Holes = 0, Samples = 0; int32 Holes = 0, Samples = 0;
float Lowest = 1.0e9f, Highest = -1.0e9f; float Lowest = 1.0e9f, Highest = -1.0e9f;
static const float Lanes[] = {-1400.0f, -167.0f, 1000.0f}; // N walk, road, S walk // Probed world-space (2026-11-08): N sidewalk -1912..-1053, kerb
for (float LaneY : Lanes) // -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; FHitResult Hit;
FCollisionQueryParams Q(TEXT("GigLineTransect"), false, this); FCollisionQueryParams Q(TEXT("GigLineTransect"), false, this);
@@ -289,6 +297,52 @@ void AGigLineCharacter::StartQASelfTest()
UE_LOG(LogTemp, Log, UE_LOG(LogTemp, Log,
TEXT("GigLine QA: transect %d samples, %d holes, ground Z %.0f..%.0f -> %s"), TEXT("GigLine QA: transect %d samples, %d holes, ground Z %.0f..%.0f -> %s"),
Samples, Holes, Lowest, Highest, Holes == 0 ? TEXT("PASS") : TEXT("FAIL")); 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. // 7.0: verdict, then stop ticking.
@@ -21,6 +21,14 @@ void AGigLineShotActor::Tick(float DeltaSeconds)
{ {
Super::Tick(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) if (bWaitingForSettle)
{ {
SettleCountdown -= DeltaSeconds; 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 - 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 world footprint (FBX carries the geo offset). Probe by loading the level
explicitly (load_level) — a fresh commandlet starts on Untitled otherwise. 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] 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. - [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] 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/*`. - [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. - [ ] 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. - [ ] 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. - [ ] Fresh project checkout builds with the documented external engine installation.