空间锚点
介绍
空间锚点(Spatial Anchors)是在虚拟或增强现实环境中用于定位和跟踪物体或场景的关键点。它们可以被用来实现虚拟物体的稳定放置、环境理解、共享虚拟场景等功能。空间锚点是一种由软件和硬件共同实现的技术,能够将虚拟内容与现实世界中的特定位置或物体相对应起来。
基本概念
名称 | 说明 |
---|---|
UUID | 锚点的唯一标识码,在创建锚点时返回 |
anchorHandle | 锚点的句柄,在应用内存中的标识 |
为应用开启空间锚点权限
- 在 Unity 中打开项目
- 为场景添加 XR Origin
- 添加 YVRManager 脚本
- 在 YVRManager 脚本面板上勾选启用 SpatialAnchorSupport
勾选 SpatialAnchorSupport 选框后,AndroidManifest.xml 文件中会添加锚点对应权限
**\<uses-permission android:name="com.yvr.permission.USE_ANCHOR_API"\\>**
空间锚点接口
创建锚点
/// <summary>
/// 使用给定的位置和旋转创建空间锚点。
/// </summary>
/// <param name="position">锚点位置</param>
/// <param name="rotation">锚点旋转</param>
/// <param name="result">创建锚点的接口回调</param>
public void CreateSpatialAnchor(Vector3 position, Quaternion rotation, Action<YVRSpatialAnchorResult,bool> result)
创建锚点后会响应 Action<YVRSpatialAnchorResult,bool> 回调,YVRSpatialAnchorResult 返回锚点信息,bool 表示锚点创建是否成功。
public struct YVRSpatialAnchorResult
{
//任务 Id
public ulong requestId;
//锚点的句柄
public ulong anchorHandle;
//锚点的唯一标识码
public Char[] uuid;
}
代码示例
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 自定义逻辑
}
保存锚点
调用 YVRSpatialAnchor.instance.SaveSpatialAnchor 接口保存锚点,可以将锚点保存在本地设备中或保存在云端,将锚点保存在云端需要用户已登陆设备账号并且设备联网
/// <summary>
/// 使用提供的保存信息保存空间锚点
/// </summary>
/// <param name="saveInfo">保存信息</param>
/// <param name="callback">保存结果回调</param>
public void SaveSpatialAnchor(YVRSpatialAnchorSaveInfo saveInfo, Action<YVRSpatialAnchorSaveCompleteInfo,bool> callback)
保存锚点参数信息 YVRSpatialAnchorSaveInfo
public struct YVRSpatialAnchorSaveInfo
{
// 需要保存锚点的句柄
public ulong anchorHandle;
// 保存位置 Local: 本地内存,Cloud: 云端
public YVRSpatialAnchorStorageLocation storageLocation;
}
保存结果的回调 Action<YVRSpatialAnchorSaveCompleteInfo,bool> YVRSpatialAnchorSaveCompleteInfo 保存结果信息,bool 保存是否成功
public struct YVRSpatialAnchorSaveCompleteInfo
{
// 任务 Id
public ulong requestId;
// 返回结果码
public int resultCode;
// 保存的锚点句柄
public ulong anchorHandle;
// 保存的锚点 UUID
public char[] uuid;
// 保存的位置
public YVRSpatialAnchorStorageLocation location;
}
代码示例:
private void SaveAnchor(ulong anchorHandle)
{
YVRSpatialAnchorSaveInfo saveInfo = new YVRSpatialAnchorSaveInfo();
saveInfo.anchorHandle = anchorHandle;
// 保存至本地
saveInfo.storageLocation = YVRSpatialAnchorStorageLocation.Local;
// 保存至云端
//saveInfo.storageLocation = YVRSpatialAnchorStorageLocation.Cloud;
YVRSpatialAnchor.instance.SaveSpatialAnchor(saveInfo, OnSaveCompleteCallback);
}
private void OnSaveCompleteCallback(YVRSpatialAnchorSaveCompleteInfo saveResult,bool success)
{
Debug.Log("Save anchor result:" + success);
}
删除锚点
调用 YVRSpatialAnchor.instance.EraseSpatialAnchor() 接口删除指定位置指定锚点
/// <summary>
/// 根据锚点句柄和存储位置删除对应的空间锚点
/// </summary>
/// <param name="anchorHandle">需要删除的锚点句柄</param>
/// <param name="location">锚点的存储位置</param>
/// <param name="callback">删除结果的回调</param>
public void EraseSpatialAnchor(UInt64 anchorHandle, YVRSpatialAnchorStorageLocation location,Action<YVRSpatialAnchorResult,bool> callback)
删除结果回调 Action<YVRSpatialAnchorResult,bool> YVRSpatialAnchorResult 删除的锚点,bool 是否成功
代码示例:
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}");
}
查询锚点
调用 YVRSpatialAnchor.instance.QuerySpatialAnchor 查询锚点
/// <summary>
/// 根据提供的查询信息查询空间锚点
/// </summary>
/// <param name="queryInfo">查询信息</param>
/// <param name="queryCallback">查询结果</param>
public void QuerySpatialAnchor(YVRSpatialAnchorQueryInfo queryInfo , Action<List<YVRSpatialAnchorResult>> queryCallback)
YVRSpatialAnchorQueryInfo 查询信息,支持通过 uuid 查询,或者 component 类型查询
public struct YVRSpatialAnchorQueryInfo
{
// 查询返回最多锚点个数(默认为零,表示不限制查询返回个数)
public uint MaxQuerySpaces;
// 查询超时时间(默认为零,表示不设置超时时间)
public double Timeout;
// 查询位置
public YVRSpatialAnchorStorageLocation storageLocation;
// 查询锚点的组件类型
public YVRSpatialAnchorComponentType component;
// 使用 uuid 查询锚点时 uuid 个数
public int numIds;
// uuid 查询列表
public YVRSpatialAnchorUUID[] ids;
}
代码示例:
// 查询当前引用在这台设备中保存的所有本地锚点
private void QueryAllLocalAnchor()
{
YVRSpatialAnchorQueryInfo queryInfo = new YVRSpatialAnchorQueryInfo();
queryInfo.storageLocation = YVRSpatialAnchorStorageLocation.Local;
YVRSpatialAnchor.instance.QuerySpatialAnchor(queryInfo, QuerySpatialAnchorComplete);
}
// 通过 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);
}
// 查询结果
private void QuerySpatialAnchorComplete(List<YVRSpatialAnchorResult> results)
{
Debug.Log("QuerySpacesComplete count:" + results.Count);
}
在同一片区域查询已保存过的锚点时,可能会查询不到锚点,可以尝试在周围进行走动,采集更多点云数据后再次调用查询,接口调用频率可自行决定,**建议 1 秒左右调用一次**
获取锚点的实时位姿
调用 YVRSpatialAnchor.instance.GetSpatialAnchorPose 接口获取锚点的实时位置,保持锚点的位置始终固定,若不获取,当用户在场景内移动或者进行 recenter 时,锚点的位置可能会发生偏移,支持每帧调用。
/// <summary>
/// 获取锚点位姿
/// </summary>
/// <param name="anchorHandle">锚点句柄</param>
/// <param name="position">返回锚点的位置</param>
/// <param name="rotation">返回锚点的旋转</param>
/// <param name="locationFlags">锚点的位置状态</param>
/// <returns></returns>
public bool GetSpatialAnchorPose(ulong anchorHandle, out Vector3 position, out Quaternion rotation,out YVRAnchorLocationFlags locationFlags)
当获取锚点位姿方法返回失败,或位置状态为未追踪时,表示当前地图发生了切换,此时锚点变为失效,返回的位姿可能是错误的,需要等用户回到创建锚点的地图下,或创建锚点的地图和其他地图融合时,锚点会再次有效。
获取锚点支持的 component 枚举类型
调用 YVRSpatialAnchor.instance.GetSpatialAnchorEnumerateSupported 可以获取指定锚点支持的 component 类型,目前第三方引用创建的锚点仅支持位姿(Locatable)、存储(Storable)、分享(Sharable)。
/// <summary>
/// 获取锚点支持的 component 枚举类型
/// </summary>
/// <param name="anchorHandle">锚点的句柄</param>
/// <param name="components">支持的 component 类型</param>
public void GetSpatialAnchorEnumerateSupported(ulong anchorHandle, out YVRSpatialAnchorSupportedComponent components)
设置锚点的 component 状态
调用 YVRSpatialAnchor.instance.SetSpatialAnchorComponentStatus() 方法可以锚点的 component 状态。创建的锚点默认包含位姿(Locatable),存储(Storable),分享(Sharable).
/// <summary>
/// 设置锚点的 component 状态
/// </summary>
/// <param name="anchorHandle">锚点句柄</param>
/// <param name="setInfo">状态信息</param>
/// <param name="callback">设置锚点状态的回调</param>
/// <returns></returns>
public bool SetSpatialAnchorComponentStatus(ulong anchorHandle, YVRSpatialAnchorComponentStatusSetInfo setInfo,
Action<YVRSpatialAnchorSetStatusCompleteInfo,bool> callback)
代码示例:
private void DisableAnchorStorableState(ulong anchorHandle)
{
YVRSpatialAnchorComponentStatusSetInfo componentStatusSetInfo = new YVRSpatialAnchorComponentStatusSetInfo();
componentStatusSetInfo.component = YVRSpatialAnchorComponentType.Storable;
//将创建锚点的 Storable 设置为 false 时,锚点将不能被保存。
componentStatusSetInfo.enable = false; YVRSpatialAnchor.instance.SetSpatialAnchorComponentStatus(result.anchorHandle, componentStatusSetInfo,null);
}
上面示例中代码将关闭锚点的存储权限
获取锚点指定 component 状态
通过调用 YVRSpatialAnchor.instance.GetSpatialAnchorComponentStatus 可以获取锚点对应组件状态
/// <summary>
/// 获取锚点指定 component 状态
/// </summary>
/// <param name="anchorHandle">锚点句柄</param>
/// <param name="componentType">组件类型</param>
/// <param name="status">返回的状态信息</param>
public void GetSpatialAnchorComponentStatus(ulong anchorHandle, YVRSpatialAnchorComponentType componentType, out YVRSpatialAnchorComponentStatus status)
批量保存锚点
YVRSpatialAnchor.instance.SaveSpatialAnchorList 一次保存多个锚点
/// <summary>
/// 批量保存锚点
/// </summary>
/// <param name="spatialAnchorHandleList">锚点句柄集合</param>
/// <param name="location">保存位置</param>
/// <param name="callback">保存结果回调</param>
public void SaveSpatialAnchorList(List<ulong> spatialAnchorHandleList, YVRSpatialAnchorStorageLocation location,
Action<bool> callback)
通过 anchorHandle 获取锚点 UUID
调用 YVRSpatialAnchor.instance.GetSpatialAnchorUUIDForHandle 通过锚点句柄获取锚点的唯一标识
/// <summary>
/// 通过锚点句柄获取锚点的唯一标识
/// </summary>
/// <param name="anchorHandle">锚点句柄</param>
/// <param name="uuid">锚点唯一标识</param>
public void GetSpatialAnchorUUIDForHandle(ulong anchorHandle, out YVRSpatialAnchorUUID uuid)
获取空间标定锚点信息
只有系统中的 空间标定 应用创建的锚点才支持设置标定信息,包括锚点组件,语义标签,平面信息,立方体信息。你可以使用 空间标定 接口获取锚点的标定信息,然后在自己的引用内使用,详情参考 空间标定 文档。
Demo
SpatialAnchorSample 示例展示空间锚点的相关功能,包括创建锚点,保存锚点,删除锚点,查询锚点,分享锚点等功能。当演示分享功能时,需要你手动配置自己的 photon id 及服务。