Develop
Develop
Select your platform

Spatial Anchors

Updated: Dec 20, 2024

Overview

The lifecycle of a Spatial Anchor allows it to be created, saved, erased, and destroyed. You can also share or receieve a shared spatial anchor. Each one of these possible lifecycle states is documented below with examples both in Blueprints and C++.
  • Recognize the functionalities covered by spatial anchors such as create, save, load, erase, destroy, and share.
  • Define the process of creating a spatial anchor using both Blueprint and C++.
  • Describe the process of destroying a spatial anchor with a using a blueprint or C++

Prerequisites

Before working with Spatial Anchors, you should ensure that you are Configuring Your Headset for App Development for Meta Quest builds. Also, you can become more familiar with the process for app development if you read Creating Your First Meta Quest VR App in Unreal Engine.

Implementation

Create a spatial anchor

A user can create a spatial anchor in their environment to create a stabilized transform that is tracked by the device and remains static even after headset position and orientation resets. Creating a spatial anchor requires specifying a valid location within the environment that will allow for localization.

Create a spatial anchor with Blueprints

Create spatial anchor Blueprint reference image In this example:
  • An actor is created at the location the anchor should be spawned at.
  • The latent action Create Spatial Anchor is called using the actor and transform as parameters.
  • If it succeeds execution continues, on failure the execution destroys the actor previously created.

Create a spatial anchor with C++

The function signature is as follows:
bool OculusXRAnchors::FOculusXRAnchors::CreateSpatialAnchor(
   const FTransform& InTransform,
   AActor* TargetActor,
   const FOculusXRSpatialAnchorCreateDelegate& ResultCallback,
   EOculusXRAnchorResult::Type& OutResult);
This is the layout of the delegate ResultCallback specified in the function.
DelegateParameters
FOculusXRSpatialAnchorCreateDelegate
EOculusXRAnchorResult::Type Result,
UOculusXRAnchorComponent* Anchor
Here is an example of calling the function and binding to the callback:

EOculusXRAnchorResult::Type CreateAnchor(AActor* TargetActor, const FTransform& WorldSpaceTransform)
{
    EOculusXRAnchorResult::Type OutResult; // Detailed immediate (non-async) result code

    OculusXRAnchors::FOculusXRAnchors::CreateSpatialAnchor(
        WorldSpaceTransform,
        TargetActor,
        FOculusXRSpatialAnchorCreateDelegate::CreateLambda([](
            EOculusResult::Type Result,
            UOculusXRAnchorComponent* Anchor)
        {
            // Post create spatial anchor logic here
        }),
        OutResult
    );

    return OutResult;
}

Save spatial anchors

Use this API to persist a spatial anchor so it can be accessed later via Discovery.

Save spatial anchors with Blueprints

Save spatial anchors Blueprint reference image
In this example:
  • An array of actors containing Spatial Anchor Components is passed to the Save Anchors function.
  • On success the array of actors is iterated over in a For Each loop.

Save spatial anchors with C++

The function signature is as follows
bool OculusXRAnchors::FOculusXRAnchors::SaveAnchors(
   const TArray<UOculusXRAnchorComponent*>& Anchors,
   const FOculusXRSaveAnchorsDelegate& ResultCallback,
   EOculusXRAnchorResult::Type& OutResult);
This is the layout of the delegate ResultCallback specified in the function.
DelegateParameters
FOculusXRSaveAnchorsDelegate
EOculusXRAnchorResult::Type Result,
const TArray<UOculusXRAnchorComponent*>& SavedAnchors
Here is an example of calling the function and binding to the callback.

EOculusXRAnchorResult::Type SaveAnchors(const TArray<UOculusXRAnchorComponent*>& Components)
{
    EOculusXRAnchorResult::Type OutResult; // Detailed immediate (non-async) result code

    OculusXRAnchors::FOculusXRAnchors::SaveAnchors(
        Components,
        FOculusXRSaveAnchorsDelegate::CreateLambda([](
            EOculusResult::Type Result,
            const TArray<UOculusXRAnchorComponent*>& SavedAnchors)
        {
            // Post save anchors logic here
        }),
        OutResult
    );

    return OutResult;
}

