AR Reset Marker Tracking

My Scenario:
I have a number of markers that can be scanned and viewed at once. This all works fine. However, my client uses tablets that aren’t so great and if put down for a minute they lose the tracking and they have to stop and restart the app.
They have requested that I put in a Restart button so they don’t have to leave the app. The button I have added, and am able to remove the gameobjects from the list (easy). If you are following my thread so far then you will know what’s coming… attempting to scan the marker again doesn’t display the gameobject for that marker because the tracked images list hasn’t been cleared and it assumes it’s still there but it isn’t.
I have researched and found no solution as most threads are from a year or so ago and longer. I am hoping that someone has a solution or it has been resolved at Unity. Here’s the code. Any help would be appreciated. Thanks!

============================

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

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

public class AR_ImageTracker : MonoBehaviour
{
private ARTrackedImageManager trackedImages;
public GameObject[ ] ArPrefabs;

List ARObjects = new List();

void Awake()
{
trackedImages = GetComponent();
}

void OnEnable()
{
trackedImages.trackedImagesChanged += OnTrackedImagesChanged;
}

void OnDisable()
{
trackedImages.trackedImagesChanged -= OnTrackedImagesChanged;
}

// Event Handler
private void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
{
//Create object based on image tracked
foreach (var trackedImage in eventArgs.added)
{
foreach (var arPrefab in ArPrefabs)
{
if (trackedImage.referenceImage.name == arPrefab.name)
{
var newPrefab = Instantiate(arPrefab, trackedImage.transform);
ARObjects.Add(newPrefab);
}
}
}

//Update tracking position
foreach (var trackedImage in eventArgs.updated)
{
foreach (var gameObject in ARObjects)
{
if (gameObject.name == trackedImage.name)
{
gameObject.SetActive(trackedImage.trackingState == TrackingState.Tracking);
}
}
}

//Remove tracking position
foreach (var trackedImage in eventArgs.removed)
{
foreach (var gameObject in ARObjects)
{
if (gameObject.name == trackedImage.name)
{
Destroy(gameObject);
}
}

}
}

public void ResetTracking() // Add a public method for reset functionality
{

foreach (var gameObject in ARObjects)
{
Destroy(gameObject);
}
ARObjects.Clear();

// Optional: Reset AR Session for potential image rediscovery
var arSession = GetComponent();
if (arSession)
{
arSession.Reset();
}
}
}

============================

1 Like

Please file a bug for this issue: Unity QA: Building quality with passion.

We’ve seen a couple reports about invalid state issues with ARSession.Reset over the years, but no one has filed a bug.

A common recommendation you’ll see on this forum is LoaderUtility.Deinitialize / LoaderUtility.Initialize, but this is slower, and I don’t think this should be necessary to accomplish what you’re trying to do.

2 Likes

Based on my experience with AR Business Card asset, the only working solution is to restart the scene, so the app will not be restarted as you want.

So in the 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.

Thanks for the reply. I shall file as a bug :slight_smile:

1 Like

That’s a bit rough and nasty (sorry) but it may be a ‘for now’ solution.

Thanks for the reply.

1 Like

I agree. When you will have any solution or link to the Bug on Unity Issue Tracker, please share it here.

Apologies . I actually put the project down for quite some time to work on some other projects. Back to it and have logged the bug (if interested):

IN-86733 - AR Reset Marker Tracking

1 Like

Thank you - we will take look.

1 Like

I’ve not heard back about the bug that I filed but I did find a solution (thanks Andy) with some other adjustments. The below code now allows me to reset everything.
As a note, before I made the ARSession public to directly access it, it would crash out so wasn’t finding it under GetComponent().

Here’s the updated code:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
using UnityEngine;

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

public class AR_ImageTracker : MonoBehaviour
{
    private ARTrackedImageManager trackedImages;
    public GameObject[] ArPrefabs;
    public ARSession arSession;

    List<GameObject> ARObjects = new List<GameObject>();

    void Awake()
    {
        trackedImages = GetComponent<ARTrackedImageManager>();
    }

    void OnEnable()
    {
        trackedImages.trackedImagesChanged += OnTrackedImagesChanged;
    }

    void OnDisable()
    {
        trackedImages.trackedImagesChanged -= OnTrackedImagesChanged;
    }


    // Event Handler
    private void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        //Create object based on image tracked
        foreach (var trackedImage in eventArgs.added)
        {
            foreach (var arPrefab in ArPrefabs)
            {
                if (trackedImage.referenceImage.name == arPrefab.name)
                {
                    var newPrefab = Instantiate(arPrefab, trackedImage.transform);
                    ARObjects.Add(newPrefab);
                }
            }
        }

        //Update tracking position
        foreach (var trackedImage in eventArgs.updated)
        {
            foreach (var gameObject in ARObjects)
            {
                if (gameObject.name == trackedImage.name)
                {
                    gameObject.SetActive(trackedImage.trackingState == TrackingState.Tracking);
                }
            }
        }

        //Remove tracking position
        foreach (var trackedImage in eventArgs.removed)
        {
            foreach (var gameObject in ARObjects)
            {
                if (gameObject.name == trackedImage.name)
                {
                    Destroy(gameObject);
                }
            }
            
        }
    }


    public void ResetTracking() // Add a public method for reset functionality
    {

        foreach (var gameObject in ARObjects)
        {
            Destroy(gameObject);
        }

        ARObjects.Clear();

        if (arSession)
        {
            LoaderUtility.Deinitialize();
            LoaderUtility.Initialize();
            SceneManager.LoadScene(0, LoadSceneMode.Single);
        }
    }
}

Yeah this is what most people seem to be doing. I don’t know what the expected behavior is for ARSession.Reset. This is platform-defined. My expectation would be that this would clear any tracked images, but I’m not familiar enough with ARCore or ARKit to say for certain.

I see that your bug is still open and awaiting QA. Apologies for the delay. Keep us posted as you get status updates on that ticket.

3 Likes

hello

I was wondering if there was any update on this? im attempting to add an image tracking scene in the Vision Pro. when I reset the ar session it doesn’t seem to trigger anything when I look at the image. If I don’t reset it, the prefab automatically spawn on start which isnt what I want. My intended workflow is:

  • User looks at the image to spawn a prefab
  • User closes the app, resetting the scene
  • User re-opens the app, looks at the image, and the logic works the same as before.

Hi Harry. Yes I got a reply:

We determined that is actually an issue with your scene - the code in question isn’t on the same GameObject as the ARSession and therefore isn’t finding the session and calling reset().

Though I’m working on Android AR apps. The Apple setup is most likely different. Have you also posted a bug? If not then best to do that.

Looking back to my original code (at the beginning of this thread), I realise that I’m not referencing the ARSession properly (I think), so it never really finds it to do a ‘reset’ (though I didn’t get any errors and it runs as intended other than the reset soo … I don’t know!).

I’ll give it another look and test at some point but the last piece of code I posted works well enough so I will leave it for now as I am working on some other projects, but I know I’ll be back to do some AR apps at some point this year.

Let me know if you get it to work!

@harry_wakeling Your use case is achievable by deinitializing the XR Loader and then reinitializing it. Here’s the script that we use for this in our sample app: arfoundation-samples/Assets/Scripts/Runtime/SceneUtility.cs at main · Unity-Technologies/arfoundation-samples · GitHub