Hello World!我是山谷大叔~接下来我将出一系列Hololens开发教程(Hololens API解析、空间共享、第三视角Spatial View,MR交互设计,视音频通讯,服务器开发,多人游戏实战……),感兴趣的朋友可以关注我哦。下面开始放干货!
本节讲解空间锚点的相关知识.
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 { /// <summary> ///防止一次初始化太多的锚(处理锚点需要时间) ///创建锚点操作队列,异步加载处理WorldAnchorStore商店 ///创建锚点信息结构体方便处理锚点。 /// </summary> 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<AnchorAttachmentInfo> anchorOperations = new Queue<AnchorAttachmentInfo>(); #if UNITY_EDITOR || UNITY_WSA /// <summary> /// WorldAnchorStore锚点商店 /// </summary> public WorldAnchorStore AnchorStore { get; private set; } /// <summary> ///WorldAnchorStore创建完成时的回调. /// </summary> 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 /// <summary> /// 将锚点附加在Gameobject上。如果锚点的名字在商店已经存在,那就加载这个acnhor,否则将以该名字保存新锚点到商店。 /// </summary> 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 } ); } /// <summary> /// 从GameObject上移除锚点,并从商店中删除改锚点。 /// </summary> 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 }); } /// <summary> /// 移除场景中所有锚点,并从锚点商店中山删除。 /// </summary> public void RemoveAllAnchors() { #if UNITY_EDITOR || UNITY_WSA SpatialMappingManager spatialMappingManager = SpatialMappingManager.Instance; if (AnchorStore == null) { Debug.LogError("锚点商店为空,RemoveAllAnchors失败!"); } WorldAnchor[] anchors = FindObjectsOfType<WorldAnchor>(); 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 } /// <summary> /// 处理锚点数据(创建、删除) /// </summary> 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<WorldAnchor>(); //从商店中删除锚点,删除锚点组件 if (anchor != null) { AnchorStore.Delete(anchor.name); DestroyImmediate(anchor); } else { Debug.LogError("要删除的锚点的物体没有WorldAnchor组件"); } break; } #endif } /// <summary> ///创建一个锚点,附加到gameObject上,并保持到锚点商店中. /// </summary> private void CreateAnchor(GameObject gameObjectToAnchor, string anchorName) { #if UNITY_EDITOR || UNITY_WSA var anchor = gameObjectToAnchor.AddComponent<WorldAnchor>(); anchor.name = anchorName; //有时锚点会立即定位,立即被保存。 if (anchor.isLocated) { SaveAnchor(anchor); } else { //其他时候,需要等待锚点定位,这时注册个TrackingChanged事件,等待锚点定位完成后再保存。 anchor.OnTrackingChanged += Anchor_OnTrackingChanged; } #endif } #if UNITY_EDITOR || UNITY_WSA /// <summary> /// 当一个锚点有定位时,就可以保存锚点了。 /// </summary> 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定位失败"); } } /// <summary> ///保存锚点到商店中 /// </summary> /// <param name="anchor"></param> 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); } } }
扫描二维码关注公众号,回复:
711995 查看本文章
如果有什么疑问或者发现笔者的错误请留言!
下一节讲解 相关的内容~~~
获取源码请在群资料中下载(Hololens Unet Share 002)
Hololens MR 技术交流群 211031265