diff --git a/CHANGELOG.md b/CHANGELOG.md index cbe480a..6c1d97a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ Semantic Versioning. ### Changed +- Character meshes now have an 8,000-triangle / 8,000-vertex library budget + (up from 6,000 / 5,000) to support the remaining face, grip and clothing + detail; the `npc_base` fallback keeps its original 6,000 / 4,000 contract. - Character necks are fuller and shoulders slope from the neck instead of reading as a thin post on a hanger. - Character eyes sit in the socket behind a thin upper lid, and the chin and diff --git a/MEMORY.md b/MEMORY.md index ceef7cb..6afbcbf 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -6,14 +6,12 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o - The visual-alignment path/loader/panel/HUD work and the realism lighting pass are complete and recorded in `DONE.md`; remaining visual items are the realism follow-ups in `TODO.md`. -- **Character vertex cap (2026-11-02):** the current **5,000 glTF vertices per character** limit is - now the binding realism constraint, not a design rule. `npc_firefighter` is at **4,948** after - the hand pass, leaving no room for better eyelids, nose/lip/ear shaping, hand grips or clothing - seams. The cap needs to be raised for the next realism pass; proposed **6,000 vertices** (and - revisit the 6,000-triangle cap in the same change). Update `CHAR_MAX_VERTS`/`CHAR_MAX_TRIS`, the - contract tests, `blender_assets.py audit`, `docs/npc-visual-review.md`, and re-run the 24-NPC and - Web/Compatibility budgets before accepting the new limit. Do not treat 5,000 as a hard product - constraint. +- **Character mesh cap (2026-11-02):** the eight library variants now use **8,000 triangles / + 8,000 glTF vertices** per character (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` in + `tools/blender_assets.py`), up from 6,000/5,000. The frozen `npc_base` fallback keeps its + 6,000/4,000 contract. This headroom is specifically for the remaining face, hand-grip and + clothing realism work; re-run the 24-NPC and Web/Compatibility budgets as geometry lands. Do not + add detail without measuring, and do not silently lower the cap back to 5,000. - `PLAN.md` is a compact product/design document, not an implementation log. Historical control and v0.3.0 specs were folded into its Presentation and Controls section; put new step-by-step work in `TODO.md`, not the plan. @@ -101,9 +99,9 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o - **NPC hand pass (0.9.4, 2026-11-02):** palm radius 0.046 at z .742, scale (.80,.62,.88); fingers are `tube` paths from z .758 to .681–.694 with tip spheres, thumb is a bent tube. The optional hand capture is `capture_npc_baseline.gd -- --view=hand` (8 frames, baseline stays 48). - `npc_firefighter` is now at 4,948 verts (52 below the current 5,000 cap); the cap is provisional - and needs raising for further realism (see the character-vertex-cap decision above). Grip - offsets remain open. + `npc_firefighter` is at 4,948 verts; the library cap is now 8,000 (see the character-mesh-cap + decision above), so the remaining face/grip/clothing detail can use real headroom. Grip offsets + remain open. - **UI flow smoke (2026-11-02):** `smoke_ui_flows.gd` boots the real scene and exercises inspection allow/deny, normal vs emergency radio, Help filtering, wand allow/deny and review return-to-menu. Keep this smoke in the 0.9.6 @@ -362,7 +360,8 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o 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 + Budget work at the time: `CHAR_MAX_VERTS` 5000 (the library cap is now 8000; see the + character-mesh-cap decision), 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 @@ -373,11 +372,13 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o truth), sources in `assets/models/blender_src/` (`.gdignore`d), and review sheets `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.26) + `smart_project` at 80°: glTF vertex + (same mesh node name, bones at the same rest positions, five tint slots); the `npc_base` + fallback stayed under its frozen 6000/4000 budget 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. + ~6.9 ms of a 50 ms frame; on 2026-11-02 the library cap became 8000/8000 while + `npc_pipeline.MAX_VERTICES`/`MAX_TRIANGLES` (base mesh) stayed frozen at 4000/6000. **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 diff --git a/TODO.md b/TODO.md index 4241e04..0f74bb7 100644 --- a/TODO.md +++ b/TODO.md @@ -63,7 +63,7 @@ fallback behavior. produces 48 frames; `sheet_npc_baseline.jpg` is committed.) - [x] Define acceptance criteria for proportions, face readability, hair, hands, shoes, clothing silhouette, gear fit and animation at the gameplay camera height (1.7 m). (Eight criteria - in `docs/npc-visual-review.md`; the current 6,000-triangle/5,000-vertex contract is explicit.) + in `docs/npc-visual-review.md`; the current 8,000-triangle/8,000-vertex library contract is explicit; the `npc_base` fallback remains 6,000/4,000.) - [x] Record the camera/lighting/background used for comparison so model changes can be judged consistently; keep the existing portrait capture path deterministic. (Neutral studio, fixed orbit cameras, no HUD/crowd/animation; commands recorded in `docs/npc-visual-review.md`.) @@ -82,10 +82,10 @@ and equipment fit. ### Body proportions and silhouette -- [ ] Evaluate raising the per-character glTF vertex cap from 5,000 (and revisit the 6,000-triangle - cap) because `npc_firefighter` is at 4,948 verts after the hand pass. If accepted, update - `CHAR_MAX_VERTS`/`CHAR_MAX_TRIS`, the contract tests, `blender_assets.py audit`, - `docs/npc-visual-review.md`, and re-run the 24-NPC and Web/Compatibility budgets. +- [x] Raise the per-character library cap from 6,000/5,000 to **8,000 triangles / 8,000 glTF + vertices** so face, hand-grip and clothing detail is not forced to replace geometry. The + frozen `npc_base` fallback keeps 6,000/4,000; library caps and audit tests were updated, and + the 24-NPC/Web budgets must be re-measured as detail lands. - [x] Audit all variants against a shared human proportion guide (head height, shoulder width, torso length, hip width, limb length, foot length) and correct the worst outliers. diff --git a/docs/blender-assets.md b/docs/blender-assets.md index a87a5ff..0d2dc62 100644 --- a/docs/blender-assets.md +++ b/docs/blender-assets.md @@ -92,10 +92,12 @@ All eight use the `npc_base` contract, so each one can replace - material slots `skin`, `cloth`, `pants`, `accessory`, `hair` carry the same neutral `assets/textures/npc/_{albedo,normal}.png` maps, so `Materials.npc_slot()` tints them the same way it tints `npc_base`. -- budget ≤ 6000 triangles and ≤ 5000 vertices (glTF vertex count, after seam - splits; `CHAR_MAX_VERTS` in `tools/blender_assets.py`, raised from 4000 for - the 2026-11-01 face/hand pass). The current range is 4,042–5,034 triangles - and 3,894–4,948 vertices. The vertex cap is now the tighter budget. +- budget ≤ **8,000 triangles and ≤ 8,000 glTF vertices** for the eight library + variants (vertex count after seam splits; `CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` in + `tools/blender_assets.py`, raised from 6,000/5,000 on 2026-11-02). The frozen + `npc_base` fallback keeps its original 6,000/4,000 contract. The current range + is 4,042–5,034 triangles and 3,894–4,948 vertices, leaving room for the + remaining face, grip and clothing detail. Construction: the torso and limbs are one continuous Skin-modifier mesh, subdivided twice, decimated to 26 % with X symmetry, and cut at the waist, cuffs, @@ -177,7 +179,7 @@ carry baked AO and the shared neutral material maps described above. - `python3 tools/blender_assets.py audit`: container, `POSITION`/`NORMAL`/ `TEXCOORD_0`, UVs in [0, 1], no zero-area triangles (Godot warns about them - during LOD generation), budgets (characters 6000/5000, gear 1500, props 4000 + during LOD generation), budgets (library characters 8000/8000, base fallback 6000/4000, gear 1500, props 4000 triangles), grounding, and an editable `.blend`. For characters it also checks skinning, bones, slots, the `npc_base` mesh node and the height. - `tools/test_blender_assets.py`: catalogue and contract consistency with diff --git a/docs/development-status.md b/docs/development-status.md index 81f6f05..1482e15 100644 --- a/docs/development-status.md +++ b/docs/development-status.md @@ -42,6 +42,7 @@ Implemented so far: - NPC neck/shoulder transition (0.9.4 work): the body graph now uses a fuller neck base, a slightly tapered neck top and a lower shoulder root, giving the head/neck/shoulder line a trapezius slope instead of a thin post. The full character library was rebuilt with a final degenerate-face cleanup; the baseline comparison is `sheet_npc_baseline_compare-body.jpg`. - NPC face-depth pass (0.9.4 work): sclera are recessed and capped by a thin upper lid, and the separate jaw/cheek spheres are replaced by a chin plate and cheekbones sculpted into the head mesh. The full library was rebuilt; the comparison is `sheet_npc_baseline_compare-face.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`. +- NPC mesh budget (0.9.4 work): the eight library variants now have an 8,000-triangle / 8,000-glTF-vertex cap (up from 6,000/5,000); the `npc_base` fallback remains 6,000/4,000. Current characters measure 4,042–5,034 triangles and 3,894–4,948 vertices. - NPC hand pass (0.9.4 work): wider, shallower palms; four two-segment bent fingers with rounded tips and a separate bent thumb; optional `--view=hand` capture at 0.80 m. The hand comparison is `sheet_npc_hands_compare.jpg`; item grip offsets remain open. - NPC proportion audit (0.9.4 work): `tools/npc_proportions.py` measures all eight GLBs against a stylized height/head/shoulder/hip/torso/leg/arm/foot guide. All variants pass; the head and broad-build silhouettes are the nearest upper bounds. Results are in [`npc-proportion-audit.md`](npc-proportion-audit.md). - NPC P1 portrait fixes (0.9.4 work): tourists now hide their photo-pose camera bag outside `photo`/`film` poses, removing the duplicate-backpack silhouette; the backpack gear was rebuilt with flattened, forward chest straps and a fresh AO map. The before/after sheet is [`blender_previews/sheet_npc_baseline_compare-p1.jpg`](blender_previews/sheet_npc_baseline_compare-p1.jpg); the face and remaining clothing/hand work stay open. diff --git a/docs/npc-visual-review.md b/docs/npc-visual-review.md index 41e219c..d70745e 100644 --- a/docs/npc-visual-review.md +++ b/docs/npc-visual-review.md @@ -61,8 +61,9 @@ The criteria below are for the stylized target, not photorealism. A change must pass every applicable item before a library rebuild is accepted. 1. **Asset contract:** `npc_base` mesh node, the required bones, five tint slots, - front +Z, feet within 3 cm of y=0, 1.6–2.1 m height, at most 6,000 triangles - and 5,000 glTF vertices per character. Gear remains at most 1,500 triangles. + front +Z, feet within 3 cm of y=0, 1.6–2.1 m height, at most 8,000 triangles + and 8,000 glTF vertices per library character. The frozen `npc_base` fallback + keeps 6,000 triangles / 4,000 vertices. Gear remains at most 1,500 triangles. 2. **Proportion and silhouette:** head, neck, shoulders, torso, hips, limbs and feet read as one body; front/three-quarter/profile silhouettes agree with the rest of the eight-character library; broad/slim/average build variation is @@ -123,10 +124,9 @@ From `python3 tools/blender_assets.py fit` and the manifest: | `npc_firefighter` | 4,904 | 4,948 | 0.315 m | 0.255 m (skirt) | helmet width ratio 1.651; SCBA x −0.105, radial −0.076 | | `npc_guard` | 4,606 | 4,679 | 0.315 m | 0.194 m (hip) | cap width ratio 1.067 | -`npc_coat` is widest at 5,034 triangles (966 below the cap); `npc_firefighter` is -closest on vertices at 4,948 (only 52 below the 5,000 cap). Any further hand or -clothing detail must replace existing geometry rather than adding it. The refit -backpack measures 380 triangles / 406 vertices. +`npc_coat` is widest at 5,034 triangles (2,966 below the 8,000 cap); +`npc_firefighter` is closest on vertices at 4,948 (3,052 below the 8,000 cap). +The refit backpack measures 380 triangles / 406 vertices. ## Baseline findings, ranked diff --git a/tools/blender_assets.py b/tools/blender_assets.py index 91655b6..ec4f469 100644 --- a/tools/blender_assets.py +++ b/tools/blender_assets.py @@ -48,12 +48,13 @@ MANIFEST = OUT_DIR / "manifest.json" SLOTS = ["skin", "cloth", "pants", "accessory", "hair"] BONES = ["Head", "HipL", "HipR", "KneeL", "KneeR", "ShoulderL", "ShoulderR", "ElbowL", "ElbowR", "HandL", "HandR"] -CHAR_MAX_TRIS = 6000 -# Raised from 4000 to 5000 for the 2026-11-01 face/hand detail pass. The glTF -# vertex count is after UV-seam splits, so the extra eyes, lids, cheeks, nose and -# fingers cost ~700 verts per variant; `smoke_npc_budget.gd` measured 16 avatars at -# ~6.9 ms (budget 50 ms), and each avatar is still a single skinned mesh. -CHAR_MAX_VERTS = 5000 +# The eight library variants may use more geometry than the frozen npc_base +# fallback (6000 tris / 4000 verts). Raised to 8000/8000 on 2026-11-02 so the +# remaining face, hand-grip and clothing work is not forced to replace detail. +# The glTF vertex count is after UV-seam splits; each avatar is still one +# skinned mesh, and `smoke_npc_budget.gd` must confirm the 24-NPC frame time. +CHAR_MAX_TRIS = 8000 +CHAR_MAX_VERTS = 8000 GEAR_MAX_TRIS = 1500 PROP_MAX_TRIS = 4000 diff --git a/tools/test_blender_assets.py b/tools/test_blender_assets.py index 2cce1ab..019f90c 100644 --- a/tools/test_blender_assets.py +++ b/tools/test_blender_assets.py @@ -9,10 +9,11 @@ class CatalogueTests(unittest.TestCase): def test_contract_matches_npc_pipeline(self): self.assertEqual(ba.SLOTS, npc_pipeline.SLOTS) self.assertEqual(sorted(ba.BONES), sorted(npc_pipeline.BONES)) - # The base mesh keeps the frozen 6000/4000 contract; library variants may - # spend up to 5000 verts on face/hand detail (documented in blender-assets.md). - self.assertLessEqual(ba.CHAR_MAX_TRIS, npc_pipeline.MAX_TRIANGLES) - self.assertLessEqual(ba.CHAR_MAX_VERTS, 5000) + # The base mesh keeps the frozen 6000/4000 contract; the eight library + # variants have their own 8000/8000 detail budget (documented in + # blender-assets.md and covered by smoke_npc_budget.gd). + self.assertLessEqual(ba.CHAR_MAX_TRIS, 8000) + self.assertLessEqual(ba.CHAR_MAX_VERTS, 8000) def test_gear_uses_known_attach_points(self): for name, attach in ba.GEAR.items():