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.)

This Rectangle is childed to the lid.

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:

a public virtual void can be overridden

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:

  1. Move the handle towards this object every frame that it is grabbed.
  2. Make the players hand disappear on grab.
  3. Snap back to the handles rotation and position on release.

We can create a new script called ConstrainedGrabbable and have it inherit from OVRGrabbable.

By inheriting we can now override methods in OVRGrabbable to suit our needs

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.

you could also determine the handle based on the parent. but this way adds some flexibility in setup.

We will start by overriding the start function, so we can keep base implementation and grab the _handles rigid body component.

make sure you keep base.Start() in there, we dont want to fully override all functionality.

We will next override the grab begin function to start a coroutine that will update the handle, and hide the hand.

be sure that the base functionality comes first.

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.

The base needs to be at the end of this one.

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!

--

--

--

A Honolulu based software developer, that enjoys surfing, spearfishing, and making videogames

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Serverless Architecture — Explained For Non-Developers

Mist NFT — Weekly Recap #1

Nail Your Software Development Workflow Early

Scaleway: Kapsule. First impressions of cloud infrastructure designed for engineer end-users.

📖 welcome to the world of #NFTs

DATA LAKE ON AWS CLOUD USING LAKEFORMATION

Google Drive and Takeout: A Backup-Sync Odyssey

Integrating Zoom API Version 2 to Ruby on Rails

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Austin Mackrell

Austin Mackrell

A Honolulu based software developer, that enjoys surfing, spearfishing, and making videogames

More from Medium

New Enemy Detected — Enemy Types and Behaviors

With 35 lectures in 2 days, focusing on industrialization problems, what substantial knowledge of…

How to detect collisions in Unity

Kibbi Keeper Postmortem — From Wrangler to Keeper