diff --git a/.agents/skills/gig-line-blender-asset-contract/SKILL.md b/.agents/skills/gig-line-blender-asset-contract/SKILL.md index e52d64c..35e205f 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 13-bone npc_base contract, five tint slots, triangle/vertex budgets, gear attach space, 256² texture/AO rules, headless flatpak Blender commands, 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, 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. 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 @@ -21,9 +21,10 @@ Use this skill for any change that touches: - Blender-authored venue/prop geometry The project contract and measured gates override any generic Blender advice. -There is **no Blender MCP** in this project. Blender runs headless through the -flatpak CLI; the `blender-skills` pack is optional, local guidance only, and -gitignored. +Blender MCP is optional interactive tooling; the headless flatpak CLI remains +authoritative and CI never needs Blender or MCP. The `blender-skills` pack is +optional, local guidance only, and gitignored. Setup and safety are in +`docs/blender-mcp.md`. ## Read first @@ -47,11 +48,11 @@ and resolve the source of truth before editing assets. | Area | Rule | | --- | --- | | Mesh root | `npc_base` mesh node, skinned under `Rig`; preserve the limb node names. | -| Bones | 13 contract bones: `Head`, `HipL/R`, `KneeL/R`, `ShoulderL/R`, `ElbowL/R`, `HandL/R`, `Spine`, `Neck` (parent/helper bones must not change the contract). | +| 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. | -| Library budget | **8,000 triangles / 8,000 glTF vertices** per character (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS`). | -| Frozen fallback | `npc_base` keeps **6,000 tris / 4,000 verts**. Do not silently raise or lower it. | +| 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. | | 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. | @@ -113,8 +114,7 @@ only the specialists the task needs: - budget/LOD/collision: `asset-optimization`, `lod-pipeline`, `collision-proxy` - final review: `qa-review` -Translate any MCP instruction into a change to `tools/*.py` or a headless CLI -run. Never add an MCP dependency to the build, CI or runtime. +If MCP is available, use it for interactive part exploration only; mirror the result into a scripted change or local `.blend`, then re-export and run the CLI audit/fit gates. Never make the build, CI, tests or runtime depend on MCP. Setup: `docs/blender-mcp.md`. ### 4. Build or bake @@ -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 8,000/8,000; gear/prop caps hold. +- No character exceeds 16,000/16,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. @@ -197,12 +197,14 @@ gates run, and any accepted limit. - [`references/asset-contract.md`](references/asset-contract.md) — full contract, inventory, file locations and provenance rules. +- `docs/blender-mcp.md` — optional MCP installation, connection, safety and + part-workflow instructions. - [`references/verification.md`](references/verification.md) — command matrix, capture gates, expected results and acceptance criteria. ## Do not -- Add an MCP server, Blender dependency or API call to the build/runtime. +- Make the build, CI, tests or runtime depend on MCP, Blender or API calls. - Change the bone/tint/contract to make a generic asset fit. - Rewrite committed baselines or overwrite existing images. - Commit `.blend` sources, raw captures or generated AI inputs. 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 0ddc269..948c7aa 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 @@ -17,7 +17,7 @@ This is a working summary. The authoritative sources remain ## Skeleton and geometry -The contract skeleton has 13 bones: +The required contract skeleton has 13 core bones: ```text Head, Spine, Neck, @@ -28,6 +28,9 @@ ElbowL, ElbowR, HandL, HandR ``` +Optional extra bones (fingers, face controls, toes) are allowed if they do not +move these core rest positions and do not break `NpcAvatar`'s animation proxies. + Requirements: - `npc_base` mesh node exists and is skinned under `Rig`. @@ -56,8 +59,7 @@ skin, cloth, pants, accessory, hair | Asset | Limit | | --- | --- | -| Library character | 8,000 triangles / 8,000 glTF vertices | -| `npc_base` fallback | 6,000 triangles / 4,000 vertices | +| Character (library and base fallback) | 16,000 triangles / 16,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 8e49c92..7242ab5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -88,15 +88,17 @@ specialists the task needs: ### Project rules that override a skill -1. **The project contract wins.** `npc_base` mesh node, the 13 contract bones at their rest - positions, five tint slots, front on Blender −Y / Godot +Z, grounded feet, 8,000 - triangles / 8,000 glTF vertices per character, 1,500 per gear, 4,000 per prop. 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 + 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. -2. **There is no Blender MCP here.** The skills assume MCP tools; this project runs Blender - as headless flatpak scripts (`tools/blender_assets.py`, `tools/npc_pipeline.py`). Translate - MCP steps into script changes or CLI runs. Never add an MCP dependency to the build, CI or - runtime. +2. **Blender MCP is optional interactive tooling.** The headless flatpak scripts + (`tools/blender_assets.py`, `tools/npc_pipeline.py`) remain authoritative. MCP may be used + for local part exploration; setup and safety are in [`docs/blender-mcp.md`](docs/blender-mcp.md). + Never add an MCP dependency to the build, CI, tests or runtime, and always re-run the CLI + audit/fit gates on anything MCP touched. 3. **CI stays offline and skill-free.** Skills are local guidance only; every gate must still work from a fresh checkout with committed `.glb`/`.png`/`.tres` files and Godot. 4. **No new asset source without the licence gate.** Skills may suggest reference packs or diff --git a/MEMORY.md b/MEMORY.md index ab7f56d..944940a 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -58,9 +58,15 @@ canonical implemented-features list in `docs/development-status.md`. 36 venue/difficulty/phase cells, seeds 1–100, and access/emergency error rates. Gotcha: `_read_npc_truth()` is type-derived, not behaviour-derived; the emergency-fairness review must account for that oracle mismatch. -- **Character mesh cap:** eight library variants use 8,000 tris / 8,000 glTF vertices - (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` in `tools/blender_assets.py`); the frozen `npc_base` fallback - keeps 6,000/4,000. Measure after any geometry change; never silently lower the cap back to 5,000. +- **Blender MCP is optional (2026-11-04):** setup and safe part workflow are in + `docs/blender-mcp.md`. 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 + (`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 + any geometry change; never silently lower the cap without a new decision. - **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/README.md b/README.md index 0b22edd..48f0733 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,7 @@ Full setup, every run/test/smoke command, and the controls table are in - [`CREDITS.md`](CREDITS.md) — Credits, AI/reference provenance and licensing notes. - [`PRIVACY.md`](PRIVACY.md) — Local-only data, save files and development API use. - [`docs/blender-assets.md`](docs/blender-assets.md) — Blender asset library: characters, gear, props, attach points. +- [`docs/blender-mcp.md`](docs/blender-mcp.md) — optional Blender MCP installation, connection and safe part-workflow. - [`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/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/adr/`](docs/adr/) — Architecture Decision Records. diff --git a/TODO.md b/TODO.md index 3beb68e..6f411a2 100644 --- a/TODO.md +++ b/TODO.md @@ -17,8 +17,8 @@ The MIT Blender skill pack lives locally at `.agents/skills/blender-skills/` (gi Goal: replace the sphere-and-primitive face and hand construction with a local, part-based 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-bone rig, -five tint slots, 8,000/8,000 character cap and Compatibility/Web path. +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. *Skill route: `character-artist`, `retopology`, `sculpting`, `rigging`, `uv-workflow`, `texture-workflow`, `materials`, `lookdev`, `asset-optimization`, `qa-review`.* @@ -42,7 +42,7 @@ the rest of §C remains the broad review checklist. UV layout and the exact locations of eye/mouth/finger geometry. - [ ] 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 8,000/8,000 cap; no contract or renderer change. + 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. - [ ] Confirm the identity boundary: `npc_base.blend` is the frozen fallback and must not absorb prototype detail unless a separate contract decision approves it. - [ ] Choose a local working-set layout: `tmp/npc-parts//` (gitignored) for part `.blend` @@ -61,6 +61,10 @@ the rest of §C remains the broad review checklist. - [ ] Add tests for deterministic part assembly, contract output (mesh root, bones, slots, budgets) and the non-Blender failure path. Verify one assembled prototype with `audit`/`fit`/`inspect` before touching production variants. +- [x] Consider optional Blender MCP for interactive part exploration and document setup/safety. + (`docs/blender-mcp.md` covers addon/client setup, Pi `pi mcp add`, flatpak networking, + viewport/`bpy` workflow and the rule that headless audit/fit remains authoritative; MCP is + not a build/CI/runtime dependency.) - [ ] Document the commands, working-set paths and “part source is not a shipped asset” rule in `docs/asset-tooling.md`, `docs/blender-assets.md` and `.agents/skills/gig-line-blender-asset-contract/references/verification.md`. @@ -84,8 +88,9 @@ the rest of §C remains the broad review checklist. - [ ] Build separate left/right hand parts with a connected palm, four multi-segment fingers, a thumb, knuckles and rounded tips. Support an open palm and a relaxed grip; preserve the current `HAND_ITEM_FORWARD` behaviour for phone/cup/clipboard/camera/flashlight/wand/radio. -- [ ] Decide finger articulation explicitly: the 13-bone contract has no finger bones, so keep the - open/relaxed-palm approach unless an ADR approves extra bones and the budget/weight path. +- [ ] Decide finger articulation explicitly: the current rig has no finger bones, so keep the + open/relaxed-palm approach unless an ADR approves optional finger bones and the + budget/weight path. - [ ] Verify all hand gear at 0.8 m (contact, clipping, direction) and capture open/grip hand close-ups for the review sheet. - [ ] Roll the approved hands into all 12 variants only after the one-variant hand sheet passes. @@ -93,7 +98,8 @@ the rest of §C remains the broad review checklist. ### 5. Assembly and rollout - [ ] Integrate the approved parts into `build_character` with deterministic joins, weights, UVs and - AO. The final output remains one `npc_base` skinned mesh under the existing 13-bone armature; + AO. The final output remains one `npc_base` skinned mesh under the existing 13-core armature; + optional extra bones are allowed but the core rest positions stay fixed; no second rig, no material-slot rename. - [ ] Keep the MakeHuman body prototype consumable with the same approved head/hands; do not let it grow a second face/hand implementation while the part pipeline is being proven. @@ -148,11 +154,11 @@ 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 8000]`): imports the GLB, applies transforms, grounds the feet, welds seam - splits and decimates to the budget, then exports. The five tint slots + 13-bone rig stay a - manual step (recorded in the command doc). + [--target-tris 16000]`): 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 - path (161/161 Python). + path (162/162 Python). - [x] Adapter commands + go/no-go documented in `docs/asset-tooling.md` §Intake adaptation. ### MPFB / MakeHuman body pipeline @@ -163,18 +169,18 @@ an active track; ADR-0015 (CC0 / CC-BY with attribution) still governs every int x ±0.53 / y 0–1.82 / z −0.12…+0.35, one neutral material, UVs present, unskinned. The body (no rig) is the input for the rigging step; the script + mesh stay in `tmp/` (CC0, not committed). -- [x] Rig strategy decided (owner): **retarget the body to the 13-bone contract**. +- [x] Rig strategy decided (owner): **retarget the body to the 13-core contract; optional extra bones are allowed**. `tmp/npc-research/makehuman_retarget.py` rotates the A-pose arms down (−38°/+38°), scales the arms 1.63× to the contract 0.70 m length, welds the split vertices, smooth-shades, adds the contract armature + `_auto_weights`, paints the five slot regions (hair/cloth/pants/accessory/ - skin) and exports `makehuman_retargeted.glb`. **Contract passes:** 6,444 / 8,000 tris, - 7,726 / 8,000 verts, 14 bones (13 + Hips), skinned, arm-down, grounded, five slots, no issues. + skin) and exports `makehuman_retargeted.glb`. **Contract passes:** 6,444 / 16,000 tris, + 7,726 / 16,000 verts, 14 bones (13 + Hips), skinned, arm-down, grounded, five slots, no issues. Vision-reviewed: arms hang down and the silhouette + slot regions read, but the 1.63× arm warp distorts the deltoid/shoulder (spiky/warped), the decimated hands are blocky, and the slot boundaries are rough — these are the refinement steps below. - [x] Head/hands/feet swap (`makehuman_final.py`): cut the decimated MakeHuman head/hands/feet and joined the project's `_face`/`_hair`/`_hands_and_shoes`, then re-weighted/re-UV'd. Contract - passes: 6,407 / 8,000 tris, 6,651 / 8,000 verts, 14 bones, skinned, five slots, no issues. + passes: 6,407 / 16,000 tris, 6,651 / 16,000 verts, 14 bones, skinned, five slots, no issues. Vision-reviewed: the head now reads as a realistic face, the hands as detailed fingers and the shoes as attached. Remaining (manual retopology): a 1.63× arm-scale warp still distorts the deltoid/shoulder, stray hand blobs linger at the hips, shirt/shirt seams are rough, and @@ -299,9 +305,11 @@ licence-free zone only. - [x] Hands/grip review: the hands ARE detailed — `tools/blender_assets.py._hands_and_shoes()` builds a wider shallower palm, four two-segment bent fingers with rounded tips and a thumb; gear contact is the open palm plus the `HAND_ITEM_FORWARD` (0.04 m) offset. Decision: **keep - the open palm + forward offset; a finger-curl rig stays out of scope** — there are no finger - bones in the 13-bone contract, so a curl rig is a contract decision, not a modelling tidy-up. - Recorded as ranked gap #6 (accept; revisit only if face work opens the budget). + the open palm + forward offset; a finger-curl rig stays out of scope** — the current rig has + no finger bones, so a curl rig is a contract decision, not a modelling tidy-up. Optional + extra finger bones are now allowed by the cap/contract extension, but require an ADR and + weight/budget verification. Recorded as ranked gap #6 (accept; revisit only if face work + opens the budget). - [x] Weights/pose evidence captured and vision-reviewed, and the P1s fixed: wrist/hand detachment (wrist + hand now 100% `Hand`, hand raised, sleeve cuff follows the hand), hip/thigh collapse + knee pinch (thigh/shin rigid with a short knee blend). Vision-verified: diff --git a/docs/3d-model-review.md b/docs/3d-model-review.md index dbbf186..2ac13d9 100644 --- a/docs/3d-model-review.md +++ b/docs/3d-model-review.md @@ -24,9 +24,10 @@ severity, explicit verdict) rather than an opinion pass: | Props, gear, foliage | `prop-artist`, `hard-surface`, `vegetation-artist` | Silhouette read, bevel/chamfer language, collision proxies, carded foliage | | Look and verdict | `lookdev`, `qa-review` | Day/night beauty captures, ship / ship-with-notes / no-ship verdict | -Project contract and gates stay authoritative; see `AGENTS.md` §Local Blender skills. The skills -assume Blender MCP, which this project does not use: everything below came from the headless -`tools/blender_assets.py` / `tools/npc_pipeline.py` pipelines plus the Godot capture harnesses. +Project contract and gates stay authoritative; see `AGENTS.md` §Local Blender skills. Blender MCP +is optional interactive tooling (see [`blender-mcp.md`](blender-mcp.md)); this review's evidence +came from the headless `tools/blender_assets.py` / `tools/npc_pipeline.py` pipelines plus the +Godot capture harnesses, so it remains reproducible without MCP. ## What was captured and measured (2026-11-03) @@ -63,14 +64,14 @@ with the runtime 4× fabric repeat). | `npc_crowd_b` | 4,734 / 4,353 | 1.809 / +0.000 | 7 | 107–118 | 434–439 | Contract pass; crowd prototype | | `npc_crowd_c` | 5,674 / 5,440 | 1.824 / +0.000 | 7 | 76–83 | 317 | Contract pass; crowd prototype | | `npc_crowd_d` | 5,814 / 5,300 | 1.856 / +0.000 | 7 | 92–106 | 377–381 | Contract pass; crowd prototype | -| `npc_base` (fallback) | 1,204 / 2,488 | 1.836 / +0.000 | 5 | 70.1–72.9 | 4× on fabric | Contract pass; far below its 6,000/4,000 cap | +| `npc_base` (fallback) | 1,204 / 2,488 | 1.836 / +0.000 | 5 | 70.1–72.9 | 4× on fabric | Contract pass; compact fallback under the 16,000/16,000 cap | Blender-side `inspect` counts can differ by ±1 vertex from the glTF accessor count in `audit` (normal-split rounding); both are recorded and neither changes a verdict. Readings: -- Every character is inside 8,000/8,000 with the farthest at 5,474 tris (68% of budget) and 5,494 +- Every character is inside 16,000/16,000 with the farthest well below the new cap and 5,494 verts (69%), so there is headroom for targeted topology detail without a cap change. - Surface area tracks clothing volume: the firefighter coat is the largest body (4.28 m²) and has the lowest authored density; `npc_casual` is the smallest (2.44 m²) and the highest. @@ -254,7 +255,7 @@ owner review decides. brow ridge, a fuller lower lip and both eyelids (upper + lower); recessed creases (nasolabial, temple, chin cleft) were rejected because they bake as dark AO patches. Vision-reviewed: the new face reads cleaner and more realistic than the old (set-in eyes, brow break, lip volume, no - faceting); tris 4,482 → 5,038 (still under 8,000). The other seven variants keep the old face + faceting); tris 4,482 → 5,038 (still under 16,000). The other seven variants keep the old face until this prototype is approved. 2. **No pose/weight evidence (unknown).** Idle, walk, sit, block and turn deformation has never been captured as a review set, so shoulder/hip/neck collapse is unmeasured. Cheap to add and it diff --git a/docs/README.md b/docs/README.md index f265900..422126c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,6 +16,7 @@ This folder holds the project documentation, visual references and generated QA - [`architecture.md`](architecture.md) — arc42 system architecture - [`getting-started.md`](getting-started.md) — setup, run/test commands and controls - [`asset-tooling.md`](asset-tooling.md) — image/model pipelines and screenshot gates +- [`blender-mcp.md`](blender-mcp.md) — optional Blender MCP setup and safety - [`../tools/README.md`](../tools/README.md) — tool inventory, categories and test runner - [`gameplay.md`](gameplay.md) — controls, venues and escalation - [`joke-shop-map.md`](joke-shop-map.md) — Sunset Strip real-site mapping diff --git a/docs/adr/0015-npc-model-variety-sourcing.md b/docs/adr/0015-npc-model-variety-sourcing.md index 47449fb..ecfbf87 100644 --- a/docs/adr/0015-npc-model-variety-sourcing.md +++ b/docs/adr/0015-npc-model-variety-sourcing.md @@ -70,3 +70,14 @@ measured. None was a drop-in; the full results are in polygon count, no rig in the base mesh and a separate authoring dependency. - **Use Mixamo or Ready Player Me.** Rejected: service terms are not a simple free/open-source redistribution basis for shipped meshes. + +## Amendment 2026-11-04 + +- The character budget is raised to **16,000 triangles / 16,000 glTF vertices** per character. + The required 13 core bones remain; optional extra bones (fingers, face, toes) are allowed if + they do not move the core rest positions. The low-poly fallback remains the fallback, not a + second contract. +- MakeHuman is now an active local development pipeline (body retarget plus project-owned + head/hands), while the procedural library remains the shipped path and CI fallback. +- Blender MCP is optional interactive tooling only; it is not a build, CI, test or runtime + dependency. Setup is in [`docs/blender-mcp.md`](../blender-mcp.md). diff --git a/docs/architecture.md b/docs/architecture.md index 17b347d..cbe69cf 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -141,8 +141,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 frozen 6,000-triangle / 4,000-vertex base contract | -| `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` | Library cap 8,000 tris / 8,000 verts per character, 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 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/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-proportion-audit.md` | 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 2bb29e1..ed16438 100644 --- a/docs/asset-tooling.md +++ b/docs/asset-tooling.md @@ -189,7 +189,7 @@ Caveats: `adapt` is the mechanical first half of an external-mesh intake (MakeHuman, MPFB, downloaded GLB): import, apply transforms, ground the feet, weld seam splits, decimate to the character budget, and export a GLB. It does **not** map -the five tint slots or rebuild the 13-bone `npc_base` armature — those stay a +the five tint slots or rebuild the 13-core-bone `npc_base` armature (optional extra bones are allowed) — those stay a manual `retopology`/`rigging` step with a recorded second-rig contract if the source rig cannot be retargeted: @@ -198,8 +198,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 8000 -# prints: adapted makehuman_adapted.glb: 36972 -> 8000 tris (bones=N, meshes=1) + --target-tris 16000 +# prints: adapted makehuman_adapted.glb: 36972 -> 16000 tris (bones=N, meshes=1) ``` Run `inspect` on the adapted GLB before and after, and keep the procedural @@ -343,6 +343,14 @@ python3 tools/model_pipeline.py audit python3 tools/npc_pipeline.py audit ``` +### Optional interactive Blender MCP + +The headless pipeline above is authoritative. For local part exploration, an +optional Blender MCP bridge can query the scene, run small `bpy` snippets and +capture viewport screenshots. It is not a build, CI, test or runtime dependency; +setup, safety and the part workflow are in +[`blender-mcp.md`](blender-mcp.md). + ## Realism pass: scene concepts, skylines and textures The skyline, surface tiles and phase lighting were rebuilt against AI concept frames. The diff --git a/docs/blender-assets.md b/docs/blender-assets.md index b12d4b4..e8da631 100644 --- a/docs/blender-assets.md +++ b/docs/blender-assets.md @@ -35,6 +35,12 @@ captures in `docs/screenshots/`. doors, stair handrails and a dark sedan. Today's in-game props are primitive boxes, and the trees are cones. +## Optional MCP + +Blender MCP can be used for interactive head/face/hand part exploration, but it +is not required. The headless commands below remain the build and audit path; +see [`blender-mcp.md`](blender-mcp.md) for installation, connection and safety. + ## Running it ```bash @@ -98,12 +104,12 @@ All eight use the `npc_base` contract, so each one can replace `Materials.npc_slot()` tints them the same way it tints `npc_base`. Cloth and pants repeat the weave 4× (`NPC_FABRIC_UV_SCALE`) and intentionally skip the per-character baked AO; skin, hair and fixed gear keep it. -- 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,482–5,474 triangles and 4,260–5,494 vertices, leaving room for the - remaining grip and clothing detail. +- budget ≤ **16,000 triangles and ≤ 16,000 glTF vertices** per character (vertex count after + seam splits; `CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` in `tools/blender_assets.py`). The 13 core bones + remain required; optional extra bones are allowed as long as the core rest positions and + `NpcAvatar` animation proxies are unchanged. The frozen low-poly `npc_base` fallback keeps its + compact geometry but is no longer capped at 6,000/4,000. The current range is 5,038–6,030 + triangles and 4,756–5,902 vertices, leaving substantial head/hand headroom. 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, @@ -185,7 +191,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 (library characters 8000/8000, base fallback 6000/4000, gear 1500, props 4000 + during LOD generation), budgets (characters 16000/16000, 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/blender-mcp.md b/docs/blender-mcp.md new file mode 100644 index 0000000..0045a09 --- /dev/null +++ b/docs/blender-mcp.md @@ -0,0 +1,149 @@ +# Optional Blender MCP + +Status: **optional interactive tooling, not a build dependency.** Blender MCP is +useful for exploring a local part scene, moving the viewport and iterating on a +head/hand mesh without a manual UI walkthrough. The authoritative asset +pipeline remains the headless CLI plus `audit`/`fit`/`inspect`; CI, tests and +release builds must continue to work with no Blender process and no MCP server. + +This project does not vend the third-party addon or pin a runtime MCP +dependency. Install it outside the repository and keep generated scenes under +`tmp/`. + +## What it adds + +With Blender MCP connected, an agent can: + +- query the current scene and object data; +- run small `bpy` snippets through the MCP bridge; +- capture a viewport screenshot for visual checks; +- inspect or modify a local part scene before exporting a GLB. + +It does **not** replace: + +- `python3 tools/blender_assets.py audit/fit/inspect`; +- `python3 tools/npc_proportions.py`; +- the Godot capture and smoke gates; +- the project's licence/provenance review. + +## Prerequisites + +- Blender 5.2 LTS, installed as the `org.blender.Blender` flatpak (the project + standard). +- An MCP-capable client. +- The upstream [BlenderMCP addon](https://github.com/ahujasid/blender-mcp) + (`addon.py`) and its MCP server. +- `uv`/`uvx` if you use the server's `uvx blender-mcp` launcher; a local install + of the server package is equally valid. + +Check the upstream README for the current package/addon version and any command +changes before installing. Do not copy the addon into this repository. + +## Setup + +### 1. Install the Blender addon + +1. Download or clone the upstream BlenderMCP project. +2. In Blender: **Edit → Preferences → Add-ons → Install from Disk**, select + `addon.py` from that checkout. +3. Enable **Interface: Blender MCP**. +4. Open the 3D View sidebar (N panel), find the **BlenderMCP** tab, and click + **Connect to MCP server**. The default server listens on + `localhost:9876`. + +The addon must be running inside the Blender process that has the scene open. +Starting a second Blender instance does not connect the first one. + +### 2. Configure the MCP client + +For Pi, add the server at user scope so it is not committed into the project: + +```bash +pi mcp add blender -- uvx blender-mcp +pi mcp list +``` + +Then start/reload Pi and use `/mcp` to inspect the connection. Other clients +use their normal MCP server configuration. A generic JSON example: + +```json +{ + "mcpServers": { + "blender": { + "command": "uvx", + "args": ["blender-mcp"] + } + } +} +``` + +For a client with a different config schema, use the equivalent server command +and keep the server name `blender`. Restart/reload the client after adding it, +then request the tool list and run a harmless `get_scene_info` before editing. + +### 3. Connect through the flatpak + +Start Blender through the project's normal flatpak command, open the local part +scene, and connect from the sidebar. If the client cannot reach the addon: + +- confirm the addon panel says connected; +- confirm the client is launching the MCP server, not just a shell; +- check port `9876` is not occupied; +- if the flatpak sandbox is blocking localhost networking, grant network + permission only for this interactive use, for example: + `flatpak override --user --share=network org.blender.Blender` + (review the permission change afterwards; do not add it to CI or build + scripts). +- restart both the MCP client and Blender after changing the addon or config. + +## Recommended part-workflow + +1. Create a local scene, for example + `tmp/npc-parts/npc_casual/head.blend`, or open a copy of an exported part GLB. + Never save over the tracked `assets/models/npc/npc_base.blend`. +2. Ask the MCP client for `get_scene_info`, then inspect the object/bone/mesh + names it reports. +3. Use `execute_blender_code` for small, reversible edits. Prefer adding a new + object or modifier over deleting existing geometry; keep a backup copy. +4. Use `get_viewport_screenshot` after camera/material changes to check the + head/face/hand before exporting. +5. Export a **local** GLB under `tmp/npc-parts/`, not directly into + `assets/models/`. +6. Run the normal gates on the exported file: + + ```bash + flatpak run org.blender.Blender --background \ + --python "$PWD/tools/blender_assets.py" -- \ + inspect --file "$PWD/tmp/npc-parts/head.glb" --category npc --json + python3 tools/blender_assets.py audit + python3 tools/blender_assets.py fit + python3 tools/npc_proportions.py report + ``` + +7. Only after the part is reviewed and the contract passes should it be + assembled into a character and rebuilt through the headless pipeline. + +## Safety and project rules + +- MCP is **not** part of `project.godot`, the build, CI, tests, release packages + or runtime. +- Do not commit `.blend` part scenes, MCP configuration, API keys or generated + previews. The working set stays in `tmp/`. +- Do not use MCP to bypass the contract, budgets, AO/UV rules or licence gate. +- The 13 core bones must remain at their rest positions; extra optional bones + are allowed only if `NpcAvatar` and the audit/tests still pass. +- Prefer scripted headless changes for reproducible work; MCP is for the + interactive exploration and review that is awkward in a one-shot script. +- If MCP is unavailable, use the headless CLI and document the manual step; never + make the project depend on MCP being present. + +## Troubleshooting + +| Symptom | Check | +| --- | --- | +| Client cannot find `blender` | MCP client config path/schema; restart client; confirm server command exists | +| `Connection refused` | Addon **Connect to MCP server** pressed; Blender still running; port 9876 | +| Tools return stale scene data | Refresh scene/object query after edits; restart the connection if needed | +| Flatpak cannot reach localhost | Check flatpak network permission; grant only for interactive use | +| Changes look wrong in export | Re-import the GLB with `inspect`; check transforms, scale, UVs and materials | +| Contract audit fails | Fix the mesh/bones first; do not edit the audit expectations around a broken asset | diff --git a/docs/development-status.md b/docs/development-status.md index affb229..44f9267 100644 --- a/docs/development-status.md +++ b/docs/development-status.md @@ -62,7 +62,8 @@ Python tooling is 161/161 after the GLB `inspect` intake coverage. - 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 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 realism pass (2026-11-03/04): all eight variants now use the `seg=24/rings=16` head with a subtle brow ridge, a fuller lower lip and both eyelids (recessed creases were rejected because they bake as dark AO patches). Vision-reviewed as cleaner/more realistic than the 0.9.4 face; characters measure 5,038–5,900 tris / 4,756–5,902 verts (still under 8,000). `sheet_npc_baseline.jpg` was refreshed. +- Character contract extension (2026-11-04): the character cap is **16,000 triangles / 16,000 glTF vertices** (library and base fallback); the 13 core bones remain required and optional extra bones are allowed. Blender MCP is documented as optional interactive tooling in [`blender-mcp.md`](blender-mcp.md), not a build/CI/runtime dependency. Blender/NPC audits still pass. +- NPC face realism pass (2026-11-03/04): all eight variants now use the `seg=24/rings=16` head with a subtle brow ridge, a fuller lower lip and both eyelids (recessed creases were rejected because they bake as dark AO patches). Vision-reviewed as cleaner/more realistic than the 0.9.4 face; characters measure 5,038–5,900 tris / 4,756–5,902 verts (still under 16,000). `sheet_npc_baseline.jpg` was refreshed. - Crowd-variety roster (character development, 2026-11-04): four new variants — `npc_crowd_a` (slim/bun/sunglasses), `npc_crowd_b` (broad/bald/beard/shoulder bag), `npc_crowd_c` (coat/umbrella), `npc_crowd_d` (slim/hood/cup) — built with the realistic face and wired into `CHARACTER_POOLS` so the routine crowd roles (tourist, confused visitor, intoxicated) pick them by seed instead of cloning `npc_casual`. The 24-NPC smoke is now 152,464 tris / 168 meshes / 6.94 ms (under the 50 ms budget). - 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 footwear pass (0.9.4 work): casual shoes gained rounded toe and heel caps; responder/firefighter boots gained matching toe/heel volumes while retaining the black rubber boot language. All eight rebuilt; comparison `sheet_npc_baseline_compare-shoes.jpg`. diff --git a/docs/npc-model-sourcing.md b/docs/npc-model-sourcing.md index b1b4fb7..f55aace 100644 --- a/docs/npc-model-sourcing.md +++ b/docs/npc-model-sourcing.md @@ -28,7 +28,7 @@ Any expansion must preserve the existing integration contract: `Hips`, `Spine`, `Neck` at the contract rest positions; - five tint slots (`skin`, `cloth`, `pants`, `accessory`, `hair`); - front on Blender −Y / Godot +Z, feet near the floor, 1.6–2.1 m height; -- at most 8,000 triangles and 8,000 glTF vertices per character; +- at most 16,000 triangles and 16,000 glTF vertices per character; - gear attach points at head, back, chest and hand. The existing `audit` command is the gate. A source that looks good in a preview @@ -68,8 +68,8 @@ Every example fails the unmodified `audit` contract: | `npc_base` mesh node | no | no | no | no | no | | Required 13 bones | no (62 different names) | no rig | no (19 different names) | no (19 different names) | no rig | | Five tint slots | no | no | no | no | no | -| ≤ 8,000 tris | yes | yes | yes | yes | no | -| ≤ 8,000 verts | no (10.5–13k) | yes | yes | yes | no (19k) | +| ≤ 16,000 tris | yes | yes | yes | yes | yes | +| ≤ 16,000 verts | yes (10.5–13k) | yes | yes | yes | no (19k) | | Feet on floor | yes | yes (2.7 m scale) | yes (−11 mm) | yes | no (needs scaling) | | Height 1.6–2.1 m | yes | no (2.7 m) | no (1.45 m) | no (1.48 m) | needs scale | | Skinned / UV mapped | yes / yes | no / yes | yes / yes | yes / no | no / no | @@ -211,7 +211,7 @@ the A-pose arms down (−38°/+38°) and scales them **1.63×** to the contract arm, welds the split vertices, smooth-shades, adds the 13-bone contract armature with the project's distance-to-bone `_auto_weights`, paints the five slot regions, renames the mesh to `npc_base`, and exports `makehuman_retargeted.glb` — **6,444 / -8,000 tris, 7,726 / 8,000 verts**, 14 bones, skinned, arm-down, grounded, five +16,000 tris, 7,726 / 16,000 verts**, 14 bones, skinned, arm-down, grounded, five slots, no contract issues. The proportion warp (1.63× arms) is the same class of issue that blocked Quaternius; here it is accepted, but the vision review shows it distorts the deltoid/shoulder, the decimated hands are blocky, and the slot @@ -283,7 +283,7 @@ are: - Weld duplicate seam vertices before decimating. Quaternius' 12k imported vertices are mostly UV/normal splits; the underlying surface is much smaller, but the glTF budget counts the splits after export. -- Decimate to a target below 8,000 tris/verts, then re-unwrap only if the +- Decimate to a target below 16,000 tris/verts, then re-unwrap only if the existing UVs cannot survive the material remap. The current library uses smart projection at 80° to keep islands large. - Map materials by semantic role, not by source name. A source "Purple" or diff --git a/docs/npc-visual-review.md b/docs/npc-visual-review.md index c7c78c8..4dae76f 100644 --- a/docs/npc-visual-review.md +++ b/docs/npc-visual-review.md @@ -71,9 +71,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 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. + 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; + 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 rest of the eight-character library; broad/slim/average build variation is @@ -134,8 +134,8 @@ From `python3 tools/blender_assets.py fit` and the manifest: | `npc_firefighter` | 5,344 | 5,494 | 0.315 m | 0.255 m (skirt) | helmet width ratio 1.651; SCBA x −0.105, radial −0.076 | | `npc_guard` | 5,046 | 5,096 | 0.315 m | 0.194 m (hip) | cap width ratio 1.067 | -`npc_coat` is widest at 5,474 triangles (2,526 below the 8,000 cap); -`npc_firefighter` is closest on vertices at 5,494 (2,506 below the 8,000 cap). +`npc_coat` is widest at 5,474 triangles (well below the 16,000 cap); +`npc_firefighter` is closest on vertices at 5,494 (well below the 16,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 31ec037..515983f 100644 --- a/tools/blender_assets.py +++ b/tools/blender_assets.py @@ -53,13 +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"] -# 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 +# 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 GEAR_MAX_TRIS = 1500 PROP_MAX_TRIS = 4000 @@ -2135,14 +2136,15 @@ def inspect_glb(path, category=None) -> dict: return result -def adapt_glb(path, out_path, target_tris=8000): +def adapt_glb(path, out_path, target_tris=16000): """Import an external GLB and adapt it toward the library contract. Applies node transforms, grounds the feet (lowest vertex at y = 0), welds duplicated seam vertices and decimates to `target_tris`, then exports the - result to `out_path` as a GLB. The five tint slots and the 13-bone contract - armature are deliberately NOT auto-mapped — that is a manual retopology/rig - step. Returns before/after measurements for the intake report. + result to `out_path` as a GLB. The five tint slots and the required 13 core + bones (optional extra bones are allowed) are deliberately NOT auto-mapped — + that is a manual retopology/rig step. Returns before/after measurements for + the intake report. """ if bpy is None: return {"ok": False, "error": "adapt must run inside Blender"} @@ -2537,8 +2539,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=8000, - help="decimate target (default 8000)") + ada.add_argument("--target-tris", type=int, default=16000, + help="decimate target (default 16000)") 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 67bea85..9f6fb6d 100644 --- a/tools/npc_pipeline.py +++ b/tools/npc_pipeline.py @@ -23,7 +23,8 @@ 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 - * <= 6000 triangles / 4000 vertices, UVs in [0,1], feet at y ~= 0 + * <= 16000 triangles / 16000 vertices, UVs in [0,1], feet at y ~= 0 + * the 13 core bones are required; extra optional bones are allowed """ import argparse @@ -44,8 +45,8 @@ BONES = [ "Head", "HipL", "HipR", "KneeL", "KneeR", "ShoulderL", "ShoulderR", "ElbowL", "ElbowR", "HandL", "HandR", ] -MAX_TRIANGLES = 6000 -MAX_VERTICES = 4000 +MAX_TRIANGLES = 16000 +MAX_VERTICES = 16000 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 33d825d..1666d71 100644 --- a/tools/tests/test_blender_assets.py +++ b/tools/tests/test_blender_assets.py @@ -9,11 +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 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) + # The character cap was raised to 16000/16000 for the head/face/hand + # 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) def test_gear_uses_known_attach_points(self): for name, attach in ba.GEAR.items(): @@ -188,10 +187,17 @@ class InspectionTests(unittest.TestCase): self.assertEqual(result["bones_missing"], []) self.assertEqual(result["budget"]["max_triangles"], ba.CHAR_MAX_TRIS) + def test_extra_optional_bones_are_allowed(self): + stats = self.stats(bones=list(ba.BONES) + ["Hips", "Spine", "Neck", + "FingerL", "FingerR"]) + result = ba.analyse_inspection(stats) + self.assertTrue(result["ok"], result["issues"]) + self.assertEqual(result["bones_missing"], []) + 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=9000, split_vertices=9000, + triangles=17000, split_vertices=17000, 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) @@ -199,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 9000 > {ba.CHAR_MAX_TRIS}", issues) - self.assertIn(f"glTF vertices 9000 > {ba.CHAR_MAX_VERTS}", issues) + self.assertIn(f"triangles 17000 > {ba.CHAR_MAX_TRIS}", issues) + self.assertIn(f"glTF vertices 17000 > {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 3c6a1a6..55acfef 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, 6000) - self.assertLessEqual(npc_pipeline.MAX_VERTICES, 4000) + self.assertLessEqual(npc_pipeline.MAX_TRIANGLES, 16000) + self.assertLessEqual(npc_pipeline.MAX_VERTICES, 16000) def test_textures_exist_for_every_slot(self): for slot in npc_pipeline.SLOTS: