Use Spatial Anchors
Updated: Sep 4, 2024
- In Edit > Project Settings > OculusVR:
- In the General section, go to the XR API list, and then select OVRPlugin OpenXR.
- In the Mobile section, select Passthrough Enabled and Anchor Support.
- Follow the typical steps for adding a Passthrough layer to an Unreal project.
Asynchronous Anchor Events
Most Spatial Anchors functions are asynchronous. That is, the results of the functions can’t be processed immediately as part of the return value and instead the results are broadcast later. In a Blueprint, this is performed using latent actions. There are success and failure execution pins available for every asynchronous Spatial Anchors function. In code, this is performed with a callback delegate passed to the function call.
Call Asynchronous Blueprint Function
Using one of the latent Spatial Anchors actions, you can respond to success or failure events for an asynchronous call by connecting to the output execution pins. Keep in mind that the success and failure execution pins don’t execute in the same frame as the start of the function call. To execute logic that isn’t dependent on the asynchronous results of Spatial Anchors Blueprints you can continue the execution flow by way of the unnamed immediate execution pin.
After the asynchronous function is completed, the success or failure pins execute. If the request was successful you can use the output data members that are part of the latent action.
Call Asynchronous C++ Function
Executing an asynchronous function in C++ requires passing a delegate as a parameter to the function that starts the asynchronous work. This delegate is executed in the case of success or failure and has a parameter that determines success as well as other parameters you can use in the success case. For more information, see
“Delegates” in the Unreal Engine documentation.
For example:
void CreateAnchorCallback(bool Success, UOculusAnchorComponent* Anchor)
{
UE_LOG(LogTemp, Log, TEXT(“Success: %d”), Success);
}
// Somewhere else in the code
OculusAnchors::CreateSpatialAnchor(
TargetActor->GetActorTransform(),
TargetActor,
FOculusSpatialAnchorCreateDelegate::CreateRaw(SomePointer, &SomeClass::CreateAnchorCallback);
Each anchor that a user wants to re-use over multiple sessions must have the anchor’s UUID saved to the headset’s local storage. Anchors saved to the cloud are not persistent indefinitely. Anchors saved using SaveAnchor or SaveAnchorList can be saved to the headset or to the cloud. This storage is accessible to a user and can be queried by way of QueryAnchors. You can load a specific set of anchors by providing a list of anchor UUIDs to the function call.
Use the Blueprint Interface
There’s no need to add any mandatory components or managers to a scene to use spatial anchors. You can access the Spatial Anchors system from Blueprints and we provide a set of Blueprint nodes that you can use. For more information, see
Blueprint API Reference.
Create Spatial Anchor Example - Spawn an actor.
- This actor does not have to have a spatial anchor component attached.
- Call the Blueprint method Oculus Async Create Spatial Anchor and pass in the anchor transform and actor as parameters.
- If the specified actor does not have a spatial anchor component attached, a new component is constructed for you.
- Execute logic using the Success and Failure pins.
- The resulting Anchor component output is only valid in the case of success.
Erase Spatial Anchor Example - Call the Blueprint method Oculus Async Erase Anchor.
- Pass in an actor that has a spatial anchor attached.
- Execute logic using the Success or Failure pins.
- The resulting Actor and UUID output is only valid in the case of success.
- The UUID of the destroyed anchor is returned for your bookkeeping.
Erase can also work as an “unsave” operation. It is up to you to decide whether you destroy the anchor actor representation as part of Erase.
Note: Cloud saved spatial anchors cannot be erased from storage.
Save Spatial Anchor Example You can save a specific spatial anchor or multiple anchors.
To save a specific spatial anchor:
- Call the Blueprint method Oculus Async Save Anchor.
- Specify the target actor that has a spatial anchor attached.
- Specify the storage location, this is either local or cloud.
- Execute logic using the Success or Failure pins.
The output Anchor Component is only valid if success is executed.
To save multiple anchors:
- Call the Blueprint method Oculus Async Save Anchors.
- Specify the target actors that have spatial anchors attached.
- Specify the storage location, this is either Local or Cloud..
- Execute logic using the Success or Failure pins.
The output Anchor Components array is only valid if success is executed.
Load Spatial Anchor Example - Get a list of Anchor UUIDs to request loading.
- This can be from a save game or anywhere else you are storing UUIDs.
- Call the Blueprint method Oculus Async Query Anchors.
- Specify the location to save to, this can be local or cloud.
- If successful, iterate the query results and then construct new actors using the Spawn Oculus Anchor Actor function.
Using the Spatial Anchors C++ API
The Spatial Anchors C++ API is accessed through the OculusAnchors
header file. Each asynchronous function that is part of the interface takes a delegate parameter as the last argument to the function. This delegate has a boolean parameter as its first argument which represents the success or failure state of that call. The following table lists each delegate and their associated parameters.
Delegate | Parameters |
---|
FOculusSpatialAnchorCreateDelegate
| EOculusResult::Type Result
UOculusAnchorComponent* Anchor
|
FOculusAnchorEraseDelegate
| EOculusResult::Type Result
FUUID AnchorUUID
|
FOculusAnchorSaveDelegate
| EOculusResult::Type Result
UOculusAnchorComponent* Anchor
|
FOculusAnchorSaveListDelegate
| bool Success
const TArray<UOculusAnchorComponent*> and SavedAnchors
|
FOculusAnchorQueryDelegate
| EOculusResult::Type Result
const TArray<FOculusSpaceQueryResult> and Results
|
Note: The example code below makes use of lambda delegate bindings. This isn’t a requirement to use the API and is only used to shorten the code being shown.
Create Spatial Anchor Example - Spawn an actor.
- This actor does not have to have a spatial anchor component attached.
- Call the method
OculusAnchors::CreateSpatialAnchor
and pass the anchor transform, actor, and result delegate in as parameters.
- If the specified actor does not have a spatial anchor component attached, a new component is constructed for you.
- Execute logic in the results delegate.
- The resulting spatial anchor component is only valid in the case of success.
AActor* NewActor = GetWorld()->SpawnActor<AActor>();
OculusAnchors::FOculusAnchors::CreateSpatialAnchor(NewActor->GetActorTransform(),
NewActor, FOculusSpatialAnchorCreateDelegate::CreateLambda([](bool Success,
UOculusAnchorComponent* AnchorComponent)
{
// Post-create logic in here
})
);
Erase Spatial Anchor Example - Retrieve an anchor from an actor.
- Call the method
OculusAnchors::EraseAnchor
and pass the anchor component and result delegate in as parameters. - Execute logic in the results delegate.
- The resulting UUID is only valid in the case of success.
UOculusAnchorComponent* AnchorComponent = … // Retrieve anchor
OculusAnchors::FOculusAnchors::EraseAnchor(AnchorComponent,
FOculusAnchorEraseDelegate::CreateLambda([](bool Success, FUUID UUID)
{
// Post-erase logic here
})
);
Save Spatial Anchor Example - Retrieve an anchor from an actor.
- Call the method
OculusAnchors::SaveAnchor
and pass the anchor component and result delegate in as parameters. - Execute logic in the results delegate.
- The resulting
AnchorComponent
is only valid in the case of success.
UOculusAnchorComponent* AnchorComponent = … // Retrieve anchor
OculusAnchors::FOculusAnchors::SaveAnchor(AnchorComponent,
EOculusSpaceStorageLocation::Local, FOculusAnchorSaveDelegate::CreateLambda([](bool
Success, UOculusAnchorComponent* AnchorComponent)
{
// Post-save logic here
})
);
Save Spatial Anchor List Example - Retrieve an anchor from an actor.
- Call the method OculusAnchors::SaveAnchor and pass the anchor component and result delegate in as parameters.
- Execute logic in the results delegate.
The resulting AnchorComponent is only valid in the case of success.
UOculusAnchorComponent* AnchorComponent = … // Retrieve anchor
OculusAnchors::FOculusAnchors::SaveAnchor(AnchorComponent,
EOculusSpaceStorageLocation::Local, FOculusAnchorSaveDelegate::CreateLambda([](bool
Success, UOculusAnchorComponent* AnchorComponent)
{
// Post-save logic here
})
);
Query Spatial Anchors Example - Generate a list of UUIDs,
- Call the method
OculusAnchors::QueryAnchors
and pass the list of UUIDs, the query location, the maximum number of anchors to load, and the result delegate in as parameters. - Execute logic in the results delegate.
- Spawn an actor of your choice, there is a helper method you can use called
SpawnActorWithAnchorQueryResults
.
uint32 MaxAnchorsToLoad = 16;
EOculusSpaceStorageLocation QueryLocation = EOculusSpaceStorageLocation::Local;
TArray<FUUID> AnchorUUIDs = ...;
OculusAnchors::FOculusAnchors::QueryAnchors(AnchorUUIDs, QueryLocation, MaxAnchorsToLoad,
FOculusAnchorQueryDelegate::CreateLambda([](bool Success, const
TArray<FOculusSpaceQueryResult>& Results)
{
if(Success)
{
for(auto& it : Results)
{
UOculusAnchorBPFuctionLibrary::SpawnActorWithAnchorQueryResults(
GetWorld(),
it,
AActor::StaticClass(), // Your class here
Owner,
Instigator,
CollisionHandlingMethod
);
}
}
})
);
We now expose error codes as the result of Spatial Anchors functions. These error codes are available as an output from the Blueprint API and the C++ API. Error codes are defined in the EOculusResult enum. Most enumeration results are general but there are specific enumerations available for spatial anchors.
UENUM(BlueprintType)
namespace EOculusResult
{
enum Type
{
Success = 0,
Success_EventUnavailable = 1,
Success_Pending = 2,
/// Failure
Failure = -1000,
Failure_InvalidParameter = -1001,
Failure_NotInitialized = -1002,
Failure_InvalidOperation = -1003,
Failure_Unsupported = -1004,
Failure_NotYetImplemented = -1005,
Failure_OperationFailed = -1006,
Failure_InsufficientSize = -1007,
Failure_DataIsInvalid = -1008,
Failure_DeprecatedOperation = -1009,
Failure_ErrorLimitReached = -1010,
Failure_ErrorInitializationFailed = -1011,
/// Space error cases
Failure_SpaceCloudStorageDisabled = -2000,
Failure_SpaceMappingInsufficient = -2001,
Failure_SpaceLocalizationFailed = -2002,
Failure_SpaceNetworkTimeout = -2003,
Failure_SpaceNetworkRequestFailed = -2004
};
}
Explanation of error values Failure_SpaceCloudStorageDisabled
: Saving anchors to cloud storage is not permitted by the user.
Failure_SpaceMappingInsufficient
: The user did not move around enough for a reliable localization. The user should walk and look around their space before calling save again. For example, the user could walk in a large circle around the center of their playspace.
Failure_SpaceLocalizationFailed
: The system failed to localize the shared anchor. This could be because the shared anchor is not near the user when calling Query.
Failure_SpaceNetworkTimeout
: Network operation timed out.
Failure_SpaceNetworkRequestFailed
: Network operation failed.
Migrating from Legacy Spatial Anchors
The API for Spatial Anchors changed to an improved version in Oculus SDK v43. Any legacy versions of Spatial Anchors in existing projects need to be migrated to this current version.
In general, all legacy Spatial Anchors calls that relied on event listeners have now been changed to latent actions. This means you can fold the event logic into a single execution flow graph rather than relying on a bifurcated event response model.
For example, the legacy Spatial Anchors logic for creating a spatial anchor looked like the following diagram:
You would:
- Bind a callback, usually in begin play, to the Spatial Anchors event you are listening for.
- Execute a Spatial Anchors method, in this case “Create Spatial Anchor”.
- Wait for the bound callback to execute.
- Complete any work necessary in the callback.
In contrast, the current Spatial Anchors logic now resembles the following diagram:
- Execute a latent action Blueprint nodes.
- Execute Success of Failure pins based on results.
Binding | Latent Action |
---|
Create Spatial Anchor | Oculus Async Create Spatial Anchor |
Erase Spatial Anchor | Oculus Async Erase Anchor |
Save Spatial Anchor | Oculus Async Save Anchor |
Query All Local Spatial Anchors | Oculus Async Query Anchors |
You can use the SpatialAnchorsSample
sample project as an example of how to use Spatial Anchors after migrating.