SteamVR Overlay with Unity: Draw Image

kurohuku

kurohuku

Posted on June 16, 2024

SteamVR Overlay with Unity: Draw Image

Prepare an image file

Prepare an image file that satisfies the following conditions.

  • Size is lower than 1920 x 1080 px.
  • File format is in PNG, JPG, or TGA (24 or 32 bit color)

From here on, I explain with my SNS icon named “sns-icon.jpg”.

Image description

Put the image file inside Assets/StreamingAssets folder.

Image description

Draw image

Call SetOverlayFromFile() to draw an image file. (read the wiki for details)

void Start()
{
    InitOpenVR();
    overlayHandle = CreateOverlay("WatchOverlayKey", "WatchOverlay");

+   var filePath = Application.streamingAssetsPath + "/sns-icon.jpg";
+   var error = OpenVR.Overlay.SetOverlayFromFile(overlayHandle, filePath);
+   if (error != EVROverlayError.None)
+   {
+       throw new Exception("Failed to draw image file: " + error);
+   }
}
Enter fullscreen mode Exit fullscreen mode

Pass the overlay handle and image file path to SetOverlayFromFile().
We use the StreamingAssets folder to get the file path at runtime with Application.streamingAssetsPath.
Error handling remains the same as before.

Run the program, then launch the Overlay Viewer.
Click WatchOverlayKey and check the image is drawing on the right preview area.

Image description

Switch overlay visibility

The overlay is hidden by default. It is shown on the Overlay Viewer but not in the VR space.
Switch the overlay visibility with ShowOverlay() and HideOverlay(). (read the wiki for details)

Let’s show the overlay with ShowOverlay() at the start of the application.

private void Start()
{
    InitOpenVR();
    overlayHandle = CreateOverlay("WatchOverlayKey", "WatchOverlay");

    var filePath = Application.streamingAssetsPath + "/sns-icon.jpg";
    var error = OpenVR.Overlay.SetOverlayFromFile(overlayHandle, filePath);
    if (error != EVROverlayError.None)
    {
        throw new Exception("Failed to draw image file: " + error);
    }

+   error = OpenVR.Overlay.ShowOverlay(overlayHandle);
+   if (error != EVROverlayError.None)
+   {
+       throw new Exception("Failed to show overlay: " + error);
+   }
}
Enter fullscreen mode Exit fullscreen mode

Run the program, put on your HMD, and look down at the floor. The overlay should appear at the center of the floor. Since overlays can’t be seen from the back, if you can’t view the overlay, move to the opposite side.

Image description

Image description
It shows during a VR game (the screenshot is Legendary Tales)

Organize code

Draw image file

Move the drawing code into SetOverlayFromFile().

void Start()
{
    InitOpenVR();
    overlayHandle = CreateOverlay("WatchOverlayKey", "WatchOverlay");

    var filePath = Application.streamingAssetsPath + "/sns-icon.jpg";
-   var error = OpenVR.Overlay.SetOverlayFromFile(overlayHandle, filePath);
-   if (error != EVROverlayError.None)
-   {
-       throw new Exception("Failed to draw image file: " + error);
-   }
+   SetOverlayFromFile(overlayHandle, filePath);

    error = OpenVR.Overlay.ShowOverlay(overlayHandle);
    if (error != EVROverlayError.None)
    {
        throw new Exception("Failed to show overlay: " + error);
    }
}

...

+ // Variable names changed
+ // overlayHandle -> handle
+ // filePath -> path
+ private void SetOverlayFromFile(ulong handle, string path)
+ {
+     var error = OpenVR.Overlay.SetOverlayFromFile(handle, path);
+     if (error != EVROverlayError.None)
+     {
+         throw new Exception("Failed to draw image file: " + error);
+     }
+ }
Enter fullscreen mode Exit fullscreen mode

Show overlay

Move the switching overlay visibility into ShowOverlay().

void Start()
{
    InitOpenVR();
    overlayHandle = CreateOverlay("WatchOverlayKey", "WatchOverlay");

    var filePath = Application.streamingAssetsPath + "/sns-icon.jpg";
    SetOverlayFromFile(overlayHandle, filePath);

-   error = OpenVR.Overlay.ShowOverlay(overlayHandle);
-   if (error != EVROverlayError.None)
-   {
-       throw new Exception("Failed to show overlay: " + error);
-   }
+   ShowOverlay(overlayHandle);
}

...

+ private void ShowOverlay(ulong handle)
+ {
+     var error = OpenVR.Overlay.ShowOverlay(handle);
+     if (error != EVROverlayError.None)
+     {
+         throw new Exception("Failed to show overlay: " + error);
+     }
+ }
}
Enter fullscreen mode Exit fullscreen mode

Final code

using UnityEngine;
using Valve.VR;
using System;

public class WatchOverlay : MonoBehaviour
{
    private ulong overlayHandle = OpenVR.k_ulOverlayHandleInvalid;

    private void Start()
    {
        InitOpenVR();
        overlayHandle = CreateOverlay("WatchOverlayKey", "WatchOverlay");

        var filePath = Application.streamingAssetsPath + "/sns-icon.jpg";
        SetOverlayFromFile(overlayHandle, filePath);
        ShowOverlay(overlayHandle);
    }

    private void OnApplicationQuit()
    {
        DestroyOverlay(overlayHandle);
    }

    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();
        }
    }

    private ulong CreateOverlay(string key, string name)
    {
        var handle = OpenVR.k_ulOverlayHandleInvalid;
        var error = OpenVR.Overlay.CreateOverlay(key, name, ref handle);
        if (error != EVROverlayError.None)
        {
            throw new Exception("Failed to create overlay: " + error);
        }
        return handle;
    }

    private void DestroyOverlay(ulong handle)
    {
        if (handle != OpenVR.k_ulOverlayHandleInvalid)
        {
            var error = OpenVR.Overlay.DestroyOverlay(handle);
            if (error != EVROverlayError.None)
            {
                throw new Exception("Failed to dispose overlay: " + error);
            }
        }
    }

    private void SetOverlayFromFile(ulong handle, string path)
    {
        var error = OpenVR.Overlay.SetOverlayFromFile(handle, path);
        if (error != EVROverlayError.None)
        {
            throw new Exception("Failed to draw image file: " + error);
        }
    }

    private void ShowOverlay(ulong handle)
    {
        var error = OpenVR.Overlay.ShowOverlay(handle);
        if (error != EVROverlayError.None)
        {
            throw new Exception("Failed to show overlay: " + error);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Here, we have displayed the image on the overlay. Next part, we will change the overlay size and position.

💖 💪 🙅 🚩
kurohuku
kurohuku

Posted on June 16, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related