Discover spatial anchors

A previously persisted spatial anchor can be found on the device or cloud storage using the Discover API. This is a filter based querying mechanism that allows you to find anchors that have been persisted via the Save API.
The discovery filters are objects you must create and pass into the function call in either Blueprints or C++. You can perform a discovery request with no filters and find every anchor in your environment, but typically you would want to either request anchors using a UUID filter or a Component Filter. See Scene Documentation for information on component filters.
The API signature also requires two callbacks to be present. One callback, Results, will fire every time there are anchors that are discovered and can be localized and provided to the user. The second callback, Complete, will only fire once all asynchronous work is complete.
It is possible to make a request, discover no anchors, and receive a Complete callback with a success code.

Discover spatial anchors with Blueprints

Discover spatial anchors Blueprint reference image
In this example:
  • A Discovery ID filter is created.
  • The filter is populated with Anchor UUIDs.
  • The filter is placed in a filter array.
  • The Discovery info struct is populated and passed to the Discover Anchors function.
  • There is logging for success and failure cases.

Discover Spatial Anchors with C++

The function signature is as follows
bool OculusXRAnchors::FOculusXRAnchors::DiscoverAnchors(
   const FOculusXRSpaceDiscoveryInfo& DiscoveryInfo,
   const FOculusXRDiscoverAnchorsResultsDelegate& DiscoveryResultsCallback,
   const FOculusXRDiscoverAnchorsCompleteDelegate& DiscoveryCompleteCallback,
   EOculusXRAnchorResult::Type& OutResult);
This is the layout of the delegates specified in the function.
DelegateParameters
FOculusXRDiscoverAnchorsResultsDelegate
const TArray<FOculusXRAnchorsDiscoverResult>& DiscoveredAnchors
FOculusXRDiscoverAnchorsCompleteDelegate
EOculusXRAnchorResult::Type Result
DiscoveryInfo is a structure that contains an array of filter objects. Here is a simplified version of the structure.
struct FOculusXRSpaceDiscoveryInfo
{
    ...
    TArray<UOculusXRSpaceDiscoveryFilterBase*> Filters;
};
The filter types are UOculusXRSpaceDiscoveryIdsFilter and UOculusXRSpaceDiscoveryComponentsFilter. You can create a filter in code using NewObject. See the code below for an example.
EOculusXRAnchorResult::Type DiscoverAnchors(const TArray<FOculusXRUUID>& UUIDsToFind)
{
    EOculusXRAnchorResult::Type OutResult; // Detailed immediate (non-async) result code

    // Create a filter object and assign UUIDs to it
    UOculusXRSpaceDiscoveryIdsFilter* IdFilter = NewObject<UOculusXRSpaceDiscoveryIdsFilter>(this);
    for(const auto& it : UUIDsToFind)
    {
        IdFilter.Uuids.Add(it);
    }

    // Create the info structure and add the filter we created to the filter list
    FOculusXRSpaceDiscoveryInfo info;
    info.Filters.Add(IdFilter);

    OculusXRAnchors::FOculusXRAnchors::DiscoverAnchors(
        info,
        FOculusXRDiscoverAnchorsResultsDelegate::CreateLambda([](
            const TArray<FOculusXRAnchorsDiscoverResult>& DiscoveredAnchors)
        {
            // Do something with the list of anchors you found
        }),
        FOculusXRDiscoverAnchorsCompleteDelegate::CreateLambda([](
            EOculusXRAnchorResult::Type Result)
        {
            // All done! Check error code, etc...
        }),
        OutResult
    );

    return Outresult;
}

Erase spatial anchors

There are several ways to erase anchors with the Spatial Anchors API. You can erase using the Anchor Component pointers, you can erase by Anchor UUIDs, or Anchor Handles. Erasing by Anchor Component or by Anchor Handle are the typical use cases. In both scenarios you will only be able to erase anchors that are known to the runtime. i.e., they have been created or queried for in this session.
Erasing by UUID is unique in that an anchor does not have to be loaded by the runtime to be erased. This is helpful if you are trying to clean up anchors that are not able to be loaded by the app or that you do not wish to persist any longer.

