Unity OVR Physics Based Interactions
Lets get some physics based interactions going in Unity with Oculus’ OVR SDK. If you have tried doing this with an OVR grabbable right out of the box, you’ll notice that it does not work as expected. Today we will be focusing on a hinge joint interaction. In our case, a chest. This will also work on doors, levers, or anything else that would require a hinge.
It seems straight forward enough, put a Hinge Joint and a grabbable on the object you want to move and it should be constrained right? Well that's what I thought, and this was the result:
So what is going on here? Well, there are a few things to note. For starters, the OVR Grabber, will turn any grabbed object to kinematic. When an object is kinematic its will completely ignore any joints or constraints. If you comment that line of code out, you still very similar behavior. Upon further testing the problem comes from using RigidBody.Move. It does not cooperate well with constraints, so we will have to work around this to get it working as we want. The solution to the problem came from some research on how others overcame this problem, followed by some of my own optimizations to help with performance.
First we will add our constraint. This can be a hinge joint, configurable joint, or even just freezing position or rotation on your rigid body.
Next we will create a cube and child it to our object. This will act as our handle. Place it where you want your player to be able to grab and interact. We will add a fixed joint on here, and set connected body to the parent.(our original object.)
Now if you grab it, it works closer to intended, but not exactly. Small hand movements result in very large movements on the object, and if you exaggerate to much, it will rip right off the hinges. The fix to this is one more degree of separating. Set your handle object to a trigger, so that it will avoid collisions, and then create one more cube that will be a child of the handle. This is the object you will actually grab. We will need to use code to have the handle move towards our grabbable object every frame. We will go over this but first lets break it down and show what's going on to avoid confusion.
We have 3 objects:
(Parent) Constrained object: This has a rigid body, and some sort of constraint. Its the object we want the player to see and interact with.
(Child) Handle: This has a rigid body and a fixed joint. Its collider, is set to trigger. It is feeding movement into our constrained object.
(Grandchild) Grabbable Object: This has a rigid body and an OVR Grabbable. This translates the hand movement to the handle and is what drives the player side of the interaction. The handle constantly updates its position to move towards this object. This is what the player physically grabs.
There are a few ways to handle updating the handle to move towards our grabbable object. The most common one that I’ve seen is simply adding a script that Rigidbody.Moves towards the target, in an update loop. The problem with that is that it doesn’t scale well. If you have 10 doors, you have 10 update loops constantly firing off. What if my level is an office? Think of all the cabinets, drawers, and doors that I would have. That's easily 100 separate instances, talking to the physics system every frame! In VR optimization is everything! So lets take a look at how to tackle this.
If we take a look a the OVRGrabbable class you will notice that it has two methods we can override:
This means that we can extend the class and create our own grabbable script that is specific to our needs. Our grabbable class will need to be able to do the following:
- Move the handle towards this object every frame that it is grabbed.
- Make the players hand disappear on grab.
- Snap back to the handles rotation and position on release.
We can create a new script called ConstrainedGrabbable and have it inherit from OVRGrabbable.
We then want to create some new variables. I created a private Transform called _handle, which is serialized so we can easily assign it in the inspector. A rigid body called _handleRB, and a bool called _grabbed.
We will start by overriding the start function, so we can keep base implementation and grab the _handles rigid body component.
We will next override the grab begin function to start a coroutine that will update the handle, and hide the hand.
We need to create the coroutine now that updates the handle. By using a coroutine we can use a while loop rather than the update loop, saving us from having to constantly update the position, and only make the check when it is actually grabbed. We can break this loop on when the grab ends.
Lastly, we override the GrabEnd function to stop updating position, resnap the grabbers position and enable the hand.
Lets give it a play and see how it works!
I left the mesh renderers on so you can see how the set up should look. And here is the final product:
There you have it! A nice, clean physics based interaction, that scales well too! Now that you have the grabbable extended, you can use this setup and script on anything you’d like to bring it to life!