From 79224c5acfac0bf4ae6e698f89afc6553294f02f Mon Sep 17 00:00:00 2001 From: Zwitschi Date: Thu, 5 Nov 2026 19:37:19 +0100 Subject: [PATCH] Raise the NPC character budget to 24k and refine the prototype neck --- .../gig-line-blender-asset-contract/SKILL.md | 8 ++-- .../references/asset-contract.md | 2 +- AGENTS.md | 4 +- CHANGELOG.md | 8 ++++ MEMORY.md | 14 ++++++- TODO.md | 23 ++++++---- docs/3d-model-review.md | 2 +- docs/README.md | 2 +- docs/adr/0016-npc-character-budget-24k.md | 42 +++++++++++++++++++ docs/adr/README.md | 1 + docs/architecture.md | 6 +-- docs/asset-tooling.md | 4 +- docs/blender-assets.md | 4 +- docs/npc-model-sourcing.md | 16 +++---- docs/npc-visual-review.md | 4 +- tools/blender_assets.py | 22 +++++----- tools/npc_pipeline.py | 6 +-- tools/tests/test_blender_assets.py | 12 +++--- tools/tests/test_npc_pipeline.py | 4 +- 19 files changed, 128 insertions(+), 56 deletions(-) create mode 100644 docs/adr/0016-npc-character-budget-24k.md diff --git a/.agents/skills/gig-line-blender-asset-contract/SKILL.md b/.agents/skills/gig-line-blender-asset-contract/SKILL.md index e29fb32..b2495ee 100644 --- a/.agents/skills/gig-line-blender-asset-contract/SKILL.md +++ b/.agents/skills/gig-line-blender-asset-contract/SKILL.md @@ -1,6 +1,6 @@ --- name: gig-line-blender-asset-contract -description: Use when adding, rebuilding, auditing or fixing any Gig Line Blender-authored character, NPC base, gear, prop or venue geometry. Covers the required 13 core bones (optional extra bones allowed), five tint slots, 16,000/16,000 character budgets, gear attach space, 256² texture/AO rules, headless flatpak Blender commands, optional MCP guidance, and the inspect/audit/fit/proportion/capture gates. Do not use for pure GDScript/UI work or release publishing. +description: Use when adding, rebuilding, auditing or fixing any Gig Line Blender-authored character, NPC base, gear, prop or venue geometry. Covers the required 13 core bones (optional extra bones allowed), five tint slots, 24,000/24,000 character budgets, gear attach space, 256² texture/AO rules, headless flatpak Blender commands, optional MCP guidance, and the inspect/audit/fit/proportion/capture gates. Do not use for pure GDScript/UI work or release publishing. compatibility: Gig Line repository checkout. Godot 4.7.2 on PATH; Blender 5.2 LTS via the org.blender.Blender flatpak for build/bake/render. Audit, fit, inspect and proportion checks are stdlib-only. metadata: project: Gig Line @@ -51,8 +51,8 @@ and resolve the source of truth before editing assets. | Bones | The 13 required core bones: `Head`, `HipL/R`, `KneeL/R`, `ShoulderL/R`, `ElbowL/R`, `HandL/R`, `Spine`, `Neck`. Optional extra bones (fingers, face, toes) are allowed; they must not move the core rest positions or break animation proxies. | | Tint slots | `skin`, `cloth`, `pants`, `accessory`, `hair`. | | Orientation | Front is Blender −Y / Godot +Z; feet grounded near y = 0; metres. | -| Character budget | **16,000 triangles / 16,000 glTF vertices** per character (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS`). | -| Frozen fallback | `npc_base` remains the low-poly fallback; it shares the 16,000/16,000 cap but is not required to use it. Do not silently lower the cap. | +| Character budget | **24,000 triangles / 24,000 glTF vertices** per character (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS`). | +| Frozen fallback | `npc_base` remains the low-poly fallback; it shares the 24,000/24,000 cap but is not required to use it. Do not silently lower the cap. | | Gear budget | **1,500 triangles** per gear piece; authored in attach-point space. | | Prop budget | **4,000 triangles** per prop. | | Gear attach | Use the catalogued attach points; verify with `fit`. Runtime `GEAR_OFFSETS` (lanyard forward, firefighter helmet up) and `HAND_ITEM_FORWARD` are intentional, not asset-contract changes. | @@ -167,7 +167,7 @@ At minimum: - `npc_proportions.py` passes the stylized guide. - `npc_pipeline.py audit` passes if the base/textures changed. - texel density is inside the authored/fabric bands. -- No character exceeds 16,000/16,000; gear/prop caps hold. +- No character exceeds 24,000/24,000; gear/prop caps hold. - 24-NPC budget and Web/Compatibility path remain green. - Contract tests, headless suite, capture gates and docs check pass. - The diff contains only the intended assets, tools, tests and docs. diff --git a/.agents/skills/gig-line-blender-asset-contract/references/asset-contract.md b/.agents/skills/gig-line-blender-asset-contract/references/asset-contract.md index 948c7aa..55204be 100644 --- a/.agents/skills/gig-line-blender-asset-contract/references/asset-contract.md +++ b/.agents/skills/gig-line-blender-asset-contract/references/asset-contract.md @@ -59,7 +59,7 @@ skin, cloth, pants, accessory, hair | Asset | Limit | | --- | --- | -| Character (library and base fallback) | 16,000 triangles / 16,000 glTF vertices | +| Character (library and base fallback) | 24,000 triangles / 24,000 glTF vertices | | Gear piece | 1,500 triangles | | Prop | 4,000 triangles | | Library prop/venue total | must stay inside the venue tests and library budget | diff --git a/AGENTS.md b/AGENTS.md index ed6e82c..ba5aec9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -91,8 +91,8 @@ specialists the task needs: ### Project rules that override a skill 1. **The project contract wins.** `npc_base` mesh node, the 13 required core bones at their rest - positions, five tint slots, front on Blender −Y / Godot +Z, grounded feet, 16,000 - triangles / 16,000 glTF vertices per character, 1,500 per gear, 4,000 per prop. Optional + positions, five tint slots, front on Blender −Y / Godot +Z, grounded feet, 24,000 + triangles / 24,000 glTF vertices per character, 1,500 per gear, 4,000 per prop. Optional extra bones (fingers, face, toes) are allowed if they do not move the core rest positions. A skill may recommend another topology, naming or budget scheme; do not adopt it unless the change is explicitly planned and the contract, tests and docs are updated together. diff --git a/CHANGELOG.md b/CHANGELOG.md index fcbb6d4..0612919 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable user-facing changes to Gig Line. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions use Semantic Versioning. +## [Unreleased] + +### Changed + +- Raised the character mesh budget from 16,000 to 24,000 triangles and glTF + vertices so the MakeHuman head, MPFB body, fused neck and clothing variants + can fit without heavy decimation. Gear and prop budgets are unchanged. + ## [0.9.8] — 2026-11-04 ### Fixed diff --git a/MEMORY.md b/MEMORY.md index 85ffcf8..c4e7bd0 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -114,11 +114,21 @@ canonical implemented-features list in `docs/development-status.md`. `docs/asset-tooling.md#optional-interactive-blender-mcp`. The headless flatpak scripts remain authoritative; MCP is never a build/CI/test/runtime dependency, and anything MCP touched must pass the CLI audit/fit gates. -- **Character mesh cap (2026-11-04):** all characters use 16,000 tris / 16,000 glTF vertices +- **Character mesh cap (2026-11-05):** all characters use 24,000 tris / 24,000 glTF vertices (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` in `tools/blender_assets.py`; `npc_pipeline.MAX_TRIANGLES`/ `MAX_VERTICES`). The required 13 core bones stay, optional extra bones are allowed, and the - low-poly `npc_base` fallback remains the shipped fallback. Measure the 24-NPC/Web budget after + low-poly `npc_base` fallback remains the shipped fallback. The raise funds the MPFB body and a + seamless neck/shoulder junction. Measure the 24-NPC/Web budget after any geometry change; never silently lower the cap without a new decision. +- **MPFB prototype neck (2026-11-05):** a boolean cylinder (r 0.102) cuts the body neck bore; a + smooth lathe covers it. The accepted head keeps a wide flat cut brim at 1.53, so the prototype + trims the head at 1.55 (discarding only the neck stub) and matches the lathe to the smaller + elliptical opening. This removes the square collar, dark notches and wide brim. Remaining: a + thin jaw crease and a hard shirt-shoulder point in three-quarter view. Do not re-add a torus, + flat disk, collar shell or destructive neck smoothing; those were rejected. +- **MPFB prototype count (2026-11-05):** 19,747 tris / 11,475 glTF verts / 1.810 m / 14 bones / + 10 materials; `inspect` clean. Body-only head/neck surgery lives in + `tmp/npc-research/build_mpfb_npc.py` (backups in `/tmp/build_mpfb_npc_94.py`). - **Engine baseline:** Godot 4.7.2 stable (official editor `~/.local/bin/godot`). The system's `godot-runner` cannot load arbitrary project paths (compiled without path overrides); use the official editor binary. diff --git a/TODO.md b/TODO.md index ff548c7..821734d 100644 --- a/TODO.md +++ b/TODO.md @@ -18,7 +18,7 @@ Goal: replace the sphere-and-primitive face and hand construction with a local, development pipeline that can build, inspect and compare the **head/face** and **hands** separately before assembling them into the shipped character. Prioritise face readability at portrait distance, then hand silhouette and gear contact. Preserve the `npc_base` contract, the 13 core-bone rig (optional extra bones allowed), -five tint slots, 16,000/16,000 character cap, optional extra bones beyond the required 13, and the Compatibility/Web path. +five tint slots, 24,000/24,000 character cap, optional extra bones beyond the required 13, and the Compatibility/Web path. *Skill route: `character-artist`, `retopology`, `sculpting`, `rigging`, `uv-workflow`, `texture-workflow`, `materials`, `lookdev`, `asset-optimization`, `qa-review`.* @@ -28,7 +28,7 @@ gitignored `.blend1`; the 12 production characters are assembled procedurally by `tools/blender_assets.py` from `_shape_head_mesh`, `_face`, `_hair` and `_hands_and_shoes`. The MakeHuman head is now a second head source (`build_character(head="mh")`, `build --head mh`, `npc_parts.py assemble --head mh`) and all 12 variants assemble inside the -16,000-triangle cap with it. The procedural body, hands and clothing remain unchanged. The +24,000-triangle cap with it. The procedural body, hands and clothing remain unchanged. The MakeHuman body prototype and its temporary head/hand swap live under `tmp/npc-research/` and are not the shipped path. This overhaul supplies the reusable head/face and hand parts that both the procedural characters and the MakeHuman body can consume. @@ -45,7 +45,7 @@ the rest of §C remains the broad review checklist. `docs/3d-model-review.md` §Baseline inventory. - [x] Define measurable acceptance: face front/three-quarter/profile at 1.5 m and 1.85 m; hands open and gripping at 0.8 m; silhouette, eye/mouth readability, ear/nose/jaw planes, finger - separation and gear contact. Keep the 16,000/16,000 cap; optional extra bones are allowed, but the required 13 core bones and rest positions must not move. + separation and gear contact. Keep the 24,000/24,000 cap; optional extra bones are allowed, but the required 13 core bones and rest positions must not move. Recorded in `docs/3d-model-review.md` §Overhaul acceptance criteria. - [x] Confirm the identity boundary: `npc_base.blend` is the frozen fallback and must not absorb prototype detail unless a separate contract decision approves it. @@ -195,7 +195,7 @@ the rest of §C remains the broad review checklist. ### Full-body MPFB prototype Goal: assemble the accepted MakeHuman head onto a CC0 MPFB body with project hands, shoes and -14-bone contract rig, inside the 16,000/16,000 character budget. Local development only until the +14-bone contract rig, inside the 24,000/24,000 character budget. Local development only until the owner reviews the silhouette and a production integration decision is recorded. - [x] Build the dev pipeline at `tmp/npc-research/build_mpfb_npc.py`: create a macro-driven MPFB @@ -203,10 +203,19 @@ owner reviews the silhouette and a production integration decision is recorded. apply the helper MASK, scale to 1.81 m, retarget the A-pose arms to the contract wrist (`x=±0.27`, `z=0.78`), cut the neck at 1.505, decimate, bisect the clothing boundaries, paint the five slots, add a short neck flare, project hands, rounded shoe shells, cuffs, the - accepted head and the 14-bone armature. Current output: **15,317 tris / 13,690 glTF verts / - 13,702 seam-split verts / 1.810 m / 14 bones / 10 materials**; `inspect` clean, feet grounded. + accepted head and the 14-bone armature. Current output: **19,747 tris / 11,475 glTF verts / + 1.810 m / 14 bones / 10 materials**; `inspect` clean, feet grounded. The torso is inflated radially by 12% through z 0.72–1.40 (tapering out at the collar) so the shirt reads as fabric rather than body paint. +- [x] Raise the character contract to 24,000 triangles / 24,000 glTF vertices so the MPFB body, + the accepted head and a fused neck can coexist with headroom for the 12-variant clothing. + Bumped `CHAR_MAX_TRIS`/`CHAR_MAX_VERTS`, `npc_pipeline.MAX_TRIANGLES`/`MAX_VERTICES`, + the adapt defaults, the tests, `AGENTS.md`, ADR-0016 and the project skills. +- [-] Fix the head/neck/shoulder junction so there are no gaps, square collars or hard rims. + Done: circular boolean bore, smooth lathe, accepted head trimmed at its narrow neck (1.55), + no dark notches or wide brim; prototype at 19,747 tris. Remaining: a thin jaw crease and a + hard shirt-shoulder point in three-quarter view. Next candidate: reshape the shirt shoulder + or a shaped collar that follows the neckline, not a torus or flat disk. - [x] Replace the spiky decimated MPFB hands with the project palm/finger primitives, straighten the splayed MPFB feet so the shoes point forward, and use rounded shoe shells + cuffs instead of flat blocks. Use flat slot colours in the prototype because the one-shot MPFB UV unwrap does @@ -299,7 +308,7 @@ an active track; ADR-0015 (CC0 / CC-BY with attribution) still governs every int ### Intake and adaptation - [x] `adapt` path added to `tools/blender_assets.py` (`adapt --file --out - [--target-tris 16000]`): imports the GLB, applies transforms, grounds the feet, welds seam + [--target-tris 24000]`): imports the GLB, applies transforms, grounds the feet, welds seam splits and decimates to the budget, then exports. The five tint slots + 13-core rig (optional extra bones allowed) stay a manual step (recorded in the command doc). - [x] `audit` stays the final gate; `test_adapt_requires_blender` covers the non-Blender error diff --git a/docs/3d-model-review.md b/docs/3d-model-review.md index 5ac34a7..ddbdc6f 100644 --- a/docs/3d-model-review.md +++ b/docs/3d-model-review.md @@ -193,7 +193,7 @@ capture). Pass conditions: ### Contract (both, every prototype) -- 16,000 triangles / 16,000 glTF vertices per character; gear stays at 1,500. +- 24,000 triangles / 24,000 glTF vertices per character; gear stays at 1,500. - Optional extra bones are allowed; the required 13 core bones and their rest positions must not move; the `npc_base` mesh node name and the five tint slots stay unchanged. diff --git a/docs/README.md b/docs/README.md index a62f147..559f5aa 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,7 +4,7 @@ This folder holds the project documentation, visual references and generated QA ## Current priorities -1. [Blender NPC model overhaul](../TODO.md#blender-npc-model-overhaul-top-priority) — part-based head/face/hands pipeline and 16,000-budget contract. +1. [Blender NPC model overhaul](../TODO.md#blender-npc-model-overhaul-top-priority) — part-based head/face/hands pipeline and 24,000-budget contract. 2. [MakeHuman and 3D model/map improvements](../TODO.md#makehuman-character-pipeline) — body intake, asset re-evaluation and local map reconstruction. 3. [0.10.0 release candidate](../TODO.md#milestone-0100--3d-model-and-map-improvements-minor) — versioned release hardening after the unversioned development tracks. diff --git a/docs/adr/0016-npc-character-budget-24k.md b/docs/adr/0016-npc-character-budget-24k.md new file mode 100644 index 0000000..d30bbdd --- /dev/null +++ b/docs/adr/0016-npc-character-budget-24k.md @@ -0,0 +1,42 @@ +# ADR-0016: 24,000-triangle character budget + +- **Status:** Accepted +- **Date:** 2026-11-05 + +## Context + +ADR-0015 raised the character contract to 16,000 triangles / 16,000 glTF +vertices for the MakeHuman head, hands and crowd variety. The local MPFB +full-body prototype now uses that head, project hands and shoes, and a fused +neck: it measures 19,747 triangles before any clothing variation. The 16,000 cap +leaves no room for the firefighter and hoodie gear, and it forces the body and +neck into a low decimation that produces visible facets. + +## Decision + +Raise the character contract to **24,000 triangles / 24,000 glTF vertices** per +character (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS`, `npc_pipeline.MAX_TRIANGLES`/ +`MAX_VERTICES`, and the `adapt` defaults). The 13 core bones, five tint slots, +front orientation, grounding and single `npc_base` skinned mesh are unchanged. +Gear stays at 1,500 triangles and props at 4,000. + +## Consequences + +- The MPFB body, accepted head and neck fit with headroom for the 12 clothing + variants and future jacket/hoodie detail. +- The 24-NPC and Web frame-time budgets must be re-measured before shipping any + variant built at the new cap; the extra geometry is not free. +- The procedural generator and the low-poly `npc_base` fallback remain valid; + they are not required to use the new headroom. +- MPFB stays a local development tool. Production must bake a committed source + GLB; CI and the build must not depend on MPFB. +- Historical reviews and measurements that state 16,000 remain accurate for the + date they were recorded; current contract documents state 24,000. + +## Alternatives + +- **Keep 16,000 and decimate the MPFB body further:** rejected because the neck + and shoulder already show facets and the clothing variants would exceed the + cap. +- **Separate caps for the MPFB prototype and the shipped characters:** rejected + because it creates a second contract and makes the rollout ambiguous. diff --git a/docs/adr/README.md b/docs/adr/README.md index bc0e385..a82c716 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -19,3 +19,4 @@ Each ADR records the context, decision, consequences and alternatives for a dura - [0013-blender-authored-npc-characters](0013-blender-authored-npc-characters.md) - [0014-runtime-image-root](0014-runtime-image-root.md) - [0015-npc-model-variety-sourcing](0015-npc-model-variety-sourcing.md) +- [0016-npc-character-budget-24k](0016-npc-character-budget-24k.md) diff --git a/docs/architecture.md b/docs/architecture.md index d2a3cff..00dc5a7 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -139,7 +139,7 @@ The runtime NPC contract is intentionally narrow. It is enforced by | Core bones | `Head`, `HipL/R`, `KneeL/R`, `ShoulderL/R`, `ElbowL/R`, `HandL/R`, `Spine`, `Neck` at the frozen rest positions. Optional extra bones (fingers, face, toes) are allowed if they do not move the core rest positions or break `NpcAvatar` proxies. | | Tint slots | `skin`, `cloth`, `pants`, `accessory`, `hair`; fixed detail materials keep their authored colours. | | Orientation | Blender −Y / Godot +Z front, feet grounded near `y = 0`, metre scale. | -| Budget | 16,000 triangles / 16,000 glTF vertices per character; 1,500 per gear piece; 4,000 per prop. The low-poly `npc_base` remains a fallback, not a second contract. | +| Budget | 24,000 triangles / 24,000 glTF vertices per character; 1,500 per gear piece; 4,000 per prop. The low-poly `npc_base` remains a fallback, not a second contract. | | Textures | 256² albedo + normal + packed ORM per slot; cloth/pants use the 4× `NPC_FABRIC_UV_SCALE` and skip per-character baked AO, while skin/hair/gear keep AO. | | Gear attach | Authored in attach-point space: head `Rig/Head` (0, 1.62, 0), back (0, 1.10, 0), chest (0, 1.30, 0), hand (±0.27, 0.78, 0.02); grip 5 cm below the origin. `GEAR_OFFSETS` and `HAND_ITEM_FORWARD` are runtime fit corrections, not authored-geometry changes. | | Fallback chain | Library variant → `npc_base.glb` → procedural `NpcAvatar` mesh. Committed GLBs and maps must keep CI offline and Blender-free. | @@ -217,8 +217,8 @@ GLBs and maps. | Tool | Role | Committed artifact | Verification gate | | --- | --- | --- | --- | -| `tools/npc_pipeline.py` | Builds the skinned base avatar, five-slot material maps, palette and AI-fabric preparation (`prepare`/`palette`) | `npc_base.glb`, `assets/textures/npc/*_{albedo,normal,orm}.png`, `palette.json` | `audit_glb` against the 16,000-triangle / 16,000-vertex base contract (13 core bones required; extras allowed) | -| `tools/blender_assets.py` | Builds/renders the library: 8 characters, 18 gear pieces, 20 props, plus `manifest.json`; stdlib `audit`/`fit`/`sheet`/`list` | `assets/models/blender/{npc,npc_gear,props}/*.glb` | Character cap 16,000 tris / 16,000 verts, 1,500 per gear, 4,000 per prop; grounding, UV, degenerate-triangle, attach-fit and manifest coverage checks | +| `tools/npc_pipeline.py` | Builds the skinned base avatar, five-slot material maps, palette and AI-fabric preparation (`prepare`/`palette`) | `npc_base.glb`, `assets/textures/npc/*_{albedo,normal,orm}.png`, `palette.json` | `audit_glb` against the 24,000-triangle / 24,000-vertex base contract (13 core bones required; extras allowed) | +| `tools/blender_assets.py` | Builds/renders the library: 8 characters, 18 gear pieces, 20 props, plus `manifest.json`; stdlib `audit`/`fit`/`sheet`/`list` | `assets/models/blender/{npc,npc_gear,props}/*.glb` | Character cap 24,000 tris / 24,000 verts, 1,500 per gear, 4,000 per prop; grounding, UV, degenerate-triangle, attach-fit and manifest coverage checks | | `tools/bake_ao.py` | Bakes per-asset AO maps | `_ao.png` (256²) | Wired through `Materials.apply_ao()`/`SurfaceMaterials`; cloth/pants opt out (see below) | | `tools/npc_proportions.py` | Measures exported GLB rest pose (height, head, shoulders, hips, torso, limbs, feet) against the stylized guide | report / JSON in `docs/npc-visual-review.md#proportion-audit` | All eight variants must stay inside the guide after a body change | | `tools/npc_baseline.py` | Assembles neutral-baseline sheets and before/after comparisons | `docs/blender_previews/sheet_npc_baseline*.jpg` | Human review against `docs/npc-visual-review.md` | diff --git a/docs/asset-tooling.md b/docs/asset-tooling.md index 03b7cb0..049c214 100644 --- a/docs/asset-tooling.md +++ b/docs/asset-tooling.md @@ -200,8 +200,8 @@ flatpak run org.blender.Blender --background \ --python "$PWD/tools/blender_assets.py" -- adapt \ --file "$PWD/tmp/npc-research/makehuman_base.glb" \ --out "$PWD/tmp/npc-research/makehuman_adapted.glb" \ - --target-tris 16000 -# prints: adapted makehuman_adapted.glb: 36972 -> 16000 tris (bones=N, meshes=1) + --target-tris 24000 +# prints: adapted makehuman_adapted.glb: 36972 -> 24000 tris (bones=N, meshes=1) ``` Run `inspect` on the adapted GLB before and after, and keep the procedural diff --git a/docs/blender-assets.md b/docs/blender-assets.md index bf04668..d7da89e 100644 --- a/docs/blender-assets.md +++ b/docs/blender-assets.md @@ -141,7 +141,7 @@ render about 2.5 min. All library variants share the [character and gear asset contract](architecture.md#character-and-gear-asset-contract): `npc_base` mesh node, required 13 core bones (optional extras allowed), five -tint slots, +Z visual front, 16,000/16,000 character budget and the same 256² +tint slots, +Z visual front, 24,000/24,000 character budget and the same 256² slot-map/AO rules. Role selection and look notes: | Character | `layer_for()` / look | Suggested roles | Preview gear | @@ -200,7 +200,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 16000/16000, gear 1500, props 4000 + during LOD generation), budgets (characters 24000/24000, 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/tests/test_blender_assets.py`: catalogue and contract consistency with diff --git a/docs/npc-model-sourcing.md b/docs/npc-model-sourcing.md index 6ae1b0d..5273649 100644 --- a/docs/npc-model-sourcing.md +++ b/docs/npc-model-sourcing.md @@ -8,7 +8,7 @@ remain references or local prototypes unless a later ADR accepts them. The library needs variety beyond the original eight silhouettes while preserving the `npc_base` contract: mesh node, 13 required core bones (optional extras -allowed), five tint slots, −Y/+Z front, grounded feet and the 16,000/16,000 +allowed), five tint slots, −Y/+Z front, grounded feet and the 24,000/24,000 character budget. | Source | Licence | Result | @@ -55,14 +55,16 @@ The MakeHuman body should reuse the approved local head/hand parts rather than f a second face implementation. The current local MPFB full-body prototype (`tmp/npc-research/build_mpfb_npc.py`) assembles the -accepted head on an MPFB 2.0.18 body at **15,317 / 16,000 tris**, 1.810 m, 14 bones and 10 +accepted head on an MPFB 2.0.18 body at **19,747 / 24,000 tris**, 1.810 m, 14 bones and 10 materials, with project hands, bevelled shoe shells with inset soles and tongues, pant cuffs, cloth sleeve cuffs and flat slot colours. The torso is radially inflated by 12% through z 0.72–1.40 -to loosen the shirt. It is a review candidate, not a shipped asset. The neck is a radial cut -of the decimated column bridged by a four-ring, 20-segment lathe (lower rings painted cloth, -reading as a crew neck); the ankles are hidden by 0.11 m shoe shells and 0.08 m pant cuffs, and a -light smoothing pass softens the closed thigh/hip region. The neck skin test is guarded to z > -1.35 so it cannot paint the crotch. Remaining polish: the crotch hollow still reads as a V under +to loosen the shirt. It is a review candidate, not a shipped asset. The neck is a boolean-cut +circular bore bridged by a smooth lathe; the accepted head is trimmed at the narrow neck (z 1.55) +so its wide flat cut brim is discarded, and the lathe flares to cover the bore, then tucks inside +the jaw. This removed the square collar, dark notches and wide brim; a thin jaw crease and a hard +shirt-shoulder point in three-quarter view remain. The ankles are hidden by 0.11 m shoe shells and +0.08 m pant cuffs, and a light smoothing pass softens the closed thigh/hip region. The neck skin +test is guarded to z > 1.35 so it cannot paint the crotch. Remaining polish: the crotch hollow still reads as a V under the shirt hem, a partly loosened shirt and angular thigh facets; a separate loose shirt shell is the fix. Lowering the hem to z 0.80, tilting it up at the front and a 13% hem flare were rejected as a unitard, high-cut swimwear and a peplum respectively. A quick open, flared solidified tube diff --git a/docs/npc-visual-review.md b/docs/npc-visual-review.md index fa76e71..26eaf5c 100644 --- a/docs/npc-visual-review.md +++ b/docs/npc-visual-review.md @@ -71,8 +71,8 @@ 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 16,000 triangles - and 16,000 glTF vertices per character. The required 13 core bones stay fixed; + front +Z, feet within 3 cm of y=0, 1.6–2.1 m height, at most 24,000 triangles + and 24,000 glTF vertices per character. The required 13 core bones stay fixed; optional extra bones are allowed. 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 diff --git a/tools/blender_assets.py b/tools/blender_assets.py index dc65b8c..da35380 100644 --- a/tools/blender_assets.py +++ b/tools/blender_assets.py @@ -53,14 +53,14 @@ MANIFEST = OUT_DIR / "manifest.json" SLOTS = ["skin", "cloth", "pants", "accessory", "hair"] BONES = ["Head", "HipL", "HipR", "KneeL", "KneeR", "ShoulderL", "ShoulderR", "ElbowL", "ElbowR", "HandL", "HandR"] -# Character cap raised to 16000/16000 on 2026-11-04 for the head/face/hand -# overhaul and possible MakeHuman parts. The required 13 core bones stay, but -# optional extra bones (fingers, face, toes) are allowed; they must not move the -# core rest positions. 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 before accepting the increase. -CHAR_MAX_TRIS = 16000 -CHAR_MAX_VERTS = 16000 +# Character cap raised to 24000/24000 on 2026-11-05 for the MPFB body, the +# accepted MakeHuman head and a seamless neck/shoulder junction. The required +# 13 core bones stay, but optional extra bones (fingers, face, toes) are +# allowed; they must not move the core rest positions. The glTF vertex count is +# after UV-seam splits; each avatar is still one skinned mesh, and the 24-NPC +# smoke test must confirm frame time before shipping. +CHAR_MAX_TRIS = 24000 +CHAR_MAX_VERTS = 24000 GEAR_MAX_TRIS = 1500 PROP_MAX_TRIS = 4000 @@ -2486,7 +2486,7 @@ def inspect_glb(path, category=None) -> dict: return result -def adapt_glb(path, out_path, target_tris=16000): +def adapt_glb(path, out_path, target_tris=24000): """Import an external GLB and adapt it toward the library contract. Applies node transforms, grounds the feet (lowest vertex at y = 0), welds @@ -2892,8 +2892,8 @@ def main(argv=None): ada.add_argument("--file", required=True, help="external GLB to adapt (absolute path; runs in Blender)") ada.add_argument("--out", required=True, help="where to write the adapted GLB") - ada.add_argument("--target-tris", type=int, default=16000, - help="decimate target (default 16000)") + ada.add_argument("--target-tris", type=int, default=24000, + help="decimate target (default 24000)") tex = sub.add_parser("texels", help="per-slot texel density of the character GLBs") tex.add_argument("--only", default="") tex.add_argument("--json", action="store_true") diff --git a/tools/npc_pipeline.py b/tools/npc_pipeline.py index 9f6fb6d..4776bdb 100644 --- a/tools/npc_pipeline.py +++ b/tools/npc_pipeline.py @@ -23,7 +23,7 @@ Contract (frozen in ADR-0013 and docs/blender-assets.md): (plus Hips/Spine/Neck as parents) * material slots: skin, cloth, pants, accessory, hair * neutral albedo + normal + packed ORM maps, albedo tinted at runtime - * <= 16000 triangles / 16000 vertices, UVs in [0,1], feet at y ~= 0 + * <= 24000 triangles / 24000 vertices, UVs in [0,1], feet at y ~= 0 * the 13 core bones are required; extra optional bones are allowed """ @@ -45,8 +45,8 @@ BONES = [ "Head", "HipL", "HipR", "KneeL", "KneeR", "ShoulderL", "ShoulderR", "ElbowL", "ElbowR", "HandL", "HandR", ] -MAX_TRIANGLES = 16000 -MAX_VERTICES = 16000 +MAX_TRIANGLES = 24000 +MAX_VERTICES = 24000 TEX_SIZE = 256 AI_DIR = TEX_DIR / "ai" # Base material slots that get an AI fabric albedo (`prepare` layers them over diff --git a/tools/tests/test_blender_assets.py b/tools/tests/test_blender_assets.py index 1666d71..3aa937e 100644 --- a/tools/tests/test_blender_assets.py +++ b/tools/tests/test_blender_assets.py @@ -9,10 +9,10 @@ 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 character cap was raised to 16000/16000 for the head/face/hand + # The character cap was raised to 24000/24000 for the MPFB body and the head # overhaul; the 13 core bones stay required and extra bones are optional. - self.assertLessEqual(ba.CHAR_MAX_TRIS, 16000) - self.assertLessEqual(ba.CHAR_MAX_VERTS, 16000) + self.assertLessEqual(ba.CHAR_MAX_TRIS, 24000) + self.assertLessEqual(ba.CHAR_MAX_VERTS, 24000) def test_gear_uses_known_attach_points(self): for name, attach in ba.GEAR.items(): @@ -197,7 +197,7 @@ class InspectionTests(unittest.TestCase): def test_character_contract_failures_are_listed(self): stats = self.stats(mesh_nodes=["Armature"], skinned=False, unskinned=["Armature"], materials=["cloth"], bones=["Head"], meshes_without_uv=1, - triangles=17000, split_vertices=17000, + triangles=25000, split_vertices=25000, world_bounds={"min": [-0.3, -0.4, -0.2], "max": [0.3, 1.2, 0.2]}) issues = "\n".join(ba.analyse_inspection(stats)["issues"]) self.assertIn("no mesh node named npc_base", issues) @@ -205,8 +205,8 @@ class InspectionTests(unittest.TestCase): self.assertIn("missing material slot skin", issues) self.assertIn("mesh not skinned", issues) self.assertIn("mesh(es) without UVs", issues) - self.assertIn(f"triangles 17000 > {ba.CHAR_MAX_TRIS}", issues) - self.assertIn(f"glTF vertices 17000 > {ba.CHAR_MAX_VERTS}", issues) + self.assertIn(f"triangles 25000 > {ba.CHAR_MAX_TRIS}", issues) + self.assertIn(f"glTF vertices 25000 > {ba.CHAR_MAX_VERTS}", issues) self.assertIn("feet not on the ground", issues) self.assertIn("unexpected height", issues) diff --git a/tools/tests/test_npc_pipeline.py b/tools/tests/test_npc_pipeline.py index 55acfef..d42b403 100644 --- a/tools/tests/test_npc_pipeline.py +++ b/tools/tests/test_npc_pipeline.py @@ -13,8 +13,8 @@ class NpcContractTests(unittest.TestCase): "ShoulderL", "ShoulderR", "ElbowL", "ElbowR", "HandL", "HandR"]: self.assertIn(bone, npc_pipeline.BONES) - self.assertLessEqual(npc_pipeline.MAX_TRIANGLES, 16000) - self.assertLessEqual(npc_pipeline.MAX_VERTICES, 16000) + self.assertLessEqual(npc_pipeline.MAX_TRIANGLES, 24000) + self.assertLessEqual(npc_pipeline.MAX_VERTICES, 24000) def test_textures_exist_for_every_slot(self): for slot in npc_pipeline.SLOTS: