Persistent anchors
AR Foundation 6 introduces an API for persistent anchors that enables you to save anchors in an AR session and load them in subsequent AR sessions. You can use this API to persist the state of your app across multiple sessions in the same physical space. The following sections explain how to use the persistent anchors API.
The Anchors sample scene shows you how to use the persistent anchor API on supported devices
Important
The AR Foundation persistent anchor API is a wrapper for persistent anchor APIs on multiple platforms. Due to the limitations of all supported platforms, you can't save an anchor on one platform and load it on another platform. Refer to the provider plug-in documentation for your target platforms to understand any additional platform-specific details.
Check support
The AR Foundation persistent anchor API consists of five optional features of the anchor subsystem:
- Save anchor
- Load anchor
- Erase anchor
- Get saved anchor IDs
- Async cancellation
Refer to the Optional features support table to learn which provider plug-ins support these features, and how to query for this information in C# scripts. The following sections explain each optional feature in more detail, including example code.
Save anchor
The save operation takes an anchor as input, saves that anchor to persistent storage, and returns a persistent anchor GUID that you can use later to load or erase the anchor.
Note
Some AR platforms may save anchors to the device's local disk, while others may save them to a cloud storage location associated with your app. Refer to the provider plug-in documentation for your target platforms to understand the implementation details of how anchors are saved.
To save an anchor, use ARAnchorManager.TrySaveAnchorAsync as shown in the following code example:
async void TrySaveAnchorAsync(ARAnchor anchor)
{
// This is inefficient. You should re-use a saved reference instead.
var manager = Object.FindAnyObjectByType<ARAnchorManager>();
var result = await manager.TrySaveAnchorAsync(anchor);
if (result.status.IsError())
{
// handle error
return;
}
// Save this value, then use it as an input parameter
// to TryLoadAnchorAsync or TryEraseAnchorAsync
SerializableGuid guid = result.value;
}
Important
Keep track of the persistent anchor GUIDs returned to you by TrySaveAnchorAsync
. Not all platforms support the ability to get your saved persistent anchor GUIDs should you lose them.
The AR Foundation Samples GitHub repository contains example code that you can use to save your persistent anchor GUIDs to Unity's Applicaiton.persistentDataPath, allowing you to quit your app and then load or erase your saved anchors in subsequent sessions.
Load anchor
The load operation takes a persistent anchor GUID returned by Save anchor as input, retrieves the associated anchor from persistent storage, and returns a newly created anchor. On the AR Anchor Manager component's next Update step, that anchor will be reported as added.
The following example code demonstrates how to load an anchor:
async void TryLoadAnchorAsync(SerializableGuid guid)
{
// This is inefficient. You should re-use a saved reference instead.
var manager = Object.FindAnyObjectByType<ARAnchorManager>();
var result = await manager.TryLoadAnchorAsync(guid);
if (result.status.IsError())
{
// handle error
return;
}
// You can use this anchor as soon as it's returned to you.
ARAnchor anchor = result.value;
}
Erase anchor
The erase operation takes a persistent anchor GUID returned by Save anchor as input, erases that anchor from persistent storage, and returns a status indicating if the operation was successful.
Note
The save and erase operations only modify the persistent storage associated with an anchor, not the tracking state of the anchor. For instance, if you create an anchor, save it, then immediately erase it, the persistent storage associated with the anchor will be erased, but the anchor itself will not be removed.
The following example code demonstrates how to erase an anchor:
async void TryEraseAnchorAsync(SerializableGuid guid)
{
// This is inefficient. You should re-use a saved reference instead.
var manager = Object.FindAnyObjectByType<ARAnchorManager>();
var status = await manager.TryEraseAnchorAsync(guid);
if (status.IsError())
{
// handle error
return;
}
// The anchor was successfully erased.
}
Get saved anchor IDs
Some platforms support the ability to get a list of your currently saved anchors. If your app has successfully kept track of its state across usages of save anchor and erase anchor, you have no reason to use this API. However, if you lose track of your currently saved anchors for any reason, this API is a useful way to recover them, allowing you to subsequently load or erase your saved anchors.
The following example code demonstrates how to get saved anchor IDs:
async void TryGetSavedAnchorIdsAsync()
{
// This is inefficient. You should re-use a saved reference instead.
var manager = Object.FindAnyObjectByType<ARAnchorManager>();
// If you need to keep the saved anchor IDs longer than a frame, use
// Allocator.Persistent instead, then remember to Dispose the array.
var result = await manager.TryGetSavedAnchorIdsAsync(Allocator.Temp);
if (result.status.IsError())
{
// handle error
return;
}
// Do something with the saved anchor IDs
NativeArray<SerializableGuid> anchorIds = result.value;
}
Async cancellation
AR Foundation's persistent anchors API is entirely asynchronous. If your target platform supports the ability to cancel async operations in progress, you can use the CancellationToken input parameter of the other persistent anchor methods. Otherwise, this input parameter is ignored on platforms that do not support cancellation.
The following example code demonstrates how to cancel an async operation:
void AsyncCancellation()
{
// This is inefficient. You should re-use a saved reference instead.
var manager = Object.FindAnyObjectByType<ARAnchorManager>();
// Create a CancellationTokenSource to serve our CancellationToken
var cts = new CancellationTokenSource();
// Use one of the other methods in the persistent anchor API
var awaitable = manager.TryGetSavedAnchorIdsAsync(Allocator.Temp, cts.Token);
// Cancel the async operation before it completes
cts.Cancel();
}