Release 0.9.5 texture and material refinement

This commit is contained in:
zwitschi committed 2026-11-02 21:04:48 +01:00
1 parent fb3da52438
commit 05d487a822
28 files changed
+160 -78

No files matched your search

+1 -1
View File
@@ -4,7 +4,7 @@ All notable user-facing changes to Gig Line. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions use [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions use
Semantic Versioning. Semantic Versioning.
## [Unreleased] ## [0.9.5] — 2026-11-02
### Changed ### Changed
+17 -12
View File
@@ -63,14 +63,20 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
`character_override` because it has no spawned NPC role. **Signed off `character_override` because it has no spawned NPC role. **Signed off
2026-11-02:** 96 final-context captures, no P0; lanyard/helmet P1 fixes; the 2026-11-02:** 96 final-context captures, no P0; lanyard/helmet P1 fixes; the
backpack straps, caps, low-poly hands/faces and optional close-range backpack straps, caps, low-poly hands/faces and optional close-range
flashlight wash were accepted or deferred. The 24-NPC budget is 6.93 ms, the flashlight wash were accepted or deferred. The 24-NPC budget is 6.94 ms, the
gallery is 13 good / 0 bad, the screen-design judge is 13/13 and a clean gallery is 13 good / 0 bad, the screen-design judge is 13/13 and a clean
portrait measured a 0.732 vision gap against the photoreal concept. No portrait measured a 0.732 vision gap against the photoreal concept. No
release build, version bump or tag was created at this gate. release build, version bump or tag was created at this gate.
- **NPC texture resolution (0.9.5, 2026-11-02):** `tools/npc_pipeline.py` now generates 256² - **NPC texture resolution (0.9.5, 2026-11-02):** `tools/npc_pipeline.py` now generates 256²
albedo/normal/ORM maps instead of 128² (AI shirt/trousers are resized to 256). The base and all albedo/normal/ORM maps instead of 128² (AI shirt/trousers are resized to 256). The base and all
eight library GLBs plus AO maps were rebuilt; texture files total ~0.5 MB, eight GLBs ~5.75 MB, eight library GLBs plus AO maps were rebuilt; texture files total ~0.5 MB, eight GLBs ~5.75 MB,
and the 24-NPC smoke remains 6.90 ms. and the 24-NPC smoke is 6.94 ms.
- **0.9.5 texture/UI audit (2026-11-02):** all 21 screen-art textures are
1280×720 and referenced by their screens; access cards are 256×128 and HUD
icons 64×64, with no oversized or unused runtime texture. The 24-NPC smoke now
reports **168 meshes / 131,616 triangles / 6.94 ms** (50 ms budget). Compressed
payloads are picks **24.55 MB**, UI art **22.67 MB**, NPC maps **0.48 MB**.
Legacy root textures remain only for `generate_textures.py` and the asset test.
- **Environment surface audit (0.9.5, 2026-11-02):** `capture_realism.gd` gained - **Environment surface audit (0.9.5, 2026-11-02):** `capture_realism.gd` gained
`surfaces` (Hollywood pavers/asphalt/limestone/facade) and `surfaces_joke` `surfaces` (Hollywood pavers/asphalt/limestone/facade) and `surfaces_joke`
(neighbour awning, canopy, pavers) stages with the HUD hidden. The Walk of Fame (neighbour awning, canopy, pavers) stages with the HUD hidden. The Walk of Fame
@@ -168,16 +174,15 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
for every new `Button`; CheckButton/OptionButton keep the engine theme. Timeline for every new `Button`; CheckButton/OptionButton keep the engine theme. Timeline
Previous/Next disable at the ends; F1 tutorial skip is keyboard-only by design. Previous/Next disable at the ends; F1 tutorial skip is keyboard-only by design.
- **Version and roadmap renumber (2026-11-02):** source was **0.9.3** at the UI - **Version and roadmap renumber (2026-11-02):** source was **0.9.3** at the UI
polish milestone, now **0.9.4** after the NPC pass; the polish milestone, **0.9.4** after the NPC pass, now **0.9.5** after the texture
completed map/NPC work and UI polish are the patch content. Next work is and material pass. Next work is **0.9.6 integration**, then the **0.10.0**
**0.9.4 NPC**, **0.9.5 textures**, **0.9.6 integration**, then the **0.10.0**
minor release candidate. `TODO.md` plans only 0.x patch/minor increments; no minor release candidate. `TODO.md` plans only 0.x patch/minor increments; no
major-version scope is defined yet. The v0.9.4 tag is the release trigger; no major-version scope is defined yet. The `v0.9.5` tag is the release trigger; no
tag was created for 0.9.3. tag was created for 0.9.3.
- **Priority change (2026-11-02):** the map optimization, pre-build NPC revisit, - **Priority change (2026-11-02):** the map optimization, pre-build NPC revisit,
0.9.3 UI polish and 0.9.4 NPC visual optimization are complete and in `DONE.md`. 0.9.3 UI polish, 0.9.4 NPC visual optimization and 0.9.5 texture/material pass
0.9.5 textures and 0.9.6 integration/0.10.0 release work are next. The current are complete and in `DONE.md`. 0.9.6 integration and 0.10.0 release work are
source version is 0.9.4. next. The current source version is 0.9.5.
- **Release v0.9.4 (2026-11-02):** commit `a57b86c` tagged `v0.9.4`; Gitea Actions - **Release v0.9.4 (2026-11-02):** commit `a57b86c` tagged `v0.9.4`; Gitea Actions
run 916 passed checks and the full build and published seven assets (Linux, run 916 passed checks and the full build and published seven assets (Linux,
Windows, macOS, NSIS setup, AppImage, Web, Desktop HQ). Release page: Windows, macOS, NSIS setup, AppImage, Web, Desktop HQ). Release page:
@@ -205,7 +210,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
`JokeGround_*`; `set_night_mode()` owns their energies and the hill tint. `JokeGround_*`; `set_night_mode()` owns their energies and the hill tint.
The latest local realism judge reports a 0.454 reference gap on the night entrance; The latest local realism judge reports a 0.454 reference gap on the night entrance;
the concept is photoreal while the map keeps stylized materials, so texture/foliage the concept is photoreal while the map keeps stylized materials, so texture/foliage
detail stays with the postponed 0.9.5 pass rather than the map milestone. detail stays with the 0.9.5 texture pass rather than the map milestone.
- **Docs validation (2026-11-02):** `python3 tools/check_docs.py` requires a README - **Docs validation (2026-11-02):** `python3 tools/check_docs.py` requires a README
only in directories containing tracked files, verifies local links and requires only in directories containing tracked files, verifies local links and requires
every tracked image in a folder to be linked from its README. Gitignored every tracked image in a folder to be linked from its README. Gitignored
@@ -843,8 +848,8 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
`PLAN.md` describes intended design; `README.md` and `DONE.md` describe what shipped. As of `PLAN.md` describes intended design; `README.md` and `DONE.md` describe what shipped. As of
2026-11-02 the playable build covers the three venues, tutorials/campaign/checkpoints, the 0.9.3 2026-11-02 the playable build covers the three venues, tutorials/campaign/checkpoints, the 0.9.3
UI/accessibility pass, the 0.9.4 NPC visual optimization, and the Blender + realism asset pipeline. `TODO.md` holds the remaining UI/accessibility pass, the 0.9.4 NPC visual optimization, the 0.9.5 texture/material pass, and the Blender + realism asset pipeline. `TODO.md` holds the remaining
0.9.4–0.10.0 work. The project uses a custom headless runner, not GUT, and Gitea Actions, not 0.9.6–0.10.0 work. The project uses a custom headless runner, not GUT, and Gitea Actions, not
GitHub Actions. GitHub Actions.
<!-- b64: RWFzdGVyIGVnZzogYSByYXJlIHJhZGlvIHRyYW5zbWlzc2lvbiAiwr9Ew7NuZGUgZXN0w6EgbGEgbW90YT8iIGZpcmVzIHZpYSBHYW1lTWFuYWdlci5fbWF5YmVfcmFkaW9fZWFzdGVyX2VnZyAoMi41JSBjaGFuY2UgYWZ0ZXIgYSBzdWNjZXNzZnVsIHJhZGlvIGNhbGwpLiBTdHJpbmcga2V5IHJhZGlvLmVhc3Rlcl9lZ2cgaW4gY29udGVudC9zdHJpbmdzLmVuLmpzb24uIERvIG5vdCByZW1vdmUu --> <!-- b64: RWFzdGVyIGVnZzogYSByYXJlIHJhZGlvIHRyYW5zbWlzc2lvbiAiwr9Ew7NuZGUgZXN0w6EgbGEgbW90YT8iIGZpcmVzIHZpYSBHYW1lTWFuYWdlci5fbWF5YmVfcmFkaW9fZWFzdGVyX2VnZyAoMi41JSBjaGFuY2UgYWZ0ZXIgYSBzdWNjZXNzZnVsIHJhZGlvIGNhbGwpLiBTdHJpbmcga2V5IHJhZGlvLmVhc3Rlcl9lZ2cgaW4gY29udGVudC9zdHJpbmdzLmVuLmpzb24uIERvIG5vdCByZW1vdmUu -->
+1 -1
View File
@@ -176,7 +176,7 @@ Primary decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md), [AD
## Versioning and Delivery ## Versioning and Delivery
`config/version` in `project.godot` is the single version source (currently `0.9.4`). Releases are tagged `v<version>`; the CI pipeline builds and publishes the standard artifacts plus the optional Desktop HQ zip. Version bumps follow [Semantic Versioning](https://semver.org/). See [`docs/RELEASING.md`](docs/RELEASING.md) and [`README.md`](README.md) for commands. `config/version` in `project.godot` is the single version source (currently `0.9.5`). Releases are tagged `v<version>`; the CI pipeline builds and publishes the standard artifacts plus the optional Desktop HQ zip. Version bumps follow [Semantic Versioning](https://semver.org/). See [`docs/RELEASING.md`](docs/RELEASING.md) and [`README.md`](README.md) for commands.
## Design Direction ## Design Direction
+12 -10
View File
@@ -38,12 +38,13 @@ precision walk, the Joke Shop's Sunset Strip frontage, the TV Studio arrival, an
> Downloads are public (no sign-in required) since the host's instance-wide > Downloads are public (no sign-in required) since the host's instance-wide
> `REQUIRE_SIGNIN_VIEW` was disabled on 2026-10-31. > `REQUIRE_SIGNIN_VIEW` was disabled on 2026-10-31.
> >
> **Latest published: v0.9.4** — the NPC visual optimization pass: face/head > **Latest published: v0.9.5** — the texture and material refinement pass:
> depth, hands and gear placement, shoes and boots, headgear clearance, and the > 256² NPC maps, a four-times fabric weave without baked AO blotches, repair of
> 8,000/8,000 character mesh budget on top of the Hollywood/Joke Shop maps and > the Walk of Fame terrazzo band and awning stripe, and per-phase skyline haze,
> on top of the v0.9.4 NPC visual optimization, the Hollywood/Joke Shop maps and
> the v0.9.3 UI/accessibility polish. > the v0.9.3 UI/accessibility polish.
> >
> **Current source: v0.9.4** — tagged and built from the same commit. > **Current source: v0.9.5** — tagged and built from the same commit.
> Releases are built automatically when a `vX.Y.Z` tag is pushed > Releases are built automatically when a `vX.Y.Z` tag is pushed
> (see [`docs/RELEASING.md`](docs/RELEASING.md)); manual builds use > (see [`docs/RELEASING.md`](docs/RELEASING.md)); manual builds use
> `./tools/build_releases.sh`. Installer/AppImage packaging runs in the same pipeline > `./tools/build_releases.sh`. Installer/AppImage packaging runs in the same pipeline
@@ -121,18 +122,19 @@ Full setup, every run/test/smoke command, and the controls table are in
- [`docs/development-status.md`](docs/development-status.md) — Implemented features and what's next. - [`docs/development-status.md`](docs/development-status.md) — Implemented features and what's next.
- [`docs/smoke-checklist.md`](docs/smoke-checklist.md) — Manual smoke-test checklist. - [`docs/smoke-checklist.md`](docs/smoke-checklist.md) — Manual smoke-test checklist.
- [`docs/blender-assets.md`](docs/blender-assets.md) — Blender asset library: characters, gear, props, attach points. - [`docs/blender-assets.md`](docs/blender-assets.md) — Blender asset library: characters, gear, props, attach points.
- [`docs/npc-visual-review.md`](docs/npc-visual-review.md) — 0.9.4 NPC baseline, acceptance criteria and ranked visual gaps. - [`docs/npc-visual-review.md`](docs/npc-visual-review.md) — 0.9.4 NPC baseline, acceptance criteria and ranked visual gaps; 0.9.5 texture comparison is in `docs/blender_previews/sheet_texture_refinement_0.9.5.jpg`.
- [`docs/npc-proportion-audit.md`](docs/npc-proportion-audit.md) — NPC proportion measurements against the shared stylized guide. - [`docs/npc-proportion-audit.md`](docs/npc-proportion-audit.md) — NPC proportion measurements against the shared stylized guide.
- [`docs/adr/`](docs/adr/) — Architecture Decision Records. - [`docs/adr/`](docs/adr/) — Architecture Decision Records.
- [`TODO.md`](TODO.md) — Active tasks plus the 0.x gap analysis and milestone roadmap. - [`TODO.md`](TODO.md) — Active tasks plus the 0.x gap analysis and milestone roadmap.
## Development Status ## Development Status
v0.9.4 is the current source version: the completed NPC visual optimization v0.9.5 is the current source version: the completed texture and material
(face/head depth, hands and gear placement, shoes/boots, headgear clearance and refinement (256² NPC maps, a 4× fabric weave with baked-AO removal, repaired
the 8,000/8,000 mesh budget), on top of the v0.9.3 UI/accessibility polish Walk of Fame/awning surfaces and per-phase skyline haze), on top of the v0.9.4
pass and v0.9.2's Hollywood/Joke Shop map rebuilds. It builds on NPC visual optimization and the v0.9.3 UI/accessibility polish pass. It builds on
v0.9.1's Godot 4.7.2 baseline, v0.9.0's production-quality pass, v0.8's v0.9.2's Hollywood/Joke Shop map rebuilds, v0.9.1's Godot 4.7.2 baseline,
v0.9.0's production-quality pass, v0.8's
tutorial/campaign/resume work and the v0.7.x venue/gear/judge work. See [`docs/development-status.md`](docs/development-status.md) tutorial/campaign/resume work and the v0.7.x venue/gear/judge work. See [`docs/development-status.md`](docs/development-status.md)
for the implemented list and [`TODO.md`](TODO.md) for the 0.x roadmap. Manual for the implemented list and [`TODO.md`](TODO.md) for the 0.x roadmap. Manual
verification uses the [`docs/smoke-checklist.md`](docs/smoke-checklist.md). verification uses the [`docs/smoke-checklist.md`](docs/smoke-checklist.md).
+34 -18
View File
@@ -5,7 +5,7 @@ see `AGENTS.md` for the workflow and `MEMORY.md` for the decisions behind these
## Gap Analysis and 0.x Roadmap ## Gap Analysis and 0.x Roadmap
Baseline: **v0.9.4** (2026-11-02). Three playable venues, tutorial/campaign/checkpoint resume, Baseline: **v0.9.5** (2026-11-02). Three playable venues, tutorial/campaign/checkpoint resume,
difficulty/help, audio/accessibility settings, a 24-NPC budget baseline, a complete difficulty/help, audio/accessibility settings, a 24-NPC budget baseline, a complete
escalation/access/radio loop, shift review, the Blender asset library, 263 headless + 101 Python escalation/access/radio loop, shift review, the Blender asset library, 263 headless + 101 Python
tests, a 21/21 clean screen-design judge and an optional Forward+ Desktop HQ build. This is a strong tests, a 21/21 clean screen-design judge and an optional Forward+ Desktop HQ build. This is a strong
@@ -37,7 +37,7 @@ release-candidate foundation, not yet a 0.10.0 release candidate.
| Animation/presentation | Procedural pose layers, portrait captures, reduced hem clipping, 8,000/8,000 NPC cap | Thorough NPC silhouette/face/gear/pose/LOD optimization before visual QA | Close-up jank reduces perceived quality | Complete (0.9.4) | | Animation/presentation | Procedural pose layers, portrait captures, reduced hem clipping, 8,000/8,000 NPC cap | Thorough NPC silhouette/face/gear/pose/LOD optimization before visual QA | Close-up jank reduces perceived quality | Complete (0.9.4) |
| Audio/accessibility | Procedural ambience/SFX, volume controls, captions/reduce-motion settings, searchable Help | Full accessibility/localization acceptance review, audio caption coverage and P0/P1 fixes | Public release cannot claim accessible play | 0.10.0 | | Audio/accessibility | Procedural ambience/SFX, volume controls, captions/reduce-motion settings, searchable Help | Full accessibility/localization acceptance review, audio caption coverage and P0/P1 fixes | Public release cannot claim accessible play | 0.10.0 |
| Localization | English JSON table, validation and input-generated Help | Pseudo-locale/layout audit and translator workflow sign-off | Text expansion/clipping at release | 0.10.0 | | Localization | English JSON table, validation and input-generated Help | Pseudo-locale/layout audit and translator workflow sign-off | Text expansion/clipping at release | 0.10.0 |
| Performance/platform | 24-NPC headless budget (6.9 ms), Compatibility/Web/HQ paths | Target hardware matrix, Web/HQ manual profiling, frame-time/memory evidence | Platform-specific drops or startup failures | 0.9.6 / 0.10.0 | | Performance/platform | 24-NPC headless budget (6.94 ms), Compatibility/Web/HQ paths | Target hardware matrix, Web/HQ manual profiling, frame-time/memory evidence | Platform-specific drops or startup failures | 0.9.6 / 0.10.0 |
| Save lifecycle | Settings/campaign/history/checkpoint files, atomic writes | Migration fixtures from 0.8/0.9, fresh-install/upgrade verification, rollback instructions | Player progress loss on upgrade | 0.10.0 | | Save lifecycle | Settings/campaign/history/checkpoint files, atomic writes | Migration fixtures from 0.8/0.9, fresh-install/upgrade verification, rollback instructions | Player progress loss on upgrade | 0.10.0 |
| QA/CI | Headless suite, smokes, screenshot compare, 21/21 judge | Release-candidate smoke matrix, final gallery and release dry run | Regressions escape the release gate | 0.9.6 / 0.10.0 | | QA/CI | Headless suite, smokes, screenshot compare, 21/21 judge | Release-candidate smoke matrix, final gallery and release dry run | Regressions escape the release gate | 0.9.6 / 0.10.0 |
| Release/legal | Unsigned desktop/macOS builds, Web/HQ packages | Signing/notarization decision, checksums, AI-asset provenance, credits, privacy/body-camera and rating review | Public release blocked by trust/policy | 0.10.0 | | Release/legal | Unsigned desktop/macOS builds, Web/HQ packages | Signing/notarization decision, checksums, AI-asset provenance, credits, privacy/body-camera and rating review | Public release blocked by trust/policy | 0.10.0 |
@@ -45,12 +45,12 @@ release-candidate foundation, not yet a 0.10.0 release candidate.
| Future 0.x | Stable 0.x feature set | Live replay, more venues, VO/music, image-to-mesh props and seasonal content | Scope creep before release | 0.11.0+ | | Future 0.x | Stable 0.x feature set | Live replay, more venues, VO/music, image-to-mesh props and seasonal content | Scope creep before release | 0.11.0+ |
**Current priority:** map optimization, the **pre-build NPC revisit**, the **Current priority:** map optimization, the **pre-build NPC revisit**, the
**0.9.3 UI polish** and **0.9.4 NPC visual optimization** passes are complete **0.9.3 UI polish**, **0.9.4 NPC visual optimization** and **0.9.5 texture
(all moved to `DONE.md` on 2026-11-02). 0.9.5 texture refinement, 0.9.6 refinement** passes are complete (all moved to `DONE.md` on 2026-11-02).
integration and the 0.10.0 release candidate are queued. The source version is 0.9.6 integration and the 0.10.0 release candidate are queued. The source
now 0.9.4. version is now 0.9.5.
## Postponed — Patch 0.9.5 — Texture and material refinement ## Patch 0.9.5 — Texture and material refinement
Goal: improve close-range surface and character texture quality while keeping GL Goal: improve close-range surface and character texture quality while keeping GL
Compatibility/Web parity, deterministic assets and offline CI. Compatibility/Web parity, deterministic assets and offline CI.
@@ -82,20 +82,36 @@ Compatibility/Web parity, deterministic assets and offline CI.
skin/hair/gear keep AO. Comparison `sheet_npc_baseline_compare-texuv.jpg`.) skin/hair/gear keep AO. Comparison `sheet_npc_baseline_compare-texuv.jpg`.)
- [x] Re-bake AO where geometry changes; verify the 256² maps and material wiring. - [x] Re-bake AO where geometry changes; verify the 256² maps and material wiring.
(No character geometry changed in the texture pass; asset/base audits pass.) (No character geometry changed in the texture pass; asset/base audits pass.)
- [ ] Audit library props and UI/card/icon textures at their actual screen sizes; - [x] Audit library props and UI/card/icon textures at their actual screen sizes;
remove blurry/oversized or unused textures where safe. remove blurry/oversized or unused textures where safe. (All 21 screen-art
- [ ] Run texture audits, import, and the full asset test suite; record texture memory textures are 1280×720 and referenced; access cards are 256×128, HUD icons
and triangle/draw-call impact. 64×64; no oversized or unused runtime texture found. Legacy root textures
remain only as the `generate_textures.py`/asset-test fallback.)
- [x] Run texture audits, import, and the full asset test suite; record texture memory
and triangle/draw-call impact. (Godot 263/263, Python 101/101; asset and base
audits pass; 24 NPCs = 168 meshes / 131,616 triangles / 6.94 ms. Compressed
payloads: picks 24.55 MB, UI art 22.67 MB, NPC maps 0.48 MB.)
### Visual verification ### Visual verification
- [ ] Run `python3 tools/scene_concepts.py realism` for the affected stages with the - [x] Run `python3 tools/scene_concepts.py realism` for the affected stages with the
judge enabled; record metric gaps and model/spend. judge enabled; record metric gaps and model/spend. (Run
- [ ] Re-run `tools/check_screenshots.sh` and the screen-design judge; clear all `docs/screens/realism/2026-11-02-tex` with `z-ai/glm-5.3-flash`, one pass per
`diff` verdicts. shot; mean `after` overall 1.8, lighting 2.3, materials 1.8, texture 1.2,
- [ ] Capture before/after close-ups for brick, pavement, asphalt, character cloth backdrop 2.0, characters 1.2, Pillow gap 0.306. The judge is optional and not
and skyline; document accepted trade-offs. a CI gate; the report stays local.)
- [ ] Update asset docs and the changelog/status with the promoted texture versions. - [x] Re-run `tools/check_screenshots.sh` and the screen-design judge; clear all
`diff` verdicts. (21 good / 0 bad; `screen_designs.py judge` = 21/21 match,
0 review, 0 diff.)
- [x] Capture before/after close-ups for brick, pavement, asphalt, character cloth
and skyline; document accepted trade-offs. (Committed
`docs/blender_previews/sheet_texture_refinement_0.9.5.jpg`: Walk of Fame
pavers, asphalt aggregate, limestone facade, day skyline haze and NPC cloth;
asphalt/limestone picks intentionally held, no replacement.)
- [x] Update asset docs and the changelog/status with the promoted texture versions.
(README/PLAN/architecture/status/MEMORY and the 0.9.5 changelog entry now
carry the texture results; the 0.9.5 section moved to `DONE.md` after the
release build.)
## Postponed — Patch 0.9.6 — Integration, performance and judge gate ## Postponed — Patch 0.9.6 — Integration, performance and judge gate
+1 -1
View File
@@ -37,7 +37,7 @@ This document follows the structure of the arc42 architecture documentation temp
- **MINOR** — new venues, NPC archetypes, systems, or features that are backward compatible. - **MINOR** — new venues, NPC archetypes, systems, or features that are backward compatible.
- **PATCH** — bug fixes and small polish that do not change behavior. - **PATCH** — bug fixes and small polish that do not change behavior.
The single source of truth for the version is `config/version` in `project.godot` (currently `0.9.4`). Each release is tagged in git as `v<version>` (e.g. `v0.6.0`). The `0.x` series is pre-stable, so MINOR bumps may introduce breaking changes while the prototype is still stabilizing. `tools/build_releases.sh` and `tools/publish_release.sh` read the version from `project.godot`, so bumping it there is the only required step before a release. The full bump checklist lives in [`RELEASING.md`](RELEASING.md). The single source of truth for the version is `config/version` in `project.godot` (currently `0.9.5`). Each release is tagged in git as `v<version>` (e.g. `v0.6.0`). The `0.x` series is pre-stable, so MINOR bumps may introduce breaking changes while the prototype is still stabilizing. `tools/build_releases.sh` and `tools/publish_release.sh` read the version from `project.godot`, so bumping it there is the only required step before a release. The full bump checklist lives in [`RELEASING.md`](RELEASING.md).
## 3. Context and Scope ## 3. Context and Scope
+25 -11
View File
@@ -235,12 +235,13 @@ godot --path . --script res://src/test/capture_npc_baseline.gd -- \
python3 tools/npc_baseline.py sheet --dir tmp/npc-baseline python3 tools/npc_baseline.py sheet --dir tmp/npc-baseline
``` ```
`capture_realism.gd` runs nine stages (day, Hollywood surface close-ups, Joke Shop surface close-ups, portrait, evening, late, Joke Shop day, Joke Shop night, studio); `capture_realism.gd` runs nine stages in this order: day, Hollywood surface close-ups,
`--stages=day,late` limits it while tuning; `--flashlight` turns on the guard lamp for portrait, evening, late, Joke Shop day, Joke Shop surface close-ups, Joke Shop night,
night stages (used by the Desktop HQ A/B). The `portrait` shot freezes one NPC on open sidewalk studio; `--stages=day,late` limits it while tuning; `--flashlight` turns on the guard
and frames the face, which is the only capture that can judge avatar detail lamp for night stages (used by the Desktop HQ A/B). The `portrait` shot freezes one
(`--portrait-type=N` picks a role). For the 0.9.5 texture audit, run the surface NPC on open sidewalk and frames the face, which is the only capture that can judge
stages directly; the HUD is hidden for them: avatar detail (`--portrait-type=N` picks a role). For the 0.9.5 texture audit, run
the surface stages directly; the HUD is hidden for them:
```bash ```bash
godot --path . --script res://src/test/capture_realism.gd \ godot --path . --script res://src/test/capture_realism.gd \
@@ -249,11 +250,24 @@ godot --path . --script res://src/test/capture_realism.gd \
The generated realism runs under The generated realism runs under
`docs/screens/realism/` are **local, gitignored QA artifacts**; commit only the `docs/screens/realism/` are **local, gitignored QA artifacts**; commit only the
resulting decisions/docs, not the run folders. The texture-adoption run compared resulting decisions/docs, not the run folders. The 0.9.5 texture/UI audit checked actual screen sizes: all screen art is
the pre-adoption captures with the current build: on the shots both sets captured, 1280×720, access cards are 256×128 and HUD icons are 64×64; no runtime texture
the judge's like-for-like means rose on every sub-score (overall 0.8 → 1.0, was oversized or unused. The 24-NPC smoke now reports 168 meshes / 131,616
backdrop 0.6 → 1.6) and the Pillow metric gap fell 0.444 → 0.348. The character triangles / 6.94 ms. Compressed payloads are 24.55 MB of surface picks, 22.67 MB
pass added the portrait shot and recorded the new faces, hands and sleeve cuffs. of screen art and 0.48 MB of NPC maps.
The 0.9.5 realism judge ran once per shot with `z-ai/glm-5.3-flash`
(`python3 tools/scene_concepts.py realism --run docs/screens/realism/2026-11-02-tex
--judge`). Its mean `after` scores were overall 1.8, lighting 2.3, materials 1.8,
texture detail 1.2, backdrop 2.0 and characters 1.2; the Pillow metric gap was
0.306. The judge still ranks the painted concept targets above the stylized build,
particularly lit night facades and dense backdrop detail. That is expected: the
pass validated close-range surfaces and promoted the texture repairs, not a
photoreal renderer. The 0.9.5 before/after close-up sheet is
[`blender_previews/sheet_texture_refinement_0.9.5.jpg`](blender_previews/sheet_texture_refinement_0.9.5.jpg);
the texture-adoption run itself was the earlier 0.8-style candidate comparison,
and its report remains local/gitignored.
The Forward+ A/B compared the Compatibility entrance with the optional Desktop HQ The Forward+ A/B compared the Compatibility entrance with the optional Desktop HQ
preset. The gear-fit run checked the sunglasses, bag and helmet against measured preset. The gear-fit run checked the sunglasses, bag and helmet against measured
head/skirt bounds with `python3 tools/blender_assets.py fit`; it also fixed the head/skirt bounds with `python3 tools/blender_assets.py fit`; it also fixed the
+1
View File
@@ -54,6 +54,7 @@ Committed contact sheets and local Blender renders for the character, gear and p
| <img src="sheet_npc_baseline_compare-shoes.jpg" width="280" alt="sheet_npc_baseline_compare-shoes.jpg"> | [`sheet_npc_baseline_compare-shoes.jpg`](sheet_npc_baseline_compare-shoes.jpg) | | <img src="sheet_npc_baseline_compare-shoes.jpg" width="280" alt="sheet_npc_baseline_compare-shoes.jpg"> | [`sheet_npc_baseline_compare-shoes.jpg`](sheet_npc_baseline_compare-shoes.jpg) |
| <img src="sheet_npc_baseline_compare-tex256.jpg" width="280" alt="sheet_npc_baseline_compare-tex256.jpg"> | [`sheet_npc_baseline_compare-tex256.jpg`](sheet_npc_baseline_compare-tex256.jpg) | | <img src="sheet_npc_baseline_compare-tex256.jpg" width="280" alt="sheet_npc_baseline_compare-tex256.jpg"> | [`sheet_npc_baseline_compare-tex256.jpg`](sheet_npc_baseline_compare-tex256.jpg) |
| <img src="sheet_npc_baseline_compare-texuv.jpg" width="280" alt="sheet_npc_baseline_compare-texuv.jpg"> | [`sheet_npc_baseline_compare-texuv.jpg`](sheet_npc_baseline_compare-texuv.jpg) | | <img src="sheet_npc_baseline_compare-texuv.jpg" width="280" alt="sheet_npc_baseline_compare-texuv.jpg"> | [`sheet_npc_baseline_compare-texuv.jpg`](sheet_npc_baseline_compare-texuv.jpg) |
| <img src="sheet_texture_refinement_0.9.5.jpg" width="280" alt="sheet_texture_refinement_0.9.5.jpg"> | [`sheet_texture_refinement_0.9.5.jpg`](sheet_texture_refinement_0.9.5.jpg) |
| <img src="sheet_npc_gear.jpg" width="280" alt="sheet_npc_gear.jpg"> | [`sheet_npc_gear.jpg`](sheet_npc_gear.jpg) | | <img src="sheet_npc_gear.jpg" width="280" alt="sheet_npc_gear.jpg"> | [`sheet_npc_gear.jpg`](sheet_npc_gear.jpg) |
| <img src="sheet_props.jpg" width="280" alt="sheet_props.jpg"> | [`sheet_props.jpg`](sheet_props.jpg) | | <img src="sheet_props.jpg" width="280" alt="sheet_props.jpg"> | [`sheet_props.jpg`](sheet_props.jpg) |
| <img src="shoulder_bag.png" width="280" alt="shoulder_bag.png"> | [`shoulder_bag.png`](shoulder_bag.png) | | <img src="shoulder_bag.png" width="280" alt="shoulder_bag.png"> | [`shoulder_bag.png`](shoulder_bag.png) |
Binary file not shown.

