Shared Spatial Anchors are forward compatible, but they are not always backward compatible. Sharing anchors to SDK versions previous to V57 is not guaranteed to work. However, sharing anchors from an older SDK version to a newer SDK version (such as from V52 to V53) will work.
Overview
The Shared Spatial Anchors (SSA) feature allows players who are located in the
same physical space to share content while playing the same game. With SSAs you
can create a shared, world-locked frame of reference for many users. For
example, two or more people can sit at the same table and play a virtual board
game on top of it. Currently, SSA supports local multiplayer games in a single
room.
Though you create and share spatial anchors with the Meta XR Core SDK, you enable
sharing using a third-party network solution. In our documentation and samples
for Unity, you can use
Photon Unity Networking. See
Multiplayer Enablement for
information on best practices and references for creating multiplayer
experiences for Meta Quest.
The How do SSAs work section below describes how SSAs fit
into a multiplayer enabled application.
After reading this page, you should be able to:
Describe the functionality of Shared Spatial Anchors in a multiplayer environment.
Explain the steps to configure an app for sharing Spatial Anchors.
Define the process of creating, saving, sharing, and loading a Spatial Anchor using OVRSpatialAnchor methods.
Understanding group-based vs user-based spatial anchor sharing and loading
As of v71, spatial anchor sharing and loading is based on groups rather than users.
Here are some key differences between group-based and user-based anchor sharing and loading:
Group-based anchor sharing and loading
A way to share and load anchors by using an arbitrary group UUID
Fewer prerequisites compared to user-based sharing
Supported in v71 and later
The recommended approach for sharing and loading shared anchors
User-based anchor sharing and loading
A way to share and load anchors by sharing specifically with users using their Oculus user ID
Requires creation of a Quest Store app in order to request access to User ID and User Profile data permissions
More prerequisites than the group-based version
Released in v49 and will remain available for later versions
For Unity development both approaches rely on variants of OVRSpatialAnchor.ShareAsync() to share a spatial anchor once it has been saved
via OVRSpatialAnchor.SaveAnchorAsync().
Once shared successfully to either a group ID or a collection of users, anchors can be loaded by each sharee by calling a variant of
OVRSpatialAnchor.LoadUnboundSharedAnchorsAsync().
When an SSA is loaded by another user, it is downloaded onto their device, at which point it behaves like a local copy of the original spatial anchor. If you destroy the anchor instance,
it does not affect the shared anchor, nor does it change the user’s permission to access it again in the future.
Group-based functions
public static OVRTask<OVRResult<OVRAnchor.ShareResult>> ShareAsync(IEnumerable<OVRSpatialAnchor> anchors, Guid groupUuid);
public static OVRTask<OVRResult<OVRAnchor.ShareResult>> ShareAsync(IEnumerable<OVRSpatialAnchor> anchors, IEnumerable<Guid> groupUuids);
public static OVRTask<OVRResult<List<UnboundAnchor>, OperationResult>> LoadUnboundSharedAnchorsAsync(Guid groupUuid, List<UnboundAnchor> unboundAnchors)
Getting started with group-based spatial anchor sharing and loading
Use the Colocation building block for Colocation Discovery
Starting from v74, you can use the Colocation building block with the "Use Colocation Session" option to enable colocation discovery. This uses the Colocation Discovery and Group Sharing API to facilitate network communication between players, such as matchmaking and anchor sharing.
To turn on Enhanced Spatial Services on your Meta Quest device, go to Settings > Privacy and Safety > Device Permissions, and select Enhanced Spatial Services.
Your app can detect when this setting is disabled and inform users to turn it on. If the user has not enabled enhanced spatial services, then your app will
receive the error code OVRSpatialAnchor.OperationResult.Failure_SpaceCloudStorageDisabled when you share it (ShareAsync) and when other users try to load it (LoadSharedAnchorsAsync).
Enabling Shared Spatial Anchors
Adding OVRManager permission
In your OVRCameraRig, go to the Unity Inspector and enable Shared Spatial Anchors and Passthrough in the OVRManager’s Quest Features section
Alternate method: Adding permission using Android manifest
Instead of enabling the permission using OVRManager you can enable shared spatial anchors by adding permissions via android manifest
To update your project manifest to support SSA in the Unity Editor, navigate to Meta > Tools, and select Create store-compatible AndroidManifest.xml.
For SSA and passthrough to work, the following permissions are required:
Group-based sharing simplifies application logic in two ways:
The player sharing the spatial anchors does not need to keep track of the user IDs to whom they will share. They can instead share via a unique group identifier that all clients can reference.
There is no longer a need to maintain a list of unique anchor identifiers to load as the group identifier can be used to query for the complete set of anchors already shared with the group.
Before sharing an SSA with a group, one of the participants needs to create a single UUID representing the group and communicate it to the others. The method of that communication can be
either via an app-managed network connection or via Colocation Discovery, which greatly reduces end-user friction around setting up colocated
experiences. Once the group ID is created and propagated, a player wishing to share a spatial anchor they have previously saved would call:
// Share multiple anchors with a group
public static OVRTask<OperationResult> ShareAsync(
IEnumerable<OVRSpatialAnchor> anchors,
Guid groupUuid);
Sharees would then call this method to load all spatial anchors shared with the group:
public static OVRTask<OVRResult<List<UnboundAnchor>, OperationResult>> LoadUnboundSharedAnchorsAsync(
Guid groupUuid,
List<UnboundAnchor> unboundAnchors)
Each unbound anchor would need to be localized before they are usable as described here.
As more anchors are shared using a group, the application should signal to each client that they need to reload the group’s anchors. But there is no need to communicate the IDs of the individual anchors
to each client.
User-based functions
public OVRTask<OperationResult> ShareAsync(OVRSpaceUser user);
public OVRTask<OperationResult> ShareAsync(OVRSpaceUser user1, OVRSpaceUser user2);
public OVRTask<OperationResult> ShareAsync(OVRSpaceUser user1, OVRSpaceUser user2, OVRSpaceUser user3);
public OVRTask<OperationResult> ShareAsync(OVRSpaceUser user1, OVRSpaceUser user2, OVRSpaceUser user3, OVRSpaceUser user4);
public OVRTask<OperationResult> ShareAsync(IEnumerable<OVRSpaceUser> users);
public static OVRTask<OperationResult> ShareAsync(IEnumerable<OVRSpatialAnchor> anchors, IEnumerable<OVRSpaceUser> users);
public static OVRTask<OVRResult<List<UnboundAnchor>, OVRAnchor.FetchResult>> LoadUnboundAnchorsAsync(IEnumerable<Guid> uuids, List<UnboundAnchor> unboundAnchors, Action<List<UnboundAnchor>, int> onIncrementalResultsAvailable = null);
public static OVRTask<OVRResult<List<UnboundAnchor>, OperationResult>> LoadUnboundSharedAnchorsAsync(IEnumerable<Guid> uuids, List<UnboundAnchor> unboundAnchors)
Getting started with user-based spatial anchor sharing and loading
There are also requirements for specific Quest headsets tied to the SDK
version used:
Quest 2, Quest Pro, Quest 3, or Quest 3S
All clients are running v57 or later
Enabling shared spatial anchors feature
Enable enhanced spatial services
To turn on Enhanced Spatial Services in the Unity Editor, go to Settings > Privacy and Safety > Device Permissions, and select Enhanced Spatial Services.
Your app can detect when this setting is disabled and inform users to turn it on. If the user has not enabled enhanced spatial services, then your app will
receive the error code OVRSpatialAnchor.OperationResult.Failure_SpaceCloudStorageDisabled when you share it (ShareAsync) and when other users try to load it (LoadSharedAnchorsAsync).
Adding OVRManager permission
Select your OVRCameraRig in the Unity Editor Hierarchy, go to the Unity Inspector, and, under OVRManager’s Quest Features section, enable Shared Spatial Anchors and Passthrough.
Alternate method: Adding permission using Android manifest
Instead of enabling the permission using OVRManager you can enable shared spatial anchors by adding permissions via the Android manifest.
To update your project manifest to support SSA in the Unity Editor, navigate to Meta > Tools, and select Create store-compatible AndroidManifest.xml.
For SSA and passthrough to work, the following permissions are required:
Enable User ID and User Profile in Data Use Checkup
Note: This section is only required if you are sharing a spatial anchor using Oculus IDs. If you are sharing a spatial anchor using a group UUID, then this section is not required.
When creating your app, choose Meta Horizon Store. If you use Link to run the app from your PC, repeat these steps to also create a PCVR app.
You must complete a Data Use Checkup on each of your apps. To enable spatial anchor persistence:
Obtain admin access to your App if you don’t have it already.
In the left-side navigation, click Requirements > Data Use Checkup.
Add User ID and User Profile Platform Features then submit the request.
More Information about how to create your application can be found on the Creating and Managing Apps page.
User-based sharing and loading explained
With the user-based approach to SSA clients that intend to share spatial anchors do so with specific users by specifying their app-scoped user ID, which is made available to each client
via OculusPlatform.Users.GetLoggedInUserID() . In addition, the unique IDs for all anchors being shared must be communicated to all sharees. Application code is responsible
for communicating these user IDs and anchor IDs amongst all colocated clients.
Once all user IDs are communicated to the sharer they can share a spatial anchor they have previously saved by calling:
// Share multiple anchors with a group
public static OVRTask<OperationResult> ShareAsync(
IEnumerable<OVRSpatialAnchor> anchors,
IEnumerable<OVRSpaceUser> users);
Sharees would then call this method to load all spatial anchors shared with the group:
public static OVRTask<OVRResult<List<UnboundAnchor>, OperationResult>> LoadUnboundSharedAnchorsAsync(
IEnumerable<Guid> uuids,
List<UnboundAnchor> unboundAnchors)
Each unbound anchor would need to be localized before they are usable as described here.
As more users join/leave an experience and more anchors are shared, the application must communicate these changes to all clients and signal each client when a new anchor share occurs.
From a high level, the process for integrating SSAs into your application
successfully is as follows:
To connect users with each other, create a room using the network solution.
Get users to join the same room, either by membership, activity board,
or invitation. For example, Photon’s
matchmaking and lobby functions can help you accomplish this.
Create an anchor by instantiating an object that has the
OVRSpatialAnchor component on it.
Save the anchor using OVRSpatialAnchor.SaveAnchorAsync(),
Wait for this call to complete before sharing the anchor.
Share the anchor with a collection of users using OVRSpatialAnchor.ShareAsync()
to all players of the room. Other players can load the SSA as soon as this call is completed.
Broadcast the anchor’s UUID. For instance, broadcast the SSA’s UUID to all players in the room
using the networking solution.
Load the anchor Each player can now load the anchor by its UUID from the step above using OVRSpatialAnchor.LoadUnboundSharedAnchorsAsync()
All players can now use the anchor as a shared coordinate frame, or origin.
How do SSAs work
When you share a spatial anchor, you are sharing its point cloud data and specifying which user IDs or which group ID are allowed to load it.
Note: Regardless of your network solution, all the users or groups with whom you plan to share a spatial anchor must have Enhanced Spatial Services enabled in your app. This gives them access to the anchors that are shared with them.
Save an SSA
Before you share a spatial anchor, it must first be saved. You can use the OVRSpatialAnchor method SaveAnchorAsync(). This method is asynchronous.
Return
ShareAsync returns an awaitable task-like object that you can await on or use a callback by using ContinueWith. See Asynchronous Tasks for more details on task-based programming in the Meta XR Core SDK.
The task’s OperationResult can be used to determine whether the share was successful, and what action should be taken if it fails.
The users parameter specifies a collection of
OVRSpaceUser objects for
the users with whom you want to share anchors. When the call to
ShareAsync() succeeds, the SSAs are available to the users.
Example
public async void ShareExample(
OVRSpatialAnchor spatialAnchor,
IEnumerable<OVRSpaceUser> users)
{
var result = await spatialAnchor.ShareAsync(users);
if (result.IsSuccess())
{
BroadcastUuidToUsers(spatialAnchor.Uuid);
return;
}
switch (result)
{
case OVRSpatialAnchor.OperationResult.Failure_SpaceNetworkRequestFailed:
{
// Unable to reach Meta servers.
// Instruct user to check internet connection
break;
}
case OVRSpatialAnchor.OperationResult.Failure_SpaceCloudStorageDisabled:
{
// inform user to turn on Enhanced Spatial Services
// Settings > Privacy and Safety > Device Permissions > Turn on "Enhanced Spatial Services"
break;
}
// ...
}
}
OVRSpaceUser object
You must specify the set of users with whom you wish to share anchors. To do
this, create an
OVRSpaceUser from each
user’s Meta Quest ID (a ulong identifier).
var users = new OVRSpaceUser[]
{
new OVRSpaceUser(userId1),
new OVRSpaceUser(userId2),
};
ShareExample(anchor, users);
This snippet demonstrates sharing spatial anchors to a collection of users.
async void ShareExample(OVRSpatialAnchor anchor, OVRSpaceUser[] users)
{
var shareResult = await anchor.ShareAsync(users);
if (shareResult.IsError())
{
Debug.LogError($"Sharing failed with {shareResult}");
return;
}
Debug.Log($"Anchor {anchor.Uuid} shared with {users.Length} users.");
}
Known issues
There are known issues where a shared spatial anchor may not be localized at the correct location. The following discusses the issues and how to mitigate them.
Issue 1:
Repro Steps
Host: Calls ShareAsync
Host: Quits App
Host: Does not significantly move their Quest device
Host: Reopens App
Host: Calls ShareAsync
Guest: Calls LoadUnboundSharedAnchorsAsync
Guest: May observe shared spatial anchor not loaded at the correct location
Mitigation
If Host quits app, the Host should move their Quest device
Issue 2:
The Guest may have too many anchors stored locally
Mitigation
Go to Settings > Privacy > Clear Physical Space History
SSA sample and walkthrough
Two samples are available that highlight the use of SSAs. Both are
available in the
oculus-samples
GitHub repository. Both of these applications use
Photon Unity Networking to share player
data.
The Unity-SharedSpatialAnchors
showcase app is an established application which highlights the implementation
of shared spatial anchors, and allows users to interact with networked objects
in a co-located space. The page
Shared Spatial Anchors Sample provides
documentation on how to build and use the sample.
The Unity-Discover
showcase app is a newer application which has fewer features, and which
demonstrates how to use a single SSA effectively in a multipurpose
application. To help you understand how the SSA is implemented, check out the
Shared Spatial Anchors (SSA) Walkthrough
Learn more
Continue learning about spatial anchors by reading these pages: