How to make SteamVR input work with Unity XR Interaction Toolkit in Unity

(Image by Unity Technologies)

Hello everyone! Today’s post is a bit technical, but it will help some VR devs out there to have fewer headaches. It is a short guide to implement some sort of compatibility between the SteamVR Unity plugin and the Unity XR Interaction Toolkit, that under the new XR Plugin Management in Unity are not working very well together.

The problem

SteamVR is a great solution to develop cross-platform applications, and so is Unity (Image by Valve)

I was working on a consultancy project with Unity, that had to be cross-platform. So I used the latest tools that Unity offers for the purpose:

  • The Unity XR Plugin Management, that lets you switch easily between different headset types in your application;
  • The XR Interaction Toolkit, that offers standardized interactions in VR: it gives you cross-platform mechanics like grab, teleport, select, etc…

With Oculus, both Quest and Rift, everything works like a charm. With SteamVR things are a bit more problematic.

The reason is a bit political: When Unity went for the new management system for VR plugins, that are now all managed within the Unity package system in a smart way, Valve didn’t let Unity develop the plugin for them, and so its support arrived months later because they wanted to develop it in house. The problem is that it may happen that when you hit play, NO INPUT gets detected from the controllers! So Interactors and interactables are not working as expected. And a VR program with no interactions is very boring…

Valve has made all its super cool interaction system and headset management, Unity now wants to make the same things its own way, and so the two solutions are clashing. Valve doesn’t want to rewrite everything just to please Unity and it especially doesn’t want to do it now that Open XR is coming, and so they know they’ll have to do the same refactory anyway in some month. To avoid making double the work, they are just not fixing things now.

This means that there are some devs out there that don’t know how they can support SteamVR for their programs/games because they implemented everything with the cross-platform XR Interaction Tookit to discover later on it is not SteamVR-compatible. Making a full refactory is too much work, and create a separate branch of the program just to make things compatible with SteamVR is a maintenance hell.

The problem is well documented here https://github.com/ValveSoftware/unity-xr-plugin/issues/16 where you can read many devs angry as hell with Valve for this problem.

Since I did absolutely want to add SteamVR compatibility with my project, I worked hard to find a hack to make things work in an elegant way. And I’ve found two solutions that may help people in solving this issue. I’m reporting them here hoping to help the other developers in shipping their products because I really believe in the power of making community all together 🙂

Before going on, remember that what I’ve made is a hack, so it is not an optimal solution, and it may not fit your needs… or it can be useful for you, but you have to modify it. Or it can make your PC to explode. Use it at your own risk!

UPDATE 2021.02.20: Looking at the link on GitHub above, you can see that some developers have found that there is an alpha implementation of OpenXR within Unity, and it may fix the issue. At the moment, I keep using this hack because the OpenXR implementation inside Unity is not stable at all, so I wait for Valve and Unity to finalize their OpenXR efforts. When this will be completed (probably within 2021), OpenXR will be the official solution for using the XR Interaction Toolkit with SteamVR and the below solutions will be deprecated.

Solution 1 – Use The Legacy VR System

The plain old legacy Virtual Reality Supported flag may be your biggest friend

This solution has been suggested to me by Nitesh Bhatia. He made me notice that if you use the legacy VR plugin management (the “Virtual Reality Supported” flag), the XR Interaction Toolkit works well also with SteamVR. This is exactly the same solution applied by Unity itself when developing the XR Interaction Toolkit examples (you can download the project to verify it yourself).

So if you are not using Unity 2020, and you don’t care using a deprecated plugin management system, ditch the super new Unity XR Plugin Management and go back to use the old-school VR management. Delete the new plugin management, then go to Player Settings -> XR Settings and hit Virtual Reality Supported. Add the “Open VR” virtual reality plugin and then you’re ready to go! The old VR management was better for Valve and integrates better with the XR Interaction Toolkit, which this way lets you work with all inputs of all headsets.

Solution 2 – Tony’s Hack

Tony’s VR hacks are the best