Erase spatial anchors with Blueprints

Erase spatial anchors Blueprint reference image
In this example:
  • An array of actors with Spatial Anchor Components is passed to the Erase Anchors function.
  • In the Success case the list of erased anchors is iterated in a For Each loop.

Erase spatial anchors with C++

Component erase
The component erase function looks like the following:
bool OculusXRAnchors::FOculusXRAnchors::EraseAnchors(
   const TArray<UOculusXRAnchorComponent*>& Anchors,
   const FOculusXRSaveAnchorsDelegate& ResultCallback,
   EOculusXRAnchorResult::Type& OutResult);
UUID erase
The Handle or UUID erase function looks like the following:
bool OculusXRAnchors::FOculusXRAnchors::EraseAnchors(
   const TArray<FOculusXRUInt64>& AnchorHandles,
   const TArray<FOculusXRUUID>& AnchorUUIDs,
   const FOculusXREraseAnchorsDelegate& ResultCallback,
   EOculusXRAnchorResult::Type& OutResult);
This is the layout of the delegate ResultCallback specified in both functions.
DelegateParameters
FOculusXREraseAnchorsDelegate
EOculusXRAnchorResult::Type Result,
const TArray<UOculusXRAnchorComponent*>& ErasedAnchors,
const TArray<FOculusXRUInt64>& ErasedAnchorHandles,
const TArray<FOculusXRUUID>& ErasedAnchorUUIDs
This example shows the anchor component erase:
EOculusXRAnchorResult::Type EraseAnchors(const TArray<UOculusXRAnchorComponent*>& Anchors)
{
    EOculusXRAnchorResult::Type OutResult; // Detailed immediate (non-async) result code

    OculusXRAnchors::FOculusXRAnchors::EraseAnchors(
        Anchors,
        FOculusXRSaveAnchorsDelegate::CreateLambda([](
            EOculusResult::Type Result,
            const TArray<UOculusXRAnchorComponent*>& ErasedAnchors,
            const TArray<FOculusXRUInt64>& ErasedAnchorHandles,
            const TArray<FOculusXRUUID>& ErasedAnchorUUID)
        {
            // Post erase anchors logic here
        }),
        OutResult
    );

    return OutResult;
}
This example shows the UUID erase:
TArray<FOculusXRUUID> AnchorUUIDs = … // Find the UUIDs of the anchors you want to erase, maybe from a save data file
EOculusXRAnchorResult::Type OutResult; // Detailed immediate (non-async) result code

OculusXRAnchors::FOculusXRAnchors::EraseAnchors(
    TArray<FOculusXRUInt64>(), // Empty
    AnchorUUIDs,
    FOculusXRSaveAnchorsDelegate::CreateLambda([](
        EOculusResult::Type Result,
        const TArray<UOculusXRAnchorComponent*>& ErasedAnchors,
        const TArray<FOculusXRUInt64>& ErasedAnchorHandles,
        const TArray<FOculusXRUUID>& ErasedAnchorUUID)
    {
        // Post erase anchors logic here
    }),
    OutResult
);

Destroy a spatial anchor

This is a non async function that will destroy the anchor’s runtime representation. If the anchor has been saved, then the anchor will not be removed from persistent storage and you can still recover the anchor with DiscoverAnchors.

Destroy spatial anchors with Blueprints

Anchors will automatically be destroyed if you delete the actor or component associated with the spatial anchor. For example:
Destroy spatial anchors Blueprint reference image
In this example, a component of type Oculus Spatial Anchor is passed into the function which will immediately destroy the internal anchor representation from the runtime. The developer is responsible for cleaning up any references to this component or actor state that may rely on it.

Destroy spatial anchors with C++

The function signature is as follows:
bool OculusXRAnchors::FOculusXRAnchors::DestroyAnchor(
   uint64 AnchorHandle,
   EOculusXRAnchorResult::Type& OutResult);
