Refine the head prototype: flatten face plane, taper jaw, nose/chin relief, fix ear-displacement sign
This commit is contained in:
1 parent
4f1eb1f5bf
commit
00bd197173
3 files changed
+55
-26
No files matched your search
@@ -85,10 +85,10 @@ the rest of §C remains the broad review checklist.
|
|||||||
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,
|
||||||
and brow/cheek/jaw planes that survive the 256² AO bake.
|
and brow/cheek/jaw planes that survive the 256² AO bake.
|
||||||
In progress: `tools/npc_parts.py build --part head_proto` displaces the shell (seg 48/rings 26)
|
In progress: `tools/npc_parts.py build --part head_proto` displaces the shell (seg 48/rings 26)
|
||||||
into sockets, a nose bridge/tip/ala, upper/lower lips and ears; the eyeballs stay separate.
|
into sockets, a nose bridge/tip/ala, upper/lower lips, a chin bump and ears; the eyeballs stay
|
||||||
Vision-judged (iteration 2): the nose + ear now protrude in profile, but the cranium still
|
separate. Five vision-judged iterations later (see `docs/3d-model-review.md` §Head prototype):
|
||||||
reads as a "ball with a nose". Next: flatten the face plane, taper the jaw/chin, widen the
|
the nose/mouth/chin/ear now read, but the forehead plane, ear helix definition and the
|
||||||
nose bridge, and shape the back of the skull before the 1.5 m/1.85 m comparison.
|
jawline-to-neck step still need work before the 1.5 m/1.85 m comparison.
|
||||||
- [ ] Compare two or three subdivision/loop variants at 1.85 m front/three-quarter/profile and a
|
- [ ] 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.
|
||||||
|
|||||||
+13
-5
@@ -217,11 +217,19 @@ head sphere is displaced (not floating spheres) into eye sockets with an orbital
|
|||||||
bridge/tip/ala, upper/lower lip volumes, and extruded ears with a concha recess; the eyeballs
|
bridge/tip/ala, upper/lower lip volumes, and extruded ears with a concha recess; the eyeballs
|
||||||
stay separate. Local renders live under `tmp/npc-parts/npc_casual/head_proto_*.png`.
|
stay separate. Local renders live under `tmp/npc-parts/npc_casual/head_proto_*.png`.
|
||||||
|
|
||||||
Vision-judged after two iterations: the nose and ear now protrude in profile (mesh y-min
|
Iteration log (vision-judged, profile view):
|
||||||
−0.186 vs the −0.155 shell front), but the cranium still reads as a "ball with a nose" — the
|
|
||||||
face plane is not flattened, the jaw/chin does not taper, and the nose reads as a narrow spike.
|
1. Initial displacement too subtle — read as a "ball with props".
|
||||||
Next refinement before the 1.5 m/1.85 m comparison: flatten the face plane, taper the jaw/chin,
|
2. Nose + ear visible in profile but the cranium still read as a "ball with a nose".
|
||||||
widen the nose bridge, and shape the back of the skull.
|
3. Added face-plane flatten + jaw/chin taper; taper read, but "~90% sphere".
|
||||||
|
4. Stronger flatten + nose + chin; nose now reads, jawline still dissolves into the skull.
|
||||||
|
5. Fixed an ear-displacement sign bug (the ± side loop cancelled the helix); the ear now
|
||||||
|
protrudes (x ±0.155 vs the ±0.139 shell) but reads as a soft blob.
|
||||||
|
|
||||||
|
Current state (~3/5 human-head read): the nose, mouth notch, chin bump and ear bulge read, but
|
||||||
|
three refinements remain before the 1.5 m/1.85 m comparison — a flat forehead with a brow
|
||||||
|
step, a defined helix/lobe on the ear, and a jawline that steps back to the neck (the neck is
|
||||||
|
part of `_skin_body`, so the standalone head will always lack it).
|
||||||
|
|
||||||
## Scorecard skeleton
|
## Scorecard skeleton
|
||||||
|
|
||||||
|
|||||||
+38
-17
@@ -105,11 +105,22 @@ def _head_proto(mats, spec):
|
|||||||
skin, acc, hair = mats["skin"], mats["accessory"], mats["hair"]
|
skin, acc, hair = mats["skin"], mats["accessory"], mats["hair"]
|
||||||
white = ba.material("eye_white", textured_solid=True)
|
white = ba.material("eye_white", textured_solid=True)
|
||||||
head = ba.sphere("HeadShell", 0.155, (0, 0, 1.635), skin, seg=48, rings=26,
|
head = ba.sphere("HeadShell", 0.155, (0, 0, 1.635), skin, seg=48, rings=26,
|
||||||
scale=(0.92, 1.0, 1.12))
|
scale=(0.90, 0.96, 1.08))
|
||||||
ba._shape_head_mesh(head) # brow ridge + cheekbone + jaw/chin planes
|
ba._shape_head_mesh(head) # brow ridge + cheekbone + jaw/chin planes
|
||||||
bm = ba.bmesh.new()
|
bm = ba.bmesh.new()
|
||||||
bm.from_mesh(head.data)
|
bm.from_mesh(head.data)
|
||||||
|
|
||||||
|
# Pass 1: skull shape — flatten the face plane and taper the jaw/chin so the
|
||||||
|
# head stops reading as an egg.
|
||||||
|
for v in bm.verts:
|
||||||
|
x, y, z = v.co
|
||||||
|
if y < -0.03 and 1.44 < z < 1.76:
|
||||||
|
v.co.y = -0.13 + (y + 0.13) * 0.10 # flatten the forward bulge
|
||||||
|
if z < 1.58:
|
||||||
|
taper = max(0.0, 1.0 - (1.58 - z) / 0.12)
|
||||||
|
v.co.x *= 1.0 - 0.16 * taper # narrow the lower face
|
||||||
|
|
||||||
|
# Pass 2: features on the flattened face.
|
||||||
for v in bm.verts:
|
for v in bm.verts:
|
||||||
x, y, z = v.co
|
x, y, z = v.co
|
||||||
ax = abs(x)
|
ax = abs(x)
|
||||||
@@ -120,16 +131,26 @@ def _head_proto(mats, spec):
|
|||||||
v.co.y += 0.018 * (1.0 - r / 0.036) # recess inward (+y)
|
v.co.y += 0.018 * (1.0 - r / 0.036) # recess inward (+y)
|
||||||
elif r < 0.046:
|
elif r < 0.046:
|
||||||
v.co.y -= 0.010 * (1.0 - (r - 0.036) / 0.010) # rim forward
|
v.co.y -= 0.010 * (1.0 - (r - 0.036) / 0.010) # rim forward
|
||||||
# --- nose: bridge/tip protrusion plus ala wings ---
|
# --- nose: a wide bridge/tip with ala wings, not a spike ---
|
||||||
if y < 0 and ax < 0.048:
|
if y < 0 and ax < 0.075:
|
||||||
band = max(0.0, 1.0 - abs(z - 1.628) / 0.052) # 1.576..1.680
|
band = max(0.0, 1.0 - abs(z - 1.632) / 0.055) # 1.577..1.687
|
||||||
if band > 0:
|
if band > 0:
|
||||||
tip = max(0.0, 1.0 - abs(z - 1.615) / 0.022)
|
tip = max(0.0, 1.0 - abs(z - 1.615) / 0.032)
|
||||||
v.co.y -= (0.035 * tip + 0.012 * (band - tip)) * (1.0 - ax / 0.048)
|
v.co.y -= (0.060 * tip + 0.018 * max(0.0, band - tip)) \
|
||||||
|
* (1.0 - ax / 0.075)
|
||||||
for s in (-1.0, 1.0):
|
for s in (-1.0, 1.0):
|
||||||
ar = math.hypot((x - 0.017 * s) / 0.011, (z - 1.606) / 0.011)
|
ar = math.hypot((x - 0.024 * s) / 0.014, (z - 1.604) / 0.013)
|
||||||
if ar < 1.0:
|
if ar < 1.0:
|
||||||
v.co.y -= 0.018 * (1.0 - ar)
|
v.co.y -= 0.022 * (1.0 - ar)
|
||||||
|
# --- chin: a distinct forward bump below the mouth ---
|
||||||
|
if y < 0 and ax < 0.040:
|
||||||
|
chin = max(0.0, 1.0 - abs(z - 1.548) / 0.022)
|
||||||
|
if chin > 0:
|
||||||
|
v.co.y -= 0.030 * chin
|
||||||
|
# jaw step: recess just below the chin so it reads as a chin-to-neck
|
||||||
|
step = max(0.0, 1.0 - abs(z - 1.516) / 0.014)
|
||||||
|
if step > 0:
|
||||||
|
v.co.y += 0.012 * step
|
||||||
# --- mouth: recessed line + upper/lower lip volumes ---
|
# --- mouth: recessed line + upper/lower lip volumes ---
|
||||||
if y < 0 and ax < 0.030:
|
if y < 0 and ax < 0.030:
|
||||||
if abs(z - 1.583) < 0.012:
|
if abs(z - 1.583) < 0.012:
|
||||||
@@ -138,17 +159,17 @@ def _head_proto(mats, spec):
|
|||||||
v.co.y -= 0.014 # upper lip
|
v.co.y -= 0.014 # upper lip
|
||||||
if abs(z - 1.577) < 0.010:
|
if abs(z - 1.577) < 0.010:
|
||||||
v.co.y -= 0.018 # fuller lower lip
|
v.co.y -= 0.018 # fuller lower lip
|
||||||
# --- ears: extrude outward with a concha recess ---
|
# --- ears: extrude outward with a concha recess, lower (brow-to-nose band) ---
|
||||||
for v in bm.verts:
|
for v in bm.verts:
|
||||||
x, y, z = v.co
|
x, y, z = v.co
|
||||||
for s in (-1.0, 1.0):
|
r = math.hypot((z - 1.60) / 0.055, (y - 0.002) / 0.045)
|
||||||
r = math.hypot((z - 1.63) / 0.055, (y - 0.008) / 0.045)
|
near = abs(x) - 0.138
|
||||||
near = abs(x) - 0.140
|
sign = 1.0 if x >= 0 else -1.0
|
||||||
if -0.02 < near < 0.05 and r < 1.0:
|
if -0.02 < near < 0.055 and r < 1.0:
|
||||||
if r < 0.35:
|
if r < 0.35:
|
||||||
v.co.x -= 0.014 * (1.0 - r / 0.35) * s # concha recess (inward)
|
v.co.x -= 0.016 * (1.0 - r / 0.35) * sign # concha recess (inward)
|
||||||
else:
|
else:
|
||||||
v.co.x += 0.028 * (1.0 - r) * s # helix rim outward
|
v.co.x += 0.034 * (1.0 - r) * sign # helix rim outward
|
||||||
bm.normal_update()
|
bm.normal_update()
|
||||||
bm.to_mesh(head.data)
|
bm.to_mesh(head.data)
|
||||||
bm.free()
|
bm.free()
|
||||||
|
|||||||
Reference in new issue
Block a user