Welcome! These docs will get you up and running with the VR Interaction Framework. If you come across any issues, please don't hesitate to contact me for support!
The VR Interaction Framework is a collection of scripts and prefabs to help you develop interactions in VR. It makes it easy to create your own interactable objects and be productive quickly.
There are multiple prefabs available to provide you with examples of common VR interactions. These range from simple blocks and balls to switches, levers, weapons and rocket arms. You are encouraged to experiment with these, inspect the scripts to see how they were made, and create your own.
*Please note that the most up to date Documentation can always be found here.
Start by downloading the Oculus SDK from the asset store, and import the package into your project.
If you are building for the Rift, you can skip all the way down to Step 5! Quest users continue below to get setup for Android Development.
Change your Build Settings (File -> Build Settings) Target to "Android". Make sure Texture Compression stays at "ASTC".
Go to Edit -> Project Settings -> Player. Under "XR Settings" make sure "Virtual Reality Supported" is checked, and that the Oculus SDK has been added.
Oculus Quest should enable V2 Signing; Low Overhead Mode is optional.
Still under Project Settings -> Player, expand the "Other Settings". Make sure "Vulcan" is not enabled under Graphics API's if you are using a Unity version < 2019.3, otherwise an error may be thrown.
Set the "Minimum API Level" to Android 4.4 'Kitkat' (API Level 19)
Make sure API compatibility level is .NET 4x.
I recommend changing your Fixed Timestep (Edit -> Project Settings... -> Time) to 0.01388889 if you are targeting the Oculus Quest. This matches the HMD's framerate (1/72). For Oculus Rift you can try 0.0111111 (1/90)
I also recommend disabling shadows (Project Settings -> Quality) and setting Pixel Light count to 1 if you are targeting the Oculus Quest.
Go ahead and import the Interaction Framework package if you haven't already.
That's it! Be sure to check out the demo in /Scenes/Demo. Make sure that scene is added to the build if you are running it on a device. If some physics collisions aren't working correctly, you may need to check your Layers. I recommend having at least a 'Player' and 'Grabbable' layer for physics purposes (See tips and tricks below). If everything is pink (and you are using URP), then you need to upgrade your project's materials : Edit -> Render Pipeline -> Universal Render Pipeline -> Upgrade Project Materials
The demo scene is meant to provide a unified place to test out how different object interact with each other, while keeping an eye on general performance. You can grab objects, interact with switches, levers, and buttons, and even do some climbing and combat.
Check out the script /Scripts/Extras/DemoScript/ for some additional code that is used in the demo scene.
The demo scene will be updated regularly with new features, so I wouldn't recommend saving your modifications to that scene. Instead, copy the prefabs over to your own scene, or just rename the scene.
The following components make up the core of this framework. The two main components are Grabber and Grabbable. The Grabber is in charge of picking up Grabbable objects that reside within it's Trigger. Grabbables designate items as grabbable by these Grabbers and allow you to tweak parameters such as grab offsets, how to handle physics, and things of that nature.
The Grabber is a Object the contains a Trigger Collider that is in charge of picking things up.
The Grabbable Component let's Grabbers know they can be picked up. There are many settings to help you tweak it's functionality to your liking.
Grab Physics Allows you to specify how this object will be held in the Grabbers
Physics Joint A ConfigurableJoint will be connect from the Grabber to the Grabbable. This allows held objects to still collide with the environment and not move through walls / other objects. The joints rigidity will be tweaked depending on what it is colliding with, in order to make sure it aligns properly with the hands during interaction and movement.
Kinematic The Grabbable will be moved to the Grabber and it's RigidBody will be set to Kinematic. The Grabbable will not allow collision from other objects and can go through walls. The object will remain firmly in place and is a reliable way of picking up objects if you don't need physical support.
None No grab mechanism will be applied. Climbable objects are not grabbed to the user, for example. They remain in place when grabbed. No Rigidbody is necessary in this case.
Grab Mechanic Specify how the object is held in the hand / Grabber
Precise The Grabbable can be picked up anywhere
Snap The Grabbable will snap to the position of the Grabber, offset by "Grab Position Offset" and "Grab Rotation Offset".
You can extend GrabbableEvents class in order to respond to all sorts of events that happen to a Grabbable. This is how many of the included prefabs are built, by either responding to Grabbable Events of by extending the Grabbable class to customize behaviour.
Check out /Scripts/Components/GrabbableHaptics.cs to see how easy it is to haptics to an object when it becomes a valid pickup.
Check out /Scripts/Extras/Flashlight.cs to see for a simple example on how to turn a light on and off. Hello World!
Climbables are modified Grabbable objects that keep track of a position for the Character Controller to offset from. See the custom included CharacterController.cs to see how climbing works.
Climbing is accomplished by checking where the controller is this frame, and then offsetting the character position by that amount.
Multiple Climbing objects can be held at once (one in each hand). You can set a "BreakDistance" if you want to prevent the players hands from getting too far away from a hold.
The Input Bridge serves as the primary class to go to for checking controller input such as position, velocity, button state, etc.
It is recommended to use this instead of something like OVRInput because this class can be more easily updated and account for other Input SDK's in the future.
Additional information on the included prefabs and scripts.
For example, a lever consists of a Grabbable part that is attached to a base via a ConfigurableJoint. That base could also be a Grabbable object. Whenever the player grabs the lever, a joint is attached, but is still constrained to the base.
Sometimes the Physics Engine can become unstable if certain conditions are met, so a helper script '/Scripts/Helpers/JointHelper.cs' is available that will help constraint objects to where they should be.
Hand models can be easily swapped out in the editor or at runtime.
The demo scene includes an example of how to change out hands by clicking in the left stick.
See /Scripts/Helpers/HandControllers.cs for an example script you can use to animate a hand model based on input and Grabbable / Grabber properties.
The demo scene has a couple of examples of using arms, body, and head IK. These examples use the standard Unity IK system, but with a bit of trickery to get the hands and elbows to position correctly.
If you just use Unitys IK system then the characters hands won't always be able to reach where the controllers are, and finger IK isn't always rigged. To get around this, you can use a hand model as your controller. Then have your wrist model point at your characters elbow joint, and then an attached upper arm look at the shoulder joint. This way the hands always match with the controller, and the arms and elbows have targets to mimic.
Grabbable objects have a BreakDistance property you can set that can force a grabber to drop and object if it goes too far away from the object. This can be useful with arm IK as you can have the player just drop whatever it is holding if the Arm length would be too far. For example, if a player was holding onto an axe stuck in a tree and walked back, you could force them to drop the axe if they go too far, preventing the arms from being crazy long.
Take a look at /Scripts/Components/CharacterIK to see how hands and head IK are positioned / rotated. You can hide different parts of the body (such as arms or legs) by scaling their joints down to 0.
Body IK can be as simple as rotating (or Lerping) the body to match the HMD's rotation, offset with the characters rotation.
There is not yet a an example for feet IK, but this would involve setting the feet height to the player's lower capsule position.
Check out Final IKas an option for Full Body IK. Keep in mind IK can be a computationally expensive feature.
Slow motion is a fun effect in VR, and can also be a helpful way to troubleshoot physics and gameplay bugs.
In the demo scene you can slow time by pressing the "Y" button on the Left Oculus Touch Controller. Try shooting weapons, throwing objects, and observing sounds while time is slowed.
See /Scripts/Extras/TimeController.cs for an example on how to slow down time and apply a sound effect.
Whenever you are playing a sound, be sure to multiply your sound pitch by Time.TimeScale. This way your sounds will be "slowed" down by decreasing pitch, relative to how you've scaled Time.TimeScale.
When adding forces to rigidbodies use ForceMode.Velocity. This will properly scale based on Time.fixedDeltaTime. Otherwise physics may not work as expected.