How to Use Location AR with Code
This how-to covers:
- Managing and tracking ARLocations through the
ARLocationManager
public API - Listening for updates to registered ARLocations
- Placing content relative to an ARLocation
- Swapping tracked ARLocations during an AR Session
Prerequisites
- You will need a Unity project with ARDK installed and a set-up basic AR scene. For more information, see Setup ARDK 3 and Setting up an AR Scene.
- If you have not added one, you will need a valid API Key.
- Your project must have an
ARLocationManager
in its AR scene to use this How-To. See Step 4 of Adding a Real-World Location to Unity to learn how to add anARLocationManager
and anARLocation
to your project. (For Swapping ARLocations, you will need more than oneARLocation
.)
Registering ARLocations to be Tracked
To add an ARLocation
to the ARLocationManager
, set it by calling SetARLocations on the ARLocationManager
.
Each time this is called, all previously set locations will be cleared. SetARLocations()
can only be called before calling StartTracking()
. After setting the ARLocations
to be tracked, call StartTracking() on the ARLocationManager
to start tracking attempts.
After setting which locations will be tracked, call StartTracking() on the ARLocationManager
to start tracking attempts.
While up to five ARLocations
can be registered simultaneously, only the first one to successfully track will report updates. Attempting to track multiple locations simultaneously will also increase the network bandwidth usage of tracking. It is recommended to only register a single ARLocation
to be tracked if you know where the user is located or are targeting a location for tracking. Registering multiple locations is useful if you are unsure exactly what the tracking target will be.
using Niantic.Lightship.AR.LocationAR;
using UnityEngine;
public class ARLocationTracking : MonoBehaviour
{
[SerializeField]
private ARLocationManager ArLocationManager;
[SerializeField]
private ARLocation[] ArLocations;
public void StartTracking()
{
ArLocationManager.SetARLocations(ArLocations);
ArLocationManager.StartTracking();
}
}
Listening for Updates to Registered ARLocations
To receive and process updates to registered ARLocations
, subscribe to locationTrackingStateChanged.
The event arguments contain the updated ARLocation
and a bool
called Tracking
to report their current tracking state. If multiple locations are registered, only the first ARLocation
to become tracked will fire events. All other ARLocations
will be automatically removed from the tracking list.
Click to reveal the updated ARLocationTracking script
using Niantic.Lightship.AR.LocationAR;
using UnityEngine;
using Niantic.Lightship.AR.PersistentAnchors;
public class ARLocationTracking : MonoBehaviour
{
[SerializeField]
private ARLocationManager ArLocationManager;
[SerializeField]
private ARLocation[] ArLocations;
private bool firstTrackingUpdateReceived = false;
public void StartTracking()
{
ArLocationManager.locationTrackingStateChanged += OnLocationTrackingStateChanged;
ArLocationManager.SetARLocations(ArLocations);
ArLocationManager.StartTracking();
}
private void OnLocationTrackingStateChanged(ARLocationTrackedEventArgs args)
{
var trackedLocation = args.ARLocation;
var isTracking = args.Tracking;
if (!firstTrackingUpdateReceived && isTracking){
Debug.Log("First tracking update received");
firstTrackingUpdateReceived = true;
}
trackedLocation.gameObject.SetActive(isTracking);
}
}
In this snippet, the ARLocation
GameObject
will be enabled and disabled depending on the tracking state. This is useful to handle loss of tracking when the ARLocation
virtual content is no longer tracking properly and may be offset from the AR camera feed.
Placing Content Relative to the ARLocation
Virtual content spawned relative to the ARLocation
at runtime should be children of the ARLocation
GameObject
. This ensures that any tracking updates to the ARLocation
will update virtual content as well. Also, using local transform methods (localPosition
, localRotation
) instead of global transforms (position
, rotation
) helps virtual content to stay relative to the ARLocation
. Local transforms relative to the ARLocation
can be stored and retrieved in a future session to place virtual content in the same location.
Click to reveal the ARLocationPlacement script
using Niantic.Lightship.AR.LocationAR;
using UnityEngine;
public class ARLocationPlacement : MonoBehaviour
{
[SerializeField]
private GameObject GameAsset;
// An ARLocation that is already tracking
private ARLocation ArLocation;
// Instantiate an object at some provided pose in world space (ie, the results of a hit test against a plane)
public GameObject SpawnObjectFromHitTest(Vector3 position, Quaternion rotation)
{
var go = Instantiate(GameAsset, position, rotation);
// Retain the previously set pose, but child the asset to the ARLocation
go.transform.SetParent(ArLocation.transform, true);
return go;
}
public void UpdateObjectPosition(Vector3 localPosition, Quaternion localRotation, GameObject go)
{
go.transform.localPosition = localPosition;
go.transform.localRotation = localRotation;
}
}
Updating Tracking When Content Is Misaligned
Over time, drift in the ARSession or losing AR tracking can cause ARLocations
to be misaligned with the real world. In the case of ARLocation
tracking loss, the ARLocationManager
will automatically attempt to reconnect with the ARLocation
upon regaining tracking. However, not all tracking loss events are reported or handled. To manually trigger ARLocation
tracking, call TryUpdateTracking() on the ARLocationManager
.
Click to reveal the updated ARLocationTracking script
using Niantic.Lightship.AR.LocationAR;
using UnityEngine;
public class ARLocationTracking : MonoBehaviour
{
[SerializeField]
private ARLocationManager ArLocationManager;
// This can be attached to a button, or called on a timer
// Requires that an ARLocation has been previously tracked
public void UpdateTracking()
{
ArLocationManager.TryUpdateTracking();
}
}
Stopping Location Tracking
ARLocation
tracking can be stopped by calling StopTracking() on the ARLocationManager
. This will remove any ARPersistentAnchors
associated with tracked locations, set all locations to inactive, and return each ARLocation
to its original parent in the Hierarchy if it still exists. To avoid leaking GameObjects
between tracking sessions, we recommend despawning and destroying any instantiated GameObjects
before calling StopTracking()
.
Click to reveal the StopTracking code snippet
using Niantic.Lightship.AR.LocationAR;
using UnityEngine;
public class ARLocationTracking : MonoBehaviour
{
[SerializeField]
private ARLocationManager ArLocationManager;
// GameObjects spawned at runtime
private GameObject[] SpawnedGameObjects;
public void StopTracking()
{
foreach (var go in SpawnedGameObjects)
{
Destroy(go);
}
ArLocationManager.StopTracking();
}
}
Swapping Locations Using Code
ARLocations
can only be swapped when tracking is stopped. This can be used to update a tracked ARLocation
, such as when the user moves to a new location. After calling StopTracking()
, set a new ARLocation
to be tracked and call StartTracking()
. If no SetARLocations
call is made, the previous set of ARLocations
will be used.
Click to reveal the location swapping code snippet
using System.Collections;
using Niantic.Lightship.AR.LocationAR;
using UnityEngine;
public class ARLocationTracking : MonoBehaviour
{
[SerializeField]
private ARLocationManager ArLocationManager;
// Already being tracked
[SerializeField]
private ARLocation InitialLocation;
[SerializeField]
private ARLocation SecondLocation;
public void UpdateLocationForTracking()
{
StartCoroutine(UpdateLocationCoroutine());
}
private IEnumerator UpdateLocationCoroutine()
{
ArLocationManager.StopTracking();
ArLocationManager.SetARLocations(SecondLocation);
// Wait a frame to clear native systems and tracking
yield return null;
ArLocationManager.StartTracking();
}
}