Objects instantiate with a major position offset from markers in marker tracking

Hey All!
I wrote a script that detects markers and spawns a game object (In this case, a prefab of type "World Object" based on the id of the marker) on the position of the marker. the script is based on the Example scene. The problem is that all objects instantiate in a major offset from the marker itself, both in app simulator and in ML2 build. The problem occurs both for QR and ArUco.

In the simulator I added markers with the length of 100 and set the "QrCodeMarkerSize" and "ArucoMarkerSize" variables to 0.1f. From other topics in the forum it appears maybe there's something i am missing here with the scale of the marker or the object?

Code is Attached below:

using MagicLeap.Examples;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.XR.MagicLeap;

public class MLMarkerIdentifier : MonoBehaviour
{

        #region Serialized fields        

        [SerializeField] private float QrCodeMarkerSize = 0.1f;

        [SerializeField] private float ArucoMarkerSize = 0.1f;

        [SerializeField] private MLMarkerTracker.MarkerType Type = MLMarkerTracker.MarkerType.Aruco_April;

        [SerializeField] private MLMarkerTracker.ArucoDictionaryName ArucoDict = MLMarkerTracker.ArucoDictionaryName.DICT_5X5_50;

        [SerializeField] private MLMarkerTracker.Profile Profile = MLMarkerTracker.Profile.Default;

        [SerializeField] WorldObjectsLoader worldObjectsLoader;

        #endregion

        #region private fields

        private ASCIIEncoding _asciiEncoder = new ASCIIEncoding(); 
        
        private HashSet<string> _activeObjects = new HashSet<string>();

        private Camera _mainCamera;

        #endregion

        #region Mono Behaviour

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

        private void Start()
        {
            MLMarkerTracker.TrackerSettings trackerSettings = MLMarkerTracker.TrackerSettings.Create(
                true, Type, QrCodeMarkerSize, ArucoDict, ArucoMarkerSize, Profile);
            _ = MLMarkerTracker.SetSettingsAsync(trackerSettings);
            _mainCamera = Camera.main;

            
        }        

        private void OnDisable()
        {
            MLMarkerTracker.OnMLMarkerTrackerResultsFound -= OnTrackerResultsFound;
            _ = MLMarkerTracker.StopScanningAsync();
        }

        #endregion        

        /// <summary>
        /// Given a marker data, extract the code Id and determine marker size
        /// </summary>
        /// <param name="data"> marker data given by scanner </param>
        /// <returns>
        /// string - the code id.
        /// float - the marker size. 
        /// </returns>
        private string ExtractInfoFromMarkerData(MLMarkerTracker.MarkerData data)
        {
            string id = "";
            switch (data.Type)
            {
                case MLMarkerTracker.MarkerType.Aruco_April:
                    id = data.ArucoData.Id.ToString();
                    break;

                case MLMarkerTracker.MarkerType.QR:
                    id = _asciiEncoder.GetString(data.BinaryData.Data, 0, data.BinaryData.Data.Length);
                    break;

                case MLMarkerTracker.MarkerType.EAN_13:
                case MLMarkerTracker.MarkerType.UPC_A:
                    id = _asciiEncoder.GetString(data.BinaryData.Data, 0, data.BinaryData.Data.Length);
                    Debug.Log("No pose is given for marker type " + data.Type + " value is " + data.BinaryData.Data);
                    break;
            }

            return id;
        }

        private void SetObjectTransform(WorldObject worldObject ,MLMarkerTracker.MarkerData data)
        {
            // set the marker object transform
            worldObject.transform.position = data.Pose.position;  // marker.PositionOffset;
            
            Debug.Log("marker pos: " + data.Pose.position);
            Debug.Log("object pos: " + worldObject.transform.position);

            // make object face the player.
            Vector3 targetDirection = -(_mainCamera.transform.position - worldObject.transform.position);            
            Quaternion targetRotation = Quaternion.LookRotation(targetDirection);            
            worldObject.transform.rotation = Quaternion.Euler(0f, targetRotation.eulerAngles.y, 0f);


            // worldObject.transform.localScale = marker.scale;

            //Debug.Log($"marker position: {marker.transform.position.ToString()}, data position: {data.Pose.position}");
        }

        private void OnTrackerResultsFound(MLMarkerTracker.MarkerData data)
        {
            
            var id = ExtractInfoFromMarkerData(data);
            if (_activeObjects.Contains(id)) return; 

            Debug.Log($"Tracker detected, id: {id} ");

            if (!string.IsNullOrEmpty(id))
            {   
                var objectToLoad = worldObjectsLoader.GetWorldObjectPrefab(id);

                if (objectToLoad == null)
                {
                    Debug.LogError($"Error: Object with the given id {id} not found, prefab wasn't loaded.");
                    return;
                }

                WorldObject newWorldObject = Instantiate(objectToLoad);                
                SetObjectTransform(newWorldObject, data);
                _activeObjects.Add(id);                
            }
        }
}


