Search Unity

XRDevice.isPresent with XRManagement on Quest

Discussion in 'AR/VR (XR) Discussion' started by Solovykh, Jan 28, 2020.

  1. Solovykh

    Solovykh

    Joined:
    Aug 28, 2017
    Posts:
    59
    Hey,

    It seems like XRDevice.isPresent always returns false on 2019.3.0f6 with the new XR Management system on Oculus Quest. Is that expected?
     
  2. Claytonious

    Claytonious

    Joined:
    Feb 16, 2009
    Posts:
    902
    Please report a bug.
     
  3. Solovykh

    Solovykh

    Joined:
    Aug 28, 2017
    Posts:
    59
    Submitted a bug report. Case: 1215467

    Thanks for the advice @Claytonious
     
    Last edited: Jan 29, 2020
    AlanMattano and ROBYER1 like this.
  4. Claytonious

    Claytonious

    Joined:
    Feb 16, 2009
    Posts:
    902
    Thank you for doing that, but don't link to your bug reports on Fogbugz - that exposes *all* of your bug reports to the public, including future ones where you might attach some files or links or info that you don't want to share with the world. Just post the case number itself (in this case, 1215467).

    But thanks again, let's hope it gets fixed now!
     
    Last edited: Jan 29, 2020
    Solovykh likes this.
  5. StayTalm_Unity

    StayTalm_Unity

    Unity Technologies

    Joined:
    May 3, 2017
    Posts:
    182
    AlanMattano likes this.
  6. Solovykh

    Solovykh

    Joined:
    Aug 28, 2017
    Posts:
    59
    I was under the impression that CommonUsage.userPresence is a replacement for XRDevice.userPresence which tells me if the user is wearing the headset or not. However, XRDevice.isPresent told me if an HMD was connected or not. Is there anything like that with the InputDevice API?
     
  7. StayTalm_Unity

    StayTalm_Unity

    Unity Technologies

    Joined:
    May 3, 2017
    Posts:
    182
    Oh right, I read that too fast.
    That should be even easier (in pseudocode written in this chat bar):

    List<InputDevice> devices = new List<InputDevice>();
    InputDevices.GetDevicesWithCharacteristics(InputDeviceCharacteristics.HeadMounted, devices);
    bool isPresent = devices.Count > 0;

    If a head mounted device is connected, then the device is present.
     
    AlanMattano and Solovykh like this.
  8. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    So, what ... the API call XRDevice.isPresent ... is now obsolete, and shouldn't be used at all? If so, shouldn't that be documented???
     
    VirtualPierogi and shomz like this.
  9. JurjenBiewenga

    JurjenBiewenga

    Joined:
    Mar 28, 2018
    Posts:
    24
    This still seems to be broken or undocumented behaviour. @StayTalm_Unity
     
    VirtualPierogi and fherbst like this.
  10. ash_at_unity3d

    ash_at_unity3d

    Unity Technologies

    Joined:
    Jan 9, 2020
    Posts:
    41
    Hey @JurjenBiewenga

    I'm currently looking into this; I'm updating the documentation and API to reflect the appropriate approach as described in this thread.

    I'll update this thread once it's live.
     
  11. fherbst

    fherbst

    Joined:
    Jun 24, 2012
    Posts:
    802
    Please note that the current "undocumented" situation is downright dangerous.

    I just spent two full days debugging total weirdness of one of our applications, and it turns out that with XRManagement active, XRDevice.refreshRate returns 0, while with "Legacy VR" it returns 72. Case 1240243

    Also @ash_at_unity3d it doesn't seem like refresh rate is part of the new xr_input API, or is it just not documented? How do I get the device refresh rate in XR Management? This is important to get frame-perfect physics, smooth animations, ...
     
  12. JanSelchow

    JanSelchow

    Joined:
    Jul 2, 2020
    Posts:
    1
    Are there any Updates on this. I want to detect if a VR-Headset is connected.
    On unity 2019.4.9f1 i have a WindowsMR Headset connected but both
    Code (CSharp):
    1. List<InputDevice> devices = new List<InputDevice>();
    2. InputDevices.GetDevicesWithCharacteristics(InputDeviceCharacteristics.HeadMounted, devices);
    3. bool isPresent = devices.Count > 0;
    and
    Code (CSharp):
    1. XRDevice.isPresent
    is always false.
     
  13. hrgchris

    hrgchris

    Joined:
    Oct 26, 2016
    Posts:
    19
    XRDevice.isPresent is still not marked as deprecated in Unity, so it took me an hour to find this. Are you intending to update.

    Also, I'd just like to voice some concern here. The massive part of the idea of Unity is to be *simple* for users.However according to the docs, the need to call XRDevice.isPresent has been replaced with the need to write the code:

    Code (CSharp):
    1.     public static bool isPresent()
    2.     {
    3.         var xrDisplaySubsystems = new List<XRDisplaySubsystem>();
    4.         SubsystemManager.GetInstances<XRDisplaySubsystem>(xrDisplaySubsystems);
    5.         foreach (var xrDisplay in xrDisplaySubsystems)
    6.         {
    7.             if (xrDisplay.running)
    8.             {
    9.                 return true;
    10.             }
    11.         }
    12.         return false;
    13.     }
    Not to mention the fact that the whole concept of sub systems is totally undocumented.

    Does this not seem like a step backwards?
     
  14. arkon

    arkon

    Joined:
    Jun 27, 2011
    Posts:
    1,122
    XR on unity is a mess!
     
    JanSelchow likes this.
  15. SunnyChow

    SunnyChow

    Joined:
    Jun 6, 2013
    Posts:
    360
    With Oculus Quest 2 (Oculus Link), it's the opposite for me. it's always true even when i put down the headset
     
  16. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,501
    I do not understand.
    I make a new Project using the VR default Template
    My VR device (Samsung Odyssey) is working fine with Unity 2019.4.18 LTS.
    But
    Code (CSharp):
    1. UnityEngine.XR.XRDevice.isPresent
    is always "false" as if there is no device.
     
  17. Barliesque

    Barliesque

    Joined:
    Jan 12, 2014
    Posts:
    128
    Working in Unity 2020.1.11f1 the following code works to detect user presence on the Oculus Rift S, but always returns false on Quest 2:

    Code (CSharp):
    1.  
    2. if (!_headset.isValid) _headset = InputDevices.GetDeviceAtXRNode(XRNode.CenterEye);
    3. _headset.TryGetFeatureValue(CommonUsages.userPresence, out bool present);
    As far as the new XR api goes, I'm quite happy with this approach. But the code presented in earlier posts by @StayTalm_Unity and @hrgchris would not be appropriate to be called every frame as it involves instantiating a list of devices. Is there any other efficient and reliable way to check for user presence?
     
    Last edited: Feb 6, 2021
    VirtualPierogi likes this.
  18. StayTalm_Unity

    StayTalm_Unity

    Unity Technologies

    Joined:
    May 3, 2017
    Posts:
    182
    That usage should work on the Quest 2, I'll ask around internally why user presence isn't supported.

    If you want to just check that a device exists you can get the current list of devices on startup, and then register to the onDeviceConnected callback: https://docs.unity3d.com/ScriptReference/XR.InputDevices-deviceConnected.html
    This will notify you of any new devices so you can assume that if there was no HMD on startup, and no callback with an HMD Input Device, there is still no HMD connected. The HMD should always be connected on first frame (Depending on platform it can sometimes be before Awake, sometimes it takes the first Update), because it is the device running the app, but the above is a good practice for 'Get All, then Notify of changes' pattern.
     
  19. Barliesque

    Barliesque

    Joined:
    Jan 12, 2014
    Posts:
    128
    Thanks for the reply. I simply want to pause the game while the user isn't wearing the headset. So, onDeviceConnected isn't really useful, unfortunately.
     
  20. StayTalm_Unity

    StayTalm_Unity

    Unity Technologies

    Joined:
    May 3, 2017
    Posts:
    182
    Yeah, it sounds like User Presence is definitely what you need.
    A few questions:
    Have you filed a bug on it? Please do so, and sometimes it can get prioritized better than me nagging a team member.
    With Link cable or standalone? Or Both?
    When you say it's returning false, is `TryGetFeatureValue` returning false, or is `present` false after calling that function?
    The former means the feature doesn't exist on the device, the latter means the user is not present.
     
  21. bruceweir1

    bruceweir1

    Joined:
    Nov 29, 2017
    Posts:
    15
    The suggested replacements for XRDevice.isPresent above don't always work in Awake(). Moving them to Start() fixes them.
     
  22. hoesterey

    hoesterey

    Joined:
    Mar 19, 2010
    Posts:
    659
    I'm not loving awake vs start race conditions when interacting with engine systems they shouldn't exist.
     
  23. joejo

    joejo

    Unity Technologies

    Joined:
    May 26, 2016
    Posts:
    958
    XRDevice.isPresent is obsolete and should not be used. You can see replacement checking for display subsystem running state here: https://docs.unity3d.com/ScriptReference/XR.XRDevice-isPresent.html

    But even that will not get you an answer in Awake necessarily because there is no direct tie between running state being set and any specific MonoBehaviour callback. For OpenXR specifically, there can be a delay of 2 or more frames (Update calls) before it's fully up and running. You should check running state for some number of frames/time delta and use that to determine if the device display is running.

    I've reported a bug on that page to get that clarified.
     
    hoesterey likes this.
  24. nikokoneko

    nikokoneko

    Joined:
    Feb 20, 2015
    Posts:
    35
    The code on the documentation page, that is supposed to be used instead of XRDevice.isPresent is not working. It always return true, for Oculus Quest 2 at least.
     
    Ikaro88 likes this.
  25. Delt4a

    Delt4a

    Joined:
    Jan 23, 2020
    Posts:
    2
    Same as you, always returning true on a Vive Focus.
     
  26. nikokoneko

    nikokoneko

    Joined:
    Feb 20, 2015
    Posts:
    35
    Ok, so at least for Oculus Quest I found a consistent way of tracking user presence, and many other session state changes.
    First, I needed to use OpenXR instead of Oculus. Good riddance, as I found a range of wierd bugs with Oculus especially using Oculus Link. OpenXR works consistently well, unless you need some very specific Quest features like passthrough features which I did not test.
    So, first switch from Oculus to OpenXR:
    Project Settings > XR Plugin In Management do not use Oculus, use OpenXR instead.
    Caveat: If you use default XR rig, by default the controllers will not be tracked, but it's easily fixed:
    In Project Settings > XR Plugin In Management>OpenXR under Interaction Profiles add a Oculus Touch Controller profile.

    Now to track state changes you want to use OpenXRFeatures which is a bit obscure functionality that I discovered by accident. However there is a very good post describing how to use it:

    https://forum.unity.com/threads/how-do-you-implement-openxr-focus-management-in-unity-2020.1117141/

    TLDR:
    The code is below.
    In order for code to work you need to enable the new feature in:
    Project Settings > XR Plugin In Management>OpenXR>OpenXR Feature Groups where you will now see a new feature group called VR State Tracking (or whatever you deide to call the feature, in UiName variable):

    Code (CSharp):
    1.  
    2. using UnityEditor;
    3. using UnityEngine;
    4. using UnityEngine.XR.OpenXR.Features;
    5. #if UNITY_EDITOR
    6. [UnityEditor.XR.OpenXR.Features.OpenXRFeature(UiName = "VR State Tracking",
    7.     BuildTargetGroups = new[] { BuildTargetGroup.WSA, BuildTargetGroup.Standalone, BuildTargetGroup.Android },
    8.     Company = "Your Company",
    9.     Desc = "Tracks state changes.",
    10.     Version = "0.0.1",
    11.     FeatureId = featureId)]
    12. #endif
    13.  
    14.  
    15. public class MyOwnXRFeature : OpenXRFeature
    16. {
    17.     public const string featureId = "com.yourcompany.features.statetracking";
    18.  
    19.  
    20.     // This is to change a number of state changes in a very granular way:
    21.     protected override void OnSessionStateChange(int oldState, int newState)
    22.     {
    23.         Debug.Log($"OnSessionStateChange: {oldState} -> {newState}");
    24.     }
    25.  
    26.     // This will happen when headset put on:
    27.     protected override void OnSessionBegin(ulong xrSession)
    28.     {
    29.         Debug.Log($"Feature OnSessionBegin: {xrSession}");
    30.     }
    31.  
    32.     // This will happen when headset taken off:
    33.     protected override void OnSessionEnd(ulong xrSession)
    34.     {
    35.         Debug.Log($"eatureOnSessionEnd: {xrSession}");
    36.     }
    37.  
    38. }
     
  27. phileday

    phileday

    Joined:
    Feb 8, 2014
    Posts:
    121

    Hi

    I know this is a post from a while back but I still hope you can help. This might be a really stupid question as well but it's something I've never managed to get my head around. Basically The script works but I don't know how to access the information. As it doesn't derive from MonoBehaviour I can't stick it on an object. It does send info to the console when the headset is removed and put back on but I don't know how to read from a script like this or get this script to set something I can read with other scripts in the project.

    I feel like I'm missing a really obvious thing here. I hope you can point me in the right direction.

    All the best

    Phil
     
  28. Claytonious

    Claytonious

    Joined:
    Feb 16, 2009
    Posts:
    902
    Where that script currently calls Debug.Log(), call into your own classes or scripts. For example, call a static method in your own class, it raise an event from a static class that your own scripts subscribe to, or whatever you like.