Refine the MakeHuman head (weld lids/brows, add hair cap) and add the user review page
This commit is contained in:
1 parent
0b2f124ffe
commit
2e1e4d7f70
5 files changed
+78
-9
No files matched your search
@@ -0,0 +1,53 @@
|
||||
# Head rework — review page (2026-11-04)
|
||||
|
||||
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
|
||||
portrait distance.
|
||||
|
||||
## What changed
|
||||
|
||||
The original procedural face is a head sphere plus separate nose, mouth, ear and eye primitives.
|
||||
The new head uses the **decimated MakeHuman head** (CC0, 1,573 tris) as the base shape and keeps
|
||||
the project's separate eyeballs, brow and mouth pieces on top. An AI judge was used to drive the
|
||||
decision: it scored the procedural rework at ~3/5 and then picked the MakeHuman head as the
|
||||
clearer silhouette.
|
||||
|
||||
| | Source | Tris (head) | Read |
|
||||
| --- | --- | --- | --- |
|
||||
| **Before** | procedural `_face` (sphere + primitives) | ~1,900 | flat face, slit eyes |
|
||||
| **After** | MakeHuman head + project eyes/brows/mouth | ~2,180 | nose/chin/jaw landmarks |
|
||||
|
||||
## AI-generated target concept
|
||||
|
||||
The rework was guided by two generated concept frames (front + profile, `bytedance-seed/seedream-4.5`).
|
||||
|
||||

|
||||
|
||||
## 1.85 m comparison (top = current, bottom = new)
|
||||
|
||||
Left to right: front, three-quarter, profile.
|
||||
|
||||

|
||||
|
||||
## New head at 1.5 m (portrait)
|
||||
|
||||

|
||||
|
||||
## Contract and checks
|
||||
|
||||
- `blender_assets.py inspect` on the assembled `npc_casual` with the new head: **14 bones,
|
||||
skinned, no issues**.
|
||||
- Source: `assets/models/blender_src/makehuman_head.glb` (CC0, attributed in `CREDITS.md`).
|
||||
- Python 167/167, Godot 277/277, `check_docs` OK.
|
||||
|
||||
## Remaining polish (known, not blockers)
|
||||
|
||||
1. The hair cap still reads as a stepped block instead of hugging the skull.
|
||||
2. The brows weld to the face but can read as a slightly separate bar.
|
||||
3. The neck underside cap is plain; it is hidden by the body neck in the assembled character.
|
||||
|
||||
## Decision needed
|
||||
|
||||
Approve or reject the MakeHuman-head direction. If approved, the next step is rolling it into the
|
||||
other 11 variants (one asset family at a time) with a before/after sheet per batch, and re-running
|
||||
the 24-NPC budget + AO bake.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
+25
-9
@@ -1008,7 +1008,28 @@ def _makehuman_head(mats, spec):
|
||||
bmesh.ops.holes_fill(bm, edges=boundary)
|
||||
bm.to_mesh(head.data)
|
||||
bm.free()
|
||||
parts = [head]
|
||||
|
||||
# Lids and brows weld into the head shell so the face reads as one surface;
|
||||
# the sclera/iris stay separate eyeballs.
|
||||
shell_parts = [head]
|
||||
for s in (-1.0, 1.0):
|
||||
ex, ez = 0.052 * s, 1.664
|
||||
shell_parts.append(sphere("UpperLid", 0.020, (ex, -0.135, ez + 0.014),
|
||||
skin, seg=8, rings=4, scale=(1.20, 0.32, 0.24),
|
||||
rot=(math.radians(-10), 0, 0)))
|
||||
shell_parts.append(sphere("LowerLid", 0.017, (ex, -0.135, ez - 0.012),
|
||||
skin, seg=8, rings=4, scale=(1.10, 0.22, 0.18),
|
||||
rot=(math.radians(6), 0, 0)))
|
||||
shell_parts.append(box("Brow", (0.055, 0.014, 0.012), (0.052 * s, -0.165, 1.705),
|
||||
hair, rot=(0, 0.14 * s, 0.0)))
|
||||
shell = join(shell_parts, "HeadShell")
|
||||
bm = bmesh.new()
|
||||
bm.from_mesh(shell.data)
|
||||
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.008)
|
||||
bm.to_mesh(shell.data)
|
||||
bm.free()
|
||||
|
||||
parts = [shell]
|
||||
for s in (-1.0, 1.0):
|
||||
# The MakeHuman socket is a deep cavity (floor ≈ −0.105); keep the
|
||||
# sclera recessed so it never breaks the face silhouette.
|
||||
@@ -1017,17 +1038,12 @@ def _makehuman_head(mats, spec):
|
||||
rings=6, scale=(1.25, 0.62, 0.85)))
|
||||
parts.append(sphere("Iris", 0.0105, (ex, ey - 0.007, ez), acc, seg=8,
|
||||
rings=5, scale=(1.0, 0.55, 1.0)))
|
||||
parts.append(sphere("UpperLid", 0.020, (ex, -0.135, ez + 0.014),
|
||||
skin, seg=8, rings=4, scale=(1.20, 0.32, 0.24),
|
||||
rot=(math.radians(-10), 0, 0)))
|
||||
parts.append(sphere("LowerLid", 0.017, (ex, -0.135, ez - 0.012),
|
||||
skin, seg=8, rings=4, scale=(1.10, 0.22, 0.18),
|
||||
rot=(math.radians(6), 0, 0)))
|
||||
parts.append(box("Brow", (0.055, 0.014, 0.012), (0.052 * s, -0.165, 1.705),
|
||||
hair, rot=(0, 0.14 * s, 0.0)))
|
||||
# A subtle mouth line on top of the MakeHuman lips for readability.
|
||||
parts.append(sphere("Mouth", 0.028, (0, -0.165, 1.58), acc, seg=8, rings=5,
|
||||
scale=(1.0, 0.28, 0.12)))
|
||||
# A skull-conforming buzz cap sized for the smaller MakeHuman cranium.
|
||||
parts.append(_hair_cap("Hair", hair, 1.70, 1.56, radius=0.115,
|
||||
center=(0, 0.008, 1.66), scale=(0.95, 1.04, 1.05)))
|
||||
return parts
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user