Programming grab and throw mechanics in VR
Grab object with hand in VR and throw it at wall – one of most basic and simultaneously one of most technically non-obvious mechanics. When works well, player notices nothing. When bad – object teleports to hand with delay, trembles when held, flies wrong direction or falls through floor.
Why standard Rigidbody + Attach doesn't work as expected
First instinct – on grab move object to controller position and make it child. Works 5 seconds. Then discovers:
Rigidbody with isKinematic = false under controller-parent behaves unpredictably: physics engine doesn't know object moves kinematically, continues computing collisions with old velocity. Object passes through surfaces on fast hand movement.
With isKinematic = true object stops participating in physics entirely: ignores collisions, doesn't push other objects. Can wave sword through everything.
Correct solution in XR Interaction Toolkit – XRGrabInteractable with Movement Type = VelocityTracking. In this mode object doesn't teleport to hand – velocity applied, moving Rigidbody toward target position. Physics stays active. Object collides with obstacles on hand movement. Parameters Track Position Strength and Track Rotation Strength define "stiffness" of tracking – high values (20–30) give tight grip, low (5–10) – soft with lag, like holding heavy ball.
Throwing: where velocity comes from
After release must transfer object velocity matching hand movement. Seems like just rigidBody.velocity = controllerVelocity. Problems:
Controller velocity in XR Node – momentary value at release moment. If player abruptly stops hand before throw (many do), velocity = 0 and object drops straight down. Real physical throw uses peak velocity in throw phase, not final.
Velocity smoothing: XRGrabInteractable collects controller position history over last N frames (default – Velocity Smoothing buffer 5–10 frames). On release, average velocity computed from buffer. This imitates physical inertia. XR Interaction Toolkit 2.3+ has Throw Velocity Scale parameter additionally scaling final velocity – value 1.5–2.0 gives more "weighty" throw feel.
Angular velocity for rotation. Without transferring angular velocity on throw – object flies without rotation, unnatural. rigidBody.angularVelocity = controllerAngularVelocity * throwAngularVelocityScale.
Specifics for Quest and mobile VR
On Quest controller tracking works with 20–30 ms latency (Prediction partially compensates). Velocity from InputDevice.TryGetFeatureValue(CommonUsages.deviceVelocity) already predicted by Meta Runtime – use exactly that, not hand-calculated from position deltas.
Haptic feedback on grab – mandatory for quality of life. XRBaseController.SendHapticImpulse(0.7f, 0.05f) on grab start, SendHapticImpulse(0.3f, 0.02f) on release. Without vibration VR-grab feels plastic.
Separate topic – two-handed grab: weapon can hold with both hands. XR Interaction Toolkit 2.x provides XRGrabInteractable with multiple Attach Points and dominant/secondary hand logic. For weapon needs custom logic: main hand determines position, second – adds rotation along barrel axis.
Timeline: basic grab/throw mechanic via XR Interaction Toolkit – 2–4 business days; custom two-handed system with haptics and velocity tuning – 1–2 weeks. Cost determined after analyzing project requirements.