If for some reason (e.g. you are using Unity 2020) you can’t use the old system, but you must use the Unity XR Plugin Management, there’s no official way to make SteamVR work. I mean, you can make the headsets and controllers to work, but you won’t be able to detect any input, meaning that for instance, all Interactors won’t work.

I’ve found a hack that somewhat makes things work. I managed to make with it an app that is compatible with Rift, Quest, and Vive. The good news is that it is future-proof, in the sense that if its features suffice to you, most probably when Unity and Valve will find a better way to work together, you can remove the hack and things should work the same. The bad news is:

  • It is pretty dirty
  • Its features are limited
  • Its setup is a bit a nuisance
  • Probably you’ll have to customize it a bit

… but I think you can survive all of that. So, let me show you how I made things to work together! This post is very technical, so if you’re here I can assume you already know Unity and I don’t have to guide you via screenshots for every step, so I won’t detail every little passage, but I think that you’re very smart and will be able to follow me easily.

1 Create your project

I mean, this step is pretty obvious… create a Unity project to learn how to use this hack. For this guide, I’ll imagine you will start from scratch. I personally used Unity 2019.4 LTS

2 Install the XR Plugin Management

If you go into the Project Settings (Edit -> Project Settings…) there is a tab about “XR Plug-In Management”. If you select it, Unity will show you a button to install it. Be brave and install it

3 Install the XR Interaction Toolkit

Use the package manager (Window -> Package Manager) and install the XR Interaction Toolkit. Remember that is in preview, and you should enable the view of preview packages to install it. At the time of writing, I have the version 0.9.4-preview

The XR Interaction Toolkit in Unity. Remember that this package is still in preview

UPDATE 2021.02.20: I have also tested this method with the version 0.10.0 of the XR Interaction Toolkit and everything works. My suggestion, to make things work with all the headsets (Wave SDK included), is to create XR Rigs that are device-based and not action-based. Furthermore, now when you install this plugin, Unity asks you if you want to enable the new Unity Input System and restart, and you should answer with yes.
After the restart, head to set Project Settings -> Player -> Other Settings -> Active Input Handling as “both” (this is not mandatory, but I keep it this way for broader compatibility). This may require another restart.

4 Install the OpenVR XR Installer

As I told you before, Valve plugin is not included in Unity installation, but you have to download it from GitHub. You find the link in the Readme of the plugin here: https://github.com/ValveSoftware/unity-xr-plugin . At the time of writing, the direct link for the download is this one: https://github.com/ValveSoftware/unity-xr-plugin/releases/tag/installer

After you have downloaded the Unitypackage, just install it inside your project (Assets -> Import Package…) and let it do its stuff.

UPDATE 2021.02.20: You can find the package to download at this link: https://github.com/ValveSoftware/unity-xr-plugin/releases . It is a tarball (.tgz) file, and you have to download it to your disk. Then you head to Unity and select the menu Window -> Package Manager, to open the package manager. In the package manager window, in the upper left corner there is a “+” sign. Click on it and select “Add package from tarball…” and in the resulting window choose the .tgz file that you have just downloaded, and let it do its stuff.

How to install a package from tarball in Unity

After that, go back to the “XR Plug-In Management” tab in the Project Settings and select the new “OpenVR Loader” entry among the available plugins, to enable SteamVR support in Unity XR.

Technically this should suffice to make things work in normal condition. So if arrived here, you hit play and your system can detect the input of your controllers, you can stop reading your guide here. Otherwise, go on for the hacky things

5 Install the SteamVR Unity plugin

You have to install the legacy SteamVR Unity plugin, but don’t take it from the asset store, but directly from GitHub. This is the best link at the time of writing https://github.com/ValveSoftware/steamvr_unity_plugin/releases/tag/2.6.1

UPDATE 2021.02.20: You can always find the most updated version of the SteamVR Unity Plugin at this link: https://github.com/ValveSoftware/steamvr_unity_plugin/releases

Download the Unitypackage and then import it into your project. If Unity shows you a dialog saying “Built in vr detected” just say Ok and then confirm again with Ok. We know we shouldn’t import this stuff with Unity XR, but we’re bad guys, so we’re doing it anyway.

