docs: reconvert architecture.adoc to markdown via asciidoctor→docbook→pandoc
Replaced the Python-converted architecture.md with a proper pandoc
conversion chain:
asciidoctor -b docbook5 → pandoc -f docbook -t gfm
This fixes table rendering (pipe tables instead of grid tables),
interpolates AsciiDoc attributes ({project-name} → Gig Line), strips
anchor IDs, and normalises escaping. Post-processed: glossary italic
leak from cols="e,2e" table, ® → (R) for the reset key, \>/> escapes.
Also:
- prettier 3.9.10 installed globally as the Markdown formatter/linter
- .prettierrc: proseWrap=never, tabWidth=2
- .prettierignore: skips Binaries/, *.uasset, *.umap, *.blend, images
- architecture.md passes prettier --check
This commit is contained in:
1 parent
d03829b699
commit
e93c27054a
3 files changed
+187
-104
No files matched your search
@@ -0,0 +1,12 @@
|
|||||||
|
# Prettier ignores — don't format generated or binary content
|
||||||
|
Binaries/
|
||||||
|
Intermediate/
|
||||||
|
Saved/
|
||||||
|
*.uasset
|
||||||
|
*.umap
|
||||||
|
*.blend
|
||||||
|
*.png
|
||||||
|
*.jpg
|
||||||
|
*.jpeg
|
||||||
|
*.gif
|
||||||
|
*.webp
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"proseWrap": "never",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false
|
||||||
|
}
|
||||||
+170
-104
@@ -91,7 +91,7 @@ The system is a self-contained single-player game. It has no server backend, no
|
|||||||
|
|
||||||
| Channel | Protocol / Format | Purpose |
|
| Channel | Protocol / Format | Purpose |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Keyboard + mouse | Enhanced Input (IA_*, IMC_Default) | First-person movement, look, jump, reset, pause |
|
| Keyboard + mouse | Enhanced Input (IA\_\*, IMC_Default) | First-person movement, look, jump, reset, pause |
|
||||||
| Vulkan RHI | GPU rendering | Scene display at 60 FPS / 1440p |
|
| Vulkan RHI | GPU rendering | Scene display at 60 FPS / 1440p |
|
||||||
| FBX | Autodesk FBX (binary) | Blender→Unreal mesh and skeleton transfer |
|
| FBX | Autodesk FBX (binary) | Blender→Unreal mesh and skeleton transfer |
|
||||||
| GeoTIFF | 3DEP 1 m DEM | Terrain heightfield source |
|
| GeoTIFF | 3DEP 1 m DEM | Terrain heightfield source |
|
||||||
@@ -102,30 +102,41 @@ The system is a self-contained single-player game. It has no server backend, no
|
|||||||
|
|
||||||
## Technology decisions
|
## Technology decisions
|
||||||
|
|
||||||
** ****Unreal Engine 5.8.4*** for rendering, World Partition, physics (Chaos), and the Enhanced Input system. Chosen for its Linux support, open C++ source, and real-time rendering quality.
|
- **Unreal Engine 5.8.4** for rendering, World Partition, physics (Chaos), and the Enhanced Input system. Chosen for its Linux support, open C++ source, and real-time rendering quality.
|
||||||
** ****Blender 5.2 LTS*** for all 3D modelling, UV work, and collision mesh authoring. Driven headlessly via `bpy` Python scripts, not MCP.
|
|
||||||
** ****QGIS 4.2.3*** for geographic data cleanup, coordinate conversion (EPSG:26911), and DEM preparation.
|
- **Blender 5.2 LTS** for all 3D modelling, UV work, and collision mesh authoring. Driven headlessly via `bpy` Python scripts, not MCP.
|
||||||
** ****Blosm 2.7.28*** for OSM building and street blockouts inside Blender (layout data only — not authoritative façade, height, or pavement detail).
|
|
||||||
** ****MPFB 2.0.18*** for human base meshes and baked materials (NPCs in `0.2.0+`).
|
- **QGIS 4.2.3** for geographic data cleanup, coordinate conversion (EPSG:26911), and DEM preparation.
|
||||||
|
|
||||||
|
- **Blosm 2.7.28** for OSM building and street blockouts inside Blender (layout data only — not authoritative façade, height, or pavement detail).
|
||||||
|
|
||||||
|
- **MPFB 2.0.18** for human base meshes and baked materials (NPCs in `0.2.0+`).
|
||||||
|
|
||||||
## Top-level decomposition
|
## Top-level decomposition
|
||||||
|
|
||||||
The system is a single Unreal game module (`GigLine`) with no plugins beyond `EnhancedInput`. Content is organised by domain under `/Game/Hollywood/`:
|
The system is a single Unreal game module (`GigLine`) with no plugins beyond `EnhancedInput`. Content is organised by domain under `/Game/Hollywood/`:
|
||||||
|
|
||||||
* `Site/` — terrain, road, sidewalks, kerbs, crossing markings, site materials
|
- `Site/` — terrain, road, sidewalks, kerbs, crossing markings, site materials
|
||||||
* `ElCapitan/` — hero façade mesh and materials
|
|
||||||
* `Frontage/` — south-side block building meshes
|
- `ElCapitan/` — hero façade mesh and materials
|
||||||
* `North/` — north-side building meshes
|
|
||||||
* `Input/` — Enhanced Input actions and mapping context
|
- `Frontage/` — south-side block building meshes
|
||||||
|
|
||||||
|
- `North/` — north-side building meshes
|
||||||
|
|
||||||
|
- `Input/` — Enhanced Input actions and mapping context
|
||||||
|
|
||||||
All modelling and geographic processing live outside the game project in `Art/`, `Geo/`, and `Tools/`. The `Game/` directory contains only engine-ready content and C++ source.
|
All modelling and geographic processing live outside the game project in `Art/`, `Geo/`, and `Tools/`. The `Game/` directory contains only engine-ready content and C++ source.
|
||||||
|
|
||||||
## Quality achievement
|
## Quality achievement
|
||||||
|
|
||||||
** **Performance*: dynamic-only lighting (no build step, no static shadow maps), world-space-noise materials (cheap procedural variation), minimal overdraw (simple street-level geometry).
|
- **Performance**: dynamic-only lighting (no build step, no static shadow maps), world-space-noise materials (cheap procedural variation), minimal overdraw (simple street-level geometry).
|
||||||
** **Walkability*: complex-as-simple collision on terrain (C++ helper forces the flag on the asset), block-all collision on every site mesh, swept transect QA verifies zero raycast holes.
|
|
||||||
** **Fidelity*: geographic data verified before modelling (footprints, bounds, DEM); building placement checked against street mesh, never in isolation; reference photography drives façade work.
|
- **Walkability**: complex-as-simple collision on terrain (C++ helper forces the flag on the asset), block-all collision on every site mesh, swept transect QA verifies zero raycast holes.
|
||||||
** **Reproducibility*: pinned toolchain in `Docs/toolchain.md`, named export presets, `Tools/check-lfs.sh` gate, fresh-checkout build procedure in `Docs/build.md`.
|
|
||||||
|
- **Fidelity**: geographic data verified before modelling (footprints, bounds, DEM); building placement checked against street mesh, never in isolation; reference photography drives façade work.
|
||||||
|
|
||||||
|
- **Reproducibility**: pinned toolchain in `Docs/toolchain.md`, named export presets, `Tools/check-lfs.sh` gate, fresh-checkout build procedure in `Docs/build.md`.
|
||||||
|
|
||||||
# Building Block View
|
# Building Block View
|
||||||
|
|
||||||
@@ -154,7 +165,7 @@ C++ classes in `Game/GigLine/Source/GigLine/`:
|
|||||||
| `AGigLineShotActor` | Screenshot camera walker | Drives cameras in `-game` mode, `FScreenshotRequest`, quits |
|
| `AGigLineShotActor` | Screenshot camera walker | Drives cameras in `-game` mode, `FScreenshotRequest`, quits |
|
||||||
| `UGigLineAssetTools` | C++ collision helpers | `SetComplexCollisionAsSimple` on `StaticMesh` assets |
|
| `UGigLineAssetTools` | C++ collision helpers | `SetComplexCollisionAsSimple` on `StaticMesh` assets |
|
||||||
|
|
||||||
Input assets in `/Game/Input/`: `IA*Move`, `IA*MoveBack`, `IA*Strafe`, `IA*StrafeLeft`, `IA*Look`, `IA*Jump`, `IA*Reset`, `IA*Pause`, bound in `IMC_Default`.
|
Input assets in `/Game/Input/`: `IA_Move`, `IA_MoveBack`, `IA_Strafe`, `IA_StrafeLeft`, `IA_Look`, `IA_Jump`, `IA_Reset`, `IA_Pause`, bound in `IMC_Default`.
|
||||||
|
|
||||||
### Site
|
### Site
|
||||||
|
|
||||||
@@ -194,62 +205,89 @@ Source data: `Art/blender/` (`.blend` files), `Geo/` (OSM extracts, DEM, verific
|
|||||||
|
|
||||||
### QA & Review
|
### QA & Review
|
||||||
|
|
||||||
* `AGigLineShotActor` walks fixed cameras in `-game` mode, captures PNGs, and quits.
|
- `AGigLineShotActor` walks fixed cameras in `-game` mode, captures PNGs, and quits.
|
||||||
* `-qaselftest` switch on `AGigLineCharacter` runs a core-ticker harness: walk 2 s, reset, pause/unpause, ground transect — all PASS/FAIL logged.
|
|
||||||
* `Screenshots/` holds committed PNGs and `README.md` approval table.
|
- `-qaselftest` switch on `AGigLineCharacter` runs a core-ticker harness: walk 2 s, reset, pause/unpause, ground transect — all PASS/FAIL logged.
|
||||||
|
|
||||||
|
- `Screenshots/` holds committed PNGs and `README.md` approval table.
|
||||||
|
|
||||||
## Level 2
|
## Level 2
|
||||||
|
|
||||||
### White Box Gameplay — Input Flow
|
### White Box Gameplay — Input Flow
|
||||||
|
|
||||||
* `AGigLineCharacter::SetupPlayerInputComponent` binds `IA_*` actions to `MoveForward`, `MoveBack`, `MoveStrafe`, `MoveLeft`, `Look`, `StartJump`/`StopJump`, `ResetToStart`, `TogglePause`.
|
1. `AGigLineCharacter::SetupPlayerInputComponent` binds `IA_*` actions to `MoveForward`, `MoveBack`, `MoveStrafe`, `MoveLeft`, `Look`, `StartJump`/`StopJump`, `ResetToStart`, `TogglePause`.
|
||||||
* Movement delegates to `ApplyMove(Forward, Strafe)` → `AddMovementInput`.
|
|
||||||
* Look applies yaw/pitch scaled by `LookSensitivity` (Y invertable via `bInvertLookY`).
|
2. Movement delegates to `ApplyMove(Forward, Strafe)` → `AddMovementInput`.
|
||||||
* `ResetToStart` teleports to `StartLocation` (captured on first grounded frame), clears velocity, resets control rotation.
|
|
||||||
* `TogglePause` toggles `APlayerController::SetPause`, swaps input mode between `FInputModeGameOnly` and `FInputModeUIOnly`, shows/hides mouse cursor.
|
3. Look applies yaw/pitch scaled by `LookSensitivity` (Y invertable via `bInvertLookY`).
|
||||||
|
|
||||||
|
4. `ResetToStart` teleports to `StartLocation` (captured on first grounded frame), clears velocity, resets control rotation.
|
||||||
|
|
||||||
|
5. `TogglePause` toggles `APlayerController::SetPause`, swaps input mode between `FInputModeGameOnly` and `FInputModeUIOnly`, shows/hides mouse cursor.
|
||||||
|
|
||||||
### White Box Site — Collision Model
|
### White Box Site — Collision Model
|
||||||
|
|
||||||
* Every site mesh (road, sidewalks, kerbs, crossing) is `STATIC` with `BlockAll` collision.
|
- Every site mesh (road, sidewalks, kerbs, crossing) is `STATIC` with `BlockAll` collision.
|
||||||
* `Terrain*DEM` uses `CTF*UseComplexAsSimple` (forced by `UGigLineAssetTools` at build time, saved on the asset).
|
|
||||||
* The terrain corridor is carved to half-width 10.7 m around the road centreline so the player can walk the carriageway and both sidewalks.
|
- `Terrain_DEM` uses `CTF_UseComplexAsSimple` (forced by `UGigLineAssetTools` at build time, saved on the asset).
|
||||||
* Ground Z: north sidewalk 395, road 366, south sidewalk 317 (3.94 m fall along the block, matching the DEM).
|
|
||||||
|
- The terrain corridor is carved to half-width 10.7 m around the road centreline so the player can walk the carriageway and both sidewalks.
|
||||||
|
|
||||||
|
- Ground Z: north sidewalk 395, road 366, south sidewalk 317 (3.94 m fall along the block, matching the DEM).
|
||||||
|
|
||||||
# Runtime View
|
# Runtime View
|
||||||
|
|
||||||
## Walk the block
|
## Walk the block
|
||||||
|
|
||||||
* Player launches game → `AGigLineGameModeBase` spawns `AGigLineCharacter` at `PlayerStart` `(-13336, -1150, 600)`.
|
1. Player launches game → `AGigLineGameModeBase` spawns `AGigLineCharacter` at `PlayerStart` `(-13336, -1150, 600)`.
|
||||||
* Character falls 144 cm to road surface (Z 456) and begins walking. `StartLocation` captured on first grounded frame.
|
|
||||||
* Player holds W → `IA_Move` fires → `ApplyMove(1, 0)` → `AddMovementInput(ForwardVector, 1)` → capsule moves at 450 cm/s.
|
2. Character falls 144 cm to road surface (Z 456) and begins walking. `StartLocation` captured on first grounded frame.
|
||||||
* Mouse move → `IA_Look` fires → yaw/pitch applied to controller rotation → camera follows (attached to capsule at 160 cm eye height).
|
|
||||||
* Player presses R → `ResetToStart` → teleport to `StartLocation`/`StartRotation`, `StopMovementImmediately`, reset control rotation.
|
3. Player holds W → `IA_Move` fires → `ApplyMove(1, 0)` → `AddMovementInput(ForwardVector, 1)` → capsule moves at 450 cm/s.
|
||||||
* Player presses Escape → `TogglePause` → `SetPause(true)`, switch to `FInputModeUIOnly`, show cursor. World timers stop; core tickers continue.
|
|
||||||
* Player presses Escape again → `TogglePause` → `SetPause(false)`, switch to `FInputModeGameOnly`, hide cursor.
|
4. Mouse move → `IA_Look` fires → yaw/pitch applied to controller rotation → camera follows (attached to capsule at 160 cm eye height).
|
||||||
|
|
||||||
|
5. Player presses R → `ResetToStart` → teleport to `StartLocation`/`StartRotation`, `StopMovementImmediately`, reset control rotation.
|
||||||
|
|
||||||
|
6. Player presses Escape → `TogglePause` → `SetPause(true)`, switch to `FInputModeUIOnly`, show cursor. World timers stop; core tickers continue.
|
||||||
|
|
||||||
|
7. Player presses Escape again → `TogglePause` → `SetPause(false)`, switch to `FInputModeGameOnly`, hide cursor.
|
||||||
|
|
||||||
## Screenshot capture
|
## Screenshot capture
|
||||||
|
|
||||||
* `Tools/render*screenshots.sh` compiles editor, builds `ReviewMap` from `Tools/ue*build*review*map.py`, launches game in `-game` mode.
|
1. `Tools/render_screenshots.sh` compiles editor, builds `ReviewMap` from `Tools/ue_build_review_map.py`, launches game in `-game` mode.
|
||||||
* `AGigLineShotActor` iterates the camera list, sets view, calls `HighResShot 1280x720`, waits for capture.
|
|
||||||
* On last camera, requests engine quit. PNGs are copied to `Screenshots/` and committed.
|
2. `AGigLineShotActor` iterates the camera list, sets view, calls `HighResShot 1280x720`, waits for capture.
|
||||||
|
|
||||||
|
3. On last camera, requests engine quit. PNGs are copied to `Screenshots/` and committed.
|
||||||
|
|
||||||
## QA self-test (`-qaselftest`)
|
## QA self-test (`-qaselftest`)
|
||||||
|
|
||||||
* Core ticker starts at `BeginPlay` (not a world timer — world timers freeze on pause).
|
1. Core ticker starts at `BeginPlay` (not a world timer — world timers freeze on pause).
|
||||||
* 1.0 s: begin driving forward input.
|
|
||||||
* 3.0 s: stop, measure displacement (> 200 cm = PASS).
|
2. 1.0 s: begin driving forward input.
|
||||||
* 3.5 s: call `ResetToStart`.
|
|
||||||
* 4.0 s: measure distance from spawn (< 100 cm = PASS).
|
3. 3.0 s: stop, measure displacement (> 200 cm = PASS).
|
||||||
* 4.5 s: call `TogglePause`, check `IsGamePaused()` (= true = PASS).
|
|
||||||
* 5.5 s: call `TogglePause`, check `IsGamePaused()` (= false = PASS).
|
4. 3.5 s: call `ResetToStart`.
|
||||||
* 6.0 s: swept ground transect across three lanes (Y −1400, −167, +1000), X −14900 to −9420 at 200 cm spacing. 84 samples, 0 holes = PASS.
|
|
||||||
* 7.0 s: final verdict logged.
|
5. 4.0 s: measure distance from spawn (< 100 cm = PASS).
|
||||||
|
|
||||||
|
6. 4.5 s: call `TogglePause`, check `IsGamePaused()` (= true = PASS).
|
||||||
|
|
||||||
|
7. 5.5 s: call `TogglePause`, check `IsGamePaused()` (= false = PASS).
|
||||||
|
|
||||||
|
8. 6.0 s: swept ground transect across three lanes (Y −1400, −167, +1000), X −14900 to −9420 at 200 cm spacing. 84 samples, 0 holes = PASS.
|
||||||
|
|
||||||
|
9. 7.0 s: final verdict logged.
|
||||||
|
|
||||||
## Build and import pipeline
|
## Build and import pipeline
|
||||||
|
|
||||||
* Blender headless (`Tools/export**.py`) reads `.blend` files, applies metre→centimetre conversion, exports FBX with `ue*metric_v1` preset.
|
1. Blender headless (`Tools/export_*.py`) reads `.blend` files, applies metre→centimetre conversion, exports FBX with `ue_metric_v1` preset.
|
||||||
* Unreal headless (`Tools/ue*import**.py`) imports FBX via Interchange, places meshes at geographic coordinates, sets collision profiles.
|
|
||||||
* `Tools/ue*build*demo_map.py` assembles `DemoMap`: creates/repositions actors, sets lighting, saves map and assets.
|
2. Unreal headless (`Tools/ue_import_*.py`) imports FBX via Interchange, places meshes at geographic coordinates, sets collision profiles.
|
||||||
|
|
||||||
|
3. `Tools/ue_build_demo_map.py` assembles `DemoMap`: creates/repositions actors, sets lighting, saves map and assets.
|
||||||
|
|
||||||
# Deployment View
|
# Deployment View
|
||||||
|
|
||||||
@@ -262,17 +300,18 @@ Source data: `Art/blender/` (`.blend` files), `Geo/` (OSM extracts, DEM, verific
|
|||||||
| Project repo | `/run/media/system/DATA/Documents/06-games/gig-line` (Git + LFS, remote at `git.allucanget.biz`) |
|
| Project repo | `/run/media/system/DATA/Documents/06-games/gig-line` (Git + LFS, remote at `git.allucanget.biz`) |
|
||||||
| Build output | `/run/media/system/DATA/Builds/GigLine` (packaged Linux build, ~1.1 GiB) |
|
| Build output | `/run/media/system/DATA/Builds/GigLine` (packaged Linux build, ~1.1 GiB) |
|
||||||
|
|
||||||
**Motivation:**
|
Motivation
|
||||||
|
|
||||||
Single-machine development. No build farm, no CI pipeline yet. The engine, toolchain, and GPU are all on the same host.
|
Single-machine development. No build farm, no CI pipeline yet. The engine, toolchain, and GPU are all on the same host.
|
||||||
|
|
||||||
**Quality and Performance Features:**
|
Quality and Performance Features
|
||||||
|
|
||||||
* Vulkan RHI on RTX 5070 Ti, open kernel module driver 615.78.08.
|
- Vulkan RHI on RTX 5070 Ti, open kernel module driver 615.78.08.
|
||||||
* System clang 23.1.4 (no bundled engine clang) compiles game code.
|
|
||||||
* Build time: ~90 s incremental, ~5 min clean for the editor target.
|
|
||||||
|
|
||||||
**Mapping of Building Blocks to Infrastructure:**
|
- System clang 23.1.4 (no bundled engine clang) compiles game code.
|
||||||
|
|
||||||
|
- Build time: ~90 s incremental, ~5 min clean for the editor target.
|
||||||
|
|
||||||
|
Mapping of Building Blocks to Infrastructure
|
||||||
|
|
||||||
| Building Block | Infrastructure Element |
|
| Building Block | Infrastructure Element |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
@@ -295,88 +334,117 @@ No server infrastructure. The game is a standalone executable.
|
|||||||
|
|
||||||
## Coordinate system and scale
|
## Coordinate system and scale
|
||||||
|
|
||||||
** ****Source CRS***: EPSG:26911 (UTM zone 11N). Local origin recorded in `Geo/`.
|
- **Source CRS**: EPSG:26911 (UTM zone 11N). Local origin recorded in `Geo/`.
|
||||||
** ****Blender***: metres. East → +X, north → +Y (Blender convention).
|
|
||||||
** ****Unreal****: centimetres. East → +X, north → ****−Y*** (confirmed from street mesh: `Sidewalk*North` Y −1912..−1053, `Sidewalk*South` Y +718..+1447).
|
- **Blender**: metres. East → +X, north → +Y (Blender convention).
|
||||||
** ****Conversion***: every exporter calls the metre→centimetre function. Import presets (`ue*metric*v1`, `ue*character*v1`) are named and repeatable.
|
|
||||||
|
- **Unreal**: centimetres. East → +X, north → **−Y** (confirmed from street mesh: `Sidewalk_North` Y −1912..−1053, `Sidewalk_South` Y +718..+1447).
|
||||||
|
|
||||||
|
- **Conversion**: every exporter calls the metre→centimetre function. Import presets (`ue_metric_v1`, `ue_character_v1`) are named and repeatable.
|
||||||
|
|
||||||
Rule: place a building only against a neighbour or street mesh, never in isolation.
|
Rule: place a building only against a neighbour or street mesh, never in isolation.
|
||||||
|
|
||||||
## Collision model
|
## Collision model
|
||||||
|
|
||||||
* Site meshes (road, sidewalks, kerbs, crossing): `STATIC` mobility, `BlockAll` collision profile.
|
- Site meshes (road, sidewalks, kerbs, crossing): `STATIC` mobility, `BlockAll` collision profile.
|
||||||
* Terrain: `STATIC`, `CTF_UseComplexAsSimple` (forced by `UGigLineAssetTools` at build time, saved on the asset — the flag lives on the `UStaticMesh`/`UBodySetup`, not the map).
|
|
||||||
* Buildings: `STATIC`, simple collision (convex hull from mesh).
|
- Terrain: `STATIC`, `CTF_UseComplexAsSimple` (forced by `UGigLineAssetTools` at build time, saved on the asset — the flag lives on the `UStaticMesh`/`UBodySetup`, not the map).
|
||||||
* Rule: the collision flag must be saved on the asset. Saving only the `.umap` silently reverts it.
|
|
||||||
|
- Buildings: `STATIC`, simple collision (convex hull from mesh).
|
||||||
|
|
||||||
|
- Rule: the collision flag must be saved on the asset. Saving only the `.umap` silently reverts it.
|
||||||
|
|
||||||
## Lighting
|
## Lighting
|
||||||
|
|
||||||
* Dynamic-only: `r.AllowStaticLighting=False`. All lights are `MOVABLE`.
|
- Dynamic-only: `r.AllowStaticLighting=False`. All lights are `MOVABLE`.
|
||||||
* Fixed daytime rig: directional light (sun, −62° pitch), sky light, exponential height fog, post-process volume with fixed exposure.
|
|
||||||
* Rationale: avoids "LIGHTING NEEDS TO BE REBUILT" warnings; no bake step; the scene never changes time of day.
|
- Fixed daytime rig: directional light (sun, −62° pitch), sky light, exponential height fog, post-process volume with fixed exposure.
|
||||||
|
|
||||||
|
- Rationale: avoids "LIGHTING NEEDS TO BE REBUILT" warnings; no bake step; the scene never changes time of day.
|
||||||
|
|
||||||
## Materials
|
## Materials
|
||||||
|
|
||||||
* All materials authored in Unreal, not carried from Blender (FBX import loses diffuse colours).
|
- All materials authored in Unreal, not carried from Blender (FBX import loses diffuse colours).
|
||||||
* World-space-noise blend nodes for cheap procedural variation (asphalt grain, concrete speckle, stucco roughness).
|
|
||||||
* Instance parameters where tunable (e.g. wetness, ageing).
|
- World-space-noise blend nodes for cheap procedural variation (asphalt grain, concrete speckle, stucco roughness).
|
||||||
|
|
||||||
|
- Instance parameters where tunable (e.g. wetness, ageing).
|
||||||
|
|
||||||
## Geographic data provenance
|
## Geographic data provenance
|
||||||
|
|
||||||
* OSM extract is layout data only — not authoritative for façade, height, or pavement detail.
|
- OSM extract is layout data only — not authoritative for façade, height, or pavement detail.
|
||||||
* DEM from 3DEP 1 m; elevation verified against cross-sections in `Geo/verification/`.
|
|
||||||
* Reference photography (local, gitignored) drives manual façade work.
|
- DEM from 3DEP 1 m; elevation verified against cross-sections in `Geo/verification/`.
|
||||||
* In-game ODbL attribution drawn by `AGigLineHUD` every frame, bottom-left.
|
|
||||||
|
- Reference photography (local, gitignored) drives manual façade work.
|
||||||
|
|
||||||
|
- In-game ODbL attribution drawn by `AGigLineHUD` every frame, bottom-left.
|
||||||
|
|
||||||
## QA harness
|
## QA harness
|
||||||
|
|
||||||
* `-qaselftest`: core ticker (not world timer) so pause cannot freeze the test that proves pause works.
|
- `-qaselftest`: core ticker (not world timer) so pause cannot freeze the test that proves pause works.
|
||||||
* `GigLine SIM` / `GigLine GROUND`: TEMP diagnostic logging, to be removed before release tag.
|
|
||||||
* Screenshot approval: human must tick `Screenshots/README.md` before visual work is marked done.
|
- `GigLine SIM` / `GigLine GROUND`: TEMP diagnostic logging, to be removed before release tag.
|
||||||
|
|
||||||
|
- Screenshot approval: human must tick `Screenshots/README.md` before visual work is marked done.
|
||||||
|
|
||||||
# Architecture Decisions
|
# Architecture Decisions
|
||||||
|
|
||||||
## ADR-1: Dynamic-only lighting for the demo
|
## ADR-1: Dynamic-only lighting for the demo
|
||||||
|
|
||||||
** ****Context***: The demo is a fixed daytime scene. Stationary lights demand a lighting build and produce "LIGHTING NEEDS TO BE REBUILT" warnings.
|
- **Context**: The demo is a fixed daytime scene. Stationary lights demand a lighting build and produce "LIGHTING NEEDS TO BE REBUILT" warnings.
|
||||||
** ****Decision***: `r.AllowStaticLighting=False`, all lights `MOVABLE`.
|
|
||||||
** ****Consequences***: No bake step, no warning, simpler iteration. Slightly higher GPU cost per frame (no baked shadows) — acceptable for the demo scope.
|
- **Decision**: `r.AllowStaticLighting=False`, all lights `MOVABLE`.
|
||||||
|
|
||||||
|
- **Consequences**: No bake step, no warning, simpler iteration. Slightly higher GPU cost per frame (no baked shadows) — acceptable for the demo scope.
|
||||||
|
|
||||||
## ADR-2: Materials authored in Unreal, not imported from Blender
|
## ADR-2: Materials authored in Unreal, not imported from Blender
|
||||||
|
|
||||||
** ****Context***: FBX→Unreal import maps all Blender diffuse colours to white. Flat colour materials do not survive the pipeline.
|
- **Context**: FBX→Unreal import maps all Blender diffuse colours to white. Flat colour materials do not survive the pipeline.
|
||||||
** ****Decision***: Build all materials (asphalt, concrete, stucco, façade stone, road paint) directly in Unreal with procedural nodes.
|
|
||||||
** ****Consequences***: Materials cannot be previewed in Blender look-dev. Must round-trip to Unreal for visual check. But: full PBR control, world-space noise, no import surprise.
|
- **Decision**: Build all materials (asphalt, concrete, stucco, façade stone, road paint) directly in Unreal with procedural nodes.
|
||||||
|
|
||||||
|
- **Consequences**: Materials cannot be previewed in Blender look-dev. Must round-trip to Unreal for visual check. But: full PBR control, world-space noise, no import surprise.
|
||||||
|
|
||||||
## ADR-3: Complex-as-simple collision on terrain via C++ helper
|
## ADR-3: Complex-as-simple collision on terrain via C++ helper
|
||||||
|
|
||||||
** ****Context***: UE 5.8 removed `bUseComplexAsSimpleCollision`. Python cannot set `CollisionTraceFlag` on `StaticMesh`/`BodySetup` at all. The Interchange default is bbox-only simple collision, which placed an invisible lid 8 m above the street.
|
- **Context**: UE 5.8 removed `bUseComplexAsSimpleCollision`. Python cannot set `CollisionTraceFlag` on `StaticMesh`/`BodySetup` at all. The Interchange default is bbox-only simple collision, which placed an invisible lid 8 m above the street.
|
||||||
** ****Decision***: `UGigLineAssetTools::SetComplexCollisionAsSimple` (C++) forces `CTF_UseComplexAsSimple` and saves the asset.
|
|
||||||
** ****Consequences***: One C++ helper class. The flag must be saved on the asset (not just the map). No Python workaround exists.
|
- **Decision**: `UGigLineAssetTools::SetComplexCollisionAsSimple` (C++) forces `CTF_UseComplexAsSimple` and saves the asset.
|
||||||
|
|
||||||
|
- **Consequences**: One C++ helper class. The flag must be saved on the asset (not just the map). No Python workaround exists.
|
||||||
|
|
||||||
## ADR-4: Reset captures StartLocation on first grounded frame
|
## ADR-4: Reset captures StartLocation on first grounded frame
|
||||||
|
|
||||||
** ****Context***: `BeginPlay` captures `StartLocation` at the PlayerStart, which is above grade (Z 600) so the capsule does not spawn embedded. Every reset dropped the player 1.4 m back into the air.
|
- **Context**: `BeginPlay` captures `StartLocation` at the PlayerStart, which is above grade (Z 600) so the capsule does not spawn embedded. Every reset dropped the player 1.4 m back into the air.
|
||||||
** ****Decision***: Repeating 0.25 s timer captures `StartLocation` once the character reports `IsMovingOnGround()`, then clears itself.
|
|
||||||
** ****Consequences***: Reset is correct. A one-shot timer at 2 s is wrong (fires after walking begins, records mid-stride position).
|
- **Decision**: Repeating 0.25 s timer captures `StartLocation` once the character reports `IsMovingOnGround()`, then clears itself.
|
||||||
|
|
||||||
|
- **Consequences**: Reset is correct. A one-shot timer at 2 s is wrong (fires after walking begins, records mid-stride position).
|
||||||
|
|
||||||
## ADR-5: Core ticker for QA self-test, not world timer
|
## ADR-5: Core ticker for QA self-test, not world timer
|
||||||
|
|
||||||
** ****Context***: Pausing the game stops world timers. A timer-driven test freezes exactly when it proves pause works.
|
- **Context**: Pausing the game stops world timers. A timer-driven test freezes exactly when it proves pause works.
|
||||||
** ****Decision***: `FTSTicker::GetCoreTicker()` drives the `-qaselftest` harness.
|
|
||||||
** ****Consequences***: Test runs even while paused. Must be enabled explicitly (`-qaselftest`), never in normal play.
|
- **Decision**: `FTSTicker::GetCoreTicker()` drives the `-qaselftest` harness.
|
||||||
|
|
||||||
|
- **Consequences**: Test runs even while paused. Must be enabled explicitly (`-qaselftest`), never in normal play.
|
||||||
|
|
||||||
## ADR-6: South = +Y, north = −Y in Unreal
|
## ADR-6: South = +Y, north = −Y in Unreal
|
||||||
|
|
||||||
** ****Context***: The street mesh established this convention: `Sidewalk*North` has Y range −1912..−1053, `Sidewalk*South` has +718..+1447.
|
- **Context**: The street mesh established this convention: `Sidewalk_North` has Y range −1912..−1053, `Sidewalk_South` has +718..+1447.
|
||||||
** ****Decision***: Adopt it project-wide. Never place a building by assumption; always verify against a street mesh or neighbour.
|
|
||||||
** ****Consequences***: Matches Blender's north→+Y after the Y-flip in the `ue*metric*v1` export preset.
|
- **Decision**: Adopt it project-wide. Never place a building by assumption; always verify against a street mesh or neighbour.
|
||||||
|
|
||||||
|
- **Consequences**: Matches Blender’s north→+Y after the Y-flip in the `ue_metric_v1` export preset.
|
||||||
|
|
||||||
## ADR-7: Headless Blender via bpy scripts, not MCP
|
## ADR-7: Headless Blender via bpy scripts, not MCP
|
||||||
|
|
||||||
** ****Context***: Blender skill packs assume an MCP server; the project does not run one.
|
- **Context**: Blender skill packs assume an MCP server; the project does not run one.
|
||||||
** ****Decision***: All Blender work driven by Python scripts in `Tools/`. Skill packs used as method guides (checklists, naming, proportions) only.
|
|
||||||
** ****Consequences***: Scripts are version-controlled and repeatable. No live Blender session needed for CI.
|
- **Decision**: All Blender work driven by Python scripts in `Tools/`. Skill packs used as method guides (checklists, naming, proportions) only.
|
||||||
|
|
||||||
|
- **Consequences**: Scripts are version-controlled and repeatable. No live Blender session needed for CI.
|
||||||
|
|
||||||
# Quality Requirements
|
# Quality Requirements
|
||||||
|
|
||||||
@@ -425,7 +493,7 @@ Rule: place a building only against a neighbour or street mesh, never in isolati
|
|||||||
| Complex-as-simple collision | `CTF_UseComplexAsSimple`: Unreal collision mode where the render mesh triangles are used as the collision surface, instead of a simplified proxy. Required for terrain so the player walks on the actual ground shape. |
|
| Complex-as-simple collision | `CTF_UseComplexAsSimple`: Unreal collision mode where the render mesh triangles are used as the collision surface, instead of a simplified proxy. Required for terrain so the player walks on the actual ground shape. |
|
||||||
| DEM | Digital Elevation Model. 3DEP 1 m resolution GeoTIFF covering the demo bounds. Source of terrain heightfield. |
|
| DEM | Digital Elevation Model. 3DEP 1 m resolution GeoTIFF covering the demo bounds. Source of terrain heightfield. |
|
||||||
| El Capitan | El Capitan Entertainment Centre, 6838 Hollywood Blvd. The hero building of the demo. |
|
| El Capitan | El Capitan Entertainment Centre, 6838 Hollywood Blvd. The hero building of the demo. |
|
||||||
| Enhanced Input | Unreal's modern input system (UE 5+). Uses Input Actions (`IA_*`) and Input Mapping Contexts (`IMC_*`) instead of legacy axis/action bindings. |
|
| Enhanced Input | Unreal’s modern input system (UE 5+). Uses Input Actions (`IA_*`) and Input Mapping Contexts (`IMC_*`) instead of legacy axis/action bindings. |
|
||||||
| EPSG:26911 | UTM zone 11N, the projected CRS used for the demo area. Local origin recorded in `Geo/`. |
|
| EPSG:26911 | UTM zone 11N, the projected CRS used for the demo area. Local origin recorded in `Geo/`. |
|
||||||
| Hero façade | The detailed, reference-calibrated model of the El Capitan building frontage. |
|
| Hero façade | The detailed, reference-calibrated model of the El Capitan building frontage. |
|
||||||
| MPFB | MakeHuman Plugin for Blender (2.0.18). Generates parametric human base meshes with rigs and baked materials. |
|
| MPFB | MakeHuman Plugin for Blender (2.0.18). Generates parametric human base meshes with rigs and baked materials. |
|
||||||
@@ -435,7 +503,7 @@ Rule: place a building only against a neighbour or street mesh, never in isolati
|
|||||||
| Site | The terrain, road, sidewalks, kerbs, and crossing markings — the ground-level infrastructure of the demo area. |
|
| Site | The terrain, road, sidewalks, kerbs, and crossing markings — the ground-level infrastructure of the demo area. |
|
||||||
| Squash merge | Git merge strategy that compresses all branch commits into one commit on `main`, keeping a linear history. |
|
| Squash merge | Git merge strategy that compresses all branch commits into one commit on `main`, keeping a linear history. |
|
||||||
| Swept transect | A QA technique that raycasts vertically at regular intervals along a path (e.g. every 200 cm along both sidewalks and the carriageway) and counts holes (misses). Zero holes = the block is fully walkable. |
|
| Swept transect | A QA technique that raycasts vertically at regular intervals along a path (e.g. every 200 cm along both sidewalks and the carriageway) and counts holes (misses). Zero holes = the block is fully walkable. |
|
||||||
| World Partition | Unreal's world composition system for large open-world levels. Not yet used in `0.1.0` but planned for `0.3.0+` driving routes. |
|
| World Partition | Unreal’s world composition system for large open-world levels. Not yet used in `0.1.0` but planned for `0.3.0+` driving routes. |
|
||||||
| Y convention | In Unreal, south = +Y, north = −Y (confirmed from street mesh orientation). In Blender, north = +Y; the `ue_metric_v1` export preset flips Y. |
|
| Y convention | In Unreal, south = +Y, north = −Y (confirmed from street mesh orientation). In Blender, north = +Y; the `ue_metric_v1` export preset flips Y. |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -444,6 +512,4 @@ Rule: place a building only against a neighbour or street mesh, never in isolati
|
|||||||
|
|
||||||
arc42, the template for documentation of software and system architecture.
|
arc42, the template for documentation of software and system architecture.
|
||||||
|
|
||||||
Template Version 0.1.0. Adapted for the Gig Line project.
|
Template Version 0.1.0. Adapted for the Gig Line project. Created, maintained and © by Dr. Peter Hruschka, Dr. Gernot Starke and contributors. See <https://arc42.org>.
|
||||||
Created, maintained and © by Dr. Peter Hruschka, Dr. Gernot Starke and contributors.
|
|
||||||
See <https://arc42.org>.
|
|
||||||
Reference in new issue
Block a user