Body physics Stage 1: PhysicsTorso chase chest (30 kg PD + yaw servo), collision layers reworked (3=body, 4=hands, no self-collision), BodyRig visual-only, BodySpike regression (PASS 3x, all spikes green)
This commit is contained in:
1 parent
d46a742b66
commit
4fdfcfd928
11 files changed
+586
-83
No files matched your search
+49
-35
@@ -65,7 +65,8 @@ TERMINOLOGY (owner-corrected — use precisely):
|
||||
near (`WorldPanel.IsBlocking`). **All deltas and turn pivots in WORLD space** (tracking-space math
|
||||
made turns orbit the map center — do not regress). Drives `XROrigin3D` directly.
|
||||
- **PhysicsHands.cs** — physical palm bodies chasing the controller poses: 0.4 kg boxes (flat slab,
|
||||
thumb-side face), gravity off, CCD, layer 1/mask 1. Chase = desired velocity `(target-pos)/dt`
|
||||
thumb-side face), gravity off, CCD, **layer 4 (player hands)/mask 1|4** — NOT colliding with the
|
||||
chest (layer 3), excluded both ways. Chase = desired velocity `(target-pos)/dt`
|
||||
force-clamped to `HandMaxForce` 90 N; rotation hard-locked by setting angular velocity to the
|
||||
controller's rotation error (clamped to 120 rad/s). Safety: stuck (> 0.2 m for 1 s) → snap +
|
||||
log; > `SnapDistance` 2 m → silent teleport snap — BOTH SUSPENDED for a hand while
|
||||
@@ -119,22 +120,26 @@ TERMINOLOGY (owner-corrected — use precisely):
|
||||
grab/teleport; `IsPanelCollider(node)` identifies interactive colliders for lasers.
|
||||
- **TeleportMarker.cs** — `scenes/teleport_marker.tscn`: disc + beam + Label3D, group
|
||||
"teleport_marker", StaticBody pick box. `SetNear` hides visuals, `SetHighlighted` swaps colors.
|
||||
- **BodyRig.cs** — placeholder cube "getting a body" v1.1 (all primitives boxes per owner). Head
|
||||
0.15³ pushed 6 cm behind the eyes (`HeadBackOffset`); torso 0.22×0.5×0.13, dropped 0.42 and
|
||||
retracted 6 cm; yaw basis from HMD (flattened forward). Proportions calibrated at runtime from
|
||||
head height (once, after height > 0.5 m): armTotal = 0.46×headHeight clamped [0.5, 0.72],
|
||||
50/50 upper/fore split, shoulder half-width 0.16 + 0.02×height. Arms: wrist-anchored IK target
|
||||
(palm base = hand body +Z·`WristOffset` 0.06, not palm center) with SOFT IK — shoulder→hand
|
||||
distance clamped to reach×`SoftIKFactor` (0.98) BEFORE the law-of-cosines solve, so the arm is
|
||||
never perfectly straight (if near-extension shake persists, lower `SoftIKFactor` toward 0.95).
|
||||
Elbow pole = down + back + slight outward, projected OUT of the shoulder→hand axis, minus hand
|
||||
forward × `PoleHandWeight` (0.25), exp-smoothed at `PoleSmoothRate` (10/s). Torso yaw SPRING,
|
||||
decoupled from the head: HMD yaw base blended toward hands-derived yaw by forwardness ×
|
||||
`TorsoYawHandsWeight` (forwardness = horizontal dot / `TorsoYawForwardness` 0.3 m, clamped 0–1),
|
||||
exp smoothing `TorsoYawSmoothRate` (12/s ≈ 200 ms response). Torso reach budget WITH HYSTERESIS:
|
||||
push only past full reach (0.8 m/s), decay
|
||||
only below 92% of reach (0.4 m/s, `MoveToward` zero); offset clamped horizontal ≤ 0.25 m,
|
||||
vertical [−0.05, +0.12]. Hidden until calibrated.
|
||||
- **PhysicsTorso.cs** — the player's PHYSICAL CHEST (body-physics Stage 1, implemented 2026-10-01).
|
||||
One RigidBody3D box (0.22×0.5×0.13, 30 kg, gravity off, CCD, contact monitor), chase-driven
|
||||
toward an HMD-derived target: target = head − 6 cm back + torso-yaw basis·(0, −0.42, +0.06)
|
||||
+ `ReachOffset` (fed by BodyRig's reach budget). Linear drive = the PhysicsHands pattern at
|
||||
body mass (force-clamped PD, `MaxForce` 2400 N ⇒ 80 m/s², `MaxSpeed` 6 m/s). Orientation =
|
||||
slewed angular-velocity servo toward the yaw target (Kp 20 rad/s per rad, spin cap 10 rad/s,
|
||||
alpha cap 150 rad/s²) — self-rights when shoved, holds yaw. `SnapDistance` 2 m snap safety
|
||||
covers teleports. Camera stays KINEMATIC — the torso chases the head, never the reverse
|
||||
(Boneworks sickness lesson). Yaw spring (HMD + hands blend) MOVED here from BodyRig.
|
||||
Collision: layer 3 (player body), mask 1|3 — props/floor touch it, own hands do NOT
|
||||
(hands moved to layer 4; excluded both ways — no self-collision, VRChat/Nimso precedent).
|
||||
Owns its torso mesh (hidden until the body first arrives at target). Spike:
|
||||
`scenes/body_spike.tscn` must print **"BODY: overall PASS"** (pair-rule proofs: one-way
|
||||
floor contact, hand-through-chest exclusion, prop-contact two-way; track/yaw/impact/snap/
|
||||
self-right asserts).
|
||||
- **BodyRig.cs** — placeholder rig VISUALS only now (v1.3): head cube (HMD-driven), 2-bone
|
||||
analytic arms (soft IK 0.98, pole as before), shoulders derived from the PhysicsTorso BODY
|
||||
pose (+ ShoulderRise 0.25, ± body X). The torso mesh and the torso yaw spring moved into
|
||||
PhysicsTorso; BodyRig computes the reach budget (hysteresis unchanged) and feeds it to
|
||||
`PhysicsTorso.ReachOffset`. Hidden until calibrated.
|
||||
- **GrabSpike.cs** + `scenes/grab_spike.tscn` — headless grab regression (v5.3): a hand stand-in
|
||||
(0.4 kg body, `HandMaxForce` 90 N chase) grabs a 1 kg prop via ConeTwist weld (server type
|
||||
verified, configure-before-AddChild); drag 2 m + 360° fast-spin sub-phase — asserts RIGID
|
||||
@@ -148,6 +153,12 @@ TERMINOLOGY (owner-corrected — use precisely):
|
||||
bodies welded via ConeTwistJoint3D (bias 0 rigid, then bias 0.5 soft); asserts relative-pose
|
||||
rigidity under torque/force (rot < 2°, sep < 1 cm), bounded excursion + full recovery for
|
||||
the soft weld. Run this FIRST whenever the addon binaries change.
|
||||
- **BodySpike.cs** + `scenes/body_spike.tscn` — headless regression for the physical torso:
|
||||
pair-rule proofs on Box3D (one-way floor contact; hand-config body passes through the chest
|
||||
with the chest undisturbed; prop-config body transfers contact), then track (walk pattern,
|
||||
error < 6 cm), yaw (90°/1 s turn: peak < 15°, settled < 4°), impact (5 kg at 3 m/s: dip
|
||||
< 0.2 m, recovers < 2 cm, never tunnels, rebounds), teleport snap, self-right (< 3° after
|
||||
a pitch impulse). Must print **"BODY: overall PASS"** 3× deterministic.
|
||||
|
||||
Research (`research/`): seven full sourced reports — `vr-arm-ik.md`, `vr-arm-ik-deep.md`,
|
||||
`vr-grabbing.md`, `vr-two-handed-grab.md` (grab v5.0→5.2 history + the verified Box3D pin
|
||||
@@ -163,7 +174,8 @@ leaving the standard RigidBody3D stack).
|
||||
|
||||
Scene wiring (`scenes/main.tscn`): Main → WorldEnvironment, Sun, Floor, XROrigin3D (XRCamera3D,
|
||||
LeftHand, RightHand, WorldPanel), SpawnPoint, 3 TeleportMarkers, Locomotion, AnchorMoveMode,
|
||||
PropShop, PropGrabber, PhysicsHands, BodyRig, FadeLayer/Fade. Action map: `openxr_action_map.tres`.
|
||||
PropShop, PropGrabber, PhysicsHands, PhysicsTorso, BodyRig, FadeLayer/Fade. Action map: `openxr_action_map.tres`.
|
||||
Floor StaticBody scans layer 3 (collision_mask 13).
|
||||
|
||||
## 4. Architecture decisions that must not regress
|
||||
|
||||
@@ -188,7 +200,10 @@ PropShop, PropGrabber, PhysicsHands, BodyRig, FadeLayer/Fade. Action map: `openx
|
||||
as fallback (git history). Stink-O's box3d-godot (custom components, more joint types) is
|
||||
the plan-B.
|
||||
- **Collision layers**: 1 = world, 2 = UI. Panel/knob bodies are layer 2 mask 0 (props pass through
|
||||
the menu); hands layer 1. Layers/masks live on `CollisionObject3D`, never `CollisionShape3D`.
|
||||
the menu); **1 = world+props, 2 = UI, 3 = player body (chest), 4 = player hands** — chest↔own
|
||||
hands excluded BOTH ways (no self-collision; props mask 1|3|4, floor mask 1|3|4, hands 4/1|4,
|
||||
chest 3/1|3). Layers/masks live on `CollisionObject3D`, never `CollisionShape3D`. The
|
||||
body_spike proves the pair rules on Box3D.
|
||||
- **Ghosts belong to hands, not props** — the whole arm gets a ghost later.
|
||||
- **Standard-RigidBody3D-only** for scene objects and tracked bodies, so the Jolt fallback stays lossless.
|
||||
- **`pose_recentered` is never used for placement** — WiVRN fires it continuously (~90 Hz);
|
||||
@@ -261,7 +276,10 @@ PropShop, PropGrabber, PhysicsHands, BodyRig, FadeLayer/Fade. Action map: `openx
|
||||
| Grip/trigger thresholds | several files | 0.6 | polled Float edges |
|
||||
| `SoftIKFactor` | BodyRig.cs | 0.98 | shoulder→hand distance clamp before IK solve (lower toward 0.95 if shake persists) |
|
||||
| `PoleHandWeight` / `PoleSmoothRate` | BodyRig.cs | 0.25 / 10 | elbow pole: hand-forward push / exp smoothing |
|
||||
| `TorsoYawHandsWeight` / `TorsoYawForwardness` / `TorsoYawSmoothRate` | BodyRig.cs | 0.6 / 0.3 m / 12 | torso yaw spring: hands blend / forwardness normalizer / exp smoothing (≈200 ms) |
|
||||
| `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` | BodyRig.cs | clamp(0.46×headHeight, 0.5, 0.72) | total arm length, 50/50 split |
|
||||
| `ReachPushSpeed` / `ReachDecaySpeed` | BodyRig.cs | 0.8 / 0.4 m/s | torso lean toward / back from overreach |
|
||||
| `ReachDecayFactor` | BodyRig.cs | 0.92 | hysteresis band (decay only below 92% of reach) |
|
||||
@@ -277,21 +295,17 @@ PropShop, PropGrabber, PhysicsHands, BodyRig, FadeLayer/Fade. Action map: `openx
|
||||
|
||||
## 7. Next steps (in order)
|
||||
|
||||
1. **Full physics body track — DECISION PENDING (owner holds implementation)** — the owner
|
||||
wants to pursue a full physics VR body (also as reusable tech for a second project idea);
|
||||
the hug should be mostly physics with detection for future interactivity. Research done:
|
||||
`research/vr-body-physics-hugs.md` (prior art + phased design; §6 = Nimso's "Hybrid
|
||||
Presence", the closest known implementation; §7 = owner-extracted video breakdowns of
|
||||
Project TX: hierarchical per-joint force budgets, script-relaxation hand adaptation,
|
||||
active-ragdoll NPCs with grab anchors) and `research/vr-body-physics-godot.md` (verified
|
||||
stack facts: no Generic6DOF, hinge velocity motors work, PD-follow proven by the hands).
|
||||
Research verdict: the technique is an independent-implementation match of our existing
|
||||
chase-drive architecture; no more video extraction needed now (conditional: Spideriini
|
||||
elbow handling if Stage-2 elbow jitter bites; Test Chamber if a locomotion stage ever
|
||||
starts). Recommendation shape: staged torso → 2-segment arm chains (chase-driven,
|
||||
Boneworks/Nimso tier, NOT per-bone skeleton sim), test hugging props; muscle model =
|
||||
hierarchical budgets (hand ≺ forearm ≺ shoulder ≺ torso) scaled from body mass.
|
||||
Character model: keep boxes for the physics work (owner asked; see research §5-6).
|
||||
1. **Full physics body track — Stage 1 (chest body) IMPLEMENTED, validate in-headset** —
|
||||
`PhysicsTorso.cs` is live: chase chest (30 kg, 2400 N), yaw spring moved in, collision
|
||||
layers reworked (3 = body, 4 = hands, no self-collision). Owner playtests: chest contact
|
||||
with props (lean a crate on it, catch the bowling ball against it), shove response
|
||||
(props push the chest, it recovers — camera never moves), turn following (torso lags
|
||||
head naturally), weight feel. Hug testing on props as agreed. Headless: `body_spike`
|
||||
PASS 3×; all other spikes still PASS 3×. **Stage 2 (arm chains, hierarchical budgets,
|
||||
Nimso/Boneworks tier) awaits Stage-1 feel verdict** — see
|
||||
`research/vr-body-physics-hugs.md` §5/§7 + `research/vr-body-physics-godot.md`.
|
||||
Tuning knobs live in HANDOFF §6 (PhysicsTorso rows); first levers if feel is off:
|
||||
`MaxForce` (gives more/less), `OrientKp` (torso yaw stiffness).
|
||||
2. **Locomotion decision** — owner report 2026-10-01: two-hand anchor turning broken (not
|
||||
2-anchor based), simultaneous two-hand movement acts weird, teleport + lasers broken
|
||||
(experiments, not current issues). Owner's candidate replacement: physics thumbstick
|
||||
|
||||
Reference in new issue
Block a user