VR in Unity: Advanced Grab Interaction Behaviors
In this guide I will break down a few ways to enhance the capability of your grab interactions to do things such as fire a bullet from a gun or activate a lightsaber. Let’s dig in!
As a reminder, we first set up Grab Interaction in our scene by adding the XR Direct Interactor component to each controller as well as a Sphere Collider with trigger set to true. To our grabbable spheres we added the XR Grab Interactable component as well as a Rigidbody and a sphere collider.
This setup works pretty well, but there is a potential bug that can occur when moving the position of the ball to be under our headset position, causing our player to fly upwards. This is due to an interaction between the ball and the character controller, and to prevent this sort of interaction we can put our grabbable objects into a new layer “Grab” and our VR Rig into its own layer “Body”. The in Edit -> Project Settings -> Physics we can disable the interaction between the Body and Grab layers:
We also have a behavior where our ray interactor is still interacting with each ball.
This can be useful if you do want to be able to pick up items at long range (pulling the trigger will summon the ball to your hand position) but in our case we want to disable this interaction so grabbable items can be picked up with the grip button only. To do this we navigate to the Ray Interactor component and under Raycast Mask disable the interaction with objects tagged as “Grab”.
Now we can see the correct behavior where our ray interactor will not register on the ball objects.
Movement Types for Grabbable Objects
There are three movement types for your grabbable objects which control their interactions with other objects — Kinematic, Instantaneous, and Velocity Tracking.
Kinematic: Compared to the other two types, kinematic has a slight movement delay and when moving can appear jittery while held. Can pass through other objects without a rigidbody while held. When interacting with another rigidbody, this object will set the rigidbody of the other object to kinematic and produce physics based movement.
Instantaneous: Very accurate movement and appears to be fixed in position when moving while held. Can pass through other objects without a rigidbody while held. When colliding with another rigidbody, it will disable the rigidbody of the other object and modify only it’s transform value without taking physics into account.
Velocity Tracking: Some delay in movement tracking while held which can be seen as jittery. Will collide with every object regardless of whether it has a rigidbody. Tracks the velocity of our hand to move the sphere.
Here you can see the difference in interaction on a rigidbody between instantaneous and kinematic movement:
The best implementation will depend on the specific requirements for your game. For our bowling demo, Velocity Tracking was the best method to track our hand motion to give velocity to the bowling ball. There are a number of additional settings you can use to tweak your grab behavior such as the time to snap to your hand, whether you want the object to track the rotation of your hand, if you want the object to be thrown when detached or not and if so how fast you would like it to be thrown.
XR Direct Interactor Settings
On our hands, there are few settings which can enhance the feeling of your grab interactions. For example, you can choose to hide the controller when grabbing an object, useful for when your player is equipping a new weapon for example. You can also trigger sounds or haptic feedback when hovering or selecting an object, which I will implement here.
Advanced Grabbed Item Behavior — Fire Gun Setup
For the next series of interaction demos I will use the following free gun prefab from SketchFab:
Gun: https://sketchfab.com/3d-models/berettalowpoly-c4977b72ed3f47b1964f7acd6bd88ce7
Download and extract the files, then drag the associated folders into the project window. Extract the materials drag the texture file into the Base Map field. If desired, update the selected material for any specific components to suit the style you are looking for.
Add the XR Grab Interactable component as well as a Rigidbody and a Box Collider to the gun, then apply the “Grab” layer.
We can know grab the gun but the position and rotation are not how we want them. To do this we can use the Attach Transform field of the Grab Interactable. Create a new child empty object inside the Gun called Pivot. Before making changes, check the settings above your scene view to be sure your tool handle settings are set to pivot and local.
We then rotate the pivot gameobject into place, understanding that the green axis represents the vertical direction of the controller, and the blue axis represents the forward direction. Thus when rotating you want the green arrow pointing towards the top of the gun while the blue arrow points down the barrel. Center the pivot position at the handle of the gun.
Drag the pivot gameobject into the Attach Transform field of the Grab Interactable and play to test.
Fire Gun Behavior
To make our gun shoot I’ve created a new bullet prefab with a capsule scaled down to 0.01 and set up the following Gun script:
Add the gun script to the gun gameobject. I’ve also created a new barrel position by placing the bullet prefab just inside the barrel of the gun, childing it within the gun, and then removing all components except for the transform. This gives us a placeholder at which to spawn our bullet. Assign the barrel gameobject to the barrel field on the gun script.
On the Interactable component of the gun, open up the Interactable Events settings. Add an On Activate event, drag the gun gameobject into the object field and add our Fire() function. This Activate event is set on the XR Controller settings for “Activate Usage” mapping to “Trigger”.
Our gunfire behavior is now complete! This works great for the left hand, but we encounter a behavior on the right hand where both the bullet activation and the teleporter activation will trigger at the same time. To prevent this we need to disable the teleporter activation when there is an object in hand.
In the Teleportation Controller script we add a bool variable for EnableRightTeleport with get and set properties so that we can access them externally. We then update our teleport activation function to incorporate the bool check.
Now on our Right Hand game object inside the Direct Interactor component, Interactor Events section, we add an event to On Select Entered, drag in our VR Rig, access the teleportation controller script and disable the bool check.
We do the same for On Select Exited to re-enable teleportation when our object is dropped.
That’s it for this guide on advanced grab behavior. There are many possible variations of the settings covered in this guide which may be useful for your own games, but hopefully this provides a useful introduction for you to be able to explore and develop further. One final note is that if you want to change the standard Grab Interactable behavior to prevent automatic snapping to your hand position, you can create a script to set an offset on pickup to reduce this effect. Personally I like the snap effect but I wanted to note that this is also possible and there are guides available on YouTube to do just that.
Thanks for reading! In the next guide I’ll get into more ways to use the ray interactor, including interacting with VR UI elements. See ya there!