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);
}
}
}
如果有什麼疑問或者發現筆者的錯誤請留言!
下一節講解 相關的內容~~~
獲取源碼請在羣資料中下載(Hololens Unet Share 002)
Hololens MR 技術交流羣 211031265