Unity 中的世界鎖定和空間錨點
本文內容
讓您的全像投影保持原狀、與您移動,或在某些情況下,相對於其他全像投影,是建立Mixed Reality應用程式的一大部分。 本文將使用世界鎖定工具引導您完成建議的解決方案,但我們也會討論在 Unity 專案中手動設定空間錨點。 在跳到任何程式碼之前,請務必瞭解 Unity 如何處理自己的引擎中的座標空間和錨點。
世界規模座標系統
現今,撰寫遊戲、資料視覺效果應用程式或虛擬實境應用程式時,典型的方法是建立一個絕對 全局座標系統 ,讓所有其他座標都能可靠地對應回。 在該環境中,您一律可以找到穩定轉換,以定義該世界中任何兩個物件之間的關聯性。 如果您未移動這些物件,其相對轉換一律會維持不變。 轉譯純虛擬世界時,這種全域座標系統很容易就能正確,您事先知道所有幾何。 現今的會議室規模 VR 應用程式通常會建立這種絕對房間縮放座標系統,其原點位於樓層。
相反地,HoloLens 之類的未系結混合實境裝置具有動態感應器驅動的世界理解能力,隨著使用者周遭環境一段時間持續調整其知識,因為他們在建築物的整個樓層上逐步執行許多公尺。 在世界規模體驗中,如果您將所有全像投影放在單純的固定座標系統中,這些全像投影最終會根據世界或彼此相對地漂移。
例如,頭戴式裝置目前可能認為世界有兩個位置相隔 4 公尺,之後再精簡該瞭解,瞭解位置實際上相隔 3.9 公尺。 如果這些全像投影一開始在單一固定座標系統中放置 4 公尺,其中一個全像投影一律會從真實世界顯示 0.1 公尺。
您可以在 Unity 中手動放置 空間錨點 ,以在使用者行動裝置時維護全像投影在實體世界中的位置。 不過,這會犧牲虛擬世界中的自我一致性。 不同的錨點會持續彼此相對地移動,也會移動全域座標空間。 在此案例中,配置等簡單工作變得困難。 物理模擬也可能有問題。
世界鎖定工具 (WLT) 讓您能充分利用這兩個世界,使用使用者四處移動時散佈的空間錨點內部供應來穩定單一固定座標系統。 WLT 會分析相機的座標,以及每個畫面的空間錨點。 WLT 不會變更世界中所有專案的座標,以補償使用者頭部座標中的更正,WLT 只會改為修正頭部的座標。
選擇您的世界鎖定方法
可能的話,請使用 世界鎖定工具 進行全像投影定位。
世界鎖定工具 提供穩定的座標系統,可將虛擬和真實世界標記之間的可見不一致降到最低。 世界鎖定工具會使用共用錨點集區鎖定整個場景,而不是使用群組自己的個別錨點鎖定每個物件群組。
世界鎖定工具會自動處理空間錨點的內部建立和管理。 您不需要與 ARAnchorManager 或 WorldAnchor 互動,才能讓全像投影世界鎖定。
針對使用 OpenXR 或 Windows XR 外掛程式的 Unity 2019/2020,請使用 ARAnchorManager 。
針對較舊的 Unity 版本或 WSA 專案,請使用 WorldAnchor 。
設定世界鎖定
若要開始使用世界鎖定工具,請下載Mixed Reality功能工具 。 若要深入瞭解基本概念,請參閱主要世界鎖定工具檔頁面,以取得概觀、快速入門和其他實用主題的連結。
自動化設定
當您的專案準備就緒時,請從Mixed Reality > 世界鎖定工具 執行設定場景公用程式:
重要
設定場景公用程式可以隨時重新執行。 例如,如果 AR 目標已從舊版變更為 XR SDK,則應該重新執行。 如果場景已正確設定,則執行公用程式沒有任何作用。
視覺化工具
在早期開發期間,新增視覺化檢視有助於確保 WLT 已設定並正常運作。 您可以使用移除視覺化檢視公用程式,移除生產效能,或基於任何原因而不再需要它們。 如需視覺化檢視的詳細資訊,請參閱 工具檔 。
Namespace: UnityEngine.XR.WSA
Type: WorldAnchor
關鍵技術是建立 空間錨點 ,以精確地鎖定實體世界中的全像投影叢集,無論使用者漫遊到多少時間,然後在 稍後的會話中再次尋找這些全像投影 。
在舊版 Unity 中,您會將 WorldAnchor Unity 元件新增至 GameObject 來建立空間錨點。
新增世界錨點
若要新增世界錨點,請在遊戲物件上呼叫 AddComponent<WorldAnchor>()
您想要錨定在真實世界中的轉換。
WorldAnchor anchor = gameObject.AddComponent<WorldAnchor>();
此遊戲物件現在已錨定在實體世界中的目前位置。 您可能會看到其 Unity 全局座標會隨著時間稍微調整,以確保實體對齊。 請參閱 載入世界錨點 ,以在未來的應用程式會話中再次尋找此錨定位置。
移除世界錨點
如果您不想再 GameObject
鎖定到實體世界位置,而且不想移動此畫面,請在 World Anchor 元件上呼叫 Destroy
。
Destroy(gameObject.GetComponent<WorldAnchor>());
如果您想要移動 GameObject
此框架,請改為呼叫 DestroyImmediate
。
DestroyImmediate(gameObject.GetComponent<WorldAnchor>());
移動世界錨定 GameObject
您無法在世界錨點上移動一段時間 GameObject
。 如果您需要移動 GameObject
此框架,您需要:
DestroyImmediate
World Anchor 元件。
GameObject
移動 。
將新的 World Anchor 元件新增至 GameObject
。
DestroyImmediate(gameObject.GetComponent<WorldAnchor>());
gameObject.transform.position = new Vector3(0, 0, 2);
WorldAnchor anchor = gameObject.AddComponent<WorldAnchor>();
處理 locatability 變更
一個世界錨點可能無法在實體世界中一次取得。 Unity 接著不會更新錨定物件的轉換。 當應用程式正在執行時,也可能會發生這種情況。 無法處理 locatability 中的變更,會導致物件不會出現在世界的正確實體位置。
若要收到有關 locatability 變更的通知:
OnTrackingChanged
訂閱事件。 OnTrackingChanged
每當基礎空間錨點在可 locatable 或無法成為 locatable 狀態之間變更時,就會呼叫 事件。
anchor.OnTrackingChanged += Anchor_OnTrackingChanged;
處理事件。
private void Anchor_OnTrackingChanged(WorldAnchor self, bool located)
{
// This simply activates/deactivates this object and all children when tracking changes
self.gameObject.SetActiveRecursively(located);
}
如果錨點立即找到, isLocated
當傳回時 AddComponent<WorldAnchor>()
,錨點的 屬性會設定為 true
。 因此, OnTrackingChanged
不會觸發事件。 更簡潔的模式是在附加錨點之後,呼叫 OnTrackingChanged
具有初始 IsLocated
狀態的處理常式。
Anchor_OnTrackingChanged(anchor, anchor.isLocated);
永續性世界鎖定
空間錨點會將全像投影儲存在應用程式會話之間的真實世界空間中。 儲存在 HoloLens 錨點存放區後,空間錨點可以在不同的會話中找到並載入,而且在沒有網際網路連線時是理想的後援。
重要
本機錨點會儲存在裝置上,而 Azure Spatial Anchors 會儲存在雲端。 您可以在相同的專案中擁有本機和 Azure 錨點,而不會發生衝突。 如需整合 Azure 雲端服務來儲存錨點的詳細資訊,請參閱 Azure Spatial Anchors 。
根據預設,世界鎖定工具會在支援本機空間錨點持續性的裝置上,還原 Unity 的座標系統相對於實體世界。 若要在結束並重新執行應用程式之後,讓全像投影出現在實體世界中的相同位置,應用程式只需要將相同的姿勢還原到全像投影。
如果應用程式需要更精細的控制,您可以在偵測器中停用 自動儲存 和 自動載入 ,以及管理腳本的持續性。 如需詳細資訊,請參閱 保存空間座標系統 。
世界鎖定工具僅支援 HoloLens 裝置上的本機錨點持續性。 針對 Android、iOS 和 HoloLens 裝置,與 Azure Spatial Anchors 整合,以支援跨會話和裝置之間協調空間的持續性和共用。 如需搭配 Azure Spatial Anchors 使用世界鎖定工具的詳細資訊和範例,請參閱 WLT (WLT) 與 Azure Spatial Anchors (ASA) 結合 。
稱為 的 XRAnchorStore
API 可讓錨點在會話之間保存。 XRAnchorStore
是裝置上已儲存錨點的標記法。 您可以從 Unity 場景中保存錨點、將錨點 ARAnchors
從儲存體載入新的 ARAnchors
,或刪除儲存體中的錨點。
命名空間
針對 Unity 2020 和 OpenXR :
using Microsoft.MixedReality.ARSubsystems.XRAnchorStore
或 Unity 2019/2020 + Windows XR 外掛程式 :
using UnityEngine.XR.WindowsMR.XRAnchorStore
公用方法
{
// A list of all persisted anchors, which can be loaded.
public IReadOnlyList<string> PersistedAnchorNames { get; }
// Clear all persisted anchors
public void Clear();
// Load a single persisted anchor by name. The ARAnchorManager will create this new anchor and report it in
// the ARAnchorManager.anchorsChanged event. The TrackableId returned here is the same TrackableId the
// ARAnchor will have when it is instantiated.
public TrackableId LoadAnchor(string name);
// Attempts to persist an existing ARAnchor with the given TrackableId to the local store. Returns true if
// the storage is successful, false otherwise.
public bool TryPersistAnchor(TrackableId id, string name);
// Removes a single persisted anchor from the anchor store. This will not affect any ARAnchors in the Unity
// scene, only the anchors in storage.
public void UnpersistAnchor(string name);
}
取得錨點存放區參考
若要使用 Unity 2020 和 OpenXR 載入 XRAnchorStore,請在 XRAnchorSubsystem 上使用擴充方法,這是 ARAnchorManager 的子系統:
public static Task<XRAnchorStore> LoadAnchorStoreAsync(this XRAnchorSubsystem anchorSubsystem)
若要使用 Unity 2019/2020 和 Windows XR 外掛程式 載入 XRAnchorStore,請使用 XRReferencePointSubsystem 上的擴充方法, (Unity 2019) 或 XRAnchorSubsystem (Unity 2020) ,ARReferencePointManager/ARAnchorManager 的子系統:
// Unity 2019 + Windows XR Plugin
public static Task<XRAnchorStore> TryGetAnchorStoreAsync(this XRReferencePointSubsystem anchorSubsystem);
// Unity 2020 + Windows XR Plugin
public static Task<XRAnchorStore> TryGetAnchorStoreAsync(this XRAnchorSubsystem anchorSubsystem);
載入錨點存放區
若要在 Unity 2020 和 OpenXR 中載入錨點存放區,請從 ARAnchorManager 的子系統存取它,如下所示:
ARAnchorManager arAnchorManager = GetComponent<ARAnchorManager>();
XRAnchorStore anchorStore = await arAnchorManager.subsystem.LoadAnchorStoreAsync();
或使用 Unity 2019/2020 和 Windows XR 外掛程式 :
// Unity 2019
ARReferencePointManager arReferencePointManager = GetComponent<ARReferencePointManager>();
XRAnchorStore anchorStore = await arReferencePointManager.subsystem.TryGetAnchorStoreAsync();
// Unity 2020
ARAnchorManager arAnchorManager = GetComponent<ARAnchorManager>();
XRAnchorStore anchorStore = await arAnchorManager.subsystem.TryGetAnchorStoreAsync();
若要查看保存/取消執行錨點的完整範例,請參閱 [Mixed Reality OpenXR 外掛程式範例場景] ( (https://github.com/microsoft/OpenXR-Unity-MixedReality-Samples ) 中的 Anchors - Anchors - > Anchors 範例 GameObject 和 AnchorsSample.cs 腳本:
如需舊版 Unity 或 WSA 專案中的全像投影持續性,請使用 WorldAnchor 。
Namespace: UnityEngine.XR.WSA.Persistence
Class: WorldAnchorStore
WorldAnchorStore 會建立全像攝影體驗,其中全像投影會保留在應用程式實例的特定真實世界位置。 使用者可以在任何想要的地方釘選個別全像投影,並在稍後在應用程式會話的相同位置中找到它們。
WorldAnchorStore
可讓您跨會話保存世界錨點的位置。 若要跨會話保存全像投影,請個別追蹤 GameObjects
使用特定世界錨點。 您可以使用世界錨點建立 GameObject
根,並使用本機位置位移來錨定子全像投影。
若要從先前會話載入全像投影:
WorldAnchorStore
取得 。
載入世界錨點應用程式資料,可提供您世界錨點的識別碼。
依其識別碼載入世界錨點。
若要儲存全像投影以供未來的會話使用:
WorldAnchorStore
取得 。
儲存世界錨點,並指定識別碼。
儲存與世界錨點相關的應用程式資料以及識別碼。
取得 WorldAnchorStore
保留 的 WorldAnchorStore
參考,讓您知道何時準備好執行作業。 由於此呼叫是非同步,因此只要應用程式啟動時,您就可以呼叫:
WorldAnchorStore.GetAsync(StoreLoaded);
StoreLoaded
是完成載入時的 WorldAnchorStore
處理常式:
private void StoreLoaded(WorldAnchorStore store)
{
this.store = store;
}
您現在有 的參考 WorldAnchorStore
,可用來儲存和載入特定世界錨點。
儲存世界錨點
若要儲存世界錨點,請將世界錨點命名為 ,並將它 WorldAnchorStore
傳入您之前取得的 。 如果您嘗試將兩個錨點儲存至相同的字串, store.Save
則傳回 false。 先刪除先前的儲存,再儲存新的儲存。
private void SaveGame()
{
// Save data about holograms that this world anchor positions
if (!this.savedRoot) // Only save the root once
{
this.savedRoot = this.store.Save("rootGameObject", anchor);
Assert(this.savedRoot);
}
}
載入世界錨點
若要載入世界錨點:
private void LoadGame()
{
// Saved data about holograms that this world anchor positions:
this.savedRoot = this.store.Load("rootGameObject", rootGameObject);
if (!this.savedRoot)
{
// Game root not saved. Re-place objects or start over.
}
}
您也可以使用 store.Delete()
來移除先前儲存的錨點,以及 store.Clear()
移除所有先前儲存的資料。
列舉現有的錨點
若要列出儲存的錨點,請呼叫 GetAllIds
。
string[] ids = this.store.GetAllIds();
for (int index = 0; index < ids.Length; index++)
{
Debug.Log(ids[index]);
}
保存多個裝置的全像投影
您可以使用 Azure Spatial Anchors 從本機世界錨點建立永久性雲端錨點。 您的應用程式可以在多個 HoloLens、iOS 和 Android 裝置之間找到雲端錨點,即使裝置並未同時一起。 因為雲端錨點是持續性的,所以多個裝置可以看到一段時間後,相對於該錨點呈現的內容。
下一步
共用世界鎖定座標空間:
瞭解空間對應:
返回至 Unity 開發檢查點:
另請參閱