Unity Marker

Introduction

Trackable Marker is a feature which facilitates the development of Mixed Reality applications by tracking external markers detected by the device.

Note

The Trackable Marker feature is current in Beta.

Contents

Prerequisite

  1. In Unity Editor, go to Project Settings -> Wave XR -> Essence to import the Trackable Marker feature pack.
../_images/TrackableMarkerFeaturePack.png

Trackable Marker Feature Pack

  1. You have to add below declaration to your AndroidManifest.xml to enable Trackable Marker.
<uses-feature android:name="wave.feature.marker" android:required="true" />

You can also select Project Settings > XR Plug-in Management > WaveXRSettings > Marker > Enable Marker, which will add the above declaration to the AndroidManifest.xml automatically.

../_images/UnityXRMarkerOption.png

How to use

  1. Add a TrackableMarkerController Component to a GameObject in your scene.
  2. Assign a GameObject reference which represents the Tracking Origin as it will be needed for pose correction.
../_images/TrackableMarkerController.png

Trackable Marker Controller component attached to a GameObject, and with the root of the VR Camera Rig assigned as the Tracking Origin

  1. Use the APIs and helper functions provided by TrackableMarkerController to start using Trackable Marker.

Note

To call the APIs and helper functions provided by TrackableMarkerController, add the Wave.Native and Wave.Essence.TrackableMarker namespaces to your script.

In the following sections, we will be referring to sample code which are simplified excerpts from the demo scripts which can be found in the imported feature pack resources in Assets/Wave/Essence/TrackableMarker/<version>/Demo/Scripts.

Marker Service and Observer

To start using Trackable Marker, you have to first start the marker service and observer:

  1. Call trackableMarkerController.StartMarkerService() to initialize the resources required to start using Trackable Marker.
  2. Call trackableMarkerController.StartMarkerObserver() to start the observer which will be necessary for detecting and tracking markers.
  3. Call other APIs and helper functions related to the Trackable Marker feature.
  4. Call trackableMarkerController.StopMarkerObserver() to stop the observer when you no longer need to detect or track markers.
  5. Call trackableMarkerController.StopMarkerService() once you have finished using Trackable Marker.
//Sample code that leverages Unity MonoBehavior lifecycle for starting and stopping Trackable Marker Service and Observer

public TrackableMarkerController trackableMarkerController = null; //Trackable marker controller reference
public bool isMarkerServiceRunning = false, isMarkerObserverRunning = false; //booleans for keeping track of the state of the Marker Service and Observer
private WVR_MarkerObserverTarget currentMarkerObserverTarget = WVR_MarkerObserverTarget.WVR_MarkerObserverTarget_Aruco; //Target marker type to be observed

public void OnEnable()
{
  //Check whether feature is supported on device or not
  if ((Interop.WVR_GetSupportedFeatures() & (ulong)WVR_SupportedFeature.WVR_SupportedFeature_Marker) != 0)
  {
   WVR_Result result = trackableMarkerController.StartMarkerService();
   if (result == WVR_Result.WVR_Success)
   {
    isMarkerServiceRunning = true;

    StartMarkerObserver();
   }
  }
 }

public void OnDisable()
{
  if (!isMarkerServiceRunning) return;

  StopMarkerObserver();

  trackableMarkerController.StopMarkerService();
  isMarkerServiceRunning = false;
}

public void StartMarkerObserver()
{
  if (isMarkerServiceRunning && !isMarkerObserverRunning)
  {
    WVR_Result result = trackableMarkerController.StartMarkerObserver(currentMarkerObserverTarget);

    if (result == WVR_Result.WVR_Success)
    {
        isMarkerObserverRunning = true;
    }
  }
}

public void StopMarkerObserver()
{
  if (isMarkerServiceRunning && isMarkerObserverRunning)
  {
    WVR_Result result = trackableMarkerController.StopMarkerObserver(currentMarkerObserverTarget);

    if (result == WVR_Result.WVR_Success)
    {
        isMarkerObserverRunning = false;
    }
  }
}

