DEV Community

kurohuku
kurohuku

Posted on • Edited on

SteamVR Overlay with Unity: Initialize OpenVR

Create new script

Create a folder named Scripts inside Assets. Then create a file named WatchOverlay.cs inside the Scripts folder. We will add our overlay code to this script.

Image description

Copy the following code to WatchOverlay.cs.

using UnityEngine;

public class WatchOverlay : MonoBehaviour
{
    private void Start()
    {
    }
}
Enter fullscreen mode Exit fullscreen mode

Put the script to the scene

In the hierarchy window, right click > Create Empty.
Change the object name to WatchOverlay, then drag the WatchOverlay.cs file from the project window to the newly created object.

Image description

Add using directive

Add using Valve.VR to WatchOverlay.cs to use the OpenVR API. This namespace is included in the SteamVR Plugin.

using UnityEngine;
+ using Valve.VR;

public class WatchOverlay : MonoBehaviour
{
   private void Start()
   {
   }
}
Enter fullscreen mode Exit fullscreen mode

Initialize OpenVR

Initialize OpenVR with Init() to use the API. (read the wiki for details)

using UnityEngine;
using Valve.VR;

public class WatchOverlay : MonoBehaviour
{
    private void Start()
    {
+       var error = EVRInitError.None;
+       OpenVR.Init(ref error, EVRApplicationType.VRApplication_Overlay);
    }
}
Enter fullscreen mode Exit fullscreen mode

We pass two arguments to Init().

The first argument is a reference. If an error occurs during initialization, Init() sets the variable's value referenced to the error. All errors are defined in EVRInitError.

The second argument is the application type, which will be EVRApplicationType.VRApplication_Overlay for overlay applications. All application types are defined in EVRApplicationType.

If the application has been initialized as an overlay, it can be run with other VR applications at the same time.

Initialize error handling

Add error handling.

using UnityEngine;
using Valve.VR;
+ using System;

public class WatchOverlay : MonoBehaviour
{
    private void Start()
    {
        var error = EVRInitError.None;
        OpenVR.Init(ref error, EVRApplicationType.VRApplication_Overlay);
+       if (error != EVRInitError.None)
+       {
+           throw new Exception("Failed to initialize OpenVR: " + error);
+       }
    }
}
Enter fullscreen mode Exit fullscreen mode

If the initialization succeeds, the error value will remain EVRInitError.None. We will throw an Exception if this is not the case. Note that you need to add using System to use Exception.

If OpenVR is already initialized

If OpenVR has already been initialized, skip the initialization.

using UnityEngine;
using Valve.VR;
using System;

