Please Select Your Location
Australia
Österreich
België
Canada
Canada - Français
中国
Česká republika
Denmark
Deutschland
France
HongKong
Iceland
Ireland
Italia
日本
Korea
Latvija
Lietuva
Lëtzebuerg
Malta
المملكة العربية السعودية (Arabic)
Nederland
New Zealand
Norge
Polska
Portugal
Russia
Saudi Arabia
Southeast Asia
España
Suisse
Suomi
Sverige
台灣
Ukraine
United Kingdom
United States
Please Select Your Location
België
Česká republika
Denmark
Iceland
Ireland
Italia
Latvija
Lietuva
Lëtzebuerg
Malta
Nederland
Norge
Polska
Portugal
España
Suisse
Suomi
Sverige

Anchor (Beta)

In virtual reality (VR), an anchor is used to maintain a consistent correspondence between virtual objects and specific locations in the real world, even when there is a reset of the headset's pose (HMD). This feature ensures that, regardless of changes in the user's viewpoint or orientation caused by resetting the headset, the virtual objects remain accurately positioned in relation to the real-world environment. Anchors effectively link virtual content to a fixed point in physical space, allowing for a coherent and consistent user experience, where virtual elements reliably appear in the same real-world locations, despite any adjustments in the headset's tracking or calibration.

Supported Platforms and Devices

Platform Headset Supported Plugin Version
PC PC Streaming Focus 3/XR Elite/Focus Vision X
Pure PC Vive Cosmos X
Vive Pro series X
AIO Focus 3 X
XR Elite V 2.5.0 and above
Focus Vision V 2.5.0 and above
Editor OpenXR Standalone Mock Runtime V See Mock Runtime

Specification

This chapter explains how to use the Anchor feature, including basic anchor usage and the persistence functionality, which allows anchors to persist across sessions, utilizing the Anchor extension.

Environment Settings

The Anchor feature has ROM dependency:

VIVE OpenXR Unity plugin supports Anchor VIVE XR Anchor which depends on the OpenXR feature group.

Enable the Anchor feature in Edit > Project Settings > XR Plug-in Management > OpenXR, enable the VIVE XR Anchor feature.


The persistence extension is default enabled in the plugin.

Golden Sample

The Sample at Asset > VIVE > OpenXR > Samples > Anchor.

What is Spatial Anchor

A spatial anchor represents a specific location in the real world that is mapped into virtual reality. By using an anchor, the system establishes a link between a real-world position and a corresponding point in virtual space, ensuring that this spatial relationship is accurately maintained.

In practice, anchors are often used with passthrough mode enabled. When passthrough is active, you can see the real-world environment while in VR. Using the controller, you can capture the real-world position and map it into VR’s tracking space. This allows you to place virtual objects relative to the anchor, ensuring their positions stay consistent with the real-world location.

Even if you adjust the VR boundary or change your view orientation, the anchor’s relative position to both the real and virtual environments will not change. This ensures that any virtual objects placed in relation to the anchor remain aligned with the real-world location, regardless of boundary adjustments or orientation changes.

Additionally, anchors can be persisted, meaning that they won’t be lost even if the application is closed. By persisting anchors, you can maintain the spatial relationships across sessions, ensuring that the anchor remains available when you reopen the app.

Furthermore, persisted anchors can be exported or imported, allowing you to save anchors for future use or transfer them to other devices. This enables sharing of spatial anchors between multiple devices, ensuring that the same real-world location is consistently mapped in different VR environments.

How to use Spatial Anchor

1. Check if the Anchor feature is supported.

Before utilizing the Anchor feature, ensure that the system supports it. You can check this upon initialization:

void OnEnable() {
    enabled = AnchorManager.IsSupported();
    if (!enabled) return;
}

2. Check if the Anchor Persistence feature is supported.

Anchor persistence allows anchors to remain available across multiple sessions, enabling the saving and restoration of anchors even after the app is closed or the VR session is restarted.

