Skip to main content

How to Use Shared AR

You can use these steps to setup a shared AR room using VPS. You will need to add the proper components to your Unity scene. Then you can use the CoverageAPI or the ARLocationManager to create a shared AR room.

Prerequisites

  1. You will need a Unity project with Lightship AR enabled.
  2. You will need to install the Shared AR plugin.
  3. You will need an AR scene with ARSession and XROrigin.

Add Components to your Scene

You will need to add these components to your Unity scene in order to use Shared AR:

  1. Add a Network Manager object to the root of your scene.

    1. In the Hierarchy, select the scene title.
    2. From the main menu, select GameObject and select Create Empty
    3. Name the object NetworkManager.
  2. Add a NetworkManager component to the object.

    1. In the Hierarchy, select the NetworkManager.

    2. In the Inspector window, click Add Component.

    3. Type "Network Manager" into the search box and select it to add.

    4. Under Network Transport, click Select transport... and select LightshipNetcodeTransport. This will automatically add the Lightship Netcode Transport component.

      Add Lightship Netcode Transport
  3. Add a SharedSpaceManager component to XROrigin

    1. In your AR Scene in the Hierarchy, select the XR Origin component.
    2. In the Inspector window, click Add Component.
    3. Type "Shared Space Manager" into the search box and select it to add.
    4. Make sure Colocalization Type is set to Vps Colocalization.

Using SharedSpaceManager with the Coverage API

You can join a shared room at any VPS location using the Coverage API. You start by using TryGetCoverage to get AreaTargets. This will give you a list of nearby VPS locations to choose from. VPS Locations are defined as a LocalizationTarget.DefaultAnchor. Once your user has chosen a location, you can join a Room using SharedSpaceManager using the DefaultAnchor as the room identifier.

Using TryGetCoverage to get AreaTargets

You can use the CoverageClientManager class to get a list of nearby VPS locations. Locations are defined as a LocalizationTarget.DefaultAnchor. These are the basic steps:

  1. Instantiate a copy of Niantic.Lightship.AR.CoverageClientManager:

    ...

    using Niantic.Lightship.AR;

    public class CoverageClientSelector : MonoBehaviour
    {
    // References to components
    [SerializeField]
    public CoverageClientManager CoverageClient;

    ...
    }
  2. Declare an event handler that takes an AreaTargetsResult. This sample handler puts the 5 nearest locations into a dictionary.

     private Dictionary<string, string> LocationToPayload = new();

    private void OnTryGetCoverage(AreaTargetsResult args)
    {
    var areaTargets = args.AreaTargets;

    // Sort the area targets by proximity to the user
    areaTargets.Sort((a, b) =>
    a.Area.Centroid.Distance(args.QueryLocation).CompareTo(
    b.Area.Centroid.Distance(args.QueryLocation)));

    // Populate the dictionary with the 5 nearest names and anchors
    for (var i = 0; i < 5; i++)
    {
    LocationToPayload[areaTargets[i].Target.Name] = areaTargets[i].Target.DefaultAnchor;
    }
    }
  3. Add the event handler to CoverageClient.TryGetCoverage.

    void Start()
    {
    CoverageClient.TryGetCoverage(OnTryGetCoverage);
    }

The CoverageClientSelector sample script shows how to use the process to populate a Unity Dropdown box. For a full example of the CoverageClient with a complete UI (including image targets and distance from device), see the Shared AR VPS sample.

Click to show the CoverageClientSelector code sample

using System.Collections.Generic;
using System.Linq;

using Niantic.Lightship.AR;
using Niantic.Lightship.AR.VpsCoverage;

using UnityEngine;
using UnityEngine.UI;

public class CoverageClientSelector : MonoBehaviour
{
// References to components
[SerializeField]
public CoverageClientManager CoverageClient;

// Note: This refers to the legacy Unity UI Dropdown component.
// If your project uses TMP, you will need to use TMP_Dropdown instead.
[SerializeField]
public Dropdown DropdownSelector;

// This will be populated by selecting an area target by name in the UI dropdown
public string SelectedPayload;

private Dictionary<string, string> LocationToPayload = new();

void Start()
{
CoverageClient.TryGetCoverage(OnTryGetCoverage);
DropdownSelector.onValueChanged.AddListener(OnValueChanged);
}

private void OnValueChanged(int arg)
{
SelectedPayload = LocationToPayload[DropdownSelector.options[arg].text];
}

private void OnTryGetCoverage(AreaTargetsResult args)
{
// Clear any previous data
DropdownSelector.ClearOptions();
LocationToPayload.Clear();
SelectedPayload = null;

var areaTargets = args.AreaTargets;

// Sort the area targets by proximity to the user
areaTargets.Sort((a, b) =>
a.Area.Centroid.Distance(args.QueryLocation).CompareTo(
b.Area.Centroid.Distance(args.QueryLocation)));

// Only populate the dropdown with the closest 5 locations.
// For a full sample with UI and image hints, see the VPSColocalization sample
for (var i = 0; i < 5; i++)
{
LocationToPayload[areaTargets[i].Target.Name] = areaTargets[i].Target.DefaultAnchor;
}

DropdownSelector.AddOptions(LocationToPayload.Keys.ToList());
}
}

Joining a Room using SharedSpaceManager

