309 lines
18 KiB
Markdown
309 lines
18 KiB
Markdown
# NPC model sourcing and expansion plan
|
||
|
||
Status: **direction chosen 2026-11-03.** The procedural generator is the primary
|
||
path, the Quaternius CC0 pack is a reviewed reference/prototype, and MakeHuman is
|
||
deferred to a separate local development pipeline. No downloaded source model is
|
||
committed to the game or included in a release; the committed research preview
|
||
sheets carry the required attribution. Local evaluation files live under
|
||
`tmp/npc-research/` (gitignored). The decision is recorded in
|
||
[ADR-0015](adr/0015-npc-model-variety-sourcing.md).
|
||
|
||
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.
|
||
|
||
## Decision and prototype outcome
|
||
|
||
The project owner reviewed this page on 2026-11-03. The decision is:
|
||
|
||
1. **CC0 is acceptable** for shipped character assets. CC-BY is acceptable only
|
||
with attribution in `CREDITS.md`; service assets whose terms restrict
|
||
redistribution remain excluded.
|
||
2. **Extend the procedural generator** as the primary path, starting with
|
||
crowd-variety looks.
|
||
3. **Prototype Quaternius** as a secondary source. It is not approved for
|
||
shipping yet; the contract-retarget result below is a no-go for the current
|
||
skeleton.
|
||
4. **Use crowd variety** as the first visual goal, not role-specific costumes.
|
||
5. **Evaluate MakeHuman for a later, separate local development pipeline.** It
|
||
is not part of the normal build, CI or release flow.
|
||
6. **Commit the research previews with attribution.** The CC-BY entries are
|
||
listed in `CREDITS.md` and remain development-only.
|
||
|
||
### Quaternius prototype
|
||
|
||
The prototype used `Casual_Hoodie.glb`:
|
||
|
||
- **Geometry budget is not the blocker.** Imported: 12,518 vertices / 6,206
|
||
triangles. After welding seam splits: 3,199 vertices / 6,206 triangles. After
|
||
a 0.75 decimate: 2,423 vertices / 4,654 triangles, comfortably inside the
|
||
library budget.
|
||
- **Animation quality is attractive.** The imported Idle and Walk clips read
|
||
well at game distance, and the model brings 24 animations.
|
||
- **The contract rest pose is the blocker.** The source is a T-pose 62-bone rig
|
||
with realistic proportions: upper leg starts near 0.96 m, arm span is about
|
||
1.68 m, and the shoulder joint sits near x = 0.153 m. The project contract is
|
||
an arm-down 13-bone rig with a hip near 0.62 m, a shoulder near x = 0.27 m and
|
||
a hand near z = 0.78 m. Rebuilding the contract armature around this mesh would
|
||
either distort the body substantially or require a full proportion warp.
|
||
- **Decision:** do not retarget Quaternius to the contract now. Keep it as a
|
||
silhouette/style reference and, if a second rig path is ever wanted, prototype
|
||
it as its own animation path (its own skeleton, AnimationPlayer clips and
|
||
per-model gear offsets) rather than forcing it into `npc_base`. That is a
|
||
separate architecture decision, not an asset conversion.
|
||
|
||
Preview: [`blender_previews/sheet_npc_sources_research.jpg`](blender_previews/sheet_npc_sources_research.jpg).
|
||
|
||
### Generator crowd prototype
|
||
|
||
Four proposed crowd specs were built with the existing generator in a temporary
|
||
output directory. All four audit clean and stay inside the character budget:
|
||
|
||
| Prototype | Look | Tris / verts | Gear |
|
||
| --- | --- | --- | --- |
|
||
| `npc_crowd_a` | slim, bun, sunglasses | 4,644 / 4,356 | sunglasses |
|
||
| `npc_crowd_b` | broad, bald, beard | 4,550 / 4,453 | shoulder bag |
|
||
| `npc_crowd_c` | average, short hair, long coat | 5,118 / 5,086 | umbrella |
|
||
| `npc_crowd_d` | slim, short hair, hood up | 5,258 / 4,907 | cup |
|
||
|
||
They vary build, head silhouette, hair/beard and outer layer while keeping the
|
||
existing face language. They are **not in the shipped catalogue**; production
|
||
integration belongs to milestone 0.11.4 after the 0.10.0 release candidate.
|
||
|
||
Preview: [`blender_previews/sheet_npc_crowd_prototypes.jpg`](blender_previews/sheet_npc_crowd_prototypes.jpg).
|
||
|
||
### MakeHuman local-pipeline evaluation
|
||
|
||
The CC0 base mesh is 19,158 vertices / 18,486 polygons (36,972 triangles after
|
||
triangulation), with 21,334 UV coordinates but no normals, material groups or
|
||
rig. Scaling it to 1.82 m and decimating to 0.35 produced 3,780 vertices / 6,468
|
||
triangles, which fits the geometry budget but is a collapse-decimation result,
|
||
not production topology.
|
||
|
||
MakeHuman is therefore **feasible only as a separate local body-shape pipeline**.
|
||
The boundary for that future work is:
|
||
|
||
- MPFB/MakeHuman is installed and run by a contributor, never by CI or the game
|
||
build.
|
||
- Generated bodies and intermediate exports stay in `tmp/` (gitignored); the
|
||
CC0 base mesh is not committed.
|
||
- The contributor scales to 1.8–1.9 m, decimates or retopologises to roughly
|
||
6–7k triangles, and checks the silhouette against `npc-visual-review.md`.
|
||
- The body gets the contract armature, weights, project-owned head/hands,
|
||
clothing and gear; it must pass `blender_assets.py audit` and `fit`.
|
||
- Only the final CC0-derived GLB and its provenance note are committed. The
|
||
application code and any non-CC0 assets stay outside the repository.
|
||
|
||
This is deferred; it is not part of the 0.11.0 crowd-variety work.
|
||
|
||
## 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` | `npc_crowd_a` (bun/slim), `npc_crowd_b` (bald/broad), `npc_crowd_c` (coat/umbrella), `npc_crowd_d` (hood/cup) | build, height, hair, facial hair, outer layer, accessory |
|
||
| Workwear | `npc_vest`, `npc_guard` | later: second hi-vis build, venue-security build | build, height, headwear, badge/radio gear |
|
||
| Responder | `npc_firefighter` | later: paramedic/medical responder only if the design supports it | turnout vs medical kit, build, helmet |
|
||
| Crowd/LOD | none | optional 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 the four
|
||
crowd prototypes), not twenty. That is enough to break the clone effect without
|
||
doubling the portrait QA matrix. `character_model_for()` 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.** Complete: ADR-0015, the CC0/CC-BY rule and the
|
||
committed preview sheets.
|
||
2. **Generator crowd variants.** Complete as a prototype (four specs, clean
|
||
audit, review sheet). Production integration is pending the 0.10.0 release.
|
||
3. **Quaternius intake.** The contract-retarget prototype is a no-go. Keep the
|
||
source as a reference; a second-rig/animation path would need its own ADR.
|
||
4. **Roster build and runtime.** Add the four approved specs to `CHARACTERS`,
|
||
build and commit their GLBs, update the manifest, and extend the role pools.
|
||
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.
|
||
- Keep the face direction unambiguous. The front is Blender −Y; verify it with
|
||
a capture, not by guessing from the source file.
|
||
- For any future external-rig path, do not silently add a second skeleton format
|
||
to `NpcAvatar`. Record the per-model skeleton, animation source and gear
|
||
offsets as an explicit contract.
|
||
|
||
## Review outcome
|
||
|
||
The project owner answered the review questions on 2026-11-03:
|
||
|
||
| Question | Answer |
|
||
| --- | --- |
|
||
| Are third-party CC0 characters acceptable? | Yes. |
|
||
| Which direction? | Prototype Quaternius and extend the procedural generator. |
|
||
| Which looks first? | Crowd variety. |
|
||
| Should MakeHuman be pursued? | Evaluate it for a later, separate local development pipeline. |
|
||
| Commit the previews? | Yes, with CC-BY attribution. |
|
||
|
||
## Downloaded example provenance
|
||
|
||
Source models were downloaded on 2026-11-03 and kept out of version control. The two
|
||
research preview sheets are committed under `docs/blender_previews/`; the CC-BY
|
||
attribution is recorded in `CREDITS.md`.
|
||
|
||
| 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.
|