Hololens 使用Unet共享详细教程(三)

Hello World!我是山谷大叔~接下来我将出一系列Hololens开发教程(Hololens API解析空间共享、第三视角Spatial ViewMR交互设计视音频通讯服务器开发,多人游戏实战……),感兴趣的朋友可以关注我哦。下面开始放干货!

本节讲解空间锚点的相关知识.

WorldAnchor API

Hololens上有四个空间摄像头不断地对周围环境扫描,通过SLAM定位技术进行空间定位。这也是Hololens MR的核心能力。

空间锚点World Anchor能够记录GameObject的空间位置和旋转

WorldAnchorStore可以存储空间锚点的数据。

Hololens 使用Unet共享详细教程(三)_第1张图片

    //读取,创建,更新锚点
    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


你可能感兴趣的:(Hololens开发)