Hololens 使用Unet共享詳細教程(三)

Hello World!我是山谷大叔~接下來我將出一系列Hololens開發教程(Hololens API解析空間共享、第三視角Spatial ViewMR交互設計視音頻通訊服務器開發,多人遊戲實戰……),感興趣的朋友可以關注我哦。下面開始放乾貨!

本節講解空間錨點的相關知識.

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
{
    /// <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);
        }
    }
}
	






如果有什麼疑問或者發現筆者的錯誤請留言!
下一節講解 相關的內容~~~

獲取源碼請在羣資料中下載(Hololens Unet Share 002)

Hololens MR 技術交流羣 211031265


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章