Observer related enum definitions as follows:

//Basic overview of observer enum definitions

public enum WVR_MarkerObserverTarget
{
  WVR_MarkerObserverTarget_Aruco = 0,
  WVR_MarkerObserverTarget_Max = 0x7FFFFFFF
}

public enum WVR_MarkerObserverState
{
  WVR_MarkerObserverState_Idle = 0,           //Observer is in idle state
  WVR_MarkerObserverState_Detecting = 1,          //Detecting surrounding markers
  WVR_MarkerObserverState_Tracking = 2,               //Tracking created trackable markers
  WVR_MarkerObserverState_Max = 0x7FFFFFFF
}

Detecting, Creating and Tracking Trackable Markers

Markers have to be detected before they can be tracked. Assuming that you have started the marker service and observer successfully, follow these tips to detect, create and track trackable markers:

  1. Call trackableMarkerController.StartMarkerDetection() to start detecting markers.
  2. When observer state of the target marker type is WVR_MarkerObserverState.WVR_MarkerObserverState_Detecting, you can call APIs to retrieve the detected markers, e.g. For Aruco Markers, call trackableMarkerController.GetArucoMarkers() to get all the detected Aruco Markers.
  3. To create trackable markers from detected markers, call trackableMarkerController.CreateTrackableMarker() with the uuid of a detected marker as parameter.
  4. After creating the trackable markers you need, call trackableMarkerController.StopMarkerDetection() to stop detecting markers.
  5. To retrieve all uuids of the Trackable Markers of a target type, call trackableMarkerController.GetTrackableMarkers().
  6. To start tracking a Trackable Marker, call trackableMarkerController.StartTrackableMarkerTracking() with the uuid of the trackable marker as parameter.
  7. To get the state of a Trackable Marker, call trackableMarkerController.GetTrackableMarkerState(). You can also get data of a trackable marker specific to its type, e.g. For Aruco Markers, call trackableMarkerController.GetArucoMarkerData().
  8. To stop tracking a Trackable Marker, call trackableMarkerController.StopTrackableMarkerTracking() with the uuid of the trackable marker as parameter.
  9. To destroy a trackable marker, call trackableMarkerController.DestroyTrackableMarker() with the uuid of a trackable marker as parameter.
  10. To destroy all trackable marker, call trackableMarkerController.ClearTrackableMarkers() .
  11. You can use the helper function TrackableMarkerController.IsUUIDEqual() for comparing the uuid of the markers.
  12. You can use the helper function trackableMarkerController.ApplyTrackingOriginCorrectionToMarkerPose() to convert the pose of a marker to world space position and rotation that are usable in the Unity coordinate system.
//Sample Code for detecting markers

private WVR_MarkerObserverState currentMarkerObserverState = WVR_MarkerObserverState.WVR_MarkerObserverState_Idle; //State of the observer
private WVR_MarkerObserverTarget currentMarkerObserverTarget = WVR_MarkerObserverTarget.WVR_MarkerObserverTarget_Aruco; //Observed target marker type

public void StartMarkerDetection()
{
  WVR_Result result = trackableMarkerController.StartMarkerDetection(markerObserverTarget);

  if (result == WVR_Result.WVR_Success)
  {
    //Marker detection started successfully
  }
}

public void StopMarkerDetection()
{
  WVR_Result result = trackableMarkerController.StopMarkerDetection(markerObserverTarget);

  if (result == WVR_Result.WVR_Success)
  {
    //Marker detection stopped successfully
  }
}

public void Update()
{
  //Check whether observer is in detection state or not
  WVR_Result result = trackableMarkerController.GetMarkerObserverState(currentMarkerObserverTarget, out currentMarkerObserverState);

  if (result == WVR_Result.WVR_Success)
  {
    if (currentMarkerObserverState == WVR_MarkerObserverState.WVR_MarkerObserverState_Detecting)
    {
     //Observer in detection state, retrieved detected markers and create trackable markers if needed
    }
  }
}
//Sample Code for creating/destroying trackable markers

