Arms playtest-1 fixes: open-loop torso lean (chest hunting), hand-driven elbow pole + height cap, held-prop arm collision exceptions

- Lean computed from PhysicsTorso.NominalTarget/TargetBasis, not the body's own shoulders:
  the closed loop made the chest hunt (spike: |v| 1.1 -> 0.019 m/s, lean range 2.7 cm -> 0.9 mm)
- Elbow on its IK circle, 75% hand-axis (forearm continues behind the wrist), bounded-rate
  rotation smoothing (no flips), capped at max(shoulder, wrist) + 5 cm
- PhysicsArms.SetHeld: held prop ignores that side's arm segments (PropGrabber calls it)
- ArmSpike: stretch settle, hug elbows out (0.17 m vs 0.02 m old pole), held-anvil stability;
  all six spikes PASS x3

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
FoxyzandClaude Opus 5.5 committed 2026-10-02 00:25:50 +03:00
1 parent 7589b13aba
commit 464cda2f71
6 files changed
+288 -65

No files matched your search

+25 -9
View File
@@ -145,16 +145,25 @@ TERMINOLOGY (owner-corrected — use precisely):
NO joints (Box3D has no usable 3-DOF shoulder/wrist joint — PinJoint's identity spring, no
Generic6DOF — and AGENTS.md forbids joints between tracked bodies): each segment PD-chases
its analytic 2-bone IK pose, solved EVERY PHYSICS TICK from the PHYSICAL chest shoulders to
the PHYSICAL hand bodies (IK moved here from BodyRig: soft IK 0.98, torso-frame pole with
the shoulder→hand axis projected out, hand-forward push, exp-smoothed). **Hierarchical
the PHYSICAL hand bodies (IK moved here from BodyRig: soft IK 0.98; elbow picked on its circle, 75% HAND-DRIVEN —
the forearm continues behind the wrist along the aim pose's forward axis, which gives
outward elbows for wraps/hugs — 25% torso-frame down/back/out; smoothed by bounded-rate
ROTATION around the arm axis (can't pass through zero and flip); capped at
max(shoulder, wrist) + 5 cm height). **Hierarchical
budgets** (Nimso muscle model) from `BodyMassStat` 60 kg: hand 90 N ≺ forearm 180 N ≺ upper
arm 360 N ≺ chest 2400 N. Orientation = slewed angular-velocity servo via
`BodyMath.RotationError`; segment roll follows the body's current X axis (no flips).
Safety: 1 m snap (teleports), `ResetIfNonFinite`. Also owns calibration (arm lengths +
shoulder width from first head height > 0.5 m; segments spawn then) and the REACH BUDGET
(torso lean toward overreach → `PhysicsTorso.ReachOffset`, hysteresis unchanged). Exposes
shoulder width from first head height > 0.5 m; segments spawn then) and the torso LEAN
toward overreaching hands → `PhysicsTorso.ReachOffset`, computed OPEN-LOOP from
`PhysicsTorso.NominalTarget/TargetBasis` (the head-derived pose without the lean). The old
closed loop (lean from the body's own shoulders) made the chest hunt back and forth —
owner-reported, spike-measured 1.1 m/s → 0.019 m/s after the fix. Props held by a hand get
a collision exception with that side's arm segments (`SetHeld`, called by PropGrabber) —
a 180 N forearm shoving a prop welded to a 90 N hand was a fight. Exposes
`Shoulder/Elbow/Wrist/ElbowTarget/WristTarget(side)`; `Elbow` = where the two physical
segments meet. Spike: `scenes/arm_spike.tscn` (track gap, fast swing, arm pushes a prop
segments meet. Spike: `scenes/arm_spike.tscn` (stretch-beyond-reach chest settle, hug elbows out
0.17 m (old pole: 0.02), held 50 kg anvil stable + forearm out of it, track gap, fast swing, arm pushes a prop
with the hand clear, forearm blocked by a bar without tunneling + quiet while pinned,
teleport snap, NaN-injection reset, chest undisturbed by own arms).
- **BodyRig.cs** — placeholder rig VISUALS only: head cube (HMD-driven) + arm boxes drawn
@@ -262,7 +271,14 @@ Floor StaticBody mask 1|3|4|5 (collision_mask 29).
static table + two-hand-welded 50 kg anvil) was tested and is stable. Full record:
`research/body-stage1-failure-brief.md` (RESOLUTION section). **RULE: never use
`Quaternion.GetAngle()/GetAxis()` for servo errors — use `BodyMath.RotationError`.**
- **Body Stage 2 (physical arms) — unvalidated in-headset.** Things to watch in the first
- **Body Stage 2 arms — owner playtest 1 (2026-10-02)**: "works fine for the most part";
reported forearm clipping through a held anvil, chest jitter when stretching one arm,
elbows mostly pointing down / unnatural. Fixed: open-loop lean (jitter), hand-driven
elbow + height cap, held-prop exceptions. The exact screenshot clip (forearm through the
held anvil) was NOT reproduced headless across 3 anvil heights — the drawn forearm is a
straight line from the PHYSICAL elbow to the hand wrist, so any elbow below a held object's
near edge can still draw through it; re-check in-headset.
- **Body Stage 2 (physical arms) — remaining watch-list.** Things to watch in the first
playtest: elbow drawn displaced when a segment is blocked (that's the honest physics view),
arms sweeping props when seated at the table, any stutter at fast swings (spike: ≤ 6 cm
joint lag at 2 Hz × 0.4 m). Known gaps by design (Stage 2b, feel-driven): a blocked forearm
@@ -337,14 +353,14 @@ Floor StaticBody mask 1|3|4|5 (collision_mask 29).
| `PalmGrabOffset` | PropGrabber.cs | ±0.045 m along hand +X (left +, right −) | grab point on the palm (taste choice) |
| Grip/trigger thresholds | several files | 0.6 | polled Float edges |
| `SoftIKFactor` | PhysicsArms.cs | 0.98 | shoulder→hand distance clamp before IK solve (lower toward 0.95 if shake persists) |
| `PoleHandWeight` / `PoleSmoothRate` | PhysicsArms.cs | 0.25 / 10 | elbow pole: hand-forward push / exp smoothing |
| `PoleHandWeight` / `PoleSmoothRate` | PhysicsArms.cs | 0.75 / 12 | elbow pole: hand-axis share (forearm continues behind the wrist) vs torso-frame down/back/out; bounded-rate rotation smoothing |
| `ElbowRiseAllowance` | PhysicsArms.cs | 0.05 m | elbow capped at max(shoulder, wrist) height + this (no chicken wings) |
| `TorsoYawHandsWeight` / `TorsoYawForwardness` / `TorsoYawSmoothRate` | PhysicsTorso.cs | 0.6 / 0.3 m / 12 | torso yaw spring: hands blend / forwardness normalizer / exp smoothing (≈200 ms) |
| `TorsoMass` / `MaxForce` / `MaxSpeed` | PhysicsTorso.cs | 30 kg / 2400 N / 6 m/s | chest chase budget (force-clamped PD) |
| `OrientKp` / `OrientMaxSpin` / `OrientMaxAlpha` | PhysicsTorso.cs | 20 / 10 rad/s / 150 rad/s² | chest orientation servo (yaw hold + self-right) |
| `SnapDistance` | PhysicsTorso.cs | 2 m | chest teleport snap safety |
| `armTotal` | PhysicsArms.cs | clamp(0.46×headHeight, 0.5, 0.72) | total arm length, 50/50 split |
| `ReachPushSpeed` / `ReachDecaySpeed` | PhysicsArms.cs | 0.8 / 0.4 m/s | torso lean toward / back from overreach |
| `ReachDecayFactor` | PhysicsArms.cs | 0.92 | hysteresis band (decay only below 92% of reach) |
| `LeanReachFactor` / `LeanSmoothRate` | PhysicsArms.cs | 0.95 / 6 per s | torso lean starts past 95% reach (open-loop from the nominal chest pose), exp-smoothed ≈170 ms |
| `ReachBudgetMax` | PhysicsArms.cs | 0.25 m | horizontal torso offset clamp |
| `ReachVerticalMin/Max` | PhysicsArms.cs | −0.05 / +0.12 m | vertical torso offset clamp (stops upward oscillation) |
| `HeadBackOffset` | BodyRig.cs / PhysicsTorso.cs | 0.06 m | keeps the head cube out of the view |