248 lines
15 KiB
Markdown
248 lines
15 KiB
Markdown
# NPC model sourcing and expansion plan
|
||
|
||
Status: **research complete, direction not chosen (2026-11-03).** No downloaded
|
||
model is committed to the game or included in a release. The local evaluation
|
||
files live under `tmp/npc-research/` (gitignored).
|
||
|
||
This page records the free/open-source character sources that were reviewed, how
|
||
they behave when imported into the existing Blender tooling, and the options for
|
||
creating a larger NPC model library. The runtime contract and current library are
|
||
documented in [`blender-assets.md`](blender-assets.md) and
|
||
[`npc-visual-review.md`](npc-visual-review.md).
|
||
|
||
## Why this review exists
|
||
|
||
The library has eight skinned characters, and `NpcAvatar.character_model_for()`
|
||
reuses them across role families. That is enough for a release candidate, but
|
||
crowds repeat the same faces, builds and outfits. Three venues, a 24-NPC budget
|
||
and close-up portraits make that repetition visible.
|
||
|
||
Any expansion must preserve the existing integration contract:
|
||
|
||
- mesh node `npc_base` under a `Skeleton3D`;
|
||
- bones `Head`, `HipL/R`, `KneeL/R`, `ShoulderL/R`, `ElbowL/R`, `HandL/R` plus
|
||
`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;
|
||
- gear attach points at head, back, chest and hand.
|
||
|
||
The existing `audit` command is the gate. A source that looks good in a preview
|
||
but fails `audit` is not usable without an adaptation step.
|
||
|
||
## What was evaluated
|
||
|
||
Blender 5.2.0 LTS (Flatpak) imported each file in background mode. Measurements
|
||
below come from the imported scene, because external GLBs often carry node
|
||
transforms that the project's audit (which reads accessor-local bounds) does not
|
||
apply. "Vertices" are the imported, seam-split counts that matter for the glTF
|
||
budget, not the source file's vertex count.
|
||
|
||
| Source | Licence | Files checked | Geometry / rig | Height | Verdict |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| **Quaternius Ultimate Modular Men / Women** (mirrored GLB pack) | CC0 1.0 | `Casual_Hoodie.glb`, `Worker.glb`, `Casual.glb` | 5,240–6,424 tris; 10,534–12,968 verts; 62 bones; 24 animations; 4 skinned meshes on one armature | 1.80–1.87 m | **Best silhouette/outfit match.** Fails the contract: wrong bone names/rest positions, no tint slots, no `npc_base` node, vertex budget exceeded. |
|
||
| **Kenney Blocky Characters 2.0** | CC0 1.0 | full pack (18 characters), `character-a.glb`, `character-f.glb` | 72 tris; 143 verts; static, no armature; one texture atlas per character | 2.7 m imported (needs 0.67× scale) | **Not a close-up character.** Useful as a crowd/impostor LOD or placeholder, but cannot be driven by the skeleton and has no separate face/clothing slots. |
|
||
| **Khronos CesiumMan** | CC BY 4.0 (© Cesium) | `CesiumMan.glb` | 4,672 tris; 3,273 verts; 19-bone walk rig; 1 material/texture; 1 animation | 1.45 m | **Technical retarget test only.** One outfit and one look, wrong rig, short; works as a skinning/pose reference. Attribution is required. |
|
||
| **Khronos RiggedFigure** | CC BY 4.0 (© Cesium) | `RiggedFigure.glb` | 256 tris; 370 verts; 19-bone walk rig; no UVs; 1 animation | 1.48 m | **Rig smoke test only.** A mannequin with no usable surface detail. |
|
||
| **MakeHuman core base mesh / MPFB** | Core assets CC0 1.0; application AGPL/GPL | `makehuman/data/3dobjs/base.obj` | 19,158 verts; 18,486 polygons; 36,972 tris; no rig in the base mesh | ~16.9 model units before scaling | **Best body-shape diversity, highest pipeline cost.** Needs scaling, decimation/retopology and a generated rig. The MakeHuman/MPFB tool itself is not bundled. |
|
||
|
||
Local review sheet (front views, not committed):
|
||
`tmp/npc-research/previews/contact_sheet.jpg`.
|
||
|
||
Rejected without downloading: Mixamo and Ready Player Me. Both are useful
|
||
services, but their terms are not a simple free/open-source redistribution basis
|
||
for shipped character meshes. Sketchfab, Poly Pizza and OpenGameArt can contain
|
||
excellent CC0 work, but each asset needs a case-by-case licence and provenance
|
||
check; they are not a consistent library source.
|
||
|
||
### Measured contract failures
|
||
|
||
Every example fails the unmodified `audit` contract:
|
||
|
||
| Check | Quaternius | Kenney | CesiumMan | RiggedFigure | MakeHuman base |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| `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) |
|
||
| 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 |
|
||
|
||
The practical conclusion is that **there is no drop-in download**. External
|
||
sources need a deliberate intake step, and the expensive part is not decimation:
|
||
it is rebuilding or retargeting the skeleton and material slots without breaking
|
||
the animation proxies and gear placement.
|
||
|
||
The table uses Blender-imported world bounds. The stdlib `audit` reads accessor-local
|
||
bounds and ignores node transforms, so an unapplied external GLB can fail floor/height
|
||
checks even when the imported scene looks correct. The intake step must apply
|
||
transforms before it measures and exports.
|
||
|
||
## Options
|
||
|
||
### Option A — extend the procedural generator
|
||
|
||
Add more variation to `tools/blender_assets.py` rather than importing models:
|
||
body builds, height ranges, head/face shapes, hair and facial hair, outfit
|
||
layers, and more `CHARACTERS` specs. This keeps a single owned style, needs no
|
||
third-party licence review, and stays inside the existing builder/audit flow.
|
||
|
||
- **Strengths:** lowest integration risk, deterministic, no new dependencies.
|
||
- **Limits:** the current face and clothing vocabulary is intentionally simple;
|
||
more variants may still read as the same model with a different coat.
|
||
- **Best for:** a quick 4–8 variant expansion and filling obvious role gaps.
|
||
|
||
### Option B — Quaternius CC0 intake with a contract adapter
|
||
|
||
Use Quaternius meshes as silhouette/outfit donors and adapt them to the project
|
||
contract. The visible result is a different body/clothing language from the
|
||
current library, so the adapter must also normalise head/hand style or rebuild
|
||
those parts.
|
||
|
||
- **Strengths:** best free outfit/hair variety, animations included, CC0,
|
||
already close to game proportions, front axis and floor contact.
|
||
- **Work:** weld/decimate to the vertex budget, remap materials to the five
|
||
slots, rebuild the armature at the contract rest positions, transfer weights,
|
||
repose/normalise proportions, rename the mesh node, export, audit and compare
|
||
in the acceptance harness.
|
||
- **Main risk:** retargeting a 62-bone T-pose rig to the 13-bone arm-down
|
||
contract. Hip/knee rest heights differ substantially (Quaternius upper leg
|
||
starts near 0.96 m; the contract hip starts near 0.62 m), so a naive
|
||
nearest-bone weight transfer can produce a good still image and bad walk
|
||
poses. Prototype one character before committing to a roster.
|
||
- **Best for:** a larger, visibly different library if the prototype passes the
|
||
portrait and walk gates.
|
||
|
||
### Option C — MakeHuman/MPFB body-shape pipeline
|
||
|
||
Generate a range of ages, builds and body shapes from the CC0 MakeHuman base
|
||
mesh, then replace the head/hands and dress them with project-owned clothing.
|
||
This is the strongest answer to "everyone has the same body", but requires an
|
||
offline authoring step, decimation/retopology and a custom rig/weight step. It
|
||
should be treated as a later pipeline project, not a quick content drop.
|
||
|
||
## Recommended direction
|
||
|
||
1. **Do not add raw external models.** Keep the current library and contract
|
||
unchanged until a human has reviewed this page.
|
||
2. **Prototype Option B once** (one Quaternius character) behind a new intake
|
||
command. If the walk pose, face style and gear fit pass, use it for a small
|
||
set of silhouette donors and keep the project's faces/hands where possible.
|
||
3. **Fall back to Option A** for the remaining variants. Procedural variation
|
||
(age, build, hair, outfit colour/layers, accessory mix) is cheaper and keeps
|
||
the library coherent.
|
||
4. **Defer Option C** until the release candidate is out and there is a concrete
|
||
need for body-shape diversity that A/B cannot meet.
|
||
|
||
This is a proposal, not a decision. The review questions are at the end of the
|
||
page.
|
||
|
||
## Provisional NPC roster
|
||
|
||
The design rule stays: clothes, props and behaviour carry the read; a model must
|
||
not label a person as "the threat". The roster therefore adds ordinary adults
|
||
across age, build and style, not costumes that telegraph the outcome.
|
||
|
||
| Look family | Current | Proposed additions | Variation axes |
|
||
| --- | --- | --- | --- |
|
||
| Everyday | `npc_casual`, `npc_jacket`, `npc_coat`, `npc_hoodie`, `npc_dress` | older casual, denim jacket, short coat, open hoodie, second dress | age, build, height, hair, facial hair, outfit colour |
|
||
| Workwear | `npc_vest`, `npc_guard` | second hi-vis build, venue-security build, cleaner/vendor apron | build, height, headwear, badge/radio gear |
|
||
| Responder | `npc_firefighter` | paramedic/medical responder (only if the design supports it) | turnout vs medical kit, build, helmet |
|
||
| Crowd/LOD | none | Kenney blocky or a decimated library variant for distant crowds | silhouette and palette only |
|
||
|
||
A first target is **12 library characters** (the current eight plus four new
|
||
looks), not twenty. That is enough to break the clone effect without doubling
|
||
the portrait QA matrix. The existing `character_model_for()` mapping becomes a
|
||
pool per role family with a deterministic seed choice; the current two-way
|
||
alternation for guests, trespassers and threats is the template.
|
||
|
||
## Implementation plan
|
||
|
||
The actionable tasks live in `TODO.md` under milestone 0.11.0. The workstreams
|
||
are:
|
||
|
||
1. **Decision and licence gate.** Review this page, choose A/B/C, record the
|
||
decision in an ADR, and add a source allow-list (CC0 preferred; CC-BY only
|
||
with attribution in `CREDITS.md`; no service assets whose terms restrict
|
||
redistribution).
|
||
2. **Intake/validator.** Add an `inspect` report and an `adapt` path. The
|
||
validator should check bones, rest positions, node name, slots, budgets,
|
||
ground/height, UVs and skinning before and after adaptation. Keep the
|
||
existing `audit` as the final gate rather than creating a second contract.
|
||
3. **One-character prototype.** Adapt a single Quaternius CC0 variant; capture
|
||
front/three-quarter/profile/full-body/crowd views and a walk cycle; compare
|
||
against `npc_casual` and `sheet_npc_baseline.jpg`. Stop if the retarget does
|
||
not pass.
|
||
4. **Roster build.** Add four approved variants, update the manifest, and extend
|
||
the runtime selection pools. Rebuild gear fit and check each new variant with
|
||
the existing acceptance criteria.
|
||
5. **QA and integration.** Run the 24-NPC budget, portrait baseline, gear fit,
|
||
headless suite and release build. Record provenance and any accepted limits.
|
||
Only then update `CHANGELOG.md` and `docs/development-status.md`.
|
||
|
||
### Adapter notes
|
||
|
||
- Apply node transforms before measuring or exporting. CesiumMan imports with a
|
||
Z-up root and an `Icosphere` helper object; exclude helpers, not just the mesh
|
||
names, when measuring.
|
||
- 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
|
||
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
|
||
"Worker_Vest" needs an explicit mapping to `cloth`, `pants`, `skin`, `hair` or
|
||
`accessory`; do not rely on colour heuristics.
|
||
- Rebuild the armature at the contract rest positions and transfer weights, or
|
||
prove that a renamed external rig produces the same rest and pose behaviour.
|
||
Do not add a second skeleton format to `NpcAvatar`.
|
||
- Keep the face direction unambiguous. The front is Blender −Y; verify it with
|
||
a capture, not by guessing from the source file.
|
||
|
||
## Review questions
|
||
|
||
The project owner should answer these before the 0.11.0 work starts:
|
||
|
||
1. Are third-party CC0 characters acceptable in shipped game assets, or should
|
||
the library stay entirely project-owned?
|
||
2. If yes, is the Quaternius CC0 pack acceptable as a silhouette/outfit donor
|
||
with a rebuilt project-style head and hands?
|
||
3. Which four role families would benefit most from a new look: everyday
|
||
guests, workwear, responders, or crowd variety?
|
||
4. Is the MakeHuman/MPFB body-shape pipeline worth a later investment, or is
|
||
procedural variation enough?
|
||
5. Should the preview sheet be committed as a review artefact (with attribution
|
||
for the CC-BY entries), or stay local under `tmp/`?
|
||
|
||
Until those answers exist, the safe default is **Option A: extend the owned
|
||
procedural generator and keep external models as references only.**
|
||
|
||
## Downloaded example provenance
|
||
|
||
Files were downloaded on 2026-11-03 and kept out of version control:
|
||
|
||
| File | Source | SHA-256 |
|
||
| --- | --- | --- |
|
||
| `quaternius/Casual_Hoodie.glb` | `raw.githubusercontent.com/LuanDucate/Ducz.CharacterCreator/HEAD/public/models/Male/Casual_Hoodie.glb` (Quaternius CC0) | `f5b722199f7628b24550989af4230f65d5230727df9c326fd2b3e360effe5249` |
|
||
| `quaternius/Worker.glb` | same mirror, `Male/Worker.glb` | `8d0f454336c2effc5c08f63a177af3a82d1a7af025ca9588b40e4c90c4703534` |
|
||
| `quaternius/Casual.glb` | same mirror, `Female/Casual.glb` | `bc2d84fba249ebaa0629cb9d133ad37234196e4b8004aa205a6397abed04e05c` |
|
||
| `kenney_blocky_characters.zip` | `kenney.nl/assets/blocky-characters` | `5e123859aa0c1598342b600c6db197024a1d63eb9ec531398b310725f589887e` |
|
||
| `khronos/CesiumMan.glb` | `github.com/KhronosGroup/glTF-Sample-Assets` | `b7001eaeea8254bd44773bcd247e78696d94169388fbb2a1800fc69434e777d9` |
|
||
| `khronos/RiggedFigure.glb` | same repository | `d6be85417d3e256861ee733eea6916093a7af7c79c16366181fd8abcaeb38cf5` |
|
||
| `makehuman/base.obj` | `github.com/makehumancommunity/makehuman/blob/master/makehuman/data/3dobjs/base.obj` | `8e761e6624b8f54536409135d1636da63b32486a90d4897f84e121d144f6fb4c` |
|
||
|
||
Source terms:
|
||
|
||
- Quaternius packs are CC0 1.0 according to the pack page and the mirror's
|
||
credits. The mirror is a convenience download; the original pack page is
|
||
<https://quaternius.com/packs/ultimatemodularcharacters.html>.
|
||
- Kenney Blocky Characters 2.0 is CC0 1.0; the pack's `License.txt` is included
|
||
in the download.
|
||
- CesiumMan and RiggedFigure are CC BY 4.0, © 2017 Cesium. If any derivative is
|
||
committed or shipped, the attribution must be added to `CREDITS.md`.
|
||
- MakeHuman core assets are CC0 per `LICENSE.ASSETS.md`; the application source
|
||
is AGPL and is not bundled.
|