This is an example of calling the function checking the result:
EOculusXRAnchorResult::Type DestroyAnchor(uint64 AnchorHandle)
{
    EOculusXRAnchorResult::Type OutResult; // Detailed result code
    OculusXRAnchors::FOculusXRAnchors::DestroyAnchor(AnchorHandle, OutResult);
    return OutResult;
}

Share spatial anchors

Sharing a spatial anchor allows multiple devices in the same environment to localize an anchor as a shared reference point and share associated content or scene data. For more information on sharing please see Anchor Sharing

Share spatial anchors with Blueprints

Share spatial anchors Blueprint reference image
In this example:
  • There is an array of actors that each have a Spatial Anchor Component. There is also an array of strings representing User IDs.
  • These two arrays are passed as parameters to the Share Anchors function.
  • On success, the array of shared anchors is iterated over in a For Each loop.

Share spatial anchors with C++

The function signature is as follows:
bool OculusXRAnchors::FOculusXRAnchors::ShareAnchors(
   const TArray<UOculusXRAnchorComponent*>& Anchors,
   const TArray<uint64>& OculusUserIDs,
   const FOculusXRAnchorShareDelegate& ResultCallback,
   EOculusXRAnchorResult::Type& OutResult);
This is the layout of the delegate ResultCallback specified in the function.
DelegateParameters
FOculusXRAnchorShareDelegate
EOculusXRResult::Type Result,
const TArray<UOculusXRAnchorComponent*> Anchors,
const TArray<uint64> Users
Here is an example of calling the function and binding to the callback:
EOculusXRAnchorResult::Type ShareAnchors(const TArray<UOculusXRAnchorComponent*>& AnchorComponents, const TArray<FString>& OculusUserIDs)
{
    EOculusXRAnchorResult::Type OutResult; // Detailed immediate (non-async) result code

    OculusXRAnchors::FOculusXRAnchors::ShareAnchors(
        AnchorComponents,
        OculusUserIDs,
        FOculusAnchorShareDelegate::CreateLambda([](
            EOculusResult::Type Result,
            const TArray<UOculusAnchorComponent*>& Anchors,
            const TArray<uint64>& Users)
        {
            // Post-share logic here
        }),
        OutResult
    );

    return OutResult;
}

Get shared spatial anchors

You can retrieve anchors that have been shared with you via the GetSharedAnchors API. This is accessible in blueprints and in C++.

Get shared spatial anchors with Blueprints

Get shared spatial anchors Blueprint reference image
In this example:
  • An array of Anchor UUIDs to retrieve is passed into the Get Shared Anchors function.
  • On success the list of UUIDs is iterated over in a For Each loop.

Get shared spatial anchors with C++

The function signature is as follows:
bool OculusXRAnchors::FOculusXRAnchors::GetSharedAnchors(
    const TArray<FOculusXRUUID>& AnchorUUIDs,
    const FOculusXRGetSharedAnchorsDelegate& ResultCallback,
    EOculusXRAnchorResult::Type& OutResult);
This is the layout of the delegate ResultCallback specified in the function.
DelegateParameters
FOculusXRGetSharedAnchorsDelegate
EOculusXRResult::Type Result,
const TArray<UOculusXRAnchorsDiscoverResult*> Results
Here is an example of calling the function and binding to the callback.
EOculusXRAnchorResult::Type OutResult GetSharedAnchors(const TArray<FOculusXRUUID>& AnchorUUIDs)
{
    EOculusXRAnchorResult::Type OutResult; // Detailed immediate (non-async) result code

    OculusXRAnchors::FOculusXRAnchors::GetSharedAnchors(
        AnchorUUIDs,
        FOculusXRGetSharedAnchorsDelegate::CreateLambda([](
            EOculusResult::Type Result,
            const TArray<UOculusXRAnchorsDiscoverResult*> Results)
        {
            // Post-receive logic here
        }),
        OutResult
    );

    return OutResult;
}

Learn more

Continue learning about spatial anchors by reading these pages:
You can find more examples of using spatial anchors with Meta Quest in the oculus-samples GitHub repository:
To get started with Meta Quest Development in Unreal, see Unreal Engine.
Did you find this page helpful?