Raise the character mesh budget to 8000
Full build / Import + headless tests (push) Successful in 33s
Full build / Full desktop build + optional release (push) Skipped

This commit is contained in:
zwitschi committed 2026-11-02 19:25:41 +01:00
1 parent cd5e0e0ff7
commit 7dc3d3c873
8 files changed
+50 -41

No files matched your search

+3
View File
@@ -8,6 +8,9 @@ Semantic Versioning.
### Changed
- Character meshes now have an 8,000-triangle / 8,000-vertex library budget
(up from 6,000 / 5,000) to support the remaining face, grip and clothing
detail; the `npc_base` fallback keeps its original 6,000 / 4,000 contract.
- Character necks are fuller and shoulders slope from the neck instead of
reading as a thin post on a hanger.
- Character eyes sit in the socket behind a thin upper lid, and the chin and
+16 -15
View File
@@ -6,14 +6,12 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
- The visual-alignment path/loader/panel/HUD work and the realism lighting pass are complete and
recorded in `DONE.md`; remaining visual items are the realism follow-ups in `TODO.md`.
- **Character vertex cap (2026-11-02):** the current **5,000 glTF vertices per character** limit is
now the binding realism constraint, not a design rule. `npc_firefighter` is at **4,948** after
the hand pass, leaving no room for better eyelids, nose/lip/ear shaping, hand grips or clothing
seams. The cap needs to be raised for the next realism pass; proposed **6,000 vertices** (and
revisit the 6,000-triangle cap in the same change). Update `CHAR_MAX_VERTS`/`CHAR_MAX_TRIS`, the
contract tests, `blender_assets.py audit`, `docs/npc-visual-review.md`, and re-run the 24-NPC and
Web/Compatibility budgets before accepting the new limit. Do not treat 5,000 as a hard product
constraint.
- **Character mesh cap (2026-11-02):** the eight library variants now use **8,000 triangles /
8,000 glTF vertices** per character (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` in
`tools/blender_assets.py`), up from 6,000/5,000. The frozen `npc_base` fallback keeps its
6,000/4,000 contract. This headroom is specifically for the remaining face, hand-grip and
clothing realism work; re-run the 24-NPC and Web/Compatibility budgets as geometry lands. Do not
add detail without measuring, and do not silently lower the cap back to 5,000.
- `PLAN.md` is a compact product/design document, not an implementation log. Historical control
and v0.3.0 specs were folded into its Presentation and Controls section; put new step-by-step
work in `TODO.md`, not the plan.
@@ -101,9 +99,9 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
- **NPC hand pass (0.9.4, 2026-11-02):** palm radius 0.046 at z .742, scale (.80,.62,.88);
fingers are `tube` paths from z .758 to .681–.694 with tip spheres, thumb is a bent tube. The
optional hand capture is `capture_npc_baseline.gd -- --view=hand` (8 frames, baseline stays 48).
`npc_firefighter` is now at 4,948 verts (52 below the current 5,000 cap); the cap is provisional
and needs raising for further realism (see the character-vertex-cap decision above). Grip
offsets remain open.
`npc_firefighter` is at 4,948 verts; the library cap is now 8,000 (see the character-mesh-cap
decision above), so the remaining face/grip/clothing detail can use real headroom. Grip offsets
remain open.
- **UI flow smoke (2026-11-02):** `smoke_ui_flows.gd` boots the real scene and
exercises inspection allow/deny, normal vs emergency radio, Help filtering,
wand allow/deny and review return-to-menu. Keep this smoke in the 0.9.6
@@ -362,7 +360,8 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
ridge, cheekbones, nose bridge/tip, ears with lobes and split upper/lower lips; the new
`eye_white` material is a *fixed-colour* slot, so `_apply_outfit_materials()` leaves it white.
`_hands_and_shoes()` has four fingers plus a thumb and `_clothing()` adds `Cuff` tori.
Budget work: `CHAR_MAX_VERTS` 5000 (see the library note), body decimation 0.26, upper lids are
Budget work at the time: `CHAR_MAX_VERTS` 5000 (the library cap is now 8000; see the
character-mesh-cap decision), body decimation 0.26, upper lids are
boxes rather than spheres, and knuckle spheres/nostrils were cut to stay inside it.
**Orientation debugging:** to check a GLB's front axis, compare the mean Z of the `eye_white`
surface (face) and of the `rubber` sole verts (toes) — all 8 avatars are +Z, so any
@@ -373,11 +372,13 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
truth), sources in `assets/models/blender_src/` (`.gdignore`d), and review sheets
`docs/blender_previews/sheet_*.jpg` (per-asset PNG renders are gitignored). 8 characters, 18
gear, 20 props; notes in `docs/blender-assets.md`. Characters are drop-in for `npc_base`
(same mesh node name, bones at the same rest positions, five tint slots) and stay under the
6000/4000 budget only because of body decimation (0.26) + `smart_project` at 80°: glTF vertex
(same mesh node name, bones at the same rest positions, five tint slots); the `npc_base`
fallback stayed under its frozen 6000/4000 budget because of body decimation (0.26) +
`smart_project` at 80°: glTF vertex
count includes UV-seam splits, so extra beveled detail quickly breaks the limit. The 2026-11-01
face/hand pass raised `CHAR_MAX_VERTS` to 5000 (tris 3,974–5,026) after measuring 16 avatars at
~6.9 ms of a 50 ms frame; `npc_pipeline.MAX_VERTICES`/`MAX_TRIANGLES` (base mesh) are unchanged.
~6.9 ms of a 50 ms frame; on 2026-11-02 the library cap became 8000/8000 while
`npc_pipeline.MAX_VERTICES`/`MAX_TRIANGLES` (base mesh) stayed frozen at 4000/6000.
**Gotchas:** `bisect_plane` and thin bevels leave zero-area triangles (Godot warns "non-finite
normal in LOD generation"); `_clean()` + a weld after bisect fix it, and the audit rejects them.
Fixed-colour detail materials carry a 4×4 texture because `_apply_outfit_materials()` sets
+5 -5
View File
@@ -63,7 +63,7 @@ fallback behavior.
produces 48 frames; `sheet_npc_baseline.jpg` is committed.)
- [x] Define acceptance criteria for proportions, face readability, hair, hands, shoes, clothing
silhouette, gear fit and animation at the gameplay camera height (1.7 m). (Eight criteria
in `docs/npc-visual-review.md`; the current 6,000-triangle/5,000-vertex contract is explicit.)
in `docs/npc-visual-review.md`; the current 8,000-triangle/8,000-vertex library contract is explicit; the `npc_base` fallback remains 6,000/4,000.)
- [x] Record the camera/lighting/background used for comparison so model changes can be judged
consistently; keep the existing portrait capture path deterministic. (Neutral studio, fixed
orbit cameras, no HUD/crowd/animation; commands recorded in `docs/npc-visual-review.md`.)
@@ -82,10 +82,10 @@ and equipment fit.
### Body proportions and silhouette
- [ ] Evaluate raising the per-character glTF vertex cap from 5,000 (and revisit the 6,000-triangle
cap) because `npc_firefighter` is at 4,948 verts after the hand pass. If accepted, update
`CHAR_MAX_VERTS`/`CHAR_MAX_TRIS`, the contract tests, `blender_assets.py audit`,
`docs/npc-visual-review.md`, and re-run the 24-NPC and Web/Compatibility budgets.
- [x] Raise the per-character library cap from 6,000/5,000 to **8,000 triangles / 8,000 glTF
vertices** so face, hand-grip and clothing detail is not forced to replace geometry. The
frozen `npc_base` fallback keeps 6,000/4,000; library caps and audit tests were updated, and
the 24-NPC/Web budgets must be re-measured as detail lands.
- [x] Audit all variants against a shared human proportion guide (head height, shoulder width,
torso length, hip width, limb length, foot length) and correct the worst outliers.
+7 -5
View File
@@ -92,10 +92,12 @@ All eight use the `npc_base` contract, so each one can replace
- material slots `skin`, `cloth`, `pants`, `accessory`, `hair` carry the same
neutral `assets/textures/npc/<slot>_{albedo,normal}.png` maps, so
`Materials.npc_slot()` tints them the same way it tints `npc_base`.
- budget ≤ 6000 triangles and ≤ 5000 vertices (glTF vertex count, after seam
splits; `CHAR_MAX_VERTS` in `tools/blender_assets.py`, raised from 4000 for
the 2026-11-01 face/hand pass). The current range is 4,042–5,034 triangles
and 3,894–4,948 vertices. The vertex cap is now the tighter budget.
- budget ≤ **8,000 triangles and ≤ 8,000 glTF vertices** for the eight library
variants (vertex count after seam splits; `CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` in
`tools/blender_assets.py`, raised from 6,000/5,000 on 2026-11-02). The frozen
`npc_base` fallback keeps its original 6,000/4,000 contract. The current range
is 4,042–5,034 triangles and 3,894–4,948 vertices, leaving room for the
remaining face, grip and clothing detail.
Construction: the torso and limbs are one continuous Skin-modifier mesh,
subdivided twice, decimated to 26 % with X symmetry, and cut at the waist, cuffs,
@@ -177,7 +179,7 @@ carry baked AO and the shared neutral material maps described above.
- `python3 tools/blender_assets.py audit`: container, `POSITION`/`NORMAL`/
`TEXCOORD_0`, UVs in [0, 1], no zero-area triangles (Godot warns about them
during LOD generation), budgets (characters 6000/5000, gear 1500, props 4000
during LOD generation), budgets (library characters 8000/8000, base fallback 6000/4000, gear 1500, props 4000
triangles), grounding, and an editable `.blend`. For characters it also
checks skinning, bones, slots, the `npc_base` mesh node and the height.
- `tools/test_blender_assets.py`: catalogue and contract consistency with
+1
View File
@@ -42,6 +42,7 @@ Implemented so far:
- NPC neck/shoulder transition (0.9.4 work): the body graph now uses a fuller neck base, a slightly tapered neck top and a lower shoulder root, giving the head/neck/shoulder line a trapezius slope instead of a thin post. The full character library was rebuilt with a final degenerate-face cleanup; the baseline comparison is `sheet_npc_baseline_compare-body.jpg`.
- NPC face-depth pass (0.9.4 work): sclera are recessed and capped by a thin upper lid, and the separate jaw/cheek spheres are replaced by a chin plate and cheekbones sculpted into the head mesh. The full library was rebuilt; the comparison is `sheet_npc_baseline_compare-face.jpg`.
- NPC torso/hip transition (0.9.4 work): the pelvis and chest are slightly wider than the waist, giving shirts and jackets a readable taper into the hips without changing the build multipliers or the skeleton. The comparison is `sheet_npc_baseline_compare-torso.jpg`.
- NPC mesh budget (0.9.4 work): the eight library variants now have an 8,000-triangle / 8,000-glTF-vertex cap (up from 6,000/5,000); the `npc_base` fallback remains 6,000/4,000. Current characters measure 4,042–5,034 triangles and 3,894–4,948 vertices.
- NPC hand pass (0.9.4 work): wider, shallower palms; four two-segment bent fingers with rounded tips and a separate bent thumb; optional `--view=hand` capture at 0.80 m. The hand comparison is `sheet_npc_hands_compare.jpg`; item grip offsets remain open.
- NPC proportion audit (0.9.4 work): `tools/npc_proportions.py` measures all eight GLBs against a stylized height/head/shoulder/hip/torso/leg/arm/foot guide. All variants pass; the head and broad-build silhouettes are the nearest upper bounds. Results are in [`npc-proportion-audit.md`](npc-proportion-audit.md).
- NPC P1 portrait fixes (0.9.4 work): tourists now hide their photo-pose camera bag outside `photo`/`film` poses, removing the duplicate-backpack silhouette; the backpack gear was rebuilt with flattened, forward chest straps and a fresh AO map. The before/after sheet is [`blender_previews/sheet_npc_baseline_compare-p1.jpg`](blender_previews/sheet_npc_baseline_compare-p1.jpg); the face and remaining clothing/hand work stay open.
+6 -6
View File
@@ -61,8 +61,9 @@ The criteria below are for the stylized target, not photorealism. A change must
pass every applicable item before a library rebuild is accepted.
1. **Asset contract:** `npc_base` mesh node, the required bones, five tint slots,
front +Z, feet within 3 cm of y=0, 1.6–2.1 m height, at most 6,000 triangles
and 5,000 glTF vertices per character. Gear remains at most 1,500 triangles.
front +Z, feet within 3 cm of y=0, 1.6–2.1 m height, at most 8,000 triangles
and 8,000 glTF vertices per library character. The frozen `npc_base` fallback
keeps 6,000 triangles / 4,000 vertices. Gear remains at most 1,500 triangles.
2. **Proportion and silhouette:** head, neck, shoulders, torso, hips, limbs and
feet read as one body; front/three-quarter/profile silhouettes agree with the
rest of the eight-character library; broad/slim/average build variation is
@@ -123,10 +124,9 @@ From `python3 tools/blender_assets.py fit` and the manifest:
| `npc_firefighter` | 4,904 | 4,948 | 0.315 m | 0.255 m (skirt) | helmet width ratio 1.651; SCBA x −0.105, radial −0.076 |
| `npc_guard` | 4,606 | 4,679 | 0.315 m | 0.194 m (hip) | cap width ratio 1.067 |
`npc_coat` is widest at 5,034 triangles (966 below the cap); `npc_firefighter` is
closest on vertices at 4,948 (only 52 below the 5,000 cap). Any further hand or
clothing detail must replace existing geometry rather than adding it. The refit
backpack measures 380 triangles / 406 vertices.
`npc_coat` is widest at 5,034 triangles (2,966 below the 8,000 cap);
`npc_firefighter` is closest on vertices at 4,948 (3,052 below the 8,000 cap).
The refit backpack measures 380 triangles / 406 vertices.
## Baseline findings, ranked
+7 -6
View File
@@ -48,12 +48,13 @@ MANIFEST = OUT_DIR / "manifest.json"
SLOTS = ["skin", "cloth", "pants", "accessory", "hair"]
BONES = ["Head", "HipL", "HipR", "KneeL", "KneeR", "ShoulderL", "ShoulderR",
"ElbowL", "ElbowR", "HandL", "HandR"]
CHAR_MAX_TRIS = 6000
# Raised from 4000 to 5000 for the 2026-11-01 face/hand detail pass. The glTF
# vertex count is after UV-seam splits, so the extra eyes, lids, cheeks, nose and
# fingers cost ~700 verts per variant; `smoke_npc_budget.gd` measured 16 avatars at
# ~6.9 ms (budget 50 ms), and each avatar is still a single skinned mesh.
CHAR_MAX_VERTS = 5000
# The eight library variants may use more geometry than the frozen npc_base
# fallback (6000 tris / 4000 verts). Raised to 8000/8000 on 2026-11-02 so the
# remaining face, hand-grip and clothing work is not forced to replace detail.
# The glTF vertex count is after UV-seam splits; each avatar is still one
# skinned mesh, and `smoke_npc_budget.gd` must confirm the 24-NPC frame time.
CHAR_MAX_TRIS = 8000
CHAR_MAX_VERTS = 8000
GEAR_MAX_TRIS = 1500
PROP_MAX_TRIS = 4000
+5 -4
View File
@@ -9,10 +9,11 @@ class CatalogueTests(unittest.TestCase):
def test_contract_matches_npc_pipeline(self):
self.assertEqual(ba.SLOTS, npc_pipeline.SLOTS)
self.assertEqual(sorted(ba.BONES), sorted(npc_pipeline.BONES))
# The base mesh keeps the frozen 6000/4000 contract; library variants may
# spend up to 5000 verts on face/hand detail (documented in blender-assets.md).
self.assertLessEqual(ba.CHAR_MAX_TRIS, npc_pipeline.MAX_TRIANGLES)
self.assertLessEqual(ba.CHAR_MAX_VERTS, 5000)
# The base mesh keeps the frozen 6000/4000 contract; the eight library
# variants have their own 8000/8000 detail budget (documented in
# blender-assets.md and covered by smoke_npc_budget.gd).
self.assertLessEqual(ba.CHAR_MAX_TRIS, 8000)
self.assertLessEqual(ba.CHAR_MAX_VERTS, 8000)
def test_gear_uses_known_attach_points(self):
for name, attach in ba.GEAR.items():