Unity 中的世界鎖定和空間錨點
本文內容
讓全像投影保持原位、與您一起移動,或在某些情況下,相對於其他全像投影本身的位置,是建立混合實境應用程式的一大部分。 本文將帶您完成使用世界鎖定工具的建議解決方案,但我們也會討論在 Unity 專案中手動設定空間錨點。 在我們跳入任何程序代碼之前,請務必瞭解 Unity 如何處理自己的引擎中的座標空間和錨點。
世界縮放座標系統
今天,在撰寫遊戲、數據視覺效果應用程式或虛擬實境應用程式時,典型的方法是建立一個絕對 世界座標系統 ,讓所有其他座標都能可靠地對應回去。 在該環境中,您隨時都能找到一個穩定轉換,以定義該世界中任何兩個對象之間的關聯性。 如果您未移動這些物件,其相對轉換一律會維持不變。 在轉譯純虛擬世界時,這種全域座標系統很容易正確,您事先知道所有幾何。 室內規模的 VR 應用程式今天通常會建立這種絕對房間規模的座標系統,其起源在地板上。
相反地,HoloLens 等未系結的混合實境裝置對世界有動態感測器驅動的瞭解,在使用者周圍的環境經過一段時間后持續調整其知識,因為他們在建築物的整個樓層走多米。 在世界規模的體驗中,如果您將所有全像投影放在天真的固定座標系統中,這些全像投影最終會隨著時間而漂移,無論是根據世界還是彼此相對。
例如,頭戴式裝置目前可能相信世界上的兩個位置相距4米,然後改進該理解,了解這些位置實際上相距3.9米。 如果這些全像投影最初被放置在單一剛性座標系統中,其中一個則總是與真實世界相距0.1公尺。
您可以在 Unity 中手動放置 空間錨點 ,以在用戶移動時維護全像投影在實體世界中的位置。 不過,這會犧牲虛擬世界中的自我一致性。 不同的錨點會不斷彼此移動,而且也會通過全域座標空間移動。 在此案例中,版面配置等簡單工作變得困難。 物理模擬也可能有問題。
世界鎖定工具 (WLT)可讓您充分利用這兩個世界,使用空間錨點的內部供應在使用者四處移動時,穩定單一剛性座標系統。 WLT 會分析相機的座標,以及每個畫面的空間錨點。 WLT 不會變更世界上所有專案的座標,以補償用戶頭部座標中的修正,而是改為修正頭部的座標。
選擇您的世界鎖定方法
可能的話,請使用 世界鎖定工具 進行全像投影定位。
世界鎖定工具 提供穩定的座標系統,可將虛擬和真實世界標記之間的可見不一致降到最低。 世界鎖定工具會使用共用錨點集區鎖定整個場景,而不是使用群組自己的個別錨點鎖定每個物件群組。
世界鎖定工具會自動處理空間錨點的內部建立和管理。 您不需要與 ARAnchorManager 或 WorldAnchor 互動,即可將您的全像投影世界鎖定。
針對使用 OpenXR 或 Windows XR 外掛程式的 Unity 2019/2020,請使用 ARAnchorManager 。
針對舊版 Unity 或 WSA 專案,請使用 WorldAnchor 。
設定世界鎖定
若要開始使用世界鎖定工具, 請下載混合實境功能工具 。 若要深入瞭解基本概念,請參閱主要世界鎖定工具文件頁面,以取得概觀、快速入門和其他實用主題的連結。
自動化設定
當您的專案準備好進行時,請從 混合實境 > 世界鎖定工具 執行設定場景公用程式:
重要
設定場景公用程式可以隨時重新執行。 例如,如果 AR 目標已從舊版變更為 XR SDK,則應該重新執行。 如果場景已正確設定,則執行公用程序沒有任何作用。
視覺化工具
在早期開發期間,新增可視化檢視有助於確保WLT已設定並正常運作。 您可以使用移除可視化檢視公用程式,移除生產效能,或基於任何原因不再需要移除它們。 如需可視化檢視的詳細資訊,請參閱 工具檔 。
混合實境 OpenXR 外掛程式透過實作 Unity 的 ARFoundation ARAnchorManager 來提供基本錨點功能。 若要瞭解 ARFoundation 中 ARAnchors 的基本概念,請流覽 AR Anchor Manager 的 ARFoundation 手冊。
命名空間: UnityEngine.XR.WSA
類型: 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>();
處理可擷取性變更
在某個時間點,世界錨點可能無法在實體世界中。 Unity 接著不會更新錨定對象的轉換。 當應用程式正在執行時,也可能會發生這種情況。 無法處理locatability中的變更,會導致物件不會出現在世界上正確的實體位置。
若要收到關於可擷取性變更的通知:
OnTrackingChanged
訂閱事件。 OnTrackingChanged
每當基礎空間錨點在可擷取或無法擷取的狀態之間變更時,就會呼叫 事件。
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 空間錨點使用世界鎖定工具的詳細資訊和範例,請參閱與 Azure Spatial Anchors (ASA) 結合的世界鎖定工具 (WLT)。
稱為的 XRAnchorStore
API 可讓錨點在會話之間保存。 XRAnchorStore
是裝置上已儲存錨點的表示法。 您可以從 Unity 場景中保存錨點、將錨點 ARAnchors
從記憶體載入新的 ARAnchors
,或刪除記憶體中的錨點。
注意
您可以在相同的裝置上儲存和載入這些錨點。 透過 Azure Spatial Anchors 支援 跨裝置錨點。
命名空間
針對 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,請在 ARAnchorManager 的子系統 XRAnchorSubsystem 上使用擴充方法:
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();
若要查看保存/取消停駐錨點的完整範例,請參閱 [混合實境 OpenXR 外掛程式範例場景]() 中的 Anchors -> Anchors 範例 GameObject 和AnchorsSample.cs腳本():https://github.com/microsoft/OpenXR-Unity-MixedReality-Samples
針對舊版 Unity 或 WSA 專案中的全像投影持續性,請使用 WorldAnchor 。
命名空間: UnityEngine.XR.WSA.Persistence
類別: 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 開發檢查點:
另請參閱