Files
VR-Mess/research/vr-body-physics-hugs.md
T

158 lines
12 KiB
Markdown

# Research: physics player bodies + hugging/contact in VR
Fourth research pass for VR Messs (Godot 4.7, C#, physics hands = force-clamped rigid palms
chasing controllers at 90 N; placeholder box rig = procedural torso + 2-bone analytic arms,
no Skeleton3D yet; Box3D physics server, joints: pin/hinge/slider/cone-twist→weld-patched).
Goal: player arms+chest react physically — hugging characters, body reacting when grabbed.
Label: [S] = sourced, [I] = inference. See also `vr-arm-ik.md`, `vr-arm-ik-deep.md`,
`vr-grabbing.md`, `vr-two-handed-grab.md`.
## 1. Prior art — player body physics in VR
- [S] **Boneworks/Bonelab** (GDC 2020 "Heuristic Based Approaches to Physics Systems"; coverage:
https://www.gamedeveloper.com/design/how-classical-game-mechanics-and-physics-converge-in-vr-hit-i-boneworks-i/,
Marrow wiki: https://boneworks.fandom.com/wiki/1Marrow_Interaction_Engine): the ENTIRE virtual
body is one physics object, 82 kg, "no infinite forces" — every interaction draws on the body's
force budget; jumping = physically thrusting feet down; exploits die because classical mechanics
is the ruleset. Arms = 2-bone chains driven by constraints toward controller targets with a
heuristic force/velocity limit; over budget → the BODY moves, not the hand. Internal solver
details beyond that are not public. Motion sickness is the accepted cost: players report it as
one of the most nauseating VR games because the physics body can shove the camera off the real
head pose (https://www.resetera.com/threads/highly-anticipated-vr-title-boneworks-is-a-collection-of-vr-sins.158449/page-5).
- [S] **HL:Alyx** shipped HANDS ONLY, deliberately — IK arms mislead because there is no
proprioception for elbow/shoulder (dev commentary:
https://combineoverwiki.net/wiki/Developer_commentary/Half-Life:_Alyx). The strongest evidence
that "collision-enabled limbs" were considered not worth it.
- [S] **Stormland** (Insomniac): fully ANIMATED rendered arms + hip/shoulder holsters that ground
body awareness; body position handled by "invisible logic" for player intent, not a simulated
chain (https://roadtovr.com/stormland-behind-the-scenes-insomniac-games/2/). Kinematic body,
fake arms — feels great, can't hug anyone.
- [S] **Vertigo 2**: solo dev moved to a full physics-driven first-person body + hand physics and
committed to "full physics going forward" (devblog:
https://www.reddit.com/r/ValveIndex/comments/d48pex/vertigo_2_devblog_new_first_person_body_hand);
no postmortem numbers published. Proof one person can ship it in a standard engine.
- [S] **Open-source / community implementations**: Valem's Boneworks-style full-body-physics Unity
tutorial series (https://www.youtube.com/watch?v=D9qQb3EvU8c — rigidbody torso + jointed limbs
chasing trackers); RealMotionVR physics player controller
(https://github.com/pierricklyons/real-motion-vr); community full-body-physics WIPs with the
recurring pattern "rigidbody hands diverge from ghost hands → haptic + visual snap-back"
(https://www.reddit.com/r/Unity3D/comments/9sjsm9/vr_fullbody_physics_because_im_tired_of_reaching/,
https://www.reddit.com/r/ValveIndex/comments/ircdm3/wip_full_body_physics_high_fidelity_hands_in).
[I] No repo named "Hurdy" surfaced in any search — likely misremembered.
- [I] Pattern across all of them: simulate at most ONE powered body (the chest/torso root) driven
toward the HMD, and let limbs be either kinematic (Stormland/Alyx) or weakly-driven physics
chains (Boneworks). Nobody ships a fully self-colliding humanoid player rig — self-collision +
comfort + tuning cost is why.
## 2. Active ragdoll / puppet techniques (how pose-tracking-on-physics is done)
- [S] **Canonical recipe** (Gang Beasts-style; https://www.reddit.com/r/Unity3D/comments/3v6kt8/does_anyone_know_how_gang_beasts_physics_are):
semi-procedural blend of keyframed pose-matching + active ragdoll. Implementation lineage:
- Joint drive to animated "master" pose: duplicate physical body, each ConfigurableJoint's
angular drive target-rotation = the animated counterpart's rotation
(https://github.com/sergioabreu-g/active-ragdolls).
- PD control per joint: proportional-derivative torques toward target pose — the standard
formulation (EggyStudio Unity.Humanoid.ActiveRagdoll, "follows an animation using a simple
PD controller" with configurable joints, weakening drives on collision:
https://github.com/CanTalat-Yakan/Unity.Humanoid.ActiveRagdoll).
- Research tier: DReCon (Bergamin et al. 2019, ACM TOG) = motion matching picks the target
pose, RL-trained policy applies PD torques + root drive for balance
(https://www.researchgate.net/publication/337117918_DReCon_data-driven_responsive_control_of_physics-based_characters);
SIMBICON-style feedback and stepping controllers for balance
(https://arxiv.org/html/2210.14730v1; survey: Geijtenbeek et al. 2012,
https://onlinelibrary.wiley.com/doi/abs/10.1111/j.1467-8659.2012.03189.x).
- Balance practicals: lock hips X/Z rotation so the ragdoll can't fall while still being pushed
(https://sergioabreu-g.medium.com/how-to-make-active-ragdolls-in-unity-35347dcb952d), or apply
an external upright torque/com-height controller — joint motors alone don't balance
(https://medium.com/@jacasch/balancing-of-active-ragdolls-in-games-367f146b25fb).
- Practical tips for making them look alive, not spastic:
https://www.gamedeveloper.com/design/8-tips-for-animating-active-ragdolls.
- [S] **Human Fall Flat** never published a technique talk (closest is design retrospectives);
the joint-motor active-ragdoll recipe above is the community-reconstructed equivalent
(https://www.reddit.com/r/godot/comments/1fnwu2v/how_to_make_an_active_ragdoll_using_joint_motors).
- [I] **Failure modes** (consistent across sources): too-high drive gains inject energy →
jitter/explosions at solver limits; too-low → mush that can't hold a pose; the balance layer is
the whole difficulty — pose tracking is easy, staying upright while pushed is not. Gain tuning
is per-body and iterative (tens of iterations), and (per wirewhiz Alyx-hands notes in
`vr-grabbing.md`) "overly aggressive joint values destabilize the sim" is a physics-server-level
truth, not engine-specific.
## 3. Hugging / close contact with characters in VR
- [S] **In-game examples are almost nonexistent.** The closest known artifact is a Unity dev
clip "Added arm physics so now you can hug stuff in VR!" — physics-driven arms colliding with
bodies produce a passable hug for free (https://www.reddit.com/r/Unity3D/comments/jnfau2/added_arm_physics_so_now_you_can_hug_stuff_in_vr);
"The Hug Game" makes the other player's arms the hug implement
(https://automaton-media.com/en/news/20220225-10037). No shipped AAA VR game has a simulated
embrace — the user's "not even Bonelab had it" observation is correct.
- [S] **VRChat avatar "hugging"** is theater, not physics: PhysBones are spring chains for
secondary motion that can collide but carry no character-to-character force exchange
(https://creators.vrchat.com/common-components/physbones); Contacts are overlap event triggers —
sender touches receiver → animator parameter — auto-placed on hand/finger colliders
(https://creators.vrchat.com/common-components/contacts). So VRChat hugs = arms clip through +
contact event plays an animation. It still sells, which is evidence contact EVENTS + reaction
matter more than force fidelity.
- [S] **HCI/haptics research on hugs** (what makes a hug read as a hug):
Hugvie — a hug-shaped pillow that improves conversation affect, i.e. the SHAPE of contact does
the work (https://eng.irl.sys.es.osaka-u.ac.jp/projects/hugvie; study:
https://www.semanticscholar.org/paper/3a11fff7f3945f1a103ef233aba2d46de1122f35);
HuggieBot — established design tenets of natural robotic hugging, haptic REACTIVITY (responding
during the hug) significantly improves perception (https://arxiv.org/html/2101.07679v1,
https://is.mpg.de/hi/projects/huggiebot-evolution-of-an-interactive-hugging-robot-with-visual-and-haptic-perception);
intra-hug gestures the huggee should respond to: holding, rubbing, patting, squeezing
(https://dl.acm.org/doi/fullHtml/10.1145/3526110);
"Anatomy of a Hug in Virtual Reality" (Deusdado & Antunes, Procedia CS 239, 2024) — hug =
wrap + pressure + duration, haptic presence over fidelity
(https://www.sciencedirect.com/science/article/pii/S187705092401528X).
- [I] Synthesis: a hug reads correctly when (1) your arms VISIBLY wrap (no clipping, no
IK explosion), (2) contact is mutual — you can push and feel resistance, (3) the other party
RESPONDS (pressure → squeeze-back, pat → shift). Force simulation provides 1+2 cheaply; 3 is
gameplay code reading contact events.
## 4. What sells contact — full sim vs pseudo-physics
- [S] Boneworks' GDC claim in essence: physics contact sells because forces are CONSISTENT
(one 82 kg budget, no infinite forces) — not because bones are individually simulated.
- [S] Alyx cut arm physics and shipped the best-feeling hands of its generation; Stormland faked
arms entirely and scored on body presence. Both prove partial approaches can carry immersion.
- [S] But neither can HUG: pseudo-physics limbs clip through characters by design, and clip = no
hug, no lean, no tug. Boneworks CAN be leaned on things and shove bodies with its chest.
- [I] Decision rule: pseudo-physics (kinematic torso collider + IK arms) is enough for
self-presence, NOT enough for contact mechanics. The minimum real-physics set for hugging is
exactly: one physics torso/chest collider + two physical arm segments (we already have palms)
with weak pose drives — i.e. an active-ragdoll-torso, not a full skeleton sim.
## 5. Recommended approach for VR Messs
Constraints: Box3D (pin/hinge/slider/weld-patched-cone-twist), placeholder box rig, no
Skeleton3D, physics hands exist. [I] throughout this section unless noted.
1. **Torso = one RigidBody3D (capsule/box), PD-driven toward an HMD-derived target** — position
from HMD, yaw from the torso-yaw spring already specced in `vr-arm-ik-deep.md`. Force-CLAMPED
chase (same 90 N-class budget pattern as the palms). This body grounds all contact: hug
pressure, tug response, door pushes. DO NOT weld the HMD to it — camera stays kinematic
(Boneworks' sickness lesson, §1); torso chases the camera, never the reverse.
2. **Arms phase 1 = visual-only 2-bone analytic IK (existing) + existing palm bodies.** Chest
contact comes from the torso body; arms don't need physics to hug at chest height. Palms
colliding with the NPC's body already provide "arms resist contact" below the face.
3. **Arms phase 2 (only if phase 1 reads as clipping) = active-ragdoll upper-arm/forearm
segments**: rigidbodies per segment, hinge joints, hinge MOTOR targets = the analytic IK
solution's angles, low gain + velocity cap (§2 recipe, adapted to Box3D's hinge motors).
Joint motors beat per-frame force application — let the solver own it (same lesson as
`vr-grabbing.md`). Skip self-collision entirely (torso↔arm excluded pairs); nobody notices.
4. **Hug detection = contact events, not force analysis**: both palms (or forearm segments) in
contact with NPC torso + player chest collider touching NPC torso + sustained ≥0.5 s →
"embracing" state; read total contact impulse for a pressure value. NPC response = squeeze
force ramp on the player torso body + reaction gestures (HuggieBot reactivity finding, §3).
Optional: fade the visual arms into a scripted wrap pose during the state — VRChat proves
players forgive clipped/faked hugs if the reaction is right.
5. **Grabbed/tugged**: free — any joint from an NPC/prop to the torso body makes the whole body
react, because the torso is now the anchored mass the palms were implicitly missing. Cap the
coupling force below the torso chase budget so tugs can't yank the camera frame (sickness).
6. **Box3D-specific risks**: [I] cone-twist is weld-patched → use hinge+motor for limb drives and
pin for torso coupling; verify hinge motor max-impulse behavior at 90 Hz before building on
it (the `godot-box3d-weld.md` patch is the precedent for upstreaming what's missing).
7. **Explicitly rejected**: full per-bone simulated player skeleton (§1 — nobody ships it;
comfort + tuning cost), VRChat-style event-only hugs (no mutual force = no resistance = hollow),
Go-Go stretch arms (rejected before in `vr-arm-ik.md`).