To use this feature, you need to verify if the system supports anchor persistence and then acquire a Persisted Anchor Collection (PAC) handle:

FutureTask<(XrResult, IntPtr)> taskPAC;
void OnEnable() {
    enabled &= AnchorManager.IsPersistedAnchorSupported();
    if (!enabled) return;
    taskPAC = AnchorManager.AcquirePersistedAnchorCollection();
    taskPAC.AutoComplete();
    taskPAC.AutoCompleteTask.ContinueWith((_) => {
        if (AnchorManager.IsPersistedAnchorCollectionAcquired()) {
            // PAC acquired successfully
        }
        // Clear the task
        taskPAC.Dispose();
        taskPAC = null;
    });
}

Since not all devices or runtimes support persistence, use AnchorManager.IsPersistedAnchorSupported() to confirm its availability before proceeding.

A PersistedAnchorCollection is required for any persistence-related operations. The first time you create a Persisted Anchor Collection, it may take some time as it reads stored anchors and loads them into the runtime. Once loaded, you can enumerate and manage these persisted anchors.

Most persistence operations are asynchronous, so you can either use C#'s asynchronous programming to manage them or poll tasks to track their completion:

void Update() {
    if (taskPAC.IsCompleted) {
        if (AnchorManager.IsPersistedAnchorCollectionAcquired()) {
            // PAC Acquired successfully
        }
    }
}

When you're done working with persisted spatial anchors, you can destroy the Persisted Anchor Collection to free up resources:

AnchorManager.DestroyPersistedAnchorCollection();

3. Create an Anchor.

To create an anchor, you need to provide a pose relative to the tracking origin and assign a unique name. The following code uses the current time to generate a unique name, preventing duplication:

public string MakeUniqueName(string name)
{
    // Not to use any UnityEngine code if you want to run in an async task.
    return name + DateTime.Now.Ticks;
}

AnchorManager.Anchor anchor = AnchorManager.CreateAnchor(relatedPose, MakeUniqueName("SpatialAnchor"));

After creating an anchor, you can retrieve its pose within the tracking space:

AnchorManager.GetTrackingSpacePose(anchor, out Pose pose);

To retrieve the name of the anchor:

anchor.GetSpatialAnchorName();

If the anchor is no longer needed, you can dispose of it to free resources:

anchor.Dispose();

4. Persisted Anchors

To retain an anchor across multiple sessions, use the persistence feature. Each persisted anchor must have a unique name:

