7
\$\begingroup\$

The Oculus and the Vive have this light proximity sensor that detects whether you have your VR headset placed on your head currently or not.

Is there any way to tap into that for our own game checks? E.g. We could pause or restart the game depending on whether the headset's being worn or not.

I'm using Unity/C#, but any (driver / API level) help is much appreciated.

\$\endgroup\$
7
\$\begingroup\$

Yes, OpenVR has events for this:

VREvent_TrackedDeviceUserInteractionStarted fires when the devices transitions from Standby -> UserInteraction or Idle -> UserInteraction. VREvent_TrackedDeviceUserInteractionEnded fires when the devices transitions from UserInteraction_Timeout -> Idle

Additionally, you can poll the status of the headset with GetTrackedDeviceActivityLevel from Valve.VR.IVRSystem. Which will return one of the following values:

public enum EDeviceActivityLevel
{
    k_EDeviceActivityLevel_Unknown = -1,
    k_EDeviceActivityLevel_Idle = 0,
    k_EDeviceActivityLevel_UserInteraction = 1,
    k_EDeviceActivityLevel_UserInteraction_Timeout = 2,
    k_EDeviceActivityLevel_Standby = 3,
}

There's also some level of this introduced into the Unity scripts (Scripts/Core/VRView.cs:GetIsUserPresent()

\$\endgroup\$
  • \$\begingroup\$ Beautiful. In the meantime I also found the Oculus OVRManager.HMDMounted event in case anyone needs that. \$\endgroup\$ – Spectraljump May 23 '17 at 8:08
  • \$\begingroup\$ In Unity using the OpenVR plugin, the function to check is: OpenVR.System.GetTrackedDeviceActivityLevel(0) However, i noticed it doesn't check when the headset is on someone's head, it just tells you when the headset has moved. 10s of no motion and it goes back to standby. \$\endgroup\$ – niltoid Apr 18 '18 at 18:55
  • \$\begingroup\$ Likely depends on the device and how they've implemented their software to work with OpenVR. \$\endgroup\$ – MichaelHouse Apr 18 '18 at 19:08
  • \$\begingroup\$ Makes sense, in my case it's the HTC Vive \$\endgroup\$ – niltoid Apr 18 '18 at 19:40
2
\$\begingroup\$

Chiming in for checking a mounted / proximity sensor event for the Oculus OVR unity plugin. This is in OVRManager:

/// <summary>
/// Occurs when an HMD is put on the user's head.
/// </summary>
public static event Action HMDMounted;

/// <summary>
/// Occurs when an HMD is taken off the user's head.
/// </summary>
public static event Action HMDUnmounted;

Which is present in the source but for some reason does not come up by searching the oculus docs.

[EDIT]

Also, if you don't want Oculus to pause the game to a black screen when you take the headset off:

  • If you're using version 1.3 (2016) or below, of the Oculus SDK, then set runInBackground = true in OVRManager, which is independent from unity's own runInBackground setting.

  • In newer versions use Unity's Application.runInBackground = true and Camera.stereoTargetEye = StereoTargetEyeMask.None

[EDIT2]

The OVRManager events didn't work for me at all. What does work is using the OVRPlugin class and doing if (!OVRPlugin.userPresent && m_wasUserPresent) yourself.

\$\endgroup\$
2
\$\begingroup\$

In Unity, using the OpenVR unity plugin, the following works:

print(SteamVR_Controller.Input(0).GetPress(EVRButtonId.k_EButton_ProximitySensor));

BTW, in a response to the accepted answer i proposed: OpenVR.System.GetTrackedDeviceActivityLevel(0), but that's more for detecting recent motion within 10 seconds.

\$\endgroup\$
2
\$\begingroup\$

You can now also use UnityEngine.XR and XRDevice.userPresence without the need for additional API's : https://docs.unity3d.com/ScriptReference/XR.XRDevice-userPresence.html

For example :

if(trackingPresence == true)
    {
        if(XRDevice.userPresence == UserPresenceState.Present && playerPresent == false)
        {
            playerPresent = true;
            Debug.Log("[PLAYER PRESENCE DETECTOR] player is now present");
        }

        if(XRDevice.userPresence == UserPresenceState.NotPresent && playerPresent == true)
        {
            playerPresent = false;
            Debug.Log("[PLAYER PRESENCE DETECTOR] player is now absent");
        }
    }
