Raise character limits and document optional Blender MCP
This commit is contained in:
1 parent
50a48d2256
commit
aec1fb7b69
20 files changed
+303
-96
No files matched your search
@@ -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.
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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/<variant>/` (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 <in> --out <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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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).
|
||||
@@ -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 | `<asset>_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` |
|
||||
|
||||
+11
-3
@@ -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
|
||||
|
||||
+13
-7
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
@@ -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`.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+15
-13
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in new issue
Block a user