# Anchor Sample

This sample demonstrates how to create and destroy local anchors to accurately track a point in the real world. For basic information about anchors and what AR Foundation's AR Anchor Manager component does, please refer to the Unity documentation (opens new window). In order to use this feature it has to be enabled in the OpenXR plugin settings located under Project Settings > XR Plug-in Management > OpenXR (> Android Tab).

# How the sample works

First and foremost, make sure to have the Spatial Anchors feature enabled in the OpenXR project settings.

For placement purposes, a transparent placement gizmo visual is floating at the center of the camera at 1-meter distance. If Place anchor on surfaces toggle is enabled, a ray is cast forwards from the center of the head every frame in order to locate the position of the placement gizmo relative to real world planes. If a hit is detected, the placement gizmo will also turn yellow. After either tapping on the touchpad on the host controller or interacting with the gaze on the UI panel that is visible if the gaze interactor is selected, an empty GameObject and an ARAnchor GameObject will be instantiated. The empty GameObject has a transparent gizmo mesh and it will be tracked by the AR Session. The AR Anchor gizmo will be updated by the ARAnchorManager's anchorsChanged event to represent it's tracking state.

    public GameObject GizmoTrackedAnchor;
    public GameObject GizmoUntrackedAnchor;

    private override void Start() {
        FindObjectOfType<ARAnchorManager>().anchorsChanged += OnAnchorsChanged;
    }

    private void OnAnchorsChanged(ARAnchorsChangedEventArgs args) {
        foreach (var anchor in args.added) {
            ...
        }

        foreach (var anchor in args.updated) {
            Destroy(anchor.transform.GetChild(0).gameObject);
            var newGizmo = Instantiate(anchor.trackingState == TrackingState.None ? GizmoUntrackedAnchor : GizmoTrackedAnchor);
            newGizmo.transform.SetParent(anchor.transform, false);
        }

        foreach (var anchor in args.removed) {
            ...
        }
    }

# Destroying all anchors

Anchor UI panel

All anchors and gizmos can be destroyed by clicking Destroy All Anchors in the UI. The deletion command is issued with a delay to prevent the creation of an anchor with the 'Select' button after everything should be deleted.

# Spaces Anchor Store

WARNING

Make sure to look around your environment in order to generate a better tracking map and reduce saving and loading times. Saving multiple anchors at once blocks the main thread, so the callback should be used to save any subsequent anchor.

By adding a Spaces Anchor Store component next to the AR Anchor Manager, anchors can be saved locally to be recognized and tracked in a later session. The component provides following API's for loading and saving an anchor, deleting a saved anchor and clearing the local storage of anchors.

namespace Qualcomm.Snapdragon.Spaces
{
    public class SpacesAnchorStore
    {
        public void ClearStore();

        public void SaveAnchor(ARAnchor anchor, string anchorName, Action<bool> onSavedCallback = null);
        public void SaveAnchor(ARAnchor anchor, Action<bool> onSavedCallback = null);
        public void SaveAnchorWithResult(ARAnchor anchor, string anchorName, Action<SaveAnchorResult> onSavedCallback = null);
        public void SaveAnchorWithResult(ARAnchor anchor, Action<SaveAnchorResult> onSavedCallback = null);

        public void DeleteSavedAnchor(string anchorName);

        public void LoadSavedAnchor(string anchorName, Action<bool> onLoadedCallback = null);
        public void LoadAllSavedAnchors(Action<bool> onLoadedCallback = null);

        public string[] GetSavedAnchorNames();
        public string GetSavedAnchorNameFromARAnchor(ARAnchor anchor);
    }
}

Until this information moves to a scripting API, here is a short description of these methods:

  • ClearStore
    • Clears the local storage of anchors.
  • SaveAnchor
    • Saves an AR Anchor object either by a given name or by a generated hash. Can invoke a callback on complete.
  • SaveAnchorWithResult
    • Saves an AR Anchor object either by a given name or by a generated hash. Can invoke a callback on complete.
    • Possible values for SaveAnchorResult are the following:
      • PENDING: Anchor is pending saving. Cannot be normally seen, therefore use ARAnchor.pending instead.
      • SAVED: Saved successfully in local storage.
      • FAILURE_RUNTIME_ERROR: Not saved in local storage due to a runtime error.
      • FAILURE_STORE_NOT_LOADED: Not saved in local storage due to Spaces Anchor Store failing to load.
      • FAILURE_INSUFFICIENT_QUALITY: Not saved in local storage due to insufficient quality of the environment map.
  • DeleteSavedAnchor
    • Deletes a saved anchor by name from local storage.
  • LoadSavedAnchor
    • Loads an anchor from the local storage and tries to locate the anchor in the scene. If the anchor was found, an AR Anchor object will be instantiated. Loaded anchors will be listed as added in ARAnchorManager's anchorsChanged event. The name of the saved anchors can be retrieved with GetSavedAnchorNames. Can invoke a callback on complete.
  • LoadAllSavedAnchors
    • Loads all anchors from storage and tries to locate them in the scene. Similar as with LoadSavedAnchor, an AR Anchor object will be instantiated upon its recognition.
  • GetSavedAnchorNames
    • Returns all saved anchors by name.
  • GetSavedAnchorNameFromARAnchor
    • If a tracked AR Anchor object is a formerly saved one, this method will return its name, otherwise an empty string. This method can be used to check if an anchor is a saved one or not.

# Saving, deleting and loading anchors in the Sample

By enabling the Save new anchors to local store toggle, whenever a new anchor is created it will be saved to the local application store. This means that as long as there is an AR Anchor Manager in the scene this saved anchor could be recreated and tracked as any other regular anchor. To differentiate between a regular anchor and a saved anchor an additional cube mesh will be generated in the center of said anchor. If the cube is red it means that the saved anchor is not being tracked and if it's white it is being tracked. By clicking Load All Saved Anchors all anchors from the local store will be loaded and the underlying feature will try to locate them. On the other hand clicking Clear Store will delete all anchors that were saved in the local store. This action will not destroy any existing anchors that were loaded from the store.