158 lines
12 KiB
Markdown
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`).
|