How to grab objects in Unity VR

As we dive into the world of virtual reality (VR), one of the most fundamental interactions we need to implement is the ability to grab objects. In Unity VR, we can achieve this by leveraging Unity's physics engine, VR frameworks, and scripting capabilities. This answer will guide you through the step-by-step process of enabling object interaction in a Unity VR scene.

Step by step approach

  1. Set up your Unity VR project: To get started, create a new Unity project and set it up for VR development. You will need to install the necessary VR packages according to your specific hardware, such as Oculus or StreamVR.

Enabling VR
Enabling VR

Here's a sample code snippet to illustrate how your project setup might look.

// Sample C# script to enable VR support in Unity
using UnityEngine;
using UnityEngine.XR;
public class EnableVR : MonoBehaviour
{
void Start()
{
XRSettings.enabled = true;
}
}
  1. Create a grabbable object: Next, create the object you want to be able to grab in your scene. This could be any 3D model. Once you've added it to your scene, be sure to attach a Rigidbody component for physics interactions and a Collider component so it can detect when it's being touched by the VR controllers.

// Sample C# script to add Rigidbody and Collider to a GameObject
using UnityEngine;
public class MakeGrabbable : MonoBehaviour
{
void Start()
{
gameObject.AddComponent<Rigidbody>();
gameObject.AddComponent<BoxCollider>();
}
}
  1. Create VR controller input: The next step is to set up the VR controllers to interact with the objects.

Input Unity Project to StreamVR
Input Unity Project to StreamVR

This usually involves creating a script that checks for input from the VR controller, such as button presses or gestures.

// Sample C# script to detect input from VR controller
using UnityEngine;
using Valve.VR;
public class VRInput : MonoBehaviour
{
public SteamVR_Action_Boolean grabAction;
void Update()
{
if (grabAction.GetStateDown(SteamVR_Input_Sources.Any))
{
Debug.Log("Grab button pressed");
}
}
}
  1. Implement the grabbing mechanic: Now that we can detect when the user wants to grab an object, we need to implement the actual grabbing mechanic. This could involve making the object a child of the controller while it's being held, adjusting its position and rotation to match the controller's.

// Sample C# script to implement grabbing mechanic
using UnityEngine;
public class GrabObject : MonoBehaviour
{
private GameObject heldObject;
void Grab(GameObject obj)
{
heldObject = obj;
obj.transform.SetParent(transform);
}
void Release()
{
heldObject.transform.SetParent(null);
heldObject = null;
}
}
  1. Combine all elements: Finally, combine all the elements. Detect when the controller is touching an object, grab the object when the grab button is pressed, and release it when the button is released.

// Sample C# script to combine all elements
using UnityEngine;
using Valve.VR;
public class VRGrab : MonoBehaviour
{
public SteamVR_Action_Boolean grabAction;
private GameObject touchingObject;
private GameObject heldObject;
void OnTriggerEnter(Collider other)
{
touchingObject = other.gameObject;
}
void OnTriggerExit(Collider other)
{
touchingObject = null;
}
void Update()
{
if (grabAction.GetStateDown(SteamVR_Input_Sources.Any) && touchingObject)
{
GrabObject();
}
if (grabAction.GetStateUp(SteamVR_Input_Sources.Any) && heldObject)
{
ReleaseObject();
}
}
void GrabObject()
{
heldObject = touchingObject;
var joint = AddFixedJoint();
joint.connectedBody = heldObject.GetComponent<Rigidbody>();
}
void ReleaseObject()
{
if (GetComponent<FixedJoint>())
{
GetComponent<FixedJoint>().connectedBody = null;
Destroy(GetComponent<FixedJoint>());
heldObject.GetComponent<Rigidbody>().velocity = SteamVR_Actions.default_Pose.GetVelocity(SteamVR_Input_Sources.Any);
heldObject.GetComponent<Rigidbody>().angularVelocity = SteamVR_Actions.default_Pose.GetAngularVelocity(SteamVR_Input_Sources.Any);
}
heldObject = null;
}
FixedJoint AddFixedJoint()
{
FixedJoint fx = gameObject.AddComponent<FixedJoint>();
fx.breakForce = 20000;
fx.breakTorque = 20000;
return fx;
}
}
  • In this final script, we're bringing together all of the previous elements:

    • OnTriggerEnter(Collider other): this is called when your controller comes into contact with another object. We use it to set touchingObject to the object the controller is currently touching.

    • OnTriggerExit(Collider other): this is called when your controller stops touching an object. We use it to clear touchingObject.

    • Grab(GameObject obj): this is the method we defined before for grabbing an object. It makes the object a child of the controller.

    • Release(): this is the method for releasing an object. It removes the object from being a child of the controller.

    • Update(): Unity calls this method once per frame. We use it to check the state of the grab action. If the grab button is pressed and the controller is touching an object, the object is grabbed. Similarly, if the grab button is released and an object is being held, the object is released.

  1. Adding haptic feedback: Adding haptic feedback can make your VR experience more immersive. Haptic feedback can be added by using the HapticCapabilities class to ensure the controller supports it, and then using the InputDevice.SendHapticImpulse function to trigger the feedback.
    Here's a simple script that triggers haptic feedback when grabbing or releasing an object:

using UnityEngine;
using UnityEngine.XR;
public class VRGrab : MonoBehaviour
{
public SteamVR_Action_Boolean grabAction;
private GameObject touchingObject;
private GameObject heldObject;
private InputDevice device;
void Start()
{
var devices = new List<InputDevice>();
InputDevices.GetDevicesAtXRNode(XRNode.RightHand, devices);
if (devices.Count == 1)
{
device = devices[0];
}
else
{
Debug.Log("Unable to find right hand device");
}
}
void Grab(GameObject obj)
{
// ... (grab code as before) ...
// Trigger haptic feedback
if (device.isValid)
{
device.SendHapticImpulse(0, 0.5f, 0.1f);
}
}
void Release()
{
// ... (release code as before) ...
// Trigger haptic feedback
if (device.isValid)
{
device.SendHapticImpulse(0, 0.5f, 0.1f);
}
}
// ... (rest of class as before) ...
}
  1. Modifying physics properties: Tweaking the physical attributes of your objects can give them a more real-world touch when you pick them up and let them go. Unity lets you do this by changing properties right in the Rigidbody component. For instance, reducing drag can make an object glide more smoothly. Similarly, messing with the mass can make an object seem heavier or lighter when you're moving it around.

Adjusting physics properties of components
Adjusting physics properties of components
  1. Test and Refine Your VR Experience: Once you have set up the basic mechanics, you should test your VR experience extensively. Try grabbing and releasing objects from different angles, with different speeds, and with different controller orientations. Look for any situations where the grabbing and releasing behavior doesn't feel intuitive or responsive, and adjust your scripts as needed. Consider getting feedback from other people as well, as different users might have different expectations about how object interaction should work in VR.

Conclusion

In conclusion, creating immersive and interactive VR experiences in Unity involves several steps that include setting up your project for VR, creating grabbable objects, implementing a grabbing mechanic, adding haptic feedback, and fine-tuning physics properties. With these tools at your disposal, you can create your own unique and engaging VR experiences. Always remember to test your project extensively and iteratively refine your designs based on feedback and observed user behavior. Happy coding!

Related Answers:

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved