Magic Leap Unity App: Inconsistent Object Placement Relative to Marker on Restart

Give us as much detail as possible regarding the issue you're experiencing.

Unity Editor version: 2022.3.11f1
ML2 OS version: 1.4.0-dev2
MLSDK version: 1.11.0
Host OS: Windows 10
Hello,

I am currently working on a Unity application for Magic Leap 2 using the MLMarkerTracker. The application involves placing a virtual object relative to a detected marker. However, I am encountering an issue where the object's placement is inconsistent when restarting the device from different positions.

Problem Description:

  • The virtual object appears rotated or offset after restarting the Magic Leap device.
  • I am using MLMarkerTracker to detect markers, and the object is instantiated based on the marker's pose.
  • Despite efforts to calculate relative positions and rotations, the inconsistency persists.

Code Summary:

using UnityEngine;
using UnityEngine.XR.MagicLeap;

public class MarkerTracking : MonoBehaviour
{
    public float qrCodeMarkerSize;
    public float arucoMarkerSize;
    public MLMarkerTracker.MarkerType markerType;
    public MLMarkerTracker.ArucoDictionaryName arucoDict;
    public GameObject trackerObject;

    private Transform cameraTransform;

    private void Start()
    {
        MLMarkerTracker.TrackerSettings trackerSettings = MLMarkerTracker.TrackerSettings.Create(
            true, markerType, qrCodeMarkerSize, arucoDict, arucoMarkerSize, MLMarkerTracker.Profile.Default);

        _ = MLMarkerTracker.SetSettingsAsync(trackerSettings);

        cameraTransform = Camera.main.transform;
    }

    private void OnEnable()
    {
        MLMarkerTracker.OnMLMarkerTrackerResultsFound += OnTrackerResultsFound;
    }

    private void OnTrackerResultsFound(MLMarkerTracker.MarkerData data)
    {
        Vector3 relativePosition = cameraTransform.InverseTransformPoint(data.Pose.position);
        Quaternion relativeRotation = Quaternion.Inverse(cameraTransform.rotation) * data.Pose.rotation;

        GameObject obj = Instantiate(trackerObject, cameraTransform.TransformPoint(relativePosition), cameraTransform.rotation * relativeRotation);
        obj.transform.up = Vector3.up;
        obj.SetActive(true);

        _ = MLMarkerTracker.StopScanningAsync();
    }
}


I would appreciate any insights or suggestions on how to achieve consistent object placement relative to the marker, regardless of the device's restart position. If anyone has faced similar challenges or has expertise in Magic Leap development, your help would be invaluable.

Thank you!

@athanasios.melenikiotis Thank you for your detailed description of the issue :clap:

I think the issue you are observing comes from the OnTrackerResultsFound function. The Magic Leap Marker Tracker provides the marker data in world space, which means you can position the object using the marker data directly.

 GameObject obj = Instantiate(trackerObject, data.Pose.position, data.Pose.rotation);

If this results in an offset where the object appears behind or in front of the marker instead of directly on top of it, you may want to verify that the size of the marker specified in the initialization function is the physical size of the marker (in meters)

Hello, thank you for your help. The problem has not been completely solved. The object is displayed in the tracker. However, when I restart the ML2 and track the tracker from the side, the wall is also rotated accordingly. Do you have any idea how to fix this? The marker is 15x15 cm and the size that I pass in the code is 0.15.

@athanasios.melenikiotis Iā€™m not sure what you are referring to when you say ā€œ when I restart the ML2 and track the tracker from the side, the wall is also rotated ā€. Do you mind clarifying?

When I start my application and track the marker, my object is displayed. Then I quit the application. When I start the app again and track the marker, the object is tracked in the same place as before. However, if I now restart Magic Leap 2 from a different point than before, then start the application and track the marker, the object is rotated or moved a little further to the right or left. It is only a few centimetres, but it is still not in the same position as before.

The current code looks like this

using UnityEngine;
using UnityEngine.XR.MagicLeap;

public class MarkerTracking : MonoBehaviour
{
    public float qrCodeMarkerSize;
    public float arucoMarkerSize;
    public MLMarkerTracker.MarkerType markerType;
    public MLMarkerTracker.ArucoDictionaryName arucoDict;
    public GameObject trackerObject;

    private void Start()
    {
        MLMarkerTracker.TrackerSettings trackerSettings = MLMarkerTracker.TrackerSettings.Create(
            true, markerType, qrCodeMarkerSize, arucoDict, arucoMarkerSize, MLMarkerTracker.Profile.Default);

        _ = MLMarkerTracker.SetSettingsAsync(trackerSettings);

    }

    private void OnEnable()
    {
        MLMarkerTracker.OnMLMarkerTrackerResultsFound += OnTrackerResultsFound;
    }

    private void OnTrackerResultsFound(MLMarkerTracker.MarkerData data)
    {

        GameObject obj = Instantiate(trackerObject, data.Pose.position, data.Pose.rotation);
        obj.transform.up = Vector3.up;
        obj.SetActive(true);

        _ = MLMarkerTracker.StopScanningAsync();
    }
}


Are you seeing the offset after you scan the marker again or before rescanning the marker?

You may want to use spatial anchors to maintain the space point in space across multiple sessions. Naturally, the headset will experience some drift when moving across multiple areas or when regaining head pose.

Here is an overview on creating Spatial Anchors. Make sure you create a Space inside the spaces app before trying to create an anchor. Spatial Anchors Overview | MagicLeap Developer Documentation

See the following example on creating persistent content using anchors : Spatial Anchors Example Project | MagicLeap Developer Documentation

The application works in such a way that nothing is visible and only when the marker is scanned does a wall object appear. This is rotated/shifted by a few centimetres depending on where I restart the ML2. That's why I would say after the scan, because only then it's activated.

In the example on creating persistent content using anchors, I changed the Buildings Settings to Android and downloaded the .apk. Although I have saved three Spaces locally, none of them are displayed in the drop-down menu. This example scene displayed the spaces.

To make sure I understand, the space does not appear inside the spaces app after scanning a new space or just your application? Do you have the space management permission enabled in your build settings?

When you confirm to save a space, what does the panel say. Is there enough feature points for the map to be created?

Regarding the marker tracker. Some noise and error is expected when scanning markers. I recommend taking a few samples and asking the user to get closer to the marker to reduce the offset. The offset results from the angle at which the marker is scanned, lighting conditions and the amount of movement.

When I start this project ( Spatial Anchors Example Project | MagicLeap Developer Documentation ) the menu says "Cannot Get Localization Status. Result: InvalidParam". The dropdown menu shows nothing. When I click "Localize" then "No Spaces Found. Please create one." appears, althought I have Spaces saved in the Spaces Application.

The saving in the Spaces App is not a problem. I have problems with the Example apk.

Okay, thanks. Good to know. If I want to display a room in my application that is cut 1:1, then marker tracking is not the best solution, unless the ML2 is always started at the same point and the code is scanned at the same point at the same distance. Right?

I recommend trying to rebuild the APK with the SDK version that matches your OS. Unfortunately, I have not been able to reproduce the issue you are referring to so I also recommend testing the Unity Examples project and it's spatial anchor demo.

If you want to overlay the virtual object over the real world, you can you techniques to reduce the % error. For example: Taking multiple samples of the marker position before stopping detection. Using multiple markers around the space and uses a closest fit algorithm.

Just a heads up this call can reset rotation, which may be causing the offset you are seeing.
-Sidney