Detail the NPC avatars and finish the realism follow-ups
Blender library - Rebuild the face: sclera, iris and upper lid per eye, brow ridge, cheekbones, nose bridge and tip, ears with lobes, split upper/lower lips. - Give each hand four fingers plus a thumb and end every sleeve in a cuff ring. - Raise CHAR_MAX_VERTS 4000 -> 5000 (16 avatars still cost ~6.9 ms of a 50 ms frame), decimate the body to 26 %; characters are now 3,974-5,026 tris and 3,744-4,807 verts. Rebuild all 8 variants and re-bake their AO maps. Capture tooling - Add a `portrait` stage to capture_realism.gd: freeze one NPC, park the crowd out of frame, stand the subject on open sidewalk, turn it into the camera and put the guard on the sunlit side. New --portrait-type=N picks the role. - Add the npc_portrait_day concept and map the shot to it, so avatar detail is scored against a portrait instead of a wide street frame. Flashlight - Drop the fake additive beam (Materials.light_beam + the cone mesh): on GL Compatibility a first-person camera inside the cone renders it as a filled disc with a bright far ring. Keep the tight spot (14 deg, 20 m, energy 4.2) and its headless test; the visible shaft is now planned behind a Forward+ preset. Docs and task tracking - Move the finished realism follow-ups (ground exposure, flashlight, NPC detail, judge re-check) to DONE.md and expand TODO.md with step-by-step plans for NPC gear fit, venue geometry plus the committed gallery, and the Forward+ preset. - Record the decisions, gotchas and portrait recipe in MEMORY.md; update the Blender contract, the concept README and the capture section of README.md. - Refresh the gallery captures affected by the avatar rebuild. Checks: headless 228/228, Python 86/86, blender_assets audit exit 0, scene_concepts audit all GOOD, screen_designs compare 11 good / 0 bad, smoke_npc_budget OK, boot clean (only the known headless mesh warning).
This commit is contained in:
1 parent
2624b54b23
commit
1ee32215b0
53 files changed
+1853
-151
No files matched your search
@@ -13,6 +13,10 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
||||
(46 `.blend` files removed from the index on 2026-11-01); the `.gdignore` marker stays tracked.
|
||||
- `screen_designs.py judge` default `google/gemini-2.5-flash-lite` worked on 2026-11-01
|
||||
(7 match / 4 review / 0 diff); `--model` remains available.
|
||||
- Post-realism work is split by theme, not by date: the finished lighting/flashlight/NPC items
|
||||
are archived in `DONE.md`, and `TODO.md` carries three planned workstreams (NPC gear fit,
|
||||
venue geometry + committed gallery, Forward+ desktop preset). New visual work should be added
|
||||
as concrete steps under one of those headings instead of a new "realism" bucket.
|
||||
|
||||
- Graphics v0.6.0 plan (2026-11-01): NPCs move to Blender-authored skinned meshes
|
||||
(`docs/plan-graphics-v0.6.md`, ADR-0013). `tools/npc_pipeline.py` builds
|
||||
@@ -58,12 +62,14 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
||||
|
||||
## Handoff (read this first)
|
||||
|
||||
- **Status (2026-11-01):** v0.6.0 is released; the post-v0.6.0 realism and visual-alignment
|
||||
work is merged and pushed to `origin/main`. Headless **227/227**, Python tooling **86/86**,
|
||||
`tools/check_screenshots.sh` **11 good / 0 bad**, `screen_designs.py judge` **7 match /
|
||||
4 review / 0 diff**. `PLAN.md` was compacted, and README/architecture were synchronized with
|
||||
the current controls, asset pipeline, CI, and release artifacts. The historical notes below
|
||||
remain useful for implementation gotchas; for current tasks, use `TODO.md`.
|
||||
- **Status (2026-11-01, after the NPC detail pass):** v0.6.0 is released. Post-v0.6.0 the
|
||||
realism pass, the visual-alignment pass and the NPC face/hand pass all landed. Headless
|
||||
**228/228**, Python tooling **86/86**, `tools/check_screenshots.sh` **11 good / 0 bad**,
|
||||
`screen_designs.py compare` 11 good / 0 bad, `scene_concepts.py audit` all GOOD,
|
||||
`blender_assets.py audit` exit 0, `smoke_npc_budget` OK (16 avatars, 6.94 ms of 50 ms).
|
||||
`PLAN.md` is compact; README/architecture track the current controls, asset pipeline, CI and
|
||||
release artifacts. The historical notes below remain useful for implementation gotchas; for
|
||||
current tasks use `TODO.md`.
|
||||
|
||||
- **Phase 2 — AI texturing (this agent, DONE 2026-11-01).** Phase 1 assets were
|
||||
already in the tree (untracked) and are preserved. Generated six seamless AI
|
||||
@@ -169,11 +175,38 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
||||
autocorrelation) + `align_stripes()` (resample to whole periods) replace the edge crossfade
|
||||
for `awning_canvas`; `audit_striped_tile()` compares the wrap step with the harshest interior
|
||||
step.
|
||||
**Judge:** `google/gemini-2.5-flash-lite` currently answers HTTP 400 "API key not valid" for
|
||||
this key, so runs use `--model google/gemini-2.5-flash`; scores are noisy (±1–2), so
|
||||
**Judge:** the default `google/gemini-2.5-flash-lite` mostly works but intermittently answers
|
||||
HTTP 400 "API key not valid" (one shot of ten on 2026-11-01); re-run or pass
|
||||
`--model google/gemini-2.5-flash` when it does. Scores are noisy (±1–2), so
|
||||
`realism --repeats 3` averages and `summarize()` reports a like-for-like mean over the shots
|
||||
every set captured. Final: overall 0.8→1.0, backdrop 0.6→1.6, metric gap 0.444→0.348.
|
||||
`screen_designs.py judge` gained one retry for the same transient 400.
|
||||
**Character portrait capture (2026-11-01):** `capture_realism.gd` has a `portrait` stage
|
||||
(`npc_portrait` -> concept `npc_portrait_day`) because crowd shots cannot judge avatars. It
|
||||
freezes one NPC, parks the rest of the crowd 140 m away (a passer-by otherwise blocks the
|
||||
frame), moves the subject to an open sidewalk patch, turns it into the camera and stands the
|
||||
guard on the sunlit side. Needed because the NPC FSM re-writes `rotation.y` every physics tick
|
||||
(so the yaw must be set after `set_physics_process(false)`), the venue's morning sun leaves a
|
||||
face in shadow from most angles, and `visible = false` does not keep the crowd out of frame.
|
||||
`--portrait-type=N` forces a role; hooded roles (trespasser/violent/crisis) are skipped.
|
||||
**Flashlight (2026-11-01, final):** a *tight* `SpotLight3D` on `Head`: `spot_range` 20,
|
||||
`spot_angle` 14, `light_energy` 4.2, `spot_attenuation` 0.9, forward `rotation_degrees = 0`,
|
||||
starts invisible. A fake additive light shaft was tried twice (cylinder with a UV ramp, then a
|
||||
vertical-fade `ShaderMaterial`) and **rejected both times**: on GL Compatibility a first-person
|
||||
camera inside the cone renders it as a filled disc and the far ring shows, so
|
||||
`Materials.light_beam()` and the beam mesh are gone. Regression guard:
|
||||
`test_flashlight_aims_a_tight_forward_spot` in `src/test/tests/test_door_and_flashlight.gd`
|
||||
(lamp on the head, aims straight, cone ≤ 20°, starts off). Night captures are staged in LATE
|
||||
(`elapsed_s` 760), not dusk.
|
||||
**NPC detail pass (2026-11-01):** `_face()` now builds sclera + iris + upper lid per eye, brow
|
||||
ridge, cheekbones, nose bridge/tip, ears with lobes and split upper/lower lips; the new
|
||||
`eye_white` material is a *fixed-colour* slot, so `_apply_outfit_materials()` leaves it white.
|
||||
`_hands_and_shoes()` has four fingers plus a thumb and `_clothing()` adds `Cuff` tori.
|
||||
Budget work: `CHAR_MAX_VERTS` 5000 (see the library note), body decimation 0.26, upper lids are
|
||||
boxes rather than spheres, and knuckle spheres/nostrils were cut to stay inside it.
|
||||
**Orientation debugging:** to check a GLB's front axis, compare the mean Z of the `eye_white`
|
||||
surface (face) and of the `rubber` sole verts (toes) — all 8 avatars are +Z, so any
|
||||
"they walk backwards" symptom is a yaw bug, not an export flip.
|
||||
- **Blender asset library (v0.6.0, integrated 2026-11-01):**
|
||||
`tools/blender_assets.py` (`build`/`render` in Blender; `audit`/`sheet`/`list` stdlib) writes
|
||||
`assets/models/blender/{npc,npc_gear,props}/*.glb`, `manifest.json` (integration source of
|
||||
@@ -181,8 +214,10 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
||||
`docs/blender_previews/sheet_*.jpg` (per-asset PNG renders are gitignored). 8 characters, 18
|
||||
gear, 20 props; notes in `docs/blender-assets.md`. Characters are drop-in for `npc_base`
|
||||
(same mesh node name, bones at the same rest positions, five tint slots) and stay under the
|
||||
6000/4000 budget only because of body decimation (0.36) + `smart_project` at 80°: glTF vertex
|
||||
count includes UV-seam splits, so extra beveled detail quickly breaks 4000.
|
||||
6000/4000 budget only because of body decimation (0.26) + `smart_project` at 80°: glTF vertex
|
||||
count includes UV-seam splits, so extra beveled detail quickly breaks the limit. The 2026-11-01
|
||||
face/hand pass raised `CHAR_MAX_VERTS` to 5000 (tris 3,974–5,026) after measuring 16 avatars at
|
||||
~6.9 ms of a 50 ms frame; `npc_pipeline.MAX_VERTICES`/`MAX_TRIANGLES` (base mesh) are unchanged.
|
||||
**Gotchas:** `bisect_plane` and thin bevels leave zero-area triangles (Godot warns "non-finite
|
||||
normal in LOD generation"); `_clean()` + a weld after bisect fix it, and the audit rejects them.
|
||||
Fixed-colour detail materials carry a 4×4 texture because `_apply_outfit_materials()` sets
|
||||
@@ -231,7 +266,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
||||
- Screen mockups with baked-in controls are used as backdrops plus an opaque `ArtPanel` cover, not as clickable full-screen skins.
|
||||
- Radio, wand, inspection, and body-camera timeline panels use their reference art as backdrops; forms sit on transparent, padded panels over the covered mockup controls.
|
||||
- HUD target names use a boxed chip under the crosshair; escalation has a five-segment bar below the text label. The body-camera REC/clock block starts at y=92 on the right so it clears the shift/rep/crowd text.
|
||||
- Staged captures were regenerated from HEAD in a clean worktree; the main working tree's `docs/screenshots` is being rewritten by the realism pass, so do not overwrite it from that run.
|
||||
- Staged captures in `docs/screenshots/` are committed and were last regenerated after the realism and NPC passes; re-run `tools/check_screenshots.sh` (not a partial capture) before replacing them.
|
||||
- `tools/check_screenshots.sh` is the repeatable capture+compare smoke; both capture scripts accept `--out=res://docs/screenshots`. Judge verdicts on the staged set were 7 match / 4 review / 0 diff.
|
||||
- Venue selection used to leave `guard.input_locked` true and the mouse visible; `_start_shift()` must call `_refresh_freeze()` after starting the clock.
|
||||
|
||||
@@ -564,7 +599,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
||||
- Joke Shop `door_staff_lines` are logged through `GameManager` (inspect / wand / refuse). They are not a separate dialogue UI.
|
||||
- Access loadout is implemented; do not re-fix `override_access` as if it were still unread.
|
||||
- `Save.SETTINGS_FILE` is declared and unused; settings persistence goes through `Save.load_settings()` / `save_settings()`.
|
||||
- Headless suite is **227/227**; the windowed smokes, screenshot compare, and judge pass. Remaining visual follow-ups are in `TODO.md`.
|
||||
- Headless suite is **228/228**; the windowed smokes, screenshot compare and judge pass. Remaining visual follow-ups are in `TODO.md`.
|
||||
- Typed spawn signal extra args: handlers must accept the 4th `event: Dictionary` or Godot will not call them (`test_shift_coordinator_runs_a_shift` failed until `_on_spawn` took four args).
|
||||
- GDScript inference trap that broke the main scene: a `var` typed as a base class
|
||||
(`radial: CanvasLayer`) exposes script members as `Variant`, so `var x := radial.is_open` is a
|
||||
@@ -595,9 +630,7 @@ GUT, and Gitea Actions, not GitHub Actions.
|
||||
|
||||
## Uncommitted Workstreams
|
||||
|
||||
- **NPC fidelity pass (2026-11-01, active):** editing the Blender NPC/gear/prop library
|
||||
(`assets/models/blender/` + `manifest.json`), `src/game/game_manager.gd`, `materials.gd`,
|
||||
`capture_realism.gd`, the door/flashlight and Blender tests, `tools/blender_assets.py`,
|
||||
`tools/scene_concepts.py`, `tools/test_blender_assets.py`, the affected screenshots, and the
|
||||
new NPC portrait concepts. Do not commit or revert these until the pass finishes; verify game
|
||||
changes in a clean `git worktree` at HEAD.
|
||||
- **None (2026-11-01).** The NPC detail pass, the realism follow-ups and the flashlight beam
|
||||
decision are committed together with the portrait capture and the refreshed screenshots.
|
||||
Keep the rule from `AGENTS.md`: check `git status` before committing, and never revert
|
||||
another contributor's in-flight files.
|
||||
Reference in new issue
Block a user