After this, let’s check we haven’t made a disaster: go back to the project settings: “XR Plug-In Management” should be there, and “OpenVR Loader” should still be selected inside its entries. Then go to Player Settings -> XR Settings and verify that Virtual Reality Supported is deselected, grayed out, or inexistent (depending on your Unity version). We must be sure we are still using the XR Plug-In Management.

6 Create SteamVR Input Actions

We need to access SteamVR Input and so we must generate the bindings between the controllers and the SteamVR Actions (If you know the SteamVR plugin, you know what I’m talking about). Go to Window -> SteamVR Input. If a pop up comes out, say Yes, then leave the default settings and just click “Save and Generate”. You can modify these things later on, if you want (but don’t forget also to modify the other files of the hack!).

7 Free the XR Interaction Toolkit from the Package Manager

This is not strictly necessary in general but makes things easier for the next steps. We must use directly the code of the XR Interaction Toolkit without passing from the package manager: we must modify its code, and if we keep it managed by the package manager, it will overwrite our code the next time we open Unity. (There are hacks to prevent that, but it is too boring and complicated)

So with your File Explorer, open the directory where the XR Interaction toolkit is saved (<Project Directory>\Library\PackageCache) and copy the whole directory (it has a name like “com.unity.xr.interaction.toolkit@0.9.4-preview”) to another directory on your hard drive (e.g. C:\). Then return to Unity and within the package manager uninstall (yes, you’ve read it well) the XR Interaction Toolkit.

After that, go back to where you backed up the directory and copy it back in the Assets\ directory of your project. We have basically freed the XR Interaction toolkit from the project manager but still kept it inside our project.

At this point, the structure of your project should more or less be this one

Notice: doing this way, your package won’t be updated again. I’ll return on it at the end of the article.

UPDATE 2021.02.20: The version 0.10.0 of the XR Interaction Toolkit may complain about the package InputSystem missing. If this is the case, head to the Package Manager again and install the package called “Input System” from the Unity Registry (You can use the search function to look for it)

8 Add SteamVR dependency

At this point the toolkit can’t use SteamVR methods and classes, because we have to add a reference to them.

Select the file Assets\com.unity.xr.interaction.toolkit@0.9.4-preview\Runtime\Unity.XR.Interaction.asmdef (It’s an Assembly Definition File). In the inspector, you should see a section called “Assembly Definition Reference”. Hit on the “+” symbol and add a reference to the SteamVR.asmdef that you find in the project, then hit the “+” again and add SteamVR_Actions as well. To find these two assemblies, you just hit on the circle that lets you select elements from your project after you have clicked on the “+”.

These are the references you should add

9 Let’s modify the code!

Let’s hack the code of the Unity XR Interaction toolkit! Here below I provide you what files to modify or to add. Keep in mind that since you may be using a little different version of the toolkit, I have highlighted in the code what I’ve modified with the tag “////MODIFIED BY TONY!” so that you can identify the tiny bits to change and you can cherrypick these changes in the files you actually have.

Let’s start from \Assets\com.unity.xr.interaction.toolkit@0.9.4-preview\Runtime\Interaction\Controllers\XRController.cs where we’ll add the support for a class called InputDeviceWrapper that substitutes the standard InputDevice. Substitute the existing code with this one

UPDATE 2021.02.20: the new XRController.cs for the toolkit version 0.10.0 is slightly different and it is here below:

Then it’s time to add support for InputDeviceWrapper also to Assets\com.unity.xr.interaction.toolkit@0.9.4-preview\Runtime\XR\InputHelpers.cs . Substitute the file content with:

UPDATE 2021.02.20: the new InputHelper.cs for the toolkit version 0.10.0 is slightly different and it is here below:

And then it is the turn of \Assets\com.unity.xr.interaction.toolkit@0.9.4-preview\Runtime\Locomotion\SnapTurn\SnapTurnProvider.cs

UPDATE 2021.02.20: The change to this file is no more necessary for the version 0.10.0 of the Toolkit