Unity Editor version: 2022.3.16f1
ML2 OS version: 1.4.0-dev2
MLSDK version: 1.4.0
ML MRTK 3: 1.0.0-pre5
Host OS: Windows

Thank you in advance!
Gal.

Hi @GalLibba,
I am happy to help you debug this, and I have a few questions for you to help us towards this goal. Could you please verify the units on the markers? The marker size is expected to be in meters and I just want to be sure that the units make sense. Also is the offset consistent? If you move where the marker is in the room does the offset change? Is the offset along one axis, or multiple?
Thank you,
-Sidney

Hi @sfernandez, thank you for the response!
In the app build, I have used the website given by magic leap docs to print the markers:

I choose the default 100 mm option on the markers I printed.
In the app simulator I added markers using the built in component and set the marker length to 100 (maybe it should be 10?). In both cases, the marker size variable in the script I attached is 0.1f.

Regarding the offset: the object seems to spawn in a constant offset from the marker. It is lower then the marker and is closer to the player camera, meaning all 3 axis are different. It's worth mentioning that the position of both the marker and spawned object is the same in the inspector.

Interesting. If you move the headset/player camera is the offset constant in relation to the player camera? ex: if you rotate around the marker does the object continue to be closer to the player camera, or does it stay at its original position.

It seems that the objects are spawned in the same position for different transform of the camera when the marker stays in the same position, theres only a change in the rotation which is normal because of my implementation. It makes sense as I give the object the position of the marker data in my code(the relevant snippet from the script I attached above):

 // set the marker object transform
 worldObject.transform.position = data.Pose.position;  // marker.PositionOffset;
            
 Debug.Log("marker pos: " + data.Pose.position);
 Debug.Log("object pos: " + worldObject.transform.position);

// make object face the player.
Vector3 targetDirection = -(_mainCamera.transform.position - worldObject.transform.position);            
Quaternion targetRotation = Quaternion.LookRotation(targetDirection);            
worldObject.transform.rotation = Quaternion.Euler(0f, targetRotation.eulerAngles.y, 0f);

Below I also attached a GIF of spawning an object on two markers with different position and rotation, it seems that the position of the object is only affected by the markers.
markers

Thank you for the gif. Are you seeing an offset on those debug statements? If not then I would suggest making sure that the object origin is where you expect it to be. If both look correct could you please post a picture of the object details in the hierarchy?

I made sure the pivot of the prefab is where I intend it to be. From the debug log it seems the position of the marker an object are identical. For a sanity check I also changed the marker track script to spawn a unity's primitive cube object instead of prefab and it still has an offset.
The object is a prefab I load from the resources folder on runtime, so it doesn't appear on the scene hierarchy. what do you mean by object details? Would you like to see it's inspector details?

Is it possible that the marker itself doesn't show in the same position as it states in the app simulator inspector and the data.Pose class?

Gal

Yes sorry for the confusion, I mean the inspector details, its transform, along with any sub hierarchy such as nested objects.

Is it possible that the marker itself doesn't show in the same position as it states in the app simulator inspector and the data.Pose class?

you could try placing a cube at the location you are expecting the markers at and then comparing their transforms?

Hey @sfernandez sorry for the late response.

As I mentioned, I load the prefab from which I instantiate the objects on runtime. Anyway I tried to replace my prefab with a primitive unity 3D cube and and it is still spawned with an offset from the marker, so I believe It has nothing to do with the object itself.

In addition, I also went back to the marker tracking scene from the magic leap examples project and changed it a bit to instantiate my prefab instead the default one in scene (called "marker visual") and it works fine.

I think it's a good indication that the problem is in the script I attached in my first message.

As you can see in the picture attached below, that marker and cube seems to be having the same position play mode (of course it's not accurate but as much as possible), but it appears in a completely different transform than the one specified on the marker. I could add manual offset to the spawned object position to align it with the marker but naturally it isn't an elegant solution.

Gal

1 Like

I solved it, the issue was related to my scene XRRig, I've been using the MRTK3 XRRig for magic leap and not the default one. As it turns out it had an offset in the transform of the main camera and in other child game objects related to camera in the rig. I aligned all the child objects of the MRTK XRRig to default transform position and it worked!

1 Like

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.