Spatial Anchors
Introduction
Spatial Anchors are key points used for positioning and tracking objects or scenes in virtual or augmented reality environments. They can be used to achieve stable placement of virtual objects, environmental understanding, shared virtual scenes, and other functions. Spatial Anchors are a technology jointly implemented by software and hardware, capable of associating virtual content with specific locations or objects in the real world.
Basic Concepts
Name | Description |
---|---|
UUID | The unique identifier of the anchor, returned when the anchor is created |
anchorHandle | The handle of the anchor, the identifier in the application's memory |
Enabling Spatial Anchor Permissions for the Application
- Open the project in Unity
- Add XR Origin to the scene
- Add the YVRManager script
- Check the Enable SpatialAnchorSupport option in the YVRManager script panel
After checking the SpatialAnchorSupport checkbox, the corresponding permission will be added to the AndroidManifest.xml file
**\<uses-permission android:name="com.yvr.permission.USE_ANCHOR_API"\\>**
Spatial Anchor Interface
Creating an Anchor
/// <summary>
/// Creates a spatial anchor using the given position and rotation.
/// </summary>
/// <param name="position">Anchor position</param>
/// <param name="rotation">Anchor rotation</param>
/// <param name="result">Callback for the anchor creation interface</param>
public void CreateSpatialAnchor(Vector3 position, Quaternion rotation, Action<YVRSpatialAnchorResult,bool> result)
After creating the anchor, the Action<YVRSpatialAnchorResult,bool> callback will be triggered. YVRSpatialAnchorResult returns anchor information, and bool indicates whether the anchor creation was successful.
public struct YVRSpatialAnchorResult
{
// Task Id
public ulong requestId;
// Anchor handle
public ulong anchorHandle;
// Anchor unique identifier
public Char[] uuid;
}
Code example
public void CreateSpatialAnchor(Transform transform)
{
YVRSpatialAnchor.instance.CreateSpatialAnchor(transform.position, transform.rotation, OnCreateSpatialAnchor);
}
private void OnCreateSpatialAnchor(YVRSpatialAnchorResult result, bool success)
{
if(!success)
{
Debug.LogError("Create spatial anchor failed!" );
return;
}
Debug.Log("Create spatial anchor success");
//TODO Custom logic
}
Saving an Anchor
Call the YVRSpatialAnchor.instance.SaveSpatialAnchor interface to save the anchor. The anchor can be saved on the local device or in the cloud. Saving the anchor in the cloud requires the user to be logged into the device account and the device to be connected to the internet
/// <summary>
/// Saves the spatial anchor using the provided save information
/// </summary>
/// <param name="saveInfo">Save information</param>
/// <param name="callback">Save result callback</param>
public void SaveSpatialAnchor(YVRSpatialAnchorSaveInfo saveInfo, Action<YVRSpatialAnchorSaveCompleteInfo,bool> callback)
Save anchor parameter information YVRSpatialAnchorSaveInfo
public struct YVRSpatialAnchorSaveInfo
{
// Handle of the anchor to be saved
public ulong anchorHandle;
// Save location Local: Local memory, Cloud: Cloud
public YVRSpatialAnchorStorageLocation storageLocation;
}
Save result callback Action<YVRSpatialAnchorSaveCompleteInfo,bool> YVRSpatialAnchorSaveCompleteInfo save result information, bool indicates whether the save was successful
public struct YVRSpatialAnchorSaveCompleteInfo
{
// Task Id
public ulong requestId;
// Result code
public int resultCode;
// Saved anchor handle
public ulong anchorHandle;
// Saved anchor UUID
public char[] uuid;
// Save location
public YVRSpatialAnchorStorageLocation location;
}
Code example:
private void SaveAnchor(ulong anchorHandle)
{
YVRSpatialAnchorSaveInfo saveInfo = new YVRSpatialAnchorSaveInfo();
saveInfo.anchorHandle = anchorHandle;
// Save to local
saveInfo.storageLocation = YVRSpatialAnchorStorageLocation.Local;
// Save to cloud
//saveInfo.storageLocation = YVRSpatialAnchorStorageLocation.Cloud;
YVRSpatialAnchor.instance.SaveSpatialAnchor(saveInfo, OnSaveCompleteCallback);
}
private void OnSaveCompleteCallback(YVRSpatialAnchorSaveCompleteInfo saveResult,bool success)
{
Debug.Log("Save anchor result:" + success);
}
Deleting an Anchor
Call the YVRSpatialAnchor.instance.EraseSpatialAnchor() interface to delete the specified anchor at the specified location
/// <summary>
/// Deletes the corresponding spatial anchor based on the anchor handle and storage location
/// </summary>
/// <param name="anchorHandle">Handle of the anchor to be deleted</param>
/// <param name="location">Storage location of the anchor</param>
/// <param name="callback">Callback for the delete result</param>
public void EraseSpatialAnchor(UInt64 anchorHandle, YVRSpatialAnchorStorageLocation location,Action<YVRSpatialAnchorResult,bool> callback)
Delete result callback Action<YVRSpatialAnchorResult,bool> YVRSpatialAnchorResult deleted anchor, bool indicates whether the deletion was successful
Code example:
private void EraseSpatialAnchor()
{
YVRSpatialAnchor.instance.EraseSpatialAnchor(m_spatialAnchor.spaceHandle, YVRSpatialAnchorStorageLocation.Local,
OnEraseCompleteCallback);
}
private void OnEraseCompleteCallback(YVRSpatialAnchorResult result,bool success)
{
Debug.Log($"Erase anchor:{result.anchorHandle}, uuid:{new string(result.uuid)} {success}");
}
Querying an Anchor
Call the YVRSpatialAnchor.instance.QuerySpatialAnchor to query the anchor
/// <summary>
/// Queries the spatial anchor based on the provided query information
/// </summary>
/// <param name="queryInfo">Query information</param>
/// <param name="queryCallback">Query result</param>
public void QuerySpatialAnchor(YVRSpatialAnchorQueryInfo queryInfo , Action<List<YVRSpatialAnchorResult>> queryCallback)
YVRSpatialAnchorQueryInfo query information, supports querying by uuid or component type
public struct YVRSpatialAnchorQueryInfo
{
// Maximum number of anchors to return in the query (default is zero, meaning no limit)
public uint MaxQuerySpaces;
// Query timeout (default is zero, meaning no timeout)
public double Timeout;
// Query location
public YVRSpatialAnchorStorageLocation storageLocation;
// Component type of the anchor to query
public YVRSpatialAnchorComponentType component;
// Number of uuids to query
public int numIds;
// List of uuids to query
public YVRSpatialAnchorUUID[] ids;
}
Code example:
// Query all local anchors saved on this device
private void QueryAllLocalAnchor()
{
YVRSpatialAnchorQueryInfo queryInfo = new YVRSpatialAnchorQueryInfo();
queryInfo.storageLocation = YVRSpatialAnchorStorageLocation.Local;
YVRSpatialAnchor.instance.QuerySpatialAnchor(queryInfo, QuerySpatialAnchorComplete);
}
// Query anchors previously saved in the cloud using uuids
private void QuerryUUIDsAnchor(List<char[]> uuids)
{
YVRSpatialAnchorQueryInfo queryInfo = new YVRSpatialAnchorQueryInfo();
queryInfo.storageLocation = YVRSpatialAnchorStorageLocation.Cloud;
queryInfo.ids = new YVRSpatialAnchorUUID[uuids.Count];
for(int i = 0; i < uuids.Count; i++)
{
queryInfo.ids[i] = new YVRSpatialAnchorUUID();
queryInfo.ids[i].Id = uuids[i];
}
YVRSpatialAnchor.instance.QuerySpatialAnchor(queryInfo, QuerySpatialAnchorComplete);
}
// Query result
private void QuerySpatialAnchorComplete(List<YVRSpatialAnchorResult> results)
{
Debug.Log("QuerySpacesComplete count:" + results.Count);
}
When querying saved anchors in the same area, you may not find the anchors. Try walking around to collect more point cloud data and then call the query again. The frequency of interface calls can be decided by yourself, **it is recommended to call once every second**
Getting the Real-time Pose of an Anchor
Call the YVRSpatialAnchor.instance.GetSpatialAnchorPose interface to get the real-time position of the anchor, keeping the anchor's position fixed. If not obtained, the anchor's position may shift when the user moves in the scene or performs recentering. It supports calling every frame.
/// <summary>
/// Gets the pose of the anchor
/// </summary>
/// <param name="anchorHandle">Anchor handle</param>
/// <param name="position">Returns the position of the anchor</param>
/// <param name="rotation">Returns the rotation of the anchor</param>
/// <param name="locationFlags">Anchor location status</param>
/// <returns></returns>
public bool GetSpatialAnchorPose(ulong anchorHandle, out Vector3 position, out Quaternion rotation,out YVRAnchorLocationFlags locationFlags)
When the method to get the anchor pose returns false, or the location status is not tracked, it means the current map has switched. At this time, the anchor becomes invalid, and the returned pose may be incorrect. You need to wait for the user to return to the map where the anchor was created, or when the map where the anchor was created merges with other maps, the anchor will become valid again.
Getting Supported Component Types of an Anchor
Call YVRSpatialAnchor.instance.GetSpatialAnchorEnumerateSupported to get the supported component types of the specified anchor. Currently, anchors created by third-party references only support pose (Locatable), storage (Storable), and sharing (Sharable).
/// <summary>
/// Gets the supported component types of the anchor
/// </summary>
/// <param name="anchorHandle">Anchor handle</param>
/// <param name="components">Supported component types</param>
public void GetSpatialAnchorEnumerateSupported(ulong anchorHandle, out YVRSpatialAnchorSupportedComponent components)
Setting the Component Status of an Anchor
Call YVRSpatialAnchor.instance.SetSpatialAnchorComponentStatus() to set the component status of the anchor. The created anchor by default includes pose (Locatable), storage (Storable), and sharing (Sharable).
/// <summary>
/// Sets the component status of the anchor
/// </summary>
/// <param name="anchorHandle">Anchor handle</param>
/// <param name="setInfo">Status information</param>
/// <param name="callback">Callback for setting the anchor status</param>
/// <returns></returns>
public bool SetSpatialAnchorComponentStatus(ulong anchorHandle, YVRSpatialAnchorComponentStatusSetInfo setInfo,
Action<YVRSpatialAnchorSetStatusCompleteInfo,bool> callback)
Code example:
private void DisableAnchorStorableState(ulong anchorHandle)
{
YVRSpatialAnchorComponentStatusSetInfo componentStatusSetInfo = new YVRSpatialAnchorComponentStatusSetInfo();
componentStatusSetInfo.component = YVRSpatialAnchorComponentType.Storable;
// When setting the Storable of the created anchor to false, the anchor cannot be saved.
componentStatusSetInfo.enable = false;
YVRSpatialAnchor.instance.SetSpatialAnchorComponentStatus(result.anchorHandle, componentStatusSetInfo,null);
}
The code example above disables the storage permission of the anchor
Getting the Component Status of an Anchor
Call YVRSpatialAnchor.instance.GetSpatialAnchorComponentStatus to get the status of the specified component of the anchor
/// <summary>
/// Gets the status of the specified component of the anchor
/// </summary>
/// <param name="anchorHandle">Anchor handle</param>
/// <param name="componentType">Component type</param>
/// <param name="status">Returned status information</param>
public void GetSpatialAnchorComponentStatus(ulong anchorHandle, YVRSpatialAnchorComponentType componentType, out YVRSpatialAnchorComponentStatus status)
Batch Saving Anchors
YVRSpatialAnchor.instance.SaveSpatialAnchorList saves multiple anchors at once
/// <summary>
/// Batch saves anchors
/// </summary>
/// <param name="spatialAnchorHandleList">List of anchor handles</param>
/// <param name="location">Save location</param>
/// <param name="callback">Save result callback</param>
public void SaveSpatialAnchorList(List<ulong> spatialAnchorHandleList, YVRSpatialAnchorStorageLocation location,
Action<bool> callback)
Getting Anchor UUID by anchorHandle
Call YVRSpatialAnchor.instance.GetSpatialAnchorUUIDForHandle to get the unique identifier of the anchor by the anchor handle
/// <summary>
/// Gets the unique identifier of the anchor by the anchor handle
/// </summary>
/// <param name="anchorHandle">Anchor handle</param>
/// <param name="uuid">Anchor unique identifier</param>
public void GetSpatialAnchorUUIDForHandle(ulong anchorHandle, out YVRSpatialAnchorUUID uuid)
Getting Spatial Calibration Anchor Information
Only anchors created by the Spatial Calibration application in the system support setting calibration information, including anchor components, semantic tags, plane information, and cube information. You can use the Spatial Calibration interface to get the calibration information of the anchor and then use it in your own reference. For details, refer to the Spatial Calibration documentation.
Demo
SpatialAnchorSample demonstrates the related functions of spatial anchors, including creating anchors, saving anchors, deleting anchors, querying anchors, sharing anchors, etc. When demonstrating the sharing function, you need to manually configure your own photon id and service.