Refit the backpack straps for both torsos (ADR-0018)
This commit is contained in:
1 parent
cd285b3a39
commit
fb3e75aba3
5 files changed
+53
-34
No files matched your search
@@ -775,29 +775,44 @@ blocked rig can no longer block the whole release.
|
|||||||
(pose-rotate → apply modifier → reset pose → edit-mode rotate arms → re-add modifier →
|
(pose-rotate → apply modifier → reset pose → edit-mode rotate arms → re-add modifier →
|
||||||
export `export_apply=False`) now yields a correct arm-down base: Blender deformed x ±0.221
|
export `export_apply=False`) now yields a correct arm-down base: Blender deformed x ±0.221
|
||||||
and the rest bone tail points down. Still local (`tmp/`), not shipped.
|
and the rest bone tail points down. Still local (`tmp/`), not shipped.
|
||||||
- [x] Re-derive the pose composition for a non-180° rest. Godot's `set_bone_pose_rotation` is
|
- [x] Re-derive the pose composition for a non-180° rest. Superseded by the rig-agnostic
|
||||||
rest-relative, so `rest * Quaternion(axis, angle)` only reproduces the old rig by accident
|
`_swing_bone()` below: the rest-relative `set_bone_pose_rotation` form was never exact,
|
||||||
(the old rest is 180°, so `rest² = identity`); the Quaternius ~76° rest breaks it. Fixed in
|
because `get_bone_rest()` is parent-relative and already carries the importer's axis
|
||||||
commit `8b1bf73`: `rest * Quaternion(rest.inverse() * axis, angle)` — backward-compatible
|
conversion. Kept in `MEMORY.md` as a rejected approach.
|
||||||
(the old 180° rest maps the axis to itself). Godot 277/277.
|
- [x] Fix the skinning/rest bake end to end (commit `cd285b3`):
|
||||||
- [ ] Godot skinning import: root causes found and narrowed. (1) The canonical base build
|
(1) the canonical base is **join-only** (`tmp/npc-research/build_base_minimal.py`: no
|
||||||
(`scale/ground transform` + `remove_doubles` weld + modifier removal before join) corrupted
|
`remove_doubles` weld, no scale/ground transform, keep the Armature modifiers) — the weld
|
||||||
the skin weights; a **join-only** base (no transform, no weld, keep modifiers) poses correctly
|
and the transform corrupted the Quaternius weights;
|
||||||
to x −0.228/0.228. Use `tmp/npc-research/build_base_minimal.py`.
|
(2) the arm-down bake (`tmp/npc-research/bake_armdown_v5.py` — pose, read pose matrices,
|
||||||
(2) Fixed: the arm-down bake (`bake_armdown_v5.py` — pose, read pose matrices, apply modifier,
|
apply modifier, **reset pose to identity**, set rest matrices, re-add modifier) bakes the
|
||||||
**reset pose to identity**, set rest matrices, re-add modifier) now bakes correctly
|
rest correctly (DEFORMED x −0.228/0.228, Godot bind pose arm-down);
|
||||||
(DEFORMED x −0.228/0.228, Godot bind_pose down). `NpcAvatar` now also has the side swap,
|
(3) `NpcAvatar._swing_bone()` now writes the **global** bone pose from
|
||||||
the arm swing axis (LEFT) and the hand-proxy position fix (`2a6f29f`). Remaining: the
|
`get_bone_global_rest()`, so one formula drives both the 62-joint Quaternius rig and the
|
||||||
handheld gear (camera) sits at the shoulder/chest instead of the wrist — re-derive the gear
|
13-core fallback (measured: posed bone axis matches the proxy pivot at dot 1.000 on the
|
||||||
attach offsets against the Quaternius skeleton, then the face/silhouette gate.
|
Quaternius, and the procedural rigs are unchanged);
|
||||||
- [ ] Add regression tests: a bone with a ~76° rest reaches a known global orientation; the
|
(4) `RIG_BONES` + `NpcAvatar.bone_name()` hold the only side mapping (the Quaternius labels
|
||||||
Quaternius joint map resolves; the 13-core fallback poses exactly as it does today.
|
`L`/`R` opposite the project), and the hand proxy is `global_wrist − global_elbow`.
|
||||||
|
Verified in Godot: idle/sit/walk captures on npc_casual plus the unchanged procedural rigs.
|
||||||
|
- [x] Add regression tests: `test_shipped_rig_resolves_the_animation_joints` covers the joint map,
|
||||||
|
the baked arm-down rest, the down-pointing arm axis and the proxy side mapping; the Blender
|
||||||
|
audit/`inspect` and `npc_proportions` now understand both rigs. Godot 278/278, Python
|
||||||
|
167/167.
|
||||||
|
- [x] Give the Quaternius base the five tint slots: `build_base_minimal.py` renames the upstream
|
||||||
|
materials to `skin`/`cloth`/`pants`/`hair`/`accessory` and keeps `Eye`/`Eyebrows` as
|
||||||
|
fixed-colour detail. The source UV map is degenerate (every loop at 0,0), so the build now
|
||||||
|
Smart-UV-unwraps and repacks the layout — texel density went from an unmeasurable 0 to
|
||||||
|
73–74 px/m on the 256² maps and the 256² AO bake works again.
|
||||||
- [ ] Verify Idle and Walk on the 62-joint rig: loop seam, foot contact, root motion and frame
|
- [ ] Verify Idle and Walk on the 62-joint rig: loop seam, foot contact, root motion and frame
|
||||||
rate. Record which of the 24 clips are in scope and which stay unused.
|
rate. Record which of the 24 clips are in scope and which stay unused.
|
||||||
- [ ] Decide and record how poses the clips do not cover (seated, raise-hand, head turn) are
|
- [ ] Decide and record how poses the clips do not cover (seated, raise-hand, head turn) are
|
||||||
driven at runtime.
|
driven at runtime.
|
||||||
- [ ] Keep the fallback tested: `npc_base`, the MakeHuman head and `_build_body()` remain
|
- [ ] Keep the fallback tested: `npc_base`, the MakeHuman head and `_build_body()` remain
|
||||||
selectable; no MPFB work is reopened and no Stage-1 proportion warp returns.
|
selectable; no MPFB work is reopened and no Stage-1 proportion warp returns. (The procedural
|
||||||
|
library is still the majority of `CHARACTER_POOLS` and captures clean, but the fallback path
|
||||||
|
itself has no dedicated test yet.)
|
||||||
|
- [ ] Re-fit the remaining gear against the Quaternius torso: the `backpack` strap geometry was
|
||||||
|
authored for the old body width and now hangs in front of the chest. The camera was fixed
|
||||||
|
with a wrist strap (a neck strap floats when the item is hand-attached).
|
||||||
|
|
||||||
### Silhouette and face gate (owner)
|
### Silhouette and face gate (owner)
|
||||||
|
|
||||||
@@ -814,10 +829,13 @@ blocked rig can no longer block the whole release.
|
|||||||
|
|
||||||
### Pilot rollout
|
### Pilot rollout
|
||||||
|
|
||||||
- [ ] Map the five tint slots onto the Quaternius materials; unwrap per slot; bake 256²
|
- [x] Map the five tint slots onto the Quaternius materials and unwrap the degenerate source
|
||||||
AO/albedo/normal/ORM and check texel density.
|
UV map; bake the 256² AO and check texel density (73–74 px/m).
|
||||||
- [ ] Re-fit gear attach points against the Quaternius skeleton and test cap, helmet, backpack,
|
- [ ] Bake the per-slot albedo/normal/ORM maps and a per-slot atlas (the five slots currently
|
||||||
shoulder bag, lanyard, clipboard and firefighter tank.
|
share one whole-body UV set).
|
||||||
|
- [-] Re-fit gear attach points against the Quaternius skeleton and test cap, helmet, backpack,
|
||||||
|
shoulder bag, lanyard, clipboard and firefighter tank. (Camera done: wrist strap instead of
|
||||||
|
the floating neck strap. Backpack straps still cut across the Quaternius chest.)
|
||||||
- [ ] Wire the approved base into one role (or the crowd roles if option b is chosen) with the
|
- [ ] Wire the approved base into one role (or the crowd roles if option b is chosen) with the
|
||||||
procedural model as an instant fallback; no runtime download or optional dependency.
|
procedural model as an instant fallback; no runtime download or optional dependency.
|
||||||
- [ ] Run `blender_assets.py inspect`/`audit`/`fit`, `npc_proportions.py`, the 24-NPC budget smoke
|
- [ ] Run `blender_assets.py inspect`/`audit`/`fit`, `npc_proportions.py`, the 24-NPC budget smoke
|
||||||
|
|||||||
@@ -28,12 +28,12 @@
|
|||||||
"attach": "back",
|
"attach": "back",
|
||||||
"bounds_godot": {
|
"bounds_godot": {
|
||||||
"max": [
|
"max": [
|
||||||
0.161,
|
0.15,
|
||||||
0.296,
|
0.296,
|
||||||
0.212
|
0.172
|
||||||
],
|
],
|
||||||
"min": [
|
"min": [
|
||||||
-0.161,
|
-0.15,
|
||||||
-0.12,
|
-0.12,
|
||||||
-0.319
|
-0.319
|
||||||
]
|
]
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
],
|
],
|
||||||
"path": "assets/models/blender/npc_gear/backpack.glb",
|
"path": "assets/models/blender/npc_gear/backpack.glb",
|
||||||
"triangles": 380,
|
"triangles": 380,
|
||||||
"vertices": 408
|
"vertices": 410
|
||||||
},
|
},
|
||||||
"bench": {
|
"bench": {
|
||||||
"bounds_godot": {
|
"bounds_godot": {
|
||||||
@@ -467,7 +467,7 @@
|
|||||||
"hair"
|
"hair"
|
||||||
],
|
],
|
||||||
"triangles": 6206,
|
"triangles": 6206,
|
||||||
"vertices": 12692
|
"vertices": 12988
|
||||||
},
|
},
|
||||||
"npc_coat": {
|
"npc_coat": {
|
||||||
"bounds_godot": {
|
"bounds_godot": {
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 36 KiB |
@@ -1492,13 +1492,14 @@ def build_gear(name):
|
|||||||
bevel=0.02, segs=2))
|
bevel=0.02, segs=2))
|
||||||
p.append(box("Zip", (0.24, 0.005, 0.01), (0, 0.317, 0.05), M("steel")))
|
p.append(box("Zip", (0.24, 0.005, 0.01), (0, 0.317, 0.05), M("steel")))
|
||||||
for s in (-1.0, 1.0):
|
for s in (-1.0, 1.0):
|
||||||
# Strap path: over the shoulder, then down the chest outside the
|
# Strap path: over the shoulder, then down the chest. The chest points
|
||||||
# torso front (Godot z≈0.21). The old chest/waist points sat at
|
# are pulled in to x 0.12 / Godot z 0.15 so the straps hug the slimmer
|
||||||
# z≈0.13 inside the body, so only thin tube fragments read as two
|
# Quaternius torso (ADR-0018) as well as the wider procedural one;
|
||||||
# rigid black bars from the front.
|
# the earlier x 0.145 / z 0.19 path floated ~5 cm proud of the
|
||||||
p.append(tube("Strap", [(0.09 * s, 0.13, 0.27), (0.11 * s, -0.02, 0.29),
|
# Quaternius chest and read as two detached blue bars.
|
||||||
(0.12 * s, -0.06, 0.25),
|
p.append(tube("Strap", [(0.075 * s, 0.13, 0.27), (0.095 * s, -0.02, 0.29),
|
||||||
(0.14 * s, -0.19, 0.18), (0.145 * s, -0.19, -0.08)],
|
(0.105 * s, -0.06, 0.25),
|
||||||
|
(0.12 * s, -0.15, 0.18), (0.125 * s, -0.15, -0.08)],
|
||||||
0.016, M("denim_bag"), seg=8, width_scale=1.35,
|
0.016, M("denim_bag"), seg=8, width_scale=1.35,
|
||||||
thickness_scale=0.42))
|
thickness_scale=0.42))
|
||||||
elif name == "shoulder_bag":
|
elif name == "shoulder_bag":
|
||||||
|
|||||||
Reference in new issue
Block a user