Skip to main content
Version: 17 Jan 2024

Marker Understanding Example

This section includes an example of detecting Fiducial Markers on the Magic Leap 2 headset.

Simple Example

This script detects markers and creates a cube at each of the target's location. The script does not handle runtime changes to the Marker Tracker settings.

caution

This feature requires the MARKER_TRACKING permission to be enabled in your project's Manifest Settings. (Edit > Project Settings > Magic Leap > Manifest Settings)

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features.MagicLeapSupport;

public class MarkerTrackerExample : MonoBehaviour
{
public MagicLeapMarkerUnderstandingFeature.ArucoType ArucoType =
MagicLeapMarkerUnderstandingFeature.ArucoType.Dictionary_5x5_50;

public MagicLeapMarkerUnderstandingFeature.MarkerDetectorProfile DetectorProfile =
MagicLeapMarkerUnderstandingFeature.MarkerDetectorProfile.Default;

private MagicLeapMarkerUnderstandingFeature.MarkerDetectorSettings detectorSettings;
private MagicLeapMarkerUnderstandingFeature markerFeature;
private Dictionary<string, GameObject> _markers = new Dictionary<string, GameObject>();

private void Start()
{
markerFeature = OpenXRSettings.Instance.GetFeature<MagicLeapMarkerUnderstandingFeature>();

if (markerFeature == null || markerFeature.enabled == false)
{
Debug.LogError("The Magic Leap 2 Marker Understanding OpenXR Feature is missing or disabled enabled. Disabling Script.");
this.enabled = false;
return;
}

//Configure a generic detector
detectorSettings.QRSettings.EstimateQRLength = true;

detectorSettings.ArucoSettings.EstimateArucoLength = true;

detectorSettings.ArucoSettings.ArucoType = ArucoType;
detectorSettings.MarkerDetectorProfile = DetectorProfile;

//Create Aruco detector
detectorSettings.MarkerType = MagicLeapMarkerUnderstandingFeature.MarkerType.Aruco;
markerFeature.CreateMarkerDetector(detectorSettings);

//Create QRCode Detector
detectorSettings.MarkerType = MagicLeapMarkerUnderstandingFeature.MarkerType.QR;
markerFeature.CreateMarkerDetector(detectorSettings);

//Create UPCA Detector
detectorSettings.MarkerType = MagicLeapMarkerUnderstandingFeature.MarkerType.UPCA;
markerFeature.CreateMarkerDetector(detectorSettings);
}

private void OnDestroy()
{
if (markerFeature != null)
{
markerFeature.DestroyAllMarkerDetectors();
}
}

void Update()
{
//Update the marker detector
markerFeature.UpdateMarkerDetectors();

// Iterate through all of the marker detectors
for (int i = 0; i < markerFeature.MarkerDetectors.Count; i++)
{
//Verify that the marker detector is running
if (markerFeature.MarkerDetectors[i].Status == MagicLeapMarkerUnderstandingFeature.MarkerDetectorStatus.Ready)
{
//Cycle through the detector's data and log it to the debug log
MagicLeapMarkerUnderstandingFeature.MarkerDetector currentDetector = markerFeature.MarkerDetectors[i];
OnUpdateDetector(currentDetector);
}
}
}

private void OnUpdateDetector(MagicLeapMarkerUnderstandingFeature.MarkerDetector detector)
{

for (int i = 0; i < detector.Data.Count; i++)
{
string id = "";
float markerSize = .01f;
var data = detector.Data[i];
switch (detector.Settings.MarkerType)
{
case MagicLeapMarkerUnderstandingFeature.MarkerType.Aruco:
id = data.MarkerNumber.ToString();
markerSize = data.MarkerLength;
break;
case MagicLeapMarkerUnderstandingFeature.MarkerType.QR:
id = data.MarkerString;
markerSize = data.MarkerLength;
break;
case MagicLeapMarkerUnderstandingFeature.MarkerType.UPCA:
Debug.Log("No pose is given for marker type UPCA, value is " + id);
break;
}

if (!string.IsNullOrEmpty(id))
{
if (_markers.ContainsKey(id))
{
GameObject marker = _markers[id];
marker.transform.position = data.MarkerPose.position;
marker.transform.rotation = data.MarkerPose.rotation;
}
else
{
//Create a primitive cube
GameObject marker = GameObject.CreatePrimitive(PrimitiveType.Cube);
//Render the cube with the default URP shader
marker.AddComponent<Renderer>();
marker.GetComponent<Renderer>().material = new Material(Shader.Find("Universal Render Pipeline/Lit"));
marker.transform.position = data.MarkerPose.position;
marker.transform.rotation = data.MarkerPose.rotation;
marker.transform.localScale = new Vector3(markerSize, markerSize, markerSize);
_markers.Add(id, marker);
}
}
}
}
}