Search Unity

Question XR Plug-In Management and MARS: manual initialization

Discussion in 'Unity MARS' started by tteneder, Jul 10, 2020.

  1. tteneder

    tteneder

    Unity Technologies

    Joined:
    Feb 22, 2011
    Posts:
    175
    Hi,

    recent ARFoundation versions utilize the XR Plug-In Management. In my use-case I don't want AR (ARKit in my case) to be initialized at start, but rather when the AR/MARS scene is loaded.

    I disabled "Initialize XR on Startup" in Project Settings -> XR Plug-In Management. With ARFoundation (only) this works after some manual init code.

    How do you pull this off with MARS? My screen stays black :/

    Thanks a lot in advance,

    atti
     
  2. leweyg_unity

    leweyg_unity

    Unity Technologies

    Joined:
    Jan 29, 2020
    Posts:
    38
    Hey @atti ,
    This may be tricky, couple of suggestions:

    - Easiest way is probably using separate scenes (but sound like you already tried this): firstly without AR, and then switch to the AR enabled scene.

    - Try having the ARSession in your scene already, so that MARS will use that instead of initializing it's own. That may do it.
     
  3. tteneder

    tteneder

    Unity Technologies

    Joined:
    Feb 22, 2011
    Posts:
    175
    thanks for your suggestions.

    I tried a lot for a whole day and eventually found a way that works. I used the MARS sample scene "Game_Simple" as a minimum use case:

    Create an initial scene with nothing but the following starter script. It starts XR and loads the actual MARS scene afterwards:

    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3. using UnityEngine.XR.ARFoundation;
    4. using UnityEngine.XR.Management;
    5. using UnityEngine.SceneManagement;
    6.  
    7. public class ARStarter : MonoBehaviour {
    8.     void Start() {
    9. #if UNITY_EDITOR
    10.         LoadARScene();
    11. #else
    12.             StartCoroutine(StartXR());
    13. #endif
    14.     }
    15.  
    16.     public IEnumerator StartXR() {
    17.         yield return XRGeneralSettings.Instance.Manager.InitializeLoader();
    18.  
    19.         if (XRGeneralSettings.Instance.Manager.activeLoader == null) {
    20.             Debug.LogError("Initializing XR Failed. Check Editor or Player log for details.");
    21.         } else {
    22.             Debug.Log("Starting XR...");
    23.             XRGeneralSettings.Instance.Manager.StartSubsystems();
    24.             yield return null;
    25.             LoadARScene();
    26.         }
    27.     }
    28.  
    29.     void LoadARScene() {
    30.         SceneManager.LoadScene("Game_Simple", LoadSceneMode.Single);
    31.     }
    32.  
    33.     void StopXR() {
    34.         Debug.Log("Stopping XR...");
    35.         XRGeneralSettings.Instance.Manager.StopSubsystems();
    36.         XRGeneralSettings.Instance.Manager.DeinitializeLoader();
    37.         Debug.Log("XR stopped completely.");
    38.     }
    39. }
    40.  
    Any other attempt ( loading scene additionally or single scene that enables MARS/AR components once XR started) failed.

    I'm now trying to apply this to my real world project.
     
    HYPERSONICs likes this.
  4. tteneder

    tteneder

    Unity Technologies

    Joined:
    Feb 22, 2011
    Posts:
    175
    Here's another version for projects where AR is optional. It tries to auto-detect if AR is supported:

    UPDATE: This does not work on non-ARKit compatible devices!!!

    Code (CSharp):
    1.     public IEnumerator StartXR() {
    2.  
    3.         yield return XRGeneralSettings.Instance.Manager.InitializeLoader();
    4.  
    5.         if (XRGeneralSettings.Instance.Manager.activeLoader == null) {
    6.             Debug.LogError("Initializing XR Failed. Check Editor or Player log for details.");
    7.         } else {
    8.             Debug.Log("Starting XR...");
    9.             XRGeneralSettings.Instance.Manager.StartSubsystems();
    10.          
    11.            // Have to add an ARSession instance to avoid Null Pointer Dereference
    12.             gameObject.AddComponent<ARSession>();
    13.             yield return null;
    14.  
    15.             if ((ARSession.state == ARSessionState.None) ||
    16.                 (ARSession.state == ARSessionState.CheckingAvailability))
    17.             {
    18.                 yield return ARSession.CheckAvailability();
    19.             }
    20.  
    21.             if (ARSession.state == ARSessionState.Unsupported)
    22.             {
    23.                 Debug.LogError("AR is not supported! Do some fallback");
    24.                 yield break;
    25.             }
    26.  
    27.             LoadARScene();
    28.         }
    29.     }
    30.  
     
    Last edited: Aug 18, 2020
  5. tteneder

    tteneder

    Unity Technologies

    Joined:
    Feb 22, 2011
    Posts:
    175
    Sadly I have to report, that the code in the last post (optional AR) is NOT working.

    Testing this on an iPhone 6 the ARSession.state ends up being ArSessionState.Ready :/

    Should I file an issue or am I doing something obviously wrong?
     
  6. leweyg_unity

    leweyg_unity

    Unity Technologies

    Joined:
    Jan 29, 2020
    Posts:
    38
    Hey @atti , have you tried with a clean project to get just the AR Foundation delayed initialization working? We can try pull in someone from the AR Foundation team if that helps. Also I would not be surprised if this is related to the version of iPhone you are using, you may want to consider only supporting later devices for the AR aspect.
     
  7. tteneder

    tteneder

    Unity Technologies

    Joined:
    Feb 22, 2011
    Posts:
    175
    Hi leweyg,

    I didn't properly describe the context. With the above method MARS is working on devices that support it (good so far).

    What I try to handle is devices that don't support ARKit (like the iPhone 6) and provide a fallback. I'd expect ARSession.state to be ArSessionState.Unsupported on those devices.

    I worked around this by manually detecting support for now:

    Assets/Plugins/iOS/MyCustomARKitCheck.mm:
    Code (CSharp):
    1. #import <ARKit/ARKit.h>
    2.  
    3. extern "C" {
    4.     bool MyCustomCheckARKitSupport() {
    5.         return ARWorldTrackingConfiguration.isSupported;
    6.     }
    7. }
    8.  
    and in C#:

    Code (CSharp):
    1. using System.Runtime.InteropServices;
    2. if(!MyCustomCheckARKitSupport()) {
    3.             Debug.LogError("ARKit is not supported!");
    4. }
    5.  
    6. [DllImport ("__Internal")]
    7. extern static bool MyCustomCheckARKitSupport();
     
  8. leweyg_unity

    leweyg_unity

    Unity Technologies

    Joined:
    Jan 29, 2020
    Posts:
    38
    Hey @atti , thanks for the clarification that this is about devices that DO NOT support AR Foundation (iPhone 6 etc.)... and it looks like you have code to detect this case. The question is now how to disable those parts of MARS which may interact with ARF? If that is the case, I believe the trick may be to use a custom "Default Island" or modify it at runtime (something like Assets/MARS/Settings/FunctionalityIslands/Default Island.asset ), so that you can configure which systems are spun up (and disable any that would cause AR Foundation to launch)? How does that sound? Or what issue are you trying to solve here?
     
  9. tteneder

    tteneder

    Unity Technologies

    Joined:
    Feb 22, 2011
    Posts:
    175
    All I wanted is optional AR with a fallback-detection. In my case the fallback is a legacy(non-MARS), custom, gyroscope-based experience. I don't want to re-invent this fallback (in other words re-build it on MARS) as it'll fade away eventually.

    MARS/ARF gives devs a good abstraction layer, so I tried to make the AR Subsystem detection abstract as well, but couldn't get it to work (with non-ARKit iOS devices).

    I'll go with my workaround posted above, even if it's not as abstract as MARS/ARF.

    Anyways, thanks for your support!
     
  10. StayTalm_Unity

    StayTalm_Unity

    Unity Technologies

    Joined:
    May 3, 2017
    Posts:
    182
    Did a quick scan of the code, it looks like the 'ARSessionState.Ready' bug is known & fixed. It's just making it's way down the pipes. Edit: Fixed in 4.1.0 Preview 6, being backported.

    As for initializing manually, what you are doing works. Another available option is to create an 'ARSession' Component on a Monobehaviour and start with it disabled. You can then enable the ARSession component in order to start up AR Foundation. You can also call `yield return ARSession.CheckAvailability();` to refresh ARSession.state to check if it can be enabled without enabling it.

    MARS should grab an existing ARSession Monobehaviour if one is already created, giving you manual control. ARSession also does a lazy initialization, so it will initialize and start subsystems if necessary, or use whatever was already initialized.
     
    Last edited: Aug 18, 2020
    tteneder likes this.
  11. tteneder

    tteneder

    Unity Technologies

    Joined:
    Feb 22, 2011
    Posts:
    175
    That's great to hear! Thanks for your excellent support!