Unity 中的本機錨點傳輸
在您無法使用 Azure Spatial Anchors的情況下,本機錨點傳輸可讓一部 HoloLens 裝置匯出要由第二個 HoloLens 裝置匯入的錨點。
注意
本機錨點傳輸提供比 Azure Spatial Anchors更強固的錨點召回率,而此方法不支援 iOS 和 Android 裝置。
設定 SpatialPerception 功能
為了讓應用程式傳輸空間錨點,必須啟用 SpatialPerception 功能。
如何啟用 SpatialPerception 功能:
- 在 Unity 編輯器中,開啟 [ 播放程式設定] 窗格, ([編輯 > 專案設定 > 播放機])
- 按一下 [Windows 市集] 索引卷 標
- 展開[發佈設定],然後在[功能] 清單中檢查「SpatialPerception」功能
注意
如果您已經將 Unity 專案匯出至 Visual Studio 方案,則必須匯出至新的資料夾,或在 Visual Studio 的 AppxManifest 中手動設定此功能。
錨點傳輸
Namespace:UnityEngine.XR.WSA.Sharing
類型: WorldAnchorTransferBatch
若要傳輸 WorldAnchor,必須建立要傳送的錨點。 一個 HoloLens 的使用者會掃描其環境,並以手動或程式設計方式選擇一個空間點作為共用體驗的錨點。 接著,代表這個點的資料可以序列化並傳輸至體驗中共用的其他裝置。 然後,每個裝置都會取消序列化錨點資料,並嘗試找出空間中的該點。 為了讓錨點傳輸能夠運作,每個裝置都必須在足夠的環境中掃描,以便識別錨點所代表的點。
安裝程式
此頁面上的範例程式碼有幾個欄位需要初始化:
- GameObject rootGameObject是 Unity 中具有WorldAnchor元件的GameObject。 共用體驗中的一位使用者會放置此 GameObject ,並將資料匯出給其他使用者。
- WorldAnchor gameRootAnchor是rootGameObject上的UnityEngine.XR.WSA.WorldAnchor。
- byte[] importedData 是序列化錨點的位元組陣列,每個用戶端都會透過網路接收。
public GameObject rootGameObject;
private UnityEngine.XR.WSA.WorldAnchor gameRootAnchor;
void Start ()
{
gameRootAnchor = rootGameObject.GetComponent<UnityEngine.XR.WSA.WorldAnchor>();
if (gameRootAnchor == null)
{
gameRootAnchor = rootGameObject.AddComponent<UnityEngine.XR.WSA.WorldAnchor>();
}
}
正在匯出
若要匯出,我們只需要 WorldAnchor ,並知道我們將呼叫它的內容,讓接收應用程式有意義。 共用體驗中的一個用戶端會執行下列步驟來匯出共用錨點:
- 建立 WorldAnchorTransferBatch
- 新增 WorldAnchors 以傳輸
- 開始匯出
- 當資料變成可用時,處理 OnExportDataAvailable 事件
- 處理 OnExportComplete 事件
我們會建立 WorldAnchorTransferBatch 來封裝將要傳輸的內容,然後將它匯出成位元組:
private void ExportGameRootAnchor()
{
WorldAnchorTransferBatch transferBatch = new WorldAnchorTransferBatch();
transferBatch.AddWorldAnchor("gameRoot", this.gameRootAnchor);
WorldAnchorTransferBatch.ExportAsync(transferBatch, OnExportDataAvailable, OnExportComplete);
}
當資料可供使用時,請將位元組傳送至用戶端或緩衝區,因為資料區段可供使用,並透過任何需要的方式傳送:
private void OnExportDataAvailable(byte[] data)
{
TransferDataToClient(data);
}
匯出完成後,如果我們已經傳輸資料和序列化失敗,請告訴用戶端捨棄資料。 如果序列化成功,請告訴用戶端已傳輸所有資料,而且匯入可以啟動:
private void OnExportComplete(SerializationCompletionReason completionReason)
{
if (completionReason != SerializationCompletionReason.Succeeded)
{
SendExportFailedToClient();
}
else
{
SendExportSucceededToClient();
}
}
匯入
從傳送者接收所有位元組之後,我們可以將資料匯回 WorldAnchorTransferBatch ,並將根遊戲物件鎖定到相同的實體位置。 注意:匯入有時會暫時失敗,而且需要重試:
// This byte array should have been updated over the network from TransferDataToClient
private byte[] importedData;
private int retryCount = 3;
private void ImportRootGameObject()
{
WorldAnchorTransferBatch.ImportAsync(importedData, OnImportComplete);
}
private void OnImportComplete(SerializationCompletionReason completionReason, WorldAnchorTransferBatch deserializedTransferBatch)
{
if (completionReason != SerializationCompletionReason.Succeeded)
{
Debug.Log("Failed to import: " + completionReason.ToString());
if (retryCount > 0)
{
retryCount--;
WorldAnchorTransferBatch.ImportAsync(importedData, OnImportComplete);
}
return;
}
this.gameRootAnchor = deserializedTransferBatch.LockObject("gameRoot", this.rootGameObject);
}
透過LockObject 呼叫鎖定 GameObject之後,它會有一個 WorldAnchor,將它保留在世界中的相同實體位置,但可能位於 Unity 座標空間中與其他使用者不同的位置。