You can use a LocalizationTarget.DefaultAnchor to join a Shared AR room as a host or a client. These are the basic steps:

  1. Instantiate a copy of the SharedSpaceManager.

  2. Take the DefaultAnchor from the selected location (defaultPayloadToSet) and pass it to the SharedSpaceManager.StartTracking and SharedSpaceManager.PrepareRoom methods.

    [SerializeField]
    private SharedSpaceManager _sharedSpaceManager;

    private void OnLocationSelected(string defaultPayloadToSet)
    {
    var vpsTrackingOptions = ISharedSpaceTrackingOptions.CreateVpsTrackingOptions(defaultPayloadToSet);
    var roomOptions = ISharedSpaceRoomOptions.CreateVpsRoomOptions(
    vpsTrackingOptions,
    "optionalPrefixForRoom_",
    10,
    "Room Description Here!");
    _sharedSpaceManager.StartSharedSpace(vpsTrackingOptions, roomOptions);

    }
  3. Setup an event listener for SharedSpaceManager.sharedSpaceManagerStateChanged. When args.Tracking is true, there is a shared space you can join. This sample uses a "Join as Host" and "Join as Client" button to set active when the user can join:

    [SerializeField]
    private Button _joinAsHostButton;

    [SerializeField]
    private Button _joinAsClientButton;

    protected void Start()
    {
    _sharedSpaceManager.sharedSpaceManagerStateChanged += OnColocalizationTrackingStateChanged;
    }

    private void OnColocalizationTrackingStateChanged(
    SharedSpaceManager.SharedSpaceManagerStateChangeEventArgs args)
    {
    if (args.Tracking)
    {
    _joinAsHostButton.gameObject.SetActive(true);
    _joinAsClientButton.gameObject.SetActive(true);
    }
    }
  4. To join as a host, call NetworkManager.Singleton.StartHost. To join as a client, call StartClient.

    protected void Start()
    {
    _joinAsHostButton.onClick.AddListener(OnJoinAsHostClicked);
    _joinAsClientButton.onClick.AddListener(OnJoinAsClientClicked);
    }

    private void OnJoinAsHostClicked()
    {
    NetworkManager.Singleton.StartHost();
    HideButtons();
    }

    private void OnJoinAsClientClicked()
    {
    NetworkManager.Singleton.StartClient();
    HideButtons();
    }

    private void HideButtons()
    {
    _joinAsHostButton.gameObject.SetActive(false);
    _joinAsClientButton.gameObject.SetActive(false);
    }
caution

Make sure the first user is the Host and the rest are Clients.

Using SharedSpaceManager with ARLocationManager

If you have followed the steps in How to Place Content in Real-World Locations Using Location AR to add an ARLocation to your scene, you can use that location when you call SharedSpaceManager.PrepareRoom. For example:

public SharedSpaceManager SharedSpaceManager;
public ARLocationManager ARLocationManager;

...

// Start is called before the first frame update
void Start()
{
// This demo only targets a single ARLocation, so we can just use the first location.
// For applications that choose from a list, use the specific ARLocation that you are localizing against
// as the room ID
var vpsTrackingOptions = ISharedSpaceTrackingOptions.CreateVpsTrackingOptions(ARLocationManager.ARLocations.First());
var roomOptions = ISharedSpaceRoomOptions.CreateVpsRoomOptions(
vpsTrackingOptions,
"optionalPrefixForRoom_",
10,
"Room Description Here!");
_sharedSpaceManager.StartSharedSpace(vpsTrackingOptions, roomOptions);
}

You can then call NetworkManager.Singleton.StartHost or StartClient to join the room.

The VPSLocationDemoManager sample script shows how to use SharedSpaceManager with an ARLocationManager. It also assumes you have a ConnectionUI object to handle the user interface. For a full example of the SharedSpaceManager, see the VpsColocalizationDemo.cs script in the Shared AR VPS sample.

Click to show the VPSLocationDemoManager code sample

using System.Linq;

using Niantic.Lightship.AR.Subsystems;
using Niantic.Lightship.AR.LocationAR;
using Niantic.Lightship.SharedAR.Colocalization;
using Unity.Netcode;

using UnityEngine;

public class VPSLocationDemoManager : MonoBehaviour
{
public SharedSpaceManager _sharedSpaceManager;
public ARLocationManager _arLocationManager;
public GameObject _connectionUI;

private bool _started;

// Start is called before the first frame update
void Start()
{
_sharedSpaceManager.sharedSpaceManagerStateChanged += OnSharedSpaceStateChanged;
// This demo only targets a single ARLocation, so we can just use the first location.
// For applications that choose from a list, use the specific ARLocation that you are localizing against
// as the room ID
var vpsTrackingOptions = ISharedSpaceTrackingOptions.CreateVpsTrackingOptions(_arLocationManager.ARLocations.First());
var roomOptions = ISharedSpaceRoomOptions.CreateVpsRoomOptions(
vpsTrackingOptions,
"optionalPrefixForRoom_",
10,
"Room Description Here!");
_sharedSpaceManager.StartSharedSpace(vpsTrackingOptions, roomOptions);
}

private void OnSharedSpaceStateChanged(SharedSpaceManager.SharedSpaceManagerStateChangeEventArgs args)
{
if (args.Tracking && !_started)
{
_connectionUI.SetActive(true);
_started = true;
}
}

public void StartAsHost()
{
NetworkManager.Singleton.StartHost();
_connectionUI.SetActive(false);
}

public void StartAsClient()
{
NetworkManager.Singleton.StartClient();
_connectionUI.SetActive(false);
}

}

Next Steps

See How to Display Shared Objects for information on how to display shared objects in the same room, or display objects in the location of each player in the room.