How to properly disable ARTrackedImageManager

Hi everyone,
something weird is happening with my script, and it has to do with how the ARTrackedImageManager works.
Let me share a simplified version of my script:

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

public class TrackedImageInfoRuntimeManager : MonoBehaviour
{
    [SerializeField]
    private Text debugLog;

    [SerializeField]
    private Text currentImageText;

    [SerializeField]
    private GameObject prefabOnTrack;

    [SerializeField]
    XRReferenceImageLibrary xrReferenceImageLibrary;

    private ARTrackedImageManager trackImageManager;
    private GameObject arObjectToPlace;

    void Awake()
    {       
        arObjectToPlace = Instantiate(prefabOnTrack, Vector3.zero, Quaternion.identity);
        arObjectToPlace.SetActive(false);
    }

    void Start()
    {
        Application.targetFrameRate = 60;
        debugLog.text += "Creating Runtime Mutable Image Library\n";

        trackImageManager = gameObject.AddComponent<ARTrackedImageManager>();
        trackImageManager.referenceLibrary = trackImageManager.CreateRuntimeLibrary(xrReferenceImageLibrary);
        trackImageManager.requestedMaxNumberOfMovingImages = 1;
        // trackImageManager.trackedImagePrefab = prefabOnTrack;

        trackImageManager.enabled = true;

        trackImageManager.trackedImagesChanged += OnTrackedImagesChanged;

        ShowTrackerInfo();
    }

    public void ShowTrackerInfo()
    {
        var runtimeReferenceImageLibrary = trackImageManager.referenceLibrary as MutableRuntimeReferenceImageLibrary;

        debugLog.text += $"TextureFormat.RGBA32 supported: {runtimeReferenceImageLibrary.IsTextureFormatSupported(TextureFormat.RGBA32)}\n";
        debugLog.text += $"Supported Texture Count ({runtimeReferenceImageLibrary.supportedTextureFormatCount})\n";
        debugLog.text += $"trackImageManager.trackables.count ({trackImageManager.trackables.count})\n";
        debugLog.text += $"trackImageManager.trackedImagePrefab.name ({trackImageManager.trackedImagePrefab.name})\n";
        debugLog.text += $"trackImageManager.maxNumberOfMovingImages ({trackImageManager.requestedMaxNumberOfMovingImages})\n";
    }
    void OnDisable()
    {
        trackImageManager.trackedImagesChanged -= OnTrackedImagesChanged;
    }
    void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        foreach (ARTrackedImage trackedImage in eventArgs.added)
        {
            UpdateARImage(trackedImage);
        }

        foreach (ARTrackedImage trackedImage in eventArgs.updated)
        {
            UpdateARImage(trackedImage);
        }
    }

    public void EnableAR()
    {
        trackImageManager.enabled = true;
        debugLog.text = $"Status of AR is: {trackImageManager.enabled}\n";
    }

    public void DisableAR()
    {
        trackImageManager.enabled = false;
        debugLog.text = $"Status of AR is: {trackImageManager.enabled}\n";
    }

    private void UpdateARImage(ARTrackedImage trackedImage)
    {
        // Display the name of the tracked image in the canvas
        currentImageText.text = trackedImage.referenceImage.name;

        arObjectToPlace.SetActive(true);
        // Assign and Place Game Object
        arObjectToPlace.transform.parent = trackedImage.transform;
        arObjectToPlace.transform.localPosition = Vector3.zero;
        arObjectToPlace.transform.localScale = new Vector3(-trackedImage.referenceImage.size.x, 0.005f, -trackedImage.referenceImage.size.y);
        // AssignGameObject(trackedImage.referenceImage, trackedImage.transform.position);

        debugLog.text = $"trackedImage.position: {trackedImage.transform.position}\n prefab.position: {arObjectToPlace.transform.position}";
    }
}

The logic is simple: I instantiate an XRReferenceImageLibrary at runtime and set it to enabled = true. Then, if the camera detects one of the images included there, I instantiate an object on top of the detected image (a video player in this case) and print the name of the detected image on the screen.

I also added some buttons to the canvas that enable/disable the ARTrackedImageManager. Here's what causes the weird thing:
- I open the app
- I disable the ARTrackedImageManager and, indeed, when I frame the target image included in the XRReferenceImageLibrary no object gets instantiated.
- I then move the camera to a different area of the world where no target image is present and enable the ARTrackedImageManager again. My expectation was that I would not see anything until I focused again on the target image. Yet, it seems that as soon as I re-enable the ARTrackedImageManager, it knows that I previously framed the target image and instantly instantiate the object at the right place (and prints out the target image name), which basically means it runs the UpdateARImage method even if I'm not pointing the camera to the target image.

Can you explain such behaviour?
Is the ARTrackedImageManager always working on the background even when I set it to enabled = false? If it is disabled, how can it knows that I previously pointed the camera at the target image and why does it run the UpdateARImage?

I'd love to learn more because I would like to optimize an app that relies heavily on such AR manager (here's my other thread if you want to chime in).

1 Like

I've tried initializing the XRReferenceImageLibrary to enabled = false, and the curious thing is that when I do this and inspect the target image, if I point the camera to someplace else and then enable the ARTrackedImageManager, nothing happens (which is what it should be).
But then, if I click the DisableARTrackedImageManager button, point the camera to the target image, then point the camera someplace else and click the EnableARTrackedImageManager, the object is instantiated immediately.

The conclusion is that, once I set the XRReferenceImageLibrary to enabled = true, whether it being on Start or at a later point, and then set it to enabled = false, when I turn it on again it remembers that it previously saw the target image and instantiates the object at the right place, even if I'm not pointing the camera at the target image.

I hope my explanation is clear.

Anyone?

Enabling ARTrackedImageManager works once. I spent several days testing re-enabling image tracking staying in the current scene, but it seems there is no way in AR Foundation 5.1.2 to do it correctly except restarting the scene.

Unfortunately, there is no such demo AR Foundation Samples with enabling & disabling this manager @andyb-unity

So in my AR Business Card asset, I run the app with Non-AR Mode by default, and provide a one-time button to activate AR. The next AR Disabling goes through roundtrip (if the user really needs it): Demo > Menu > Demo.

Thank you for taking the time to answer anyway. Much appreciated

1 Like

When you disable the ARTrackedImageManager, that doesn't necessarily mean that the platform stops image tracking. It just means XRImageTrackingSubsystem stops retrieving the data from the platform. Image tracking may still be running, depending on the platform implementation, and can detect images. When ARTrackedImageManager is later enabled, XRImageTrackingSubsystem will start calling GetChanges which will report all of the tracked image data since the last time GetChanges was called before it was disabled. This means when you looked at the image, image tracking detected and was waiting on the subsystem to call get changes and when it finally did, the trackedImagesChanged event fired and the manager created the tracked image trackable at the position you looked at.

How can I achieve the experience manually (that I described above), such as when reloading a scene, but without reloading? I guess in this case, Image Tracking stops working. SceneUtility and SceneUtilitySetup are in the project.

@makaka-org Your most recent question in this thread is unrelated to OP’s post. Please make a new thread if you have new questions.