Add reviewed MakeHuman head prototype (vision gate rejected)

This commit is contained in:
zwitschi committed 2026-11-04 17:04:20 +01:00
1 parent d1898b3221
commit 958d3ae0ff
13 files changed
+197 -14

No files matched your search

+8 -4
View File
@@ -15,6 +15,10 @@ been cleared for public distribution.
## 3D characters, gear and props ## 3D characters, gear and props
The local MakeHuman head prototype uses the CC0 MakeHuman/MPFB base mesh
(see [`docs/makehuman-head-review.md`](docs/makehuman-head-review.md)); it is a
development prototype, not a shipped character.
The character, gear and prop library is generated by project-owned scripts The character, gear and prop library is generated by project-owned scripts
(`tools/blender_assets.py`, `tools/npc_pipeline.py`, `tools/model_pipeline.py`) (`tools/blender_assets.py`, `tools/npc_pipeline.py`, `tools/model_pipeline.py`)
using Blender. The `.blend` working sources are developer artifacts and are not using Blender. The `.blend` working sources are developer artifacts and are not
@@ -42,10 +46,10 @@ shipped derivative of CesiumMan or RiggedFigure must keep the attribution above.
### MakeHuman head source ### MakeHuman head source
The decimated head used by the character head prototype is derived from the The standalone MakeHuman head prototype is derived from the MakeHuman / MPFB base
MakeHuman / MPFB base mesh, **CC0** (`assets/models/blender_src/makehuman_head.glb`; mesh, **CC0** (`assets/models/blender_src/makehuman_head.glb`; source
source `tmp/npc-research/makehuman/base.obj` with its bundled `tmp/npc-research/makehuman/base.obj` with its bundled
`LICENSE.md`/`LICENSE.ASSETS.md`). It is retargeted, decimated and re-weighted by `LICENSE.md`/`LICENSE.ASSETS.md`). It is cut, retopologised and re-weighted by
project scripts; the exported character GLBs remain project assets. See ADR-0015 project scripts; the exported character GLBs remain project assets. See ADR-0015
and `docs/npc-model-sourcing.md`. and `docs/npc-model-sourcing.md`.
+9
View File
@@ -10,6 +10,15 @@ canonical implemented-features list in `docs/development-status.md`.
the licence gate. Downloads live in `tmp/research/` (gitignored): DDG image search, street-view the licence gate. Downloads live in `tmp/research/` (gitignored): DDG image search, street-view
frames, neighbouring buildings — never committed, never shipped. Promotion into frames, neighbouring buildings — never committed, never shipped. Promotion into
`docs/screens/refs/` always passes the sidecar licence + privacy gate and `CREDITS.md`. `docs/screens/refs/` always passes the sidecar licence + privacy gate and `CREDITS.md`.
- **MakeHuman head prototype (2026-11-04):** `assets/models/blender_src/makehuman_head.glb`
is a local 12,641-tri/7,690-split-vert head derived from the CC0 MakeHuman base,
with a review sheet and `docs/makehuman-head-review.md`. The latest build uses a
skin eyelid mask (almond aperture cut from a sphere), recessed globes, flat iris/pupil
discs and surface-anchored brows. The automated vision gate still rejected it:
the eye depth reads inconsistently across front/three-quarter/profile and the lid
does not visibly overlap the globe. It is not rigged, textured, integrated or
shipped; keep the source/rejected parts in `tmp/` until real eyelid masses pass
the gate.
- **Project agent skills (2026-11-03):** two tracked skills live in `.agents/skills/`: - **Project agent skills (2026-11-03):** two tracked skills live in `.agents/skills/`:
`gig-line-blender-asset-contract` and `gig-line-release-qa`. They are guidance only, `gig-line-blender-asset-contract` and `gig-line-release-qa`. They are guidance only,
add no runtime dependency and are referenced from `tools/README.md`. The third-party add no runtime dependency and are referenced from `tools/README.md`. The third-party
+1
View File
@@ -160,6 +160,7 @@ Full setup, every run/test/smoke command, and the controls table are in
- [`TODO.md`](TODO.md) — Priority-ordered tasks: character and local-map development, release milestones, and future work. - [`TODO.md`](TODO.md) — Priority-ordered tasks: character and local-map development, release milestones, and future work.
- [`docs/README.md`](docs/README.md) — Documentation index, current priorities and visual previews. - [`docs/README.md`](docs/README.md) — Documentation index, current priorities and visual previews.
- [`docs/npc-model-sourcing.md`](docs/npc-model-sourcing.md) — Character-source evaluation, licence rules and the character-development plan. - [`docs/npc-model-sourcing.md`](docs/npc-model-sourcing.md) — Character-source evaluation, licence rules and the character-development plan.
- [`docs/makehuman-head-review.md`](docs/makehuman-head-review.md) — Local MakeHuman head prototype, provenance and review verdict.
- [`AGENTS.md`](AGENTS.md) — Development, commit, build and collaboration workflow. - [`AGENTS.md`](AGENTS.md) — Development, commit, build and collaboration workflow.
- [`DONE.md`](DONE.md) — Completed task sections. - [`DONE.md`](DONE.md) — Completed task sections.
- [`MEMORY.md`](MEMORY.md) — Persistent session notes. - [`MEMORY.md`](MEMORY.md) — Persistent session notes.
+11 -2
View File
@@ -80,8 +80,6 @@ the rest of §C remains the broad review checklist.
### 3. Head and face prototype ### 3. Head and face prototype
### 3. Head and face prototype
- [x] Build one `npc_casual` head/face prototype as a connected head shell plus intentional feature - [x] Build one `npc_casual` head/face prototype as a connected head shell plus intentional feature
geometry — not a sphere with floating facial balls. Use loop-based eye sockets/lids, a geometry — not a sphere with floating facial balls. Use loop-based eye sockets/lids, a
readable nose bridge/tip/ala, a mouth with upper/lower lip volumes, ears with concha depth, readable nose bridge/tip/ala, a mouth with upper/lower lip volumes, ears with concha depth,
@@ -95,6 +93,17 @@ the rest of §C remains the broad review checklist.
- [x] Compare two or three subdivision/loop variants at 1.85 m front/three-quarter/profile and a - [x] Compare two or three subdivision/loop variants at 1.85 m front/three-quarter/profile and a
1.5 m portrait. Pick the variant that reads best before changing all 12 characters; keep the 1.5 m portrait. Pick the variant that reads best before changing all 12 characters; keep the
rejected variants local. rejected variants local.
- [-] Rebuild a standalone MakeHuman-derived head from the researched CC0 base and save it to
`assets/models/blender_src/makehuman_head.glb`; record provenance/review in
`docs/makehuman-head-review.md` and the preview sheet. (Final build: 12,641 tris / 7,690
split verts; assembled `npc_casual` 15,532 tris / 13,310 verts / 14 bones, `inspect` clean.
Latest attempt: skin eyelid mask, recessed globes, flat iris/pupil discs, surface-anchored
brows. Vision verdict: still **REJECT** — globe depth is inconsistent between front,
three-quarter and profile, the lid does not visibly clip the globe, and the iris reads
decal-locked at three-quarter; prototype stays local and un-integrated.)
- [ ] Build true upper/lower eyelid masses that overlap the globe in front, three-quarter and
profile views (not a socket hole), then re-run the vision gate before integrating the head.
Compared `head_proto` at seg 24 (670 verts), 48 (1,558 verts) and 64 (2,470 verts) at 1.85 m Compared `head_proto` at seg 24 (670 verts), 48 (1,558 verts) and 64 (2,470 verts) at 1.85 m
and 1.5 m, front/three-quarter/profile. Vision-judged: **s48 wins** — s24 is too faceted and 1.5 m, front/three-quarter/profile. Vision-judged: **s48 wins** — s24 is too faceted
(nose/lips melt, jagged silhouette), s64 is visually identical to s48 at both distances (nose/lips melt, jagged silhouette), s64 is visually identical to s48 at both distances
Binary file not shown.
+11
View File
@@ -257,6 +257,14 @@ at the MakeHuman landmarks. `build_character(name, head="mh")` assembles it; the
`inspect` (14 bones, skinned, no issues). The judge reads the face ~3.5/5; remaining polish is `inspect` (14 bones, skinned, no issues). The judge reads the face ~3.5/5; remaining polish is
welding the added eye/brow pieces into the head shell and a skull-conforming hair cap. welding the added eye/brow pieces into the head shell and a skull-conforming hair cap.
**Standalone head re-review (2026-11-04):** the separate
`assets/models/blender_src/makehuman_head.glb` prototype (12,641 tris / 7,690 split verts,
with a skin eyelid mask, recessed globes, flat iris/pupil discs and surface-anchored brows)
was **rejected** by the vision gate: the globe depth reads inconsistently between front,
three-quarter and profile, the iris reads decal-locked at three-quarter, and the lid does
not visibly clip the globe. It stays local until real eyelid geometry passes; see
[`makehuman-head-review.md`](makehuman-head-review.md).
### Head subdivision comparison (2026-11-04) ### Head subdivision comparison (2026-11-04)
Three `head_proto` variants at UV-sphere segments 24/48/64 were rendered at 1.85 m and 1.5 m in Three `head_proto` variants at UV-sphere segments 24/48/64 were rendered at 1.85 m and 1.5 m in
@@ -485,6 +493,9 @@ and the full carded-cluster foliage pass is the one remaining owner-gated P1. No
## Next actions ## Next actions
- Review the standalone [`makehuman-head-review.md`](makehuman-head-review.md) prototype before integrating any head/hand part into the character library.
Tracked in [`TODO.md`](../TODO.md) `3D model re-evaluation`: the remaining `A. Baseline…` item is Tracked in [`TODO.md`](../TODO.md) `3D model re-evaluation`: the remaining `A. Baseline…` item is
this owner review; `B`/`C`/`D` carry the per-family work, and `E` adds the pose/weight, this owner review; `B`/`C`/`D` carry the per-family work, and `E` adds the pose/weight,
collider-coverage and scorecard-coverage gates this document found missing. collider-coverage and scorecard-coverage gates this document found missing.
+1
View File
@@ -13,6 +13,7 @@ This folder holds the project documentation, visual references and generated QA
- [`../PLAN.md`](../PLAN.md) — product, design intent and development priorities - [`../PLAN.md`](../PLAN.md) — product, design intent and development priorities
- [`../TODO.md`](../TODO.md) — priority-ordered active tasks and roadmap - [`../TODO.md`](../TODO.md) — priority-ordered active tasks and roadmap
- [`npc-model-sourcing.md`](npc-model-sourcing.md) — character-source evaluation, licence rules and the character-development plan - [`npc-model-sourcing.md`](npc-model-sourcing.md) — character-source evaluation, licence rules and the character-development plan
- [`makehuman-head-review.md`](makehuman-head-review.md) — local MakeHuman head prototype, provenance and review verdict
- [`architecture.md`](architecture.md) — arc42 system architecture - [`architecture.md`](architecture.md) — arc42 system architecture
- [`getting-started.md`](getting-started.md) — setup, run/test commands and controls - [`getting-started.md`](getting-started.md) — setup, run/test commands and controls
- [`asset-tooling.md`](asset-tooling.md) — image/model pipelines and screenshot gates - [`asset-tooling.md`](asset-tooling.md) — image/model pipelines and screenshot gates
+1
View File
@@ -9,6 +9,7 @@ capture harnesses.
| --- | --- | | --- | --- |
| [![sheet_npc.jpg](sheet_npc.jpg)](sheet_npc.jpg) <br> `sheet_npc.jpg` | Eight skinned character variants (casual, jacket, coat, hi-vis vest, dress, hoodie, firefighter, guard) with their gear attach points. | | [![sheet_npc.jpg](sheet_npc.jpg)](sheet_npc.jpg) <br> `sheet_npc.jpg` | Eight skinned character variants (casual, jacket, coat, hi-vis vest, dress, hoodie, firefighter, guard) with their gear attach points. |
| [![sheet_npc_baseline.jpg](sheet_npc_baseline.jpg)](sheet_npc_baseline.jpg) <br> `sheet_npc_baseline.jpg` | Neutral studio baseline: 8 characters x front, three-quarter, profile, back, full body and crowd views. | | [![sheet_npc_baseline.jpg](sheet_npc_baseline.jpg)](sheet_npc_baseline.jpg) <br> `sheet_npc_baseline.jpg` | Neutral studio baseline: 8 characters x front, three-quarter, profile, back, full body and crowd views. |
| [![sheet_makehuman_head.jpg](sheet_makehuman_head.jpg)](sheet_makehuman_head.jpg) <br> `sheet_makehuman_head.jpg` | Local MakeHuman head prototype: front, three-quarter and profile review views. The vision gate rejected this build (inconsistent globe depth and no visible lid overlap); see [`../makehuman-head-review.md`](../makehuman-head-review.md). |
| [![sheet_npc_baseline_compare-body.jpg](sheet_npc_baseline_compare-body.jpg)](sheet_npc_baseline_compare-body.jpg) <br> `sheet_npc_baseline_compare-body.jpg` | Neck/shoulder transition: fuller neck base and a lower shoulder root. | | [![sheet_npc_baseline_compare-body.jpg](sheet_npc_baseline_compare-body.jpg)](sheet_npc_baseline_compare-body.jpg) <br> `sheet_npc_baseline_compare-body.jpg` | Neck/shoulder transition: fuller neck base and a lower shoulder root. |
| [![sheet_npc_baseline_compare-face-detail.jpg](sheet_npc_baseline_compare-face-detail.jpg)](sheet_npc_baseline_compare-face-detail.jpg) <br> `sheet_npc_baseline_compare-face-detail.jpg` | Face detail: nose ala wings, a single rounded mouth and a darker ear concha. | | [![sheet_npc_baseline_compare-face-detail.jpg](sheet_npc_baseline_compare-face-detail.jpg)](sheet_npc_baseline_compare-face-detail.jpg) <br> `sheet_npc_baseline_compare-face-detail.jpg` | Face detail: nose ala wings, a single rounded mouth and a darker ear concha. |
| [![sheet_npc_baseline_compare-face.jpg](sheet_npc_baseline_compare-face.jpg)](sheet_npc_baseline_compare-face.jpg) <br> `sheet_npc_baseline_compare-face.jpg` | Face-depth pass: recessed sclera, upper lid and sculpted chin/cheek planes. | | [![sheet_npc_baseline_compare-face.jpg](sheet_npc_baseline_compare-face.jpg)](sheet_npc_baseline_compare-face.jpg) <br> `sheet_npc_baseline_compare-face.jpg` | Face-depth pass: recessed sclera, upper lid and sculpted chin/cheek planes. |
Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

