Key and Name
Overlay needs two strings key
and name
.
key
is a unique string among all overlays.
name
is just an overlay name sometimes shown to users.
We use "WatchOverlayKey"
and "WatchOverlay"
.
void Start()
{
InitOpenVR();
+ var key = "WatchOverlayKey";
+ var name = "WatchOverlay";
}
Overlay handle
Create a variable to save an overlay handle.
Similar to controlling a file with a file handle, overlays are controlled with an overlay handle.
void Start()
{
InitOpenVR();
var key = "WatchOverlayKey";
var name = "WatchOverlay";
+ var overlayHandle = OpenVR.k_ulOverlayHandleInvalid;
}
OpenVR.k_ulOverlayHandleInvalid means the overlay is not created. Overlay handle is ulong
type.
Create an overlay and get a handle
Use CreateOverlay() to create an overlay. (read the wiki for details)
Pass the key
and name
and reference of overlayHandle
to CreateOverlay()
.
void Start()
{
InitOpenVR();
var key = "WatchOverlayKey";
var name = "WatchOverlay";
var overlayHandle = OpenVR.k_ulOverlayHandleInvalid;
+ var error = OpenVR.Overlay.CreateOverlay(key, name, ref overlayHandle);
}
CreateOverlay()
sets overlay handle to the variable overlayHandle
.
The return value is an overlay creation error. All overlay errors are defined in EVROverlayError.
Error handling
Add error handling for overlay creation.
void Start()
{
InitOpenVR();
var key = "WatchOverlayKey";
var name = "WatchOverlay";
var overlayHandle = OpenVR.k_ulOverlayHandleInvalid;
var error = OpenVR.Overlay.CreateOverlay(key, name, ref overlayHandle);
+ if (error != EVROverlayError.None)
+ {
+ throw new Exception("Failed to create overlay: " + error);
+ }
}
If there is no error, EVROverlayError.None
is back.
Cleanup overlay
Add code to dispose of the overlay at the end of the application.
Move overlay handle
Move overlayHandle
from Start()
to the class member variable.
public class WatchOverlay : MonoBehaviour
{
+ private ulong overlayHandle = OpenVR.k_ulOverlayHandleInvalid;
private void Start()
{
InitOpenVR();
var key = "WatchOverlayKey";
var name = "WatchOverlay";
- var overlayHandle = OpenVR.k_ulOverlayHandleInvalid;
var error = OpenVR.Overlay.CreateOverlay(key, name, ref overlayHandle);
if (error != EVROverlayError.None)
{
throw new Exception("Failed to create overlay: " + error);
}
}
...
}
Dispose of overlay
The function for overlay cleanup is DestroyOverlay(). (read the wiki for details)
Add OnApplicationQut()
with overlay cleanup code.
public class WatchOverlay : MonoBehaviour
{
private ulong overlayHandle = OpenVR.k_ulOverlayHandleInvalid;
private void Start()
{
InitOpenVR();
var key = "WatchOverlayKey";
var name = "WatchOverlay";
var error = OpenVR.Overlay.CreateOverlay(key, name, ref overlayHandle);
if (error != EVROverlayError.None)
{
throw new Exception("Failed to create overlay: " + error);
}
}
+ private void OnApplicationQuit()
+ {
+ if (overlayHandle != OpenVR.k_ulOverlayHandleInvalid)
+ {
+ var error = OpenVR.Overlay.DestroyOverlay(overlayHandle);
+ if (error != EVROverlayError.None)
+ {
+ throw new Exception("Failed to dispose overlay: " + error);
+ }
+ }
+ }
private void OnDestroy()
{
ShutdownOpenVR();
}
...
}
DestroyOverlay()
must be called before Shutdown()
so we put the overlay cleanup code inside OnApplicationQuit()
that is called before OnDestroy()
.
Check created overlay
Check whether the overlay is created.
Overlay Viewer included in the SteamVR is useful to check overlays.
Select Developer > Overlay Viewer in the SteamVR menu.
Overlay Viewer displays a list of created overlays. You can see many overlays already created by SteamVR system.
In this state, run the program from Unity.
Then the overlay key WatchOverlayKey
is added to the list. You can see the overlay details by clicking the key.
The overlay preview is shown on the right side gray area but now we draw nothing to the overlay yet.
Here, we confirmed the overlay is created. Stop the program and close Overlay Viewer.
Optional: Overlay Viewer location
Overlay Viewer is located in the SteamVR install directory.
C:/ProgramFiles(x86)/Steam/steamapps/common/SteamVR/bin/win32/overlay_viewer.exe
We use this tool frequently during development so I recommend creating short cut.
Organize code
Create overlay
Move the overlay creation code intoCreateOverlay()
. It gets key
and name
as arguments, and return created overlay handle. Please note that some variable names are changed in code organization.
public class WatchOverlay : MonoBehaviour
{
private ulong overlayHandle = OpenVR.k_ulOverlayHandleInvalid;
private void Start()
{
InitOpenVR();
- var key = "WatchOverlayKey";
- var name = "WatchOverlay";
- var error = OpenVR.Overlay.CreateOverlay(key, name, ref overlayHandle);
- if (error != EVROverlayError.None)
- {
- throw new Exception("Failed to create overlay: " + error);
- }
+ overlayHandle = CreateOverlay("WatchOverlayKey", "WatchOverlay");
}
...
+ private ulong CreateOverlay(string key, string name) {
+ // Some code changed here.
+ 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;
+ }
}
Cleanup overlay
Similarly, move the overlay cleanup code into DestroyOverlay()
.
public class WatchOverlay : MonoBehaviour
{
...
private void OnApplicationQuit()
{
- if (overlayHandle != OpenVR.k_ulOverlayHandleInvalid)
- {
- var error = OpenVR.Overlay.DestroyOverlay(overlayHandle);
- if (error != EVROverlayError.None)
- {
- throw new Exception("Failed to dispose overlay: " + error);
- }
- }
+ DestroyOverlay(overlayHandle);
}
...
+ // overlayHandle -> handle variable name changed.
+ 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);
+ }
+ }
+ }
}
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");
}
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);
}
}
}
}
With that, we have created and cleaned up an overlay. Next part, we will draw an image file to the overlay.
Top comments (0)