Search Unity

  1. Unity wants to learn about your experiences working on a Unity project today. We'd like to hear from you via this survey.
    Dismiss Notice
  2. Read here for Unity's latest plans on OpenXR.
    Dismiss Notice

Help Wanted How to detect if headset is available and initialize XR only if true?

Discussion in 'AR/VR (XR) Discussion' started by xofreshxo, Jul 7, 2020.

  1. xofreshxo

    xofreshxo

    Joined:
    Apr 12, 2017
    Posts:
    60
    Problem
    I'm working on a game that will be primarily played in VR. There are restrictions for some users that won't allow them to use VR. Those users need to be able to play using the desktop and an FPS controller. If I try to "Initialize XR on Startup" for the case that no VR headset is connected, I get errors.

    What I've tried
    I turned off the setting "Initialize XR on Startup" and this allows me to run in desktop mode when no headset is connected.
    I have a XR controller script that should 1) Check if hardware is present and 2)Initialize XR if hardware is present.

    Issues
    The only methods I came across for detecting if there are any headsets plugged in, seem to require XR be initialized.
    Code (CSharp):
    1.     public static bool isHardwarePresent()
    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.     }
    I also check InputDevices and got similar results. The list is empty unless XR is initialized.

    Code (CSharp):
    1.         List<InputDevice> deviceList = new List<InputDevice>();
    2.         InputDevices.GetDevices(deviceList);
    So if I don't initialize XR, I don't detect any headsets or inputs even when one is plugged in. If I attempt to initialize the XR loader, I get errors saying that it is unable to start the Oculus XR Plugin. A chicken and egg situation

    Code (CSharp):
    1.     public IEnumerator StartXR()
    2.     {
    3.         Debug.Log("Initializing XR...");
    4.         yield return XRGeneralSettings.Instance.Manager.InitializeLoader();
    5.  
    6.         if (XRGeneralSettings.Instance.Manager.activeLoader == null)
    7.         {
    8.             Debug.LogError("Initializing XR Failed. Check Editor or Player log for details.");
    9.         }
    10.         else
    11.         {
    12.             Debug.Log("Starting XR...");
    13.             XRGeneralSettings.Instance.Manager.StartSubsystems();
    14.         }
    15.     }
    Errors are given within InitializeLoader(), so I don't have the opportunity to provide an "else" statement in the case we cannot load.

    What I'm asking
    Is there a way to check if a headset is plugged in without initializing XR? Or is there a way to change the behavior within InitializeLoader() to not break the game if it cannot start plugins or load the subsystems? Any other feedback or suggestions are appreciated.

    Thanks
     
    Last edited: Jul 7, 2020
  2. jeromeatunity

    jeromeatunity

    Unity Technologies

    Joined:
    Jul 1, 2018
    Posts:
    7
    In general, breaking the controllers into separate scenes or prefabs and loading or instantiating them based on the availability of an XR sub-system after initialization. The default behaviour is to initialize on load and check in the first scene if an XR subsystem is loaded.

    Iterate through the display subsystems to see if anything running, indicating the user has an XR device connected. If VR is active, there will be an object in that list that returns true for its running property

    Code (CSharp):
    1. List<XRDisplaySubsystem> displaySubsystems = new List<XRDisplaySubsystem>();
    2.  
    3. SubsystemManager.GetInstances<XRDisplaySubsystem>(displaySubsystems);
    4.             foreach (var subsystem in displaySubsystems)
    5.             {
    6.              ...
    7.             }
    If nothing was connected you can load your FPS controller scene otherwise load the XR controller scene.

    You can do that XR initialization manually as described here and then go through that same routine.

    hth.
     
  3. xofreshxo

    xofreshxo

    Joined:
    Apr 12, 2017
    Posts:
    60
    I try the loop that you propose in my isHardwarePresent() function. The problem is that if XR is turned off, no headsets are ever detected. If XR is initialized (manually or automatically) and no headset is connected, we get an error immediately. I need a way to see if there are any available XR headsets before XR is initialized unless there is a way to override the function for giving an error.
     
  4. badawim-idcc

    badawim-idcc

    Joined:
    Dec 10, 2015
    Posts:
    10
    I'm having the exact same problem, and would love to know if a solution is found.

    I'll keep digging on my end and post anything relevant I find.
     
  5. badawim-idcc

    badawim-idcc

    Joined:
    Dec 10, 2015
    Posts:
    10
    If you're using OpenVR,
    OpenVR.IsHMDPresent()
    seems to do the trick.

    Here's my HMDChecker code, I don't have the same needs as you do, but I think it will answer your needs.

    Code (CSharp):
    1. public class HMDChecker : MonoBehaviour
    2. {
    3.     public XRLoader OpenVRLoader;
    4.     public XRLoader MockVRLoader;
    5.  
    6.     void Start()
    7.     {
    8.         XRGeneralSettings.Instance.Manager.loaders.Clear();
    9.  
    10.         if ( OpenVR.IsHmdPresent() )
    11.         {
    12.             XRGeneralSettings.Instance.Manager.loaders.Add(OpenVRLoader);
    13.         }
    14.         else
    15.         {
    16.             XRGeneralSettings.Instance.Manager.loaders.Add(MockVRLoader);
    17.         }
    18.  
    19.         XRGeneralSettings.Instance.Manager.InitializeLoaderSync();
    20.         XRGeneralSettings.Instance.Manager.StartSubsystems();
    21.     }
    22. }
    I'm still curious if there is a way to do this using native XR stuff.
     
  6. xofreshxo

    xofreshxo

    Joined:
    Apr 12, 2017
    Posts:
    60
    Thanks for the suggestion, I guess we'll try that out. However, I wish there was a way to do it using the native XR package, like you mentioned. As of right now we would only be including the OpenVR package for checking the HMD status. It probably exists, how else are we supposed to handle players who don't plug in their headsets without crashing the game?
     
  7. badawim-idcc

    badawim-idcc

    Joined:
    Dec 10, 2015
    Posts:
    10
    Well that solution lasted an entire weekend!

    The OpenVR XR plugin got update yesterday (august 3rd) and does not support legacy input anymore. So now you alos have to import the Steam VR Plugin for inputs to work... and that causes a conflict on the
    OpenVR
    symbol:
    Error    CS0433    The type 'OpenVR' exists in both 'SteamVR, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'Unity.XR.OpenVR, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'


    Back to the drawing board :'(
     
  8. Kleptine

    Kleptine

    Joined:
    Dec 23, 2013
    Posts:
    141
    This is pretty embarrassing. There doesn't seem to be any way to check for headsets without *enabling* an XRSubsystem, but enabling the Oculus subsystem immediately crashes if there is no headset connected.
     
  9. ErikWelling

    ErikWelling

    Joined:
    Dec 20, 2014
    Posts:
    1
    I might have found a solution that seems to be working (tested on 2019.4.5f1):


    Code (CSharp):
    1.     public XRLoader WMRLoader;
    2.     public XRLoader MockLoader;
    3.  
    4.     void Awake() {
    5.         XRGeneralSettings.Instance.Manager.loaders.Clear();
    6.  
    7.         //Initialize WMR.
    8.         XRGeneralSettings.Instance.Manager.loaders.Add(WMRLoader);
    9.         XRGeneralSettings.Instance.Manager.InitializeLoaderSync();
    10.         XRGeneralSettings.Instance.Manager.StartSubsystems();
    11.  
    12.         //Check if initialization was successfull.
    13.         var xrDisplaySubsystems = new List<XRDisplaySubsystem>();
    14.         SubsystemManager.GetInstances(xrDisplaySubsystems);
    15.         bool success = xrDisplaySubsystems[0].running;
    16.  
    17.         if (!success) {
    18.             //Initialization was not successfull, load mock instead.
    19.             print("loading mock");
    20.  
    21.             //Deinitialize WMR
    22.             XRGeneralSettings.Instance.Manager.loaders.Clear();
    23.             XRGeneralSettings.Instance.Manager.StopSubsystems();
    24.             XRGeneralSettings.Instance.Manager.DeinitializeLoader();
    25.  
    26.             //Initialize mock.
    27.             XRGeneralSettings.Instance.Manager.loaders.Add(MockLoader);
    28.             XRGeneralSettings.Instance.Manager.InitializeLoaderSync();
    29.             XRGeneralSettings.Instance.Manager.StartSubsystems();
    30.         }
    31.     }
    For this to work you need to disable "Initialize XR on Startup" in the XR Plug-in management settings.
    This one is made for Windows Mixed Reality but should work with any HMD.
     
    erlandu and Magasenakwa like this.
  10. erlandu

    erlandu

    Joined:
    Jan 31, 2020
    Posts:
    1
    Thanks! This is the first working solution I have seen and it's easy to modify to fall back to "normal 2D" when no loader starts ok.
     
  11. nixcry

    nixcry

    Joined:
    Mar 13, 2017
    Posts:
    2
    Try this:
    Code (CSharp):
    1.         public IEnumerator StartXR()
    2.         {
    3.             Debug.Log("Initializing XR...");
    4.             yield return XRGeneralSettings.Instance.Manager.InitializeLoader();
    5.  
    6.             if (XRGeneralSettings.Instance.Manager.activeLoader == null)
    7.             {
    8.                 Debug.LogError("Initializing XR Failed. Directing to Normal Interaciton Mode...!.");
    9.                 StopXR();
    10.                 DirectToNormal();
    11.             }
    12.             else
    13.             {
    14.                 Debug.Log("Initialization Finished.Starting XR Subsystems...");
    15.  
    16.                 //Try to start all subsystems and check if they were all successfully started ( thus HMD prepared).
    17.                 bool loaderSuccess = XRGeneralSettings.Instance.Manager.activeLoader.Start();              
    18.                 if(loaderSuccess)
    19.                 {
    20.                     Debug.Log("All Subsystems Started!");
    21.                 }
    22.                 else
    23.                 {
    24.                     Debug.LogError("Starting Subsystems Failed. Directing to Normal Interaciton Mode...!");
    25.                     StopXR();
    26.                     DirectToNormal();
    27.                 }
    28.             }
    29.         }
    30.  
    31.         void StopXR()
    32.         {
    33.             ...
    34.             Debug.Log("XR stopped completely.");
    35.         }
    36.         void DirectToNormal()
    37.         {
    38.             ...
    39.             Debug.Log("Fell back to Mouse & Keyboard Interaciton!");
    40.         }
    Just use XRLoader.Start() to detect if the Hmd is prepared, as this method returns a bool indicating Whether or not all subsystems were successfully started.

    It works for me, in scenario:
    Unity 2019.4.11
    XR Plugin Management 3.2.16 with
    Oculus XR Plugin 1.4.3 and
    OpenVR XR Plugin 1.0.1 enabled.
     
  12. Banksy

    Banksy

    Joined:
    Mar 31, 2013
    Posts:
    369
    umm for XR check is active or not I use

    InputBridge.Instance.HMDActive
     
    Last edited: Apr 20, 2021
  13. creat327

    creat327

    Joined:
    Mar 19, 2009
    Posts:
    1,335
    What's inputbridge? there is no such thing in unity
     
  14. creat327

    creat327

    Joined:
    Mar 19, 2009
    Posts:
    1,335
    I'm having a similar problem now that we are moving to OpenXR. Since we don't install OpenVR at all, we can't find a solution. All I'm trying to do is to detect if my device is ready and then decide if I need to setup the game for VR or for regular view. Anyone got it working with OpenXR and without OpenVR?
     
  15. Cloudwalker_

    Cloudwalker_

    Joined:
    Jan 3, 2014
    Posts:
    35
    Don't think there is an easy way to do this, you probably need to try starting the XRPlugin, if it succeeds + headset check, then you know. Otherwise no HMD and stop the XRPlugin if it did load successfully.
     
  16. creat327

    creat327

    Joined:
    Mar 19, 2009
    Posts:
    1,335
    nope, doesn't work
     
  17. Sab_Rango

    Sab_Rango

    Joined:
    Aug 30, 2019
    Posts:
    81
    for new OpenXR package to check the XR devices
    link https://docs.unity3d.com/Manual/xr_input.html#AccessingInputDevices

    Code (CSharp):
    1. var inputDevices = new List<UnityEngine.XR.InputDevice>();
    2. UnityEngine.XR.InputDevices.GetDevices(inputDevices);
    3.  
    4. foreach (var device in inputDevices)
    5. {
    6.     Debug.Log(string.Format("Device found with name '{0}' and role '{1}'", device.name, device.role.ToString()));
    7. }
    8.  
     
unityunity