+119
View File
@@ -0,0 +1,119 @@
# MakeHuman head prototype
Status: **local prototype, rejected by the automated visual gate, not integrated.**
The asset is a standalone head/neck extracted from the CC0 MakeHuman base in
`tmp/npc-research/makehuman/base.obj`. It is kept as a reviewable experiment and
is not part of the shipped NPC contract.
## Asset
- GLB: [`assets/models/blender_src/makehuman_head.glb`](../assets/models/blender_src/makehuman_head.glb)
- Review sheet: [`blender_previews/sheet_makehuman_head.jpg`](blender_previews/sheet_makehuman_head.jpg)
- Source workflow (development-only): `tmp/npc-research/build_makehuman_head.py`
— extracts the MakeHuman head, cuts it at the neck, keeps the head/eye/mouth
components, cuts an almond aperture through a skin eyelid mask, adds recessed
eyeballs with flat iris/pupil discs, anchors brows to the face surface, renders
front/three-quarter/profile and exports the standalone GLB.
- Measurements (final build, `inspect`): **12,641 triangles / 7,690 split
vertices**; bounds approximately `x ±0.094 m`, `y -0.180…0.042 m`,
`z 1.530…1.803 m` in project Z-up space. It is inside the 16,000/16,000
character cap.
- Materials used: `skin`, `eye_white`, `iris`, `pupil`, `hair`. No textures are
baked into this prototype.
![MakeHuman head review sheet](blender_previews/sheet_makehuman_head.jpg)
## What was done
1. Imported the CC0 MakeHuman base OBJ and cleared the importer axis rotation.
2. Applied the project scale/axis transform: 1.82 m body, Z-up, metres,
front −Y.
3. Cut the head at the neck (`z ≈ 1.53`) rather than keeping the cut shoulders;
capped the neck opening.
4. Built an eyelid mask by subtracting an almond aperture from a skin sphere
centred on each eye (`solver = "EXACT"`), then recessed the globes so the
cornea sits behind the lid plane.
5. Added flat iris/pupil discs on the globe axis; disabled backface culling so
the discs stay visible at three-quarter angles.
6. Anchored brow strips to the skin with object-space ray casts and added a
shallow supraorbital ridge so they do not float, then reduced the crown
height to improve the profile silhouette.
7. Fixed a material-remap bug introduced by joining the extra eye objects: the
joined head faces were pointing at the `eye_white` slot, making the whole
head render as white clay. The largest connected component is now forced
back onto `skin` after the join.
8. Rendered front/three-quarter/profile views in a neutral review studio and
exported the standalone GLB.
## Provenance
- Base mesh: MakeHuman / MPFB base, CC0, from the local research set
`tmp/npc-research/makehuman/`; see [`CREDITS.md`](../CREDITS.md).
- The head is a **derived prototype**, not a shipped NPC. It does not enter
`assets/models/blender/npc/`, `npc_base`, the runtime `NpcAvatar` path, CI, or
a release package until the NPC overhaul plan accepts it.
- Source photographs/proportions are not used as textures here; this is a
geometry-only head built from the researched model data.
## Review criteria
Accept only if:
- the head reads as human at front/three-quarter/profile and the neck is a
clean head/bust silhouette, not a shoulder cut;
- eyes, brow, nose, mouth and ears are readable without spikes, holes or
floating shells;
- the asset is inside the character budget and has no script/contract violation;
- the prototype remains clearly local and un-integrated until the part pipeline
is approved.
## Judge result
**VERDICT: REJECT** (vision judge `z-ai/glm-5.3-flash`, final build render set
above). The gate is blocked; the prototype is not presented as an accepted head.
Blocking findings:
- **P0 — globe depth is inconsistent across views.** The front/three-quarter
reads still show a bead-like iris with a pale sclera halo, while the profile
reduces the eye to a brown sliver. The judge reads this as a faked recess
rather than a socketed globe under a lid.
- **P0 — no convincing lid overlap.** The iris remains nearly circular in front
and the upper lid does not visibly clip the globe; the skin lid mask reads as
a crater around a bead.
- **P0 — iris orientation reads decal-locked** at three-quarter, so the gaze
appears to drift off the head axis.
- **P0 — the aperture/lid mask is too circular** and lacks medial/lateral
canthi, so the eye still reads as a doll eye at portrait distance.
Should-fix findings:
- the brow tubes are better anchored but the medial ends still detach in
three-quarter/profile;
- nose lacks a defined tip/wing and nostrils;
- mouth is a faint geometric seam with no lip volume;
- crown/back-of-skull is still faceted and egg-like in profile;
- the catchlight is baked geometry and is not consistent between eyes.
What passed: the skin/eye material remap is correct, the eye openings are
closed, the standalone GLB reports **12,641 triangles / 7,690 split vertices**
with no issues, and an assembled `npc_casual` with this head passes `inspect` at
**15,532 / 16,000 triangles, 13,310 split vertices, 14 bones, no issues**.
Known limits: bald mannequin-like presentation, stylized geometry-only
iris/pupil, no rig, no UV texture pass, and the neck cap is a review cut rather
than a body-welded seam.
## Next steps after the gate passes
- Replace the radial lid mask with real upper/lower lid masses that fold over
the globe, with pointed canthi, and pass the profile view.
- Move the iris onto a curved cornea cap so its orientation follows the globe at
three-quarter angles, and use a lighting-driven catchlight instead of baked
white geometry.
- Compare against the project `_face` baseline and decide whether this head is
the base for the local head/face overhaul.
- Add a clean UV/material pass and a contract armature/weights if it becomes
part of a library character.
- Keep the source script under `tmp/`; promote only the reviewed GLB and durable
docs/preview sheet.
+4
View File
@@ -46,6 +46,10 @@ project head/hands swap reduced this to **6,407 / 16,000 tris and**
**6,651 / 16,000 verts**, but manual shoulder/neck retopology and part cleanup **6,651 / 16,000 verts**, but manual shoulder/neck retopology and part cleanup
remain before it can be considered shippable. remain before it can be considered shippable.
A standalone MakeHuman head prototype is recorded in
[`makehuman-head-review.md`](makehuman-head-review.md); it remains local/un-integrated
until the overhaul accepts it.
The head/face/hand overhaul in [`TODO.md`](../TODO.md) is the prerequisite: the The head/face/hand overhaul in [`TODO.md`](../TODO.md) is the prerequisite: the
MakeHuman body should reuse the approved local head/hand parts rather than MakeHuman body should reuse the approved local head/hand parts rather than
forking a second face implementation. forking a second face implementation.
+8
View File
@@ -1,5 +1,13 @@
# Head rework — review page (2026-11-04) # Head rework — review page (2026-11-04)
> **Historical page / changed source (2026-11-04).** The numbers below describe the
> earlier decimated MakeHuman head (1,548-tri skin). The shared source
> `assets/models/blender_src/makehuman_head.glb` now holds the higher-resolution
> standalone prototype; its automated vision gate returned **REJECT** (inconsistent
> globe depth across views and no visible lid overlap). See
> [`../../makehuman-head-review.md`](../../makehuman-head-review.md). Re-run the
> library head build before relying on the comparison counts below.
This page is the review checkpoint for the NPC head rework. The goal was to replace the This page is the review checkpoint for the NPC head rework. The goal was to replace the
sphere-and-floating-primitive face with a head that has real nose / chin / jaw landmarks at sphere-and-floating-primitive face with a head that has real nose / chin / jaw landmarks at
portrait distance. portrait distance.
+24 -8
View File
@@ -968,11 +968,12 @@ def _head_proto(mats, spec, subdiv=48):
def _makehuman_head(mats, spec): def _makehuman_head(mats, spec):
"""MakeHuman head shape plus the project's eye/mouth/brow pieces. """MakeHuman head shape plus the project's eye/mouth/brow pieces.
The AI-judged head rework (2026-11-04) picked the decimated MakeHuman head The AI-judged head rework (2026-11-04) picked the MakeHuman head over the
over the displacement shell: it keeps the nose/chin/jaw landmarks at 1,573 displacement shell: it keeps the nose/chin/jaw landmarks. Newer part builds
tris. The MakeHuman mesh has no eyeballs, so the project's sclera/iris/lid/ carry their own embedded eye/iris/pupil/mouth geometry, so those materials
brow pieces are added at the MakeHuman landmarks (eyes ≈ ±0.052, −0.160, are preserved; the older shell-only asset still gets the project's
1.664) for readability. Blender Z-up, face front −Y. sclera/iris/lid/brow pieces added at the MakeHuman landmarks. Blender Z-up,
face front −Y.
""" """
skin, acc, hair = mats["skin"], mats["accessory"], mats["hair"] skin, acc, hair = mats["skin"], mats["accessory"], mats["hair"]
white = material("eye_white", textured_solid=True) white = material("eye_white", textured_solid=True)
@@ -991,9 +992,24 @@ def _makehuman_head(mats, spec):
if head is None: if head is None:
raise SystemExit(f"no head mesh in {src}") raise SystemExit(f"no head mesh in {src}")
head.name = "HeadShell" head.name = "HeadShell"
# The decimated MakeHuman "hair" scalp slot reads as shaggy shards; collapse # Newer MakeHuman part builds carry their own eye/mouth/brow materials and
# the head to one skin slot so the join does not collide with the body's # geometry. Use those instead of adding the project's primitive face pieces
# cloth/pants slots (the project `_hair` cap provides hair later). # a second time; only the old shell-only asset falls through to that path.
embedded = {m.name.split(".")[0] for m in head.data.materials if m}
if "eye_white" in embedded:
# Preserve the embedded iris/pupil/mouth materials; only map the
# project contract slots onto the imported head.
remap = {"skin": skin, "eye_white": white, "hair": hair}
for index, mat in enumerate(list(head.data.materials)):
if mat:
target = remap.get(mat.name.split(".")[0])
if target is not None:
head.data.materials[index] = target
return [head]
# The old decimated MakeHuman "hair" scalp slot reads as shaggy shards;
# collapse the head to one skin slot so the join does not collide with the
# body's cloth/pants slots (the project `_hair` cap provides hair later).
head.data.materials.clear() head.data.materials.clear()
head.data.materials.append(skin) head.data.materials.append(skin)
# Clean the ragged neck cut left by the Head-group extraction: bisect below # Clean the ragged neck cut left by the Head-group extraction: bisect below