public class WatchOverlay : MonoBehaviour
{
    private void Start()
    {
+       if (OpenVR.System != null) return;

        var error = EVRInitError.None;
        OpenVR.Init(ref error, EVRApplicationType.VRApplication_Overlay);
        if (error != EVRInitError.None)
        {
            throw new Exception("Failed to initialize OpenVR: " + error);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

If OpenVR has not been initialized, OpenVR.System is null.
The API is broken down into parts such as the following. They are null before initialization.

  • OpenVR.System
  • OpenVR.Chaperone
  • OpenVR.Compositor
  • OpenVR.Overlay
  • OpenVR.RenderModels
  • OpenVR.Screenshots
  • OpenVR.Input

Cleanup

Add cleanup to dispose of the initialized OpenVR.
Call Shutdown() at the end of the program. (read the wiki for details)

using UnityEngine;
using Valve.VR;
using System;

public class WatchOverlay : MonoBehaviour
{
    private void Start()
    {
        if (OpenVR.System != null) return;

        var error = EVRInitError.None;
        OpenVR.Init(ref error, EVRApplicationType.VRApplication_Overlay);
        if (error != EVRInitError.None)
        {
            throw new Exception("Failed to initialize OpenVR: " + error);
        }
    }

+   private void OnDestroy()
+   {
+       if (OpenVR.System != null)
+       {
+           OpenVR.Shutdown();
+       }
+   }
}
Enter fullscreen mode Exit fullscreen mode

Check the initialization works

Let's access the initialized OpenVR API.

using UnityEngine;
using Valve.VR;
using System;

public class WatchOverlay : MonoBehaviour
{
    private void Start()
    {
        if (OpenVR.System != null) return;

+       Debug.Log(OpenVR.Overlay);

        var error = EVRInitError.None;
        OpenVR.Init(ref error, EVRApplicationType.VRApplication_Overlay);
        if (error != EVRInitError.None)
        {
            throw new Exception("Failed to initialize OpenVR: " + error);
            return;
        }

+       Debug.Log(OpenVR.Overlay);
    }

    private void OnDestroy()
    {
        if (OpenVR.System != null)
        {
            OpenVR.Shutdown();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Image description

We can see that the API is available after initialization.
If the SteamVR has not launched, it should be automatically launched by Init().

Image description


Optional: Initialize OpenVR by SteamVR Plugin setting

We don’t use it in this tutorial, but the SteamVR Unity Plugin has an automatic initialization setting.
Check Initialize XR on Project Settings > Startup In XR Plug-in Management.

Image description

Select Overlay as the Application Type in the OpenVR setting.


Delete the Debug.Log().

private void Start()
{
    if (OpenVR.System != null) return;

-   Debug.Log(OpenVR.Overlay);
    var error = EVRInitError.None;
    OpenVR.Init(ref error, EVRApplicationType.VRApplication_Overlay);
    if (error != EVRInitError.None)
    {
        throw new Exception("Failed to initialize OpenVR: " + error);
        return;
    }
-   Debug.Log(OpenVR.Overlay);
}
Enter fullscreen mode Exit fullscreen mode

Organize code

We have initialized and cleaned up OpenVR. Let’s organize the code here.
This tutorial will organize code periodically to keep methods small for clarity.

Initialize

Move the initialization code into InitOpenVR().

using UnityEngine;
using Valve.VR;
using System;

public class WatchOverlay : MonoBehaviour
{
    private void Start()
    {
+       InitOpenVR();
-       if (OpenVR.System != null) return;
-
-       var error = EVRInitError.None;
-       OpenVR.Init(ref error, EVRApplicationType.VRApplication_Overlay);
-       if (error != EVRInitError.None)
-       {
-           throw new Exception("Failed to initialize OpenVR: " + error);
-       }
    }

    private void OnDestroy()
    {
        if (OpenVR.System != null)
        {
            OpenVR.Shutdown();
        }
    }

+   private void InitOpenVR()
+   {
+       if (OpenVR.System != null) return;
+
+       var error = EVRInitError.None;
+       OpenVR.Init(ref error, EVRApplicationType.VRApplication_Overlay);
+       if (error != EVRInitError.None)
+       {
+           throw new Exception("Failed to initialize OpenVR: " + error);
+       }
+   }
}
Enter fullscreen mode Exit fullscreen mode

Optional: If you want to use return instead of throw

This tutorial uses throw for readability of error handling. If you prefer return to return an error code or a bool value, replace the error handling code with the following.

// Return error code
private bool InitOpenVR()
{
    if (OpenVR.System != null) return;

    var error = EVRInitError.None;
    OpenVR.Init(ref error, EVRApplicationType.VRApplication_Overlay);
    if (error != EVRInitError.None)
    {
        Debug.LogError("Failed to initialize OpenVR: " + error);
    }
    return error;
}
Enter fullscreen mode Exit fullscreen mode
// Return bool value
private bool InitOpenVR()
{
    if (OpenVR.System != null) return;

    var error = EVRInitError.None;
    OpenVR.Init(ref error, EVRApplicationType.VRApplication_Overlay);
    if (error != EVRInitError.None)
    {
        Debug.LogError("Failed to initialize OpenVR: " + error);
        return false;
    }
    return true;
}
Enter fullscreen mode Exit fullscreen mode

Cleanup

Similarly, move the cleanup code to ShutdownOpenVR().

using UnityEngine;
using Valve.VR;
using System;

public class WatchOverlay : MonoBehaviour
{
    private void Start()
    {
       InitOpenVR();
    }

    private void OnDestroy()
    {
-       if (OpenVR.System != null)
-       {
-           OpenVR.Shutdown();
-       }
+       ShutdownOpenVR();
    }

    private void InitOpenVR()
    {
        if (OpenVR.System != null) return;

        var error = EVRInitError.None;
        OpenVR.Init(ref error, EVRApplicationType.VRApplication_Overlay);
        if (error != EVRInitError.None)
        {
            throw new Exception("Failed to initialize OpenVR: " + error);
        }
    }

+   private void ShutdownOpenVR()
+   {
+       if (OpenVR.System != null)
+       {
+           OpenVR.Shutdown();
+       }
+   }
}
Enter fullscreen mode Exit fullscreen mode

Final code

using UnityEngine;
using Valve.VR;
using System;

public class WatchOverlay : MonoBehaviour
{
    private void Start()
    {
       InitOpenVR();
    }

    private void OnDestroy()
    {
       ShutdownOpenVR();
    }

    private void InitOpenVR()
    {
        if (OpenVR.System != null) return;

        var error = EVRInitError.None;
        OpenVR.Init(ref error, EVRApplicationType.VRApplication_Overlay);
        if (error != EVRInitError.None)
        {
            throw new Exception("Failed to initialize OpenVR: " + error);
        }
    }

   private void ShutdownOpenVR()
   {
       if (OpenVR.System != null)
       {
           OpenVR.Shutdown();
       }
   }
}
Enter fullscreen mode Exit fullscreen mode

Here, we have initialized and cleaned up OpenVR. Now we can access OpenVR APIs like overlay. In the next part, we will create an overlay with this API.




Enter fullscreen mode Exit fullscreen mode

Top comments (0)