// Create unique name for persisted anchor
string persistedAnchorName = MakeUniqueName("PersistedAnchor");
// Use async task to persist the anchor
Task task = Task.Run(async () => {
    // For simplicity, this example ignores error handling. Assume tasks succeed.
    FutureTask<XrResult> persistTask = AnchorManager.PersistAnchor(anchor, persistedAnchorName);
    persistTask.AutoComplete();
    await persistTask.AutoCompleteTask;
    persistTask.Dispose();
    persistTask = null;
}

To list all exist persisted anchors:

AnchorManager.EnumeratePersistedAnchorNames(out string[] names);

To retrieve the pose of a persisted anchor, you first need to recreate the spatial anchor. Locating a persisted anchor may take time as it relies on real-world mapping. Using the HMD to scan the environment can improve anchor location accuracy. However, there's a chance the anchor may not be located -- check the result for details.

Task task = Task.Run(async () => {
    string spatialAnchorName = MakeUniqueName("SpatialAnchorCreatedFromPersistedAnchor");
    FutureTask<(XrResult, Anchor)> csafpTask = AnchorManager.CreateSpatialAnchorFromPersistedAnchor(persistedAnchorName, spatialAnchorName);
    csafpTask.AutoComplete();
    await csafpTask.AutoCompleteTask;

    Anchor anchor = csafpTask.Result.Item2;
    Debug.Log("Created SpatialAnchorName is " + anchor.Name);
    csafpTask.Dispose();
    csafpTask = null;

    // Get the anchor's pose
    AnchorManager.GetTrackingSpacePose(anchor, out Pose pose);
}

You can remove persisted anchors individually by name, or clear all persisted anchors at once:

// Remove a single persisted anchor
AnchorManager.UnpersistAnchor(persistedAnchorName);

// Clear all persisted anchors
AnchorManager.ClearPersistedAnchors();

5. Export and Import Persisted Anchors

Persisted anchors can be exported and imported, allowing you to save and load them across devices or sessions. The export function returns a byte array, which can then be saved to a file or transferred to another device:

Task task = Task.Run(async () => {
    var exportTask = AnchorManager.ExportPersistedAnchor(persistedAnchorName);
    await exportTask;
    byte [] anchorData = exportTask.Result.Item3;
    exportTask.Dispose();
    exportTask = null;
}

Once exported, you can store the byte array in a file or send it to another device.

The persisted anchor name can be retrieved from the byte array, which is useful when receiving anchor data from another device. You can verify the persisted anchor name before or after importing:

AnchorManager.GetPersistedAnchorNameFromBuffer(anchorData, out string persistedAnchorName);

To import a persisted anchor, simply provide the byte array that was previously exported:

// Load the byte array from a file or receive it from another device
byte [] anchorData = ...;
// Import the persisted anchor from the byte array
Task task = Task.Run(async () => {
    var importTask = AnchorManager.ImportPersistedAnchor(anchorData);
    await importTask;
    importTask.Dispose();
    importTask = null;
}

Mock Runtime

The OpenXR Standalone Mock Runtime is a valuable tool for developers, enabling them to test OpenXR applications without requiring a physical device. It simulates the behavior of an OpenXR runtime, providing a controlled environment for testing.

We offer a beta version of the VIVE XR Mock Runtime, which allows developers to test the Anchor feature directly in the editor. This mock runtime can generate simulated anchors and supports testing for anchor persistence, export, and import functionalities. All asynchronous operations, such as anchor creation and persistence, are simulated and take time to complete.

Please note that the VIVE XR Mock Runtime may experience instability due to known issues with Unity's Mock Runtime. It is recommended to save your project before using it.

To use the Mock Runtime with the Anchor feature, follow these steps:

  • Go to: Edit > Project Settings > XR Plug-in Management > OpenXR
  • Select the Standalone tab.
  • Enable the Mock Runtime, VIVE XR Anchor, and Vive XR MockRuntime feature in the Feature list.
  • Click the gear icon next to Vive XR MockRuntime, and ensure Enable Future and Enable Anchor are checked.
  • Click the Install Mock Runtime Library button to install the necessary library, which will be copied to the project's Plugins folder.
  • Open a sample scene, such as AnchorPersistenceTest.
  • Run the project within the editor to test the anchor functionality.


See Also

Anchor extension.

FAQ

  • Why is my spatial anchor gone after restarting the application?
    Spatial anchors are not automatically saved across sessions. To retain an anchor after the application restarts, you must use a persisted anchor.

  • Why is my persisted anchor missing after restarting the application?
    If your environment has changed, the persisted anchor from the previous session can still be listed, but the spatial anchor created from it may no longer be locatable.

  • Why can't I create a spatial anchor from a persisted anchor?
    If you're unable to create a spatial anchor from a persisted anchor, try scanning the environment with your HMD to help locate the anchor, and then attempt the creation again.

  • How can I improve the chances of locating a spatial anchor from a persisted anchor?
    Before creating a spatial anchor from a persisted anchor, use your HMD to scan the environment. If the persisted anchor was shared between devices, focus on the area where the original anchor was created to improve the chances of successfully locating it.

  • What does it mean to scan the environment?
    Scanning the environment involves wearing the HMD and walking around the space. The HMD will map the surroundings, which helps in creating and locating the spatial anchor by providing a reference to the real-world environment.