Querying VPS Coverage for AR Locations at Runtime
The VPS Coverage API provides functionality for discovering AR Locations at runtime to display them on maps and use them as localization targets for an ARLocationManager.
Configuring the CoverageClientManager
CoverageClientManager can either be added to your scene in the Unity Editor or at runtime through AddComponent
. It can either query for ARLocations
around the user's current GPS location or one they specify (for example, remotely viewing a city on a map). CoverageClientManager also provides configuration for a QueryRadius
which defines the radius (in meters) to query around the GPS location.
Your Unity project will need location usage permissions set up for the build target. For iOS, a Location Usage Description is required in Project Settings. For Android, the user will need to grant the ACCESS_FINE_LOCATION
permission, which the CoverageClientManager will request upon use.
The following code snippet demonstrates setting up and configuring the CoverageClientManager to query for ARLocations
within 1km of the user's current location.
Click to reveal CoverageClientManagerExample.cs
using Niantic.Lightship.AR.VpsCoverage;
using UnityEngine;
public class CoverageClientManagerExample : MonoBehaviour
{
[SerializeField]
private CoverageClientManager CoverageClientManager;
public void QueryAroundUser()
{
// If not provided, create one on the current gameobject
if (!CoverageClientManager)
{
CoverageClientManager = gameObject.AddComponent<CoverageClientManager>();
}
// Use the current location of the device to query coverage. The query radius is set to 1000 meters.
CoverageClientManager.UseCurrentLocation = true;
CoverageClientManager.QueryRadius = 1000;
CoverageClientManager.TryGetCoverage(OnCoverageResult);
}
private void OnCoverageResult(AreaTargetsResult result)
{
// Currently does nothing
}
}
Using Coverage Results
The AreaTargetsResult class returns information from the VPS Coverage API query. Check that the Status is Success or handle failure cases as needed. Most of the relevant data from the VPS Coverage API query will be contained in the AreaTargets
list.
Area Targets and Their Contents
Each AreaTarget contains two fields, the CoverageArea and LocalizationTarget.
A CoverageArea defines a 2-dimensional polygon in real-world space where Location AR is supported. For example, the Shape
property can be used to draw an overlay on a map using LatLng
points, while the LocalizabilityQuality
property reports the overall quality of tracking in the area.
A LocalizationTarget defines a point in real-world space where VPS localization is supported. The Name
and ImageURL
properties can be used to create a information card about a specific location, while the DefaultAnchor
property can be passed into the ARLocationManager to start tracking.
For more information on these fields and their properties, see the API documentation.
This snippet combines CoverageArea and LocalizationTarget data to sort and filter AreaTargetsResults
into a usable list:
Click to reveal the Area Targets example script
using Niantic.Lightship.AR.VpsCoverage;
using UnityEngine;
public class CoverageClientManagerExample : MonoBehaviour
{
[SerializeField]
private CoverageClientManager CoverageClientManager;
public void QueryAroundUser()
{
CoverageClientManager.TryGetCoverage(OnCoverageResult);
}
private void OnCoverageResult(AreaTargetsResult areaTargetsResult)
{
if (areaTargetsResult.Status == ResponseStatus.Success)
{
// Sort the area targets by distance from the query location
areaTargetsResult.AreaTargets.Sort((a, b) =>
a.Area.Centroid.Distance(areaTargetsResult.QueryLocation).CompareTo(
b.Area.Centroid.Distance(areaTargetsResult.QueryLocation)));
// Only consider the 5 nearest production quality areas
var maxCount = 5;
foreach (var result in areaTargetsResult.AreaTargets)
{
if (result.Area.LocalizabilityQuality != CoverageArea.Localizability.PRODUCTION)
{
continue;
}
Debug.Log($"Got a localization target: {result.Target.Name}, anchor payload: {result.Target.DefaultAnchor}");
maxCount--;
if (maxCount == 0)
{
break;
}
}
}
else
{
Debug.LogError($"Coverage query failed with status: {areaTargetsResult.Status}");
}
}
}
Downloading Hint Images
Each LocalizationTarget contains an ImageURL which points to a hosted hint image corresponding to the LocalizationTarget. This information can be used to guide users to the real-world location to localize against. The CoverageClientManager contains a few utility methods to download and create a Texture
with the hint image, as in the following code snippet:
Click to reveal the hint image code snippet
using Niantic.Lightship.AR.VpsCoverage;
using UnityEngine;
public class CoverageClientManagerExample : MonoBehaviour
{
[SerializeField]
private CoverageClientManager CoverageClientManager;
public void QueryAroundUser()
{
CoverageClientManager.TryGetCoverage(OnCoverageResult);
}
private async void OnCoverageResult(AreaTargetsResult areaTargetsResult)
{
if (areaTargetsResult.Status == ResponseStatus.Success)
{
foreach (var result in areaTargetsResult.AreaTargets)
{
if (string.IsNullOrEmpty(result.Target.ImageURL))
{
continue;
}
var hintTexture = await CoverageClientManager.TryGetImageFromUrl(result.Target.ImageURL);
// Do something with the texture
}
}
else
{
Debug.LogError($"Coverage query failed with status: {areaTargetsResult.Status}");
}
}
}
Due to the performance impact of blocking on downloads and texture generation, it is recommended to call this API asynchronously. We also recommend limiting the number of images downloaded at a time rather than handling every image in the response.
Using CoverageClientManager Output in ARLocationManager
After getting a list of nearby AreaTargets, the user or application can select a specific LocalizationTarget to use as an ARLocation to track. The following example chooses the first result in the response list as the ARLocation to track.
Click to reveal the example script
using Niantic.Lightship.AR.LocationAR;
using Niantic.Lightship.AR.PersistentAnchors;
using Niantic.Lightship.AR.VpsCoverage;
using UnityEngine;
public class CoverageClientManagerExample : MonoBehaviour
{
[SerializeField]
private CoverageClientManager CoverageClientManager;
[SerializeField]
private ARLocationManager ArLocationManager;
public void QueryAroundUser()
{
CoverageClientManager.TryGetCoverage(OnCoverageResult);
}
private void OnCoverageResult(AreaTargetsResult areaTargetsResult)
{
if (areaTargetsResult.Status == ResponseStatus.Success)
{
var firstResult = areaTargetsResult.AreaTargets[0];
var anchorPayloadString = firstResult.Target.DefaultAnchor;
if (string.IsNullOrEmpty(anchorPayloadString))
{
// If this area has no anchor payload, don't do anything
// Select a different area target in a real application
Debug.LogError($"No anchor found for {firstResult.Target.Name}");
return;
}
var anchorPayload = new ARPersistentAnchorPayload(anchorPayloadString);
var locationGameObject = new GameObject();
var arLocation = locationGameObject.AddComponent<ARLocation>();
arLocation.Payload = anchorPayload;
ArLocationManager.SetARLocations(arLocation);
ArLocationManager.StartTracking();
}
else
{
Debug.LogError($"Coverage query failed with status: {areaTargetsResult.Status}");
}
}
}
Surfacing Test Scans Using CoverageClientManager
CoverageClientManager will only surface public VPS locations around the query location. However, test scans can be manually added to CoverageClientManager to be surfaced in the AreaTargetsResult response, regardless of location. Adding the ARLocationManifest of a test scan using the CoverageClientManager PrivateARLocations
array will append them to the AreaTargetsResult response as if they were queried at runtime. This allows you to use the same flow for discovering public VPS locations and private test scans.
For more information about creating and important test scans, see Managing Test Scans.