\$\endgroup\$
  • \$\begingroup\$ Nice. Finally. Heads up that it's high level API and not explicitly the proximity: "The exact behavior of this property will vary with each type of device -- some devices will have a sensor specifically to detect user proximity, and users will rely on movement" \$\endgroup\$ – Spectraljump Jun 17 at 9:02
1
\$\begingroup\$

In Android, there is the Proximity Sensor. This is used to disable the screen when you're calling someone. I'm not sure if you have access to the proximity sensor in Unity, but you can call the native method through Unity.

\$\endgroup\$
1
\$\begingroup\$

If anyone wants to force the Oculus VR application to not pause the game while the headset is turned off, you need to do some dll stuff. [source]

Here's how, and I have also included code for the SteamVR / OpenVR settings:

    using System.Runtime.InteropServices;
    [DllImport("OVRPlugin", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool ovrp_SetAppIgnoreVrFocus(bool value);
    [DllImport("OVRPlugin", CallingConvention = CallingConvention.Cdecl)]
    public static extern uint ovrp_GetStatus2(uint query);

    void Start () {
        Application.runInBackground = true; 
        SteamVR_Render.instance.pauseGameWhenDashboardIsVisible = false;
        ovrp_SetAppIgnoreVrFocus(true);
        //ovrp_GetStatus2(uint query);
        //m_vrCam.stereoTargetEye = StereoTargetEyeMask.None;
    }
\$\endgroup\$
1
\$\begingroup\$

The SteamVR input has recently changed completely, it now uses Actions and here is a step by step tutorial from valve on how to set it up.

Here's one of the (best) ways to poll it in code:

    void Update(){


    //NOTE: I could have used one-off events. But I used these constant Update() polls instead because if the VR Dashboard is on while the headset is taken off or put on, 
    //then the OnDown and OnUp events get eaten by the dashboard and will never reach this code in unity. (github issue here: https://github.com/ValveSoftware/openvr/issues/628)

    // m_inputSourceDevice needs to be Any - there's no entry for "Headset", but the headset's sensors are reported under the Any "hand".
    SteamVR_Input_Sources m_inputSourceDevice = SteamVR_Input_Sources.Any;

    if(!m_isHeadsetOn && SteamVR_Input._default.inActions.Proximity_Sensor.GetState(m_inputSourceDevice)){
            Debug.Log("Headset On.");
            HeadsetOn();
    }
    else if(m_isHeadsetOn && !SteamVR_Input._default.inActions.Proximity_Sensor.GetState(m_inputSourceDevice)){
        Debug.Log("Headset Off (cancellable)");
        StartCoroutine(HeadsetOff());
    }

}

Note that as of right now, there is a bug that prevents you from using SteamVR to assign the Proximity Sensor to an action if you have a HTC Vive or Vive Pro, even though ironically it works as intended if you're using it with an Oculus headset. There is an easy fix on this steamvr github issues page.

Also note that even though the builtin unity OpenVR usually implements what SteamVR comes up with, for now it does not let you access the proximity sensor. The only thing you can do with OpenVR is to check the EDeviceActivityLevel as MichaelHouse explained in his answer. However that is useless because the only level that involves the prox sensor is the k_EDeviceActivityLevel_UserInteraction but it's a union of both the prox and the gyro, so according to OpenVR the headset is always interacting with the user forever as long as a gentle breeze or vibration tilts the headset a little bit once every 10 seconds.

[EDIT]

Some things got fixed in the meantime. For instance now there is an entry for the Hmd, instead of Any; and OpenVR does have an XRDevice.userPresence value (though it might not explicitly be the proximity sensor).

\$\endgroup\$
  • \$\begingroup\$ Thanks for creating a new answer with the latest info! \$\endgroup\$ – MichaelHouse Oct 24 '18 at 19:44
0
\$\begingroup\$

For OVR ovr_GetSessionStatus() tells you this, OVRSessionStatus has a field HmdMounted.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.