After

Width:  |  Height:  |  Size: 482 KiB

+3 -1
View File
@@ -44,7 +44,9 @@ Implemented so far:
- NPC torso/hip transition (0.9.4 work): the pelvis and chest are slightly wider than the waist, giving shirts and jackets a readable taper into the hips without changing the build multipliers or the skeleton. The comparison is `sheet_npc_baseline_compare-torso.jpg`. - NPC torso/hip transition (0.9.4 work): the pelvis and chest are slightly wider than the waist, giving shirts and jackets a readable taper into the hips without changing the build multipliers or the skeleton. The comparison is `sheet_npc_baseline_compare-torso.jpg`.
- Release v0.9.4 (2026-11-02): the tagged commit `a57b86c` passed the Gitea checks and full build and published seven artifacts (Linux, Windows, macOS, NSIS setup, AppImage, Web and Desktop HQ). Release page: <https://git.allucanget.biz/zwitschi/security-game/releases/tag/v0.9.4>. - Release v0.9.4 (2026-11-02): the tagged commit `a57b86c` passed the Gitea checks and full build and published seven artifacts (Linux, Windows, macOS, NSIS setup, AppImage, Web and Desktop HQ). Release page: <https://git.allucanget.biz/zwitschi/security-game/releases/tag/v0.9.4>.
- Environment texture pass (0.9.5 work): `capture_realism.gd` now has hidden-HUD `surfaces`/`surfaces_joke` close-up stages. The Walk of Fame band uses the paver texture as dark terrazzo, the neighbour awning keeps its cream stripe, and the skyline shader blends its lower 42 m toward a per-phase haze colour. Brick, asphalt, limestone and paver UV scales/profiles passed without replacement. - Environment texture pass (0.9.5 work): `capture_realism.gd` now has hidden-HUD `surfaces`/`surfaces_joke` close-up stages. The Walk of Fame band uses the paver texture as dark terrazzo, the neighbour awning keeps its cream stripe, and the skyline shader blends its lower 42 m toward a per-phase haze colour. Brick, asphalt, limestone and paver UV scales/profiles passed without replacement.
- Texture/prop audit (0.9.5 work): all 21 screen-art textures are 1280×720 and referenced; access cards are 256×128 and HUD icons 64×64. No oversized or unused runtime texture was found; the legacy root textures remain only as the texture-generator/asset-test fallback. The 24-NPC smoke now reports 168 meshes, 131,616 triangles and 6.94 ms (50 ms budget); compressed payload is 24.55 MB of surface picks, 22.67 MB of screen art and 0.48 MB of NPC maps.
- NPC texture pass (0.9.5 work): the NPC base and all eight library characters now use 256² albedo/normal/ORM maps instead of 128². Cloth and pants use `NPC_FABRIC_UV_SCALE` (4× weave) and skip the baked per-character AO, removing the large blotchy patches in portraits; skin, hair and gear keep baked AO. The base and eight GLBs plus AO maps were rebuilt; the 24-NPC smoke remains green. - NPC texture pass (0.9.5 work): the NPC base and all eight library characters now use 256² albedo/normal/ORM maps instead of 128². Cloth and pants use `NPC_FABRIC_UV_SCALE` (4× weave) and skip the baked per-character AO, removing the large blotchy patches in portraits; skin, hair and gear keep baked AO. The base and eight GLBs plus AO maps were rebuilt; the 24-NPC smoke remains green.
- Texture visual verification (0.9.5 work): the nine-stage realism run used `z-ai/glm-5.3-flash` once per shot; mean `after` scores were overall 1.8, lighting 2.3, materials 1.8, texture detail 1.2, backdrop 2.0 and characters 1.2, with a Pillow metric gap of 0.306. The judge remains an optional review aid, not a CI gate. The committed before/after close-up sheet is [`blender_previews/sheet_texture_refinement_0.9.5.jpg`](blender_previews/sheet_texture_refinement_0.9.5.jpg); it records that the paver/Walk of Fame and NPC fabric repairs are visible, while asphalt, limestone and skyline picks held without a replacement. `tools/check_screenshots.sh` passed 21 good / 0 bad and the screen-design judge passed 21/21 match with 0 review.
- NPC visual optimization (0.9.4, complete 2026-11-02): all eight variants passed the portrait/readability, proportion, gear, foot/shoe, headgear and final-context gates. The library uses an 8,000-triangle / 8,000-glTF-vertex cap (up from 6,000/5,000; `npc_base` fallback remains 6,000/4,000); current characters measure 4,482–5,474 triangles and 4,260–5,494 vertices. The 48-frame baseline and 96-frame final-context review pass, the hand/gear offset and shoes are in, and the accepted stylized limits are documented in `npc-visual-review.md`. - NPC visual optimization (0.9.4, complete 2026-11-02): all eight variants passed the portrait/readability, proportion, gear, foot/shoe, headgear and final-context gates. The library uses an 8,000-triangle / 8,000-glTF-vertex cap (up from 6,000/5,000; `npc_base` fallback remains 6,000/4,000); current characters measure 4,482–5,474 triangles and 4,260–5,494 vertices. The 48-frame baseline and 96-frame final-context review pass, the hand/gear offset and shoes are in, and the accepted stylized limits are documented in `npc-visual-review.md`.
- NPC face-detail pass (0.9.4 work): ala wings and a smaller nose bridge/tip, one rounded mouth slot, and a darker ear concha; all eight rebuilt. The comparison is `sheet_npc_baseline_compare-face-detail.jpg`. - NPC face-detail pass (0.9.4 work): ala wings and a smaller nose bridge/tip, one rounded mouth slot, and a darker ear concha; all eight rebuilt. The comparison is `sheet_npc_baseline_compare-face-detail.jpg`.
- NPC headgear clearance (0.9.4 work): the 96-frame final-context review after the face-detail pass confirms the cap, firefighter helmet, hood and sunglasses clear the refined brow and eyes; no gear rebuild was needed. - NPC headgear clearance (0.9.4 work): the 96-frame final-context review after the face-detail pass confirms the cap, firefighter helmet, hood and sunglasses clear the refined brow and eyes; no gear rebuild was needed.
@@ -74,6 +76,6 @@ Implemented so far:
- Keyboard/gamepad focus pass (0.9.3 work): `UiFocus` rings wrap through visible/enabled controls, hidden Continue and disabled timeline actions are skipped, each modal has a default focus, and A/B are bound to `ui_accept`/`ui_cancel` for pad-only navigation. Recorded in `docs/ui-copy.md`. - Keyboard/gamepad focus pass (0.9.3 work): `UiFocus` rings wrap through visible/enabled controls, hidden Continue and disabled timeline actions are skipped, each modal has a default focus, and A/B are bound to `ui_accept`/`ui_cancel` for pad-only navigation. Recorded in `docs/ui-copy.md`.
- Button-state pass (0.9.3 work): a shared `UiStyles` helper now gives every action button explicit normal, hover, pressed, focus and disabled styles; the timeline disables Previous/Next at its boundaries, while hidden continue states and the keyboard-only tutorial skip remain intentional. Recorded in `docs/ui-copy.md`. - Button-state pass (0.9.3 work): a shared `UiStyles` helper now gives every action button explicit normal, hover, pressed, focus and disabled styles; the timeline disables Previous/Next at its boundaries, while hidden continue states and the keyboard-only tutorial skip remain intentional. Recorded in `docs/ui-copy.md`.
- Dialogue pass (0.9.3 work): NPC reason answers now use the authored `reason` context, with an in-character answer for every shared archetype; Hollywood and Studio gained door-staff lines; radio cancellation, tutorial Ask terminology, help, start hints and campaign reset copy were clarified. Audit recorded in `docs/ui-copy.md`. - Dialogue pass (0.9.3 work): NPC reason answers now use the authored `reason` context, with an in-character answer for every shared archetype; Hollywood and Studio gained door-staff lines; radio cancellation, tutorial Ask terminology, help, start hints and campaign reset copy were clarified. Audit recorded in `docs/ui-copy.md`.
- Pre-build NPC review (2026-11-02): all eight library characters were staged at portrait, conversation and crowd distance on Hollywood and the Joke Shop, in day and night lighting, with the normal crowd hidden (`src/test/capture_npc_review.gd`). No P0 issues were found. Two P1 gear-fit issues were fixed with runtime attach offsets: the authorized-guest lanyard badge now clears the jacket and the firefighter helmet sits above the eyes. Backpack straps, caps, hands and the intentionally low-poly faces were accepted for the stylized target; close-range flashlight wash remains an optional-lighting follow-up. The 24-NPC budget stayed at 6.93 ms, the gallery passed 13 good / 0 bad and the screen-design judge stayed 13/13, and a clean portrait scored a 0.732 vision gap against the photoreal concept. - Pre-build NPC review (2026-11-02): all eight library characters were staged at portrait, conversation and crowd distance on Hollywood and the Joke Shop, in day and night lighting, with the normal crowd hidden (`src/test/capture_npc_review.gd`). No P0 issues were found. Two P1 gear-fit issues were fixed with runtime attach offsets: the authorized-guest lanyard badge now clears the jacket and the firefighter helmet sits above the eyes. Backpack straps, caps, hands and the intentionally low-poly faces were accepted for the stylized target; close-range flashlight wash remains an optional-lighting follow-up. The 24-NPC budget stayed at 6.94 ms, the gallery passed 13 good / 0 bad and the screen-design judge stayed 13/13, and a clean portrait scored a 0.732 vision gap against the photoreal concept.
Current gaps for the 0.x release line: deeper authored content/dialogue, animation and audio production, localization/accessibility expansion, 24-NPC/platform profiling, external playtesting, and signed/notarized release packaging. The full gap analysis and milestone plan live in [`TODO.md`](../TODO.md); the current architecture and documentation ownership map are in [`docs/architecture.md`](architecture.md). Current gaps for the 0.x release line: deeper authored content/dialogue, animation and audio production, localization/accessibility expansion, 24-NPC/platform profiling, external playtesting, and signed/notarized release packaging. The full gap analysis and milestone plan live in [`TODO.md`](../TODO.md); the current architecture and documentation ownership map are in [`docs/architecture.md`](architecture.md).
+7 -4
View File
@@ -93,7 +93,7 @@ pass every applicable item before a library rebuild is accepted.
authored grip points. authored grip points.
8. **Crowd and performance:** the silhouette remains readable at the 8 m crowd 8. **Crowd and performance:** the silhouette remains readable at the 8 m crowd
frame and the LOD/impostor tiers match the full mesh; the 24-NPC budget stays frame and the LOD/impostor tiers match the full mesh; the 24-NPC budget stays
within the existing 6.93 ms baseline (no regression beyond the measured within the existing 6.94 ms baseline (no regression beyond the measured
variance), and no new per-frame material or mesh churn is introduced. variance), and no new per-frame material or mesh churn is introduced.
Asset-space `fit` values are measurements of the untouched GLBs, not a pass/fail Asset-space `fit` values are measurements of the untouched GLBs, not a pass/fail
@@ -224,11 +224,14 @@ The face-detail pass is [`sheet_npc_baseline_compare-face-detail.jpg`](blender_p
The hand pass is [`sheet_npc_hands_compare.jpg`](blender_previews/sheet_npc_hands_compare.jpg); The hand pass is [`sheet_npc_hands_compare.jpg`](blender_previews/sheet_npc_hands_compare.jpg);
the forward-grip pass is the forward-grip pass is
[`sheet_npc_hands_grip_compare.jpg`](blender_previews/sheet_npc_hands_grip_compare.jpg). [`sheet_npc_hands_grip_compare.jpg`](blender_previews/sheet_npc_hands_grip_compare.jpg).
Keep the baseline sheet as the before artifact and add a new comparison sheet The 0.9.5 texture pass adds
rather than replacing it. [`sheet_texture_refinement_0.9.5.jpg`](blender_previews/sheet_texture_refinement_0.9.5.jpg),
which pairs the close-range surface and cloth comparisons. Keep the baseline
sheet as the before artifact and add a new comparison sheet rather than
replacing it.
## Next implementation order ## Next implementation order
0.9.4 is closed. The next visual work belongs to the 0.9.5 texture pass and the 0.9.4 and the 0.9.5 texture pass are closed. The next visual work belongs to the
0.10.0 acceptance review; keep the NPC baseline/final-context commands as the 0.10.0 acceptance review; keep the NPC baseline/final-context commands as the
regression gate for any future character edit. regression gate for any future character edit.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 KiB

After

Width:  |  Height:  |  Size: 543 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 659 KiB

After

Width:  |  Height:  |  Size: 660 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 KiB

After

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 761 KiB

After

Width:  |  Height:  |  Size: 761 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 KiB

After

Width:  |  Height:  |  Size: 406 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 567 KiB

After

Width:  |  Height:  |  Size: 567 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 830 KiB

After

Width:  |  Height:  |  Size: 841 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 529 KiB

After

Width:  |  Height:  |  Size: 529 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

+1 -1
View File
@@ -12,7 +12,7 @@ config_version=5
config/name="Gig Line" config/name="Gig Line"
config/description="Workplace security simulation about observation, access verification, and proportionate escalation." config/description="Workplace security simulation about observation, access verification, and proportionate escalation."
config/version="0.9.4" config/version="0.9.5"
run/main_scene="res://scenes/main.tscn" run/main_scene="res://scenes/main.tscn"
config/features=PackedStringArray("4.7", "GL Compatibility") config/features=PackedStringArray("4.7", "GL Compatibility")
+45 -15
View File
@@ -81,15 +81,16 @@ const SHOTS_PORTRAIT := [
] ]
## Stage list: shift time selects the phase, `venue` switches the scenario first. ## Stage list: shift time selects the phase, `venue` switches the scenario first.
const STAGES := [ const STAGES := [
{"name": "day", "elapsed": 0.0, "venue": "", "shots": SHOTS_DAY, "night": false}, {"name": "day", "elapsed": 0.0, "venue": "hollywood_building", "shots": SHOTS_DAY, "night": false},
{"name": "surfaces", "elapsed": 0.0, "venue": "", "shots": SHOTS_SURFACES, "night": false}, {"name": "surfaces", "elapsed": 0.0, "venue": "hollywood_building", "shots": SHOTS_SURFACES, "night": false},
{"name": "surfaces_joke", "elapsed": 0.0, "venue": "joke_shop", "shots": SHOTS_SURFACES_JOKE, "night": false}, # Portrait before the venue switch: re-staging a close-up after a rebuild is
# Portrait next, while the day crowd is still on the street. # not reliable, and this keeps the day crowd on Hollywood.
{"name": "portrait", "elapsed": 0.0, "venue": "", "shots": SHOTS_PORTRAIT, {"name": "portrait", "elapsed": 0.0, "venue": "hollywood_building", "shots": SHOTS_PORTRAIT,
"night": false}, "night": false},
{"name": "evening", "elapsed": 620.0, "venue": "", "shots": SHOTS_EVENING, "night": true}, {"name": "evening", "elapsed": 620.0, "venue": "hollywood_building", "shots": SHOTS_EVENING, "night": true},
{"name": "late", "elapsed": 760.0, "venue": "", "shots": SHOTS_LATE, "night": true}, {"name": "late", "elapsed": 760.0, "venue": "hollywood_building", "shots": SHOTS_LATE, "night": true},
{"name": "joke_shop_day", "elapsed": 0.0, "venue": "joke_shop", "shots": SHOTS_JOKE_DAY, "night": false}, {"name": "joke_shop_day", "elapsed": 0.0, "venue": "joke_shop", "shots": SHOTS_JOKE_DAY, "night": false},
{"name": "surfaces_joke", "elapsed": 0.0, "venue": "joke_shop", "shots": SHOTS_SURFACES_JOKE, "night": false},
{"name": "joke_shop", "elapsed": 700.0, "venue": "joke_shop", "shots": SHOTS_JOKE, "night": true}, {"name": "joke_shop", "elapsed": 700.0, "venue": "joke_shop", "shots": SHOTS_JOKE, "night": true},
{"name": "studio", "elapsed": 700.0, "venue": "tv_studio", "shots": SHOTS_STUDIO, "night": true}, {"name": "studio", "elapsed": 700.0, "venue": "tv_studio", "shots": SHOTS_STUDIO, "night": true},
] ]
@@ -180,6 +181,7 @@ func _process(delta: float) -> bool:
return false return false
func _begin_stage() -> void: func _begin_stage() -> void:
_clear_capture_pause()
_stage += 1 _stage += 1
while _stage < STAGES.size() and not _only_stages.is_empty() \ while _stage < STAGES.size() and not _only_stages.is_empty() \
and not _only_stages.has(str(STAGES[_stage]["name"])): and not _only_stages.has(str(STAGES[_stage]["name"])):
@@ -209,6 +211,7 @@ func _begin_stage() -> void:
print("capture_realism: stage %s at %d ms" % [stage["name"], Time.get_ticks_msec()]) print("capture_realism: stage %s at %d ms" % [stage["name"], Time.get_ticks_msec()])
func _run_queue(delta: float) -> void: func _run_queue(delta: float) -> void:
_clear_capture_pause()
if _queue.is_empty(): if _queue.is_empty():
_phase = "stage" _phase = "stage"
return return
@@ -241,9 +244,18 @@ func _run_queue(delta: float) -> void:
_queue.pop_front() _queue.pop_front()
_shot_frames = 0 _shot_frames = 0
## Capture staging must not inherit a pause overlay from the previous stage or a
## window-focus change; a paused frame hides the very surfaces the pass audits.
func _clear_capture_pause() -> void:
if gm == null:
return
var pause = gm.get("pause_overlay")
if pause != null and pause.visible:
gm.call("_close_pause")
## Frame a nearby NPC from the front, with the sun behind the camera so the face ## Frame a nearby NPC from the front, with the sun behind the camera so the face
## is lit. The subject's own yaw is re-written every frame by its FSM, so the ## is lit. The subject's FSM and idle head-turn are frozen so the still keeps the
## portrait turns the visual `Rig` child instead and stands on the sunlit side. ## face toward the lens; photo/film poses are skipped because their props cover it.
func _stage_portrait(delta: float, angle_deg: float = 0.0) -> bool: func _stage_portrait(delta: float, angle_deg: float = 0.0) -> bool:
var guard_pos: Vector3 = gm.guard.global_position var guard_pos: Vector3 = gm.guard.global_position
var light := _sun_direction() var light := _sun_direction()
@@ -254,7 +266,17 @@ func _stage_portrait(delta: float, angle_deg: float = 0.0) -> bool:
var npc := node as Node3D var npc := node as Node3D
if npc == null or _faces_covered(npc): if npc == null or _faces_covered(npc):
continue continue
if _portrait_type >= 0 and int(_profile_of(npc).get("npc_type")) != _portrait_type: var profile = _profile_of(npc)
if profile == null:
continue
if _portrait_type >= 0 and int(profile.get("npc_type")) != _portrait_type:
continue
# A film/photo pose holds a camera or phone in front of the face; keep the
# default portrait on an idle person so the texture pass sees skin.
var pose := ""
if npc.has_method("theater_pose"):
pose = str(npc.call("theater_pose"))
if _portrait_type < 0 and pose in ["photo", "film", "perform"]:
continue continue
var distance: float = npc.global_position.distance_to(guard_pos) var distance: float = npc.global_position.distance_to(guard_pos)
if distance > 25.0: if distance > 25.0:
@@ -280,9 +302,10 @@ func _stage_portrait(delta: float, angle_deg: float = 0.0) -> bool:
continue continue
other.set_physics_process(false) other.set_physics_process(false)
other.global_position += Vector3(0.0, 0.0, 140.0) other.global_position += Vector3(0.0, 0.0, 140.0)
# Freeze the subject: its FSM re-writes the yaw every physics tick, which # Freeze the subject: its FSM re-writes the yaw every physics tick, and the
# would turn it away from the camera again. # idle head-turn would still look away after the body is aimed at the camera.
best.set_physics_process(false) best.set_physics_process(false)
best.set_process(false)
# Clear standing spot on the sidewalk, away from the queue: the close-up is a # Clear standing spot on the sidewalk, away from the queue: the close-up is a
# character still, not a slice of the scene, and the crowd would block it. # character still, not a slice of the scene, and the crowd would block it.
var spot := Vector3(0.0, 0.0, 0.0) var spot := Vector3(0.0, 0.0, 0.0)
@@ -290,6 +313,11 @@ func _stage_portrait(delta: float, angle_deg: float = 0.0) -> bool:
spot = gm.guard.get("spawn_position") spot = gm.guard.get("spawn_position")
best.global_position = spot + _portrait_spot best.global_position = spot + _portrait_spot
best.rotation.y = 0.0 best.rotation.y = 0.0
var subject_head := best.get_node_or_null("Rig/Head") as Node3D
if subject_head == null:
subject_head = best.find_child("Head", true, false) as Node3D
if subject_head != null:
subject_head.rotation.y = 0.0
# Stand between the subject and the sun, so the face is front-lit. # Stand between the subject and the sun, so the face is front-lit.
var to_light := -light var to_light := -light
to_light = to_light.rotated(Vector3.UP, deg_to_rad(angle_deg)) to_light = to_light.rotated(Vector3.UP, deg_to_rad(angle_deg))
@@ -305,10 +333,12 @@ func _stage_portrait(delta: float, angle_deg: float = 0.0) -> bool:
# Face the camera: from the subject, the guard lies in the -look direction. # Face the camera: from the subject, the guard lies in the -look direction.
# Use the drawn rig so an FSM yaw on the root cannot fight the pose. # Use the drawn rig so an FSM yaw on the root cannot fight the pose.
var rig := best.find_child("Rig", true, false) as Node3D var rig := best.find_child("Rig", true, false) as Node3D
# NPC art faces +Z; yaw the root toward the guard so the face, not the
# back, is under the camera.
var face := atan2(-look.x, -look.z)
best.rotation.y = face
if rig != null: if rig != null:
rig.rotation.y = atan2(-look.x, -look.z) rig.rotation.y = 0.0
else:
best.rotation.y = atan2(-look.x, -look.z)
return true return true
+12 -3
View File
@@ -42,10 +42,19 @@ func _process(delta: float) -> bool:
if frame >= WARMUP_FRAMES + SAMPLE_FRAMES: if frame >= WARMUP_FRAMES + SAMPLE_FRAMES:
var average := sample_ms / SAMPLE_FRAMES var average := sample_ms / SAMPLE_FRAMES
var meshes := 0 var meshes := 0
var triangles := 0
for avatar in avatars: for avatar in avatars:
meshes += avatar.find_children("*", "MeshInstance3D", true, false).size() for node in avatar.find_children("*", "MeshInstance3D", true, false):
print("NPC budget: %d avatars, %d meshes, avg frame %.2f ms (budget %.0f ms)" % [ var mi := node as MeshInstance3D
COUNT, meshes, average, BUDGET_MS]) if mi == null or mi.mesh == null:
continue
meshes += 1
for surface in mi.mesh.get_surface_count():
var arrays := mi.mesh.surface_get_arrays(surface)
var indices: PackedInt32Array = arrays[Mesh.ARRAY_INDEX]
triangles += indices.size() / 3
print("NPC budget: %d avatars, %d meshes, %d triangles, avg frame %.2f ms (budget %.0f ms)" % [
COUNT, meshes, triangles, average, BUDGET_MS])
if average > BUDGET_MS: if average > BUDGET_MS:
printerr("SMOKE FAIL: frame time %.1f ms exceeds the %.0f ms budget" % [ printerr("SMOKE FAIL: frame time %.1f ms exceeds the %.0f ms budget" % [
average, BUDGET_MS]) average, BUDGET_MS])