Hello World!我是山谷大叔~接下来我将出一系列Hololens开发教程(Hololens API解析、空间共享、第三视角Spatial View,MR交互设计,视音频通讯,服务器开发,多人游戏实战……),感兴趣的朋友可以关注我哦。下面开始放干货!
本节讲解空间锚点的相关知识.
WorldAnchor API
Hololens上有四个空间摄像头不断地对周围环境扫描,通过SLAM定位技术进行空间定位。这也是Hololens MR的核心能力。
空间锚点World Anchor能够记录GameObject的空间位置和旋转。
WorldAnchorStore可以存储空间锚点的数据。
//读取,创建,更新锚点
public void TestSaveAnchor() {
foreach (var item in GlobleData.Instance.handDraggableDic)
{
string name= item.Key;
GameObject go = item.Value.gameObject;
AnchorAttachmentInfo info = new AnchorAttachmentInfo();
info.AnchorName = name;
info.GameObjectToAnchor = go;
info.Operation = AnchorOperation.Create;
anchorOperations.Enqueue(info);
}
}
//删除锚点
public void TestDelAnchor()
{
foreach (var item in GlobleData.Instance.handDraggableDic)
{
string name = item.Key;
GameObject go = item.Value.gameObject;
AnchorAttachmentInfo info = new AnchorAttachmentInfo();
info.AnchorName = name;
info.GameObjectToAnchor = go;
info.Operation = AnchorOperation.Delete;
anchorOperations.Enqueue(info);
}
}
using System.Collections.Generic;
using UnityEngine;
using HoloToolkit.Unity.SpatialMapping;
#if UNITY_EDITOR || UNITY_WSA
using UnityEngine.VR.WSA.Persistence;
using UnityEngine.VR.WSA;
#endif
public class WorldAnchorHandle :MonoBehaviour
{
///
///防止一次初始化太多的锚(处理锚点需要时间)
///创建锚点操作队列,异步加载处理WorldAnchorStore商店
///创建锚点信息结构体方便处理锚点。
///
private struct AnchorAttachmentInfo
{
public GameObject GameObjectToAnchor { get; set; }
public string AnchorName { get; set; }
public AnchorOperation Operation { get; set; }
}
private enum AnchorOperation
{
Create,
Delete
}
private Queue anchorOperations = new Queue();
#if UNITY_EDITOR || UNITY_WSA
///
/// WorldAnchorStore锚点商店
///
public WorldAnchorStore AnchorStore { get; private set; }
///
///WorldAnchorStore创建完成时的回调.
///
private void AnchorStoreReady(WorldAnchorStore anchorStore)
{
AnchorStore = anchorStore;
}
#endif
void Awake()
{
#if UNITY_EDITOR
Debug.LogWarning("World Anchor在编辑器模式下不能使用!(要在真机上才能使用)");
#endif
#if UNITY_EDITOR || UNITY_WSA
AnchorStore = null;
WorldAnchorStore.GetAsync(AnchorStoreReady);
#endif
}
#if UNITY_EDITOR || UNITY_WSA
private void Update()
{
if (AnchorStore != null && anchorOperations.Count > 0)
{
//处理锚点操作队列等待处理的锚点
DoAnchorOperation(anchorOperations.Dequeue());
}
}
#endif
///
/// 将锚点附加在Gameobject上。如果锚点的名字在商店已经存在,那就加载这个acnhor,否则将以该名字保存新锚点到商店。
///
public void AttachAnchor(GameObject gameObjectToAnchor, string anchorName)
{
if (gameObjectToAnchor == null)
{
Debug.LogError("要附加锚点的物体不能为空!");
return;
}
if (string.IsNullOrEmpty(anchorName))
{
Debug.LogError("锚点名字不能为空!");
return;
}
anchorOperations.Enqueue(
new AnchorAttachmentInfo
{
GameObjectToAnchor = gameObjectToAnchor,
AnchorName = anchorName,
Operation = AnchorOperation.Create
}
);
}
///
/// 从GameObject上移除锚点,并从商店中删除改锚点。
///
public void RemoveAnchor(GameObject gameObjectToUnanchor)
{
if (gameObjectToUnanchor == null)
{
Debug.LogError("要删除锚点的物体不能为空!");
return;
}
#if UNITY_EDITOR || UNITY_WSA
if (AnchorStore == null)
{
Debug.LogError("锚点商店为空,删除失败!");
return;
}
#endif
anchorOperations.Enqueue(
new AnchorAttachmentInfo
{
GameObjectToAnchor = gameObjectToUnanchor,
AnchorName = string.Empty,
Operation = AnchorOperation.Delete
});
}
///
/// 移除场景中所有锚点,并从锚点商店中山删除。
///
public void RemoveAllAnchors()
{
#if UNITY_EDITOR || UNITY_WSA
SpatialMappingManager spatialMappingManager = SpatialMappingManager.Instance;
if (AnchorStore == null)
{
Debug.LogError("锚点商店为空,RemoveAllAnchors失败!");
}
WorldAnchor[] anchors = FindObjectsOfType();
if (anchors != null)
{
foreach (WorldAnchor anchor in anchors)
{
//如果SpatialMapping不存在,或者anchors物体不在spatialMappingManager下,可以删除
if (spatialMappingManager == null ||
anchor.gameObject.transform.parent.gameObject != spatialMappingManager.gameObject)
{
anchorOperations.Enqueue(new AnchorAttachmentInfo()
{
AnchorName = anchor.name,
GameObjectToAnchor = anchor.gameObject,
Operation = AnchorOperation.Delete
});
}
}
}
#endif
}
///
/// 处理锚点数据(创建、删除)
///
private void DoAnchorOperation(AnchorAttachmentInfo anchorAttachmentInfo)
{
#if UNITY_EDITOR || UNITY_WSA
switch (anchorAttachmentInfo.Operation)
{
case AnchorOperation.Create:
string anchorName = anchorAttachmentInfo.AnchorName;
GameObject gameObjectToAnchor = anchorAttachmentInfo.GameObjectToAnchor;
if (gameObjectToAnchor == null)
{
Debug.LogError("要添加锚点的物体已经不存在!");
break;
}
//先从锚点商店中查看是否存在该名字的锚点
WorldAnchor savedAnchor = AnchorStore.Load(anchorName, gameObjectToAnchor);
if (savedAnchor == null)
{
//不存在的就创建一个
Debug.LogWarning(gameObjectToAnchor.name + " : 商店中不存在该名字的锚点");
CreateAnchor(gameObjectToAnchor, anchorName);
}
else
{
savedAnchor.name = anchorName;
Debug.Log(gameObjectToAnchor.name + " : 商店中存在该名字的锚点,导入并更新");
}
break;
case AnchorOperation.Delete:
if (AnchorStore == null)
{
Debug.LogError("锚点商店为空,不能执行删除操作");
break;
}
GameObject gameObjectToUnanchor = anchorAttachmentInfo.GameObjectToAnchor;
var anchor = gameObjectToUnanchor.GetComponent();
//从商店中删除锚点,删除锚点组件
if (anchor != null)
{
AnchorStore.Delete(anchor.name);
DestroyImmediate(anchor);
}
else
{
Debug.LogError("要删除的锚点的物体没有WorldAnchor组件");
}
break;
}
#endif
}
///
///创建一个锚点,附加到gameObject上,并保持到锚点商店中.
///
private void CreateAnchor(GameObject gameObjectToAnchor, string anchorName)
{
#if UNITY_EDITOR || UNITY_WSA
var anchor = gameObjectToAnchor.AddComponent();
anchor.name = anchorName;
//有时锚点会立即定位,立即被保存。
if (anchor.isLocated)
{
SaveAnchor(anchor);
}
else
{
//其他时候,需要等待锚点定位,这时注册个TrackingChanged事件,等待锚点定位完成后再保存。
anchor.OnTrackingChanged += Anchor_OnTrackingChanged;
}
#endif
}
#if UNITY_EDITOR || UNITY_WSA
///
/// 当一个锚点有定位时,就可以保存锚点了。
///
private void Anchor_OnTrackingChanged(WorldAnchor self, bool located)
{
if (located)
{
Debug.Log(gameObject.name + " : World anchor定位成功");
SaveAnchor(self);
//一旦锚定了位置,就可以退订这个事件
self.OnTrackingChanged -= Anchor_OnTrackingChanged;
}
else
{
Debug.LogError(gameObject.name + " : World anchor定位失败");
}
}
///
///保存锚点到商店中
///
///
private void SaveAnchor(WorldAnchor anchor)
{
if (AnchorStore.Save(anchor.name, anchor))
{
Debug.Log(gameObject.name + " : 锚点保存成功");
}
else
{
Debug.LogError(gameObject.name + " : 锚点保存失败");
}
}
#endif
public void TestSaveAnchor() {
foreach (var item in GlobleData.Instance.handDraggableDic)
{
string name= item.Key;
GameObject go = item.Value.gameObject;
AnchorAttachmentInfo info = new AnchorAttachmentInfo();
info.AnchorName = name;
info.GameObjectToAnchor = go;
info.Operation = AnchorOperation.Create;
anchorOperations.Enqueue(info);
}
}
public void TestDelAnchor()
{
foreach (var item in GlobleData.Instance.handDraggableDic)
{
string name = item.Key;
GameObject go = item.Value.gameObject;
AnchorAttachmentInfo info = new AnchorAttachmentInfo();
info.AnchorName = name;
info.GameObjectToAnchor = go;
info.Operation = AnchorOperation.Delete;
anchorOperations.Enqueue(info);
}
}
}
如果有什么疑问或者发现笔者的错误请留言!
下一节讲解 相关的内容~~~
获取源码请在群资料中下载(Hololens Unet Share 002)
Hololens MR 技术交流群 211031265