As you can see, the changes are very little in these files and you can easily cherrypick them by just looking for the comments and modifying your existing files.

Now, after we have made everything compatible with this InputDeviceWrapper class, it is the time to create it. Create the file \Assets\com.unity.xr.interaction.toolkit@0.9.4-preview\Runtime\Interaction\InputDeviceWrapper.cs and put this code inside

This file basically does one thing: it wraps the InputDevice class, and if you’re not using OpenVR, it just calls the methods in InputDevice, otherwise, it invokes the methods of SteamVR Input. Notice that in the code I already mapped the functions that I needed to grab, trigger and rotate, but it is just the beginning of the implementation, and you can follow my example to map any other input you may need in your application.

After this, we are almost done!

10 Let’s make SteamVR read some input

At this point, everything is ready to work, but if you run the program, it won’t work yet because SteamVR needs some objects in scene to start the input detection. To create two new gameobjects and add to each one of them the script SteamVR_Behaviour_Pose.

Select these gameobjects and in the inspector specify as “Input Source” for one “Left Hand” and for the other one “Right Hand”.

After this step, you should be done, but let’s do some other things to let you build the application successfully…

11 Let’s check things for the build…

In SteamVR_Resources\Resources there is a file called SteamVR_Settings. Select it and you should see in the inspector some settings. Make sure that “Auto Enable VR” is false.

Then copy the file “XR\Settings\Open VR Settings.asset” in the folder “StreamingAssets\SteamVR”. You can do that inside Unity or with the File Manager.

In the build settings for PC, select that you want to build for the Architecture “x86_64”. Unity will make some recompiling after it.

x86 builds just made my program to crash

With these settings, you are sure that the build won’t crash (at least, it saved the project for me)

12 Let’s care about the Quest

If you plan one day to build for Android, make yourself a favour and exclude SteamVR from the Android Build. Select Assets\SteamVR\SteamVR.asmdef and in the Inspector check that in the Platform section at the “Platforms Excluded” voice, Android is selected. Then do the same for Assets\SteamVR_Input\SteamVR_Actions.asmdef . Apply the settings if needed.

Exclude SteamVR from the mobile builds so that you can also build for Quest

13 Enjoy!

If you did everything correctly, you should be able to create a simple project with some interactions, hit play, and see everything working! And you can also build it and run it outside the editor! That’s amazing!

14 What about if Unity and Valve fix the issue?

If you discover that a new version of the toolkit solves the issue, it’s easy to revert the hack for your project. Delete all the SteamVR folders from the project, delete the directory of the Interaction Toolkit that you added to your Assets folder, and re-import the new XR Interaction Toolkit from the Package Manager. Everything should work without changing the code. This is possible because my class InputDeviceWrapper has the same methods with the same signature of the class InputDevice, so when it gets removed, you end up calling the methods of InputDevice and everything works the same. At maximum, if you have made some direct references to InputDeviceWrapper, you have just to modify some little things here and there (my advice is to use “var” anytime you want to access the Input Device to avoid these issues).

UPDATE 2020.10.04: Beep2BleepGames has created a GitHub repo with an out-of-the-box ready Unity 2020 solution already implementing this hack! You can check it out at this GitHub repo: https://github.com/beep2bleep/SteamVRWorkingWithUnityXTToolkit


And that’s it! I hope this guide is useful to some other VR developers like me! It took me many hours to find this hack, so I hope to have spared you some time. And If you are reading this guide and something is not clear to you, feel free to contact me and ask for some help.

And if this post has helped you, consider subscribing to my newsletter or donating to my Patreon!

(Header image by Unity Technologies)

Skarredghost: AR/VR developer, startupper, zombie killer. Sometimes I pretend I can blog, but actually I've no idea what I'm doing. I tried to change the world with my startup Immotionar, offering super-awesome full body virtual reality, but now the dream is over. But I'm not giving up: I've started an AR/VR agency called New Technology Walkers with which help you in realizing your XR dreams with our consultancies (Contact us if you need a project done!)
Related Post
Disqus Comments Loading...