public void CreateTrackableMarker(WVR_Uuid targetMarkerId, WVR_MarkerObserverTarget observerTarget)
{
  string markerNameString = BitConverter.ToString(targetMarkerId.data); //As an example, we use the uuid of the marker as marker name
  char[] markerNameCharArray = markerNameString.ToCharArray();

  WVR_Result result = trackableMarkerController.CreateTrackableMarker(targetMarkerId, markerNameCharArray);

  if (result == WVR_Result.WVR_Success)
  {
    //Trackable Marker created successfully
  }
}

public void DestroyTrackableMarker(WVR_Uuid targetMarkerId)
{
  WVR_Result result = trackableMarkerController.DestroyTrackableMarker(targetMarkerId);

  if (result == WVR_Result.WVR_Success)
  {
    //Trackable Marker destroyed successfully
  }
}
//Sample Code for tracking and get the state of trackable markers

public void StartTrackingTrackableMarkers(WVR_Uuid targetMarkerId)
{
  WVR_Result result = trackableMarkerController.StartTrackingTrackableMarkers(targetMarkerId);

  if (result == WVR_Result.WVR_Success)
  {
    //Trackable Marker is tracked
  }
}

public void StopTrackingTrackableMarkers(WVR_Uuid targetMarkerId)
{
  WVR_Result result = trackableMarkerController.StopTrackingTrackableMarkers(targetMarkerId);

  if (result == WVR_Result.WVR_Success)
  {
    //Trackable Marker is no longer tracked
  }
}

public void GetTrackableMarkerState(WVR_Uuid targetMarkerId, out WVR_TrackableMarkerState markerState)
{
  markerState = default(WVR_TrackableMarkerState);

  WVR_Result result = trackableMarkerController.GetTrackableMarkerState(targetMarkerId, TrackableMarkerController.GetCurrentPoseOriginModel(), out markerState);

  if (result == WVR_Result.WVR_Success)
  {
    //state of Trackable Marker retrieved successfully
  }
}

As for the data of markers, you can refer to the struct and enum definitions as follows:

//Basic overview of marker data

public struct WVR_ArucoMarker
{
  public WVR_Uuid uuid;                   //Uuid of the marker
  public UInt64 trackerId;                //Marker id of the Aruco Marker
  public float size;                      //Size of the Aruco Marker
  public WVR_MarkerTrackingState state;   //Tracking state of the marker
  public WVR_Pose_t pose;                 //Pose of the marker
  public WVR_MarkerName markerName;       //Name of the marker (Set when designated as a trackable marker)
}

public struct WVR_TrackableMarkerState
{
  public WVR_MarkerObserverTarget target;     //Target type of the marker
  public WVR_MarkerTrackingState state;       //Tracking state of the marker
  public WVR_Pose_t pose;                     //Pose of the marker
  public WVR_MarkerName markerName;           //Name of the marker
}

public struct WVR_ArucoMarkerData
{
  public UInt64 trackerId;    //Marker id of the Aruco Marker
  public float size;          //Size of the Aruco Marker
}

public struct WVR_MarkerName
{
  public char[] name;   //Limited to 256 characters (including null terminating character)
}

public enum WVR_MarkerTrackingState
{
  WVR_MarkerTrackingState_Detected,
  WVR_MarkerTrackingState_Tracked,
  WVR_MarkerTrackingState_Paused,
  WVR_MarkerTrackingState_Stopped
}

Other Useful Functions

Other than the ones mentioned in this tutorial, there are still other APIs and functions that might be useful to you that are not explained in this documentation. You can find the details on the APIs and helper functions in the form of XML API documentation in the TrackableMarkerController script.

Resources

The imported resources of the Trackable Marker Feature Pack can be found in Assets/Wave/Essence/TrackableMarker.

../_images/TrackableMarkerFeaturePackAssets.png

Trackable Marker Feature Pack Assets

Points to take note of and Known Issues

  1. Trackable Markers are tied to the active tracking map when they are created. Changing the active tracking map will result in the loss of Trackable Markers that exist in the previous tracking map(s).