Share via


Unity 中的本機錨點傳輸

在您無法使用 Azure Spatial Anchors的情況下,本機錨點傳輸可讓一部 HoloLens 裝置匯出要由第二個 HoloLens 裝置匯入的錨點。

注意

本機錨點傳輸提供比 Azure Spatial Anchors更強固的錨點召回率,而此方法不支援 iOS 和 Android 裝置。

設定 SpatialPerception 功能

為了讓應用程式傳輸空間錨點,必須啟用 SpatialPerception 功能。

如何啟用 SpatialPerception 功能:

  1. 在 Unity 編輯器中,開啟 [ 播放程式設定] 窗格, ([編輯 > 專案設定 > 播放機])
  2. 按一下 [Windows 市集] 索引卷
  3. 展開[發佈設定],然後在[功能] 清單中檢查「SpatialPerception」功能

注意

如果您已經將 Unity 專案匯出至 Visual Studio 方案,則必須匯出至新的資料夾,或在 Visual Studio 的 AppxManifest 中手動設定此功能

錨點傳輸

Namespace:UnityEngine.XR.WSA.Sharing
類型WorldAnchorTransferBatch

若要傳輸 WorldAnchor,必須建立要傳送的錨點。 一個 HoloLens 的使用者會掃描其環境,並以手動或程式設計方式選擇一個空間點作為共用體驗的錨點。 接著,代表這個點的資料可以序列化並傳輸至體驗中共用的其他裝置。 然後,每個裝置都會取消序列化錨點資料,並嘗試找出空間中的該點。 為了讓錨點傳輸能夠運作,每個裝置都必須在足夠的環境中掃描,以便識別錨點所代表的點。

安裝程式

此頁面上的範例程式碼有幾個欄位需要初始化:

  1. GameObject rootGameObject是 Unity 中具有WorldAnchor元件的GameObject。 共用體驗中的一位使用者會放置此 GameObject ,並將資料匯出給其他使用者。
  2. WorldAnchor gameRootAnchorrootGameObject上的UnityEngine.XR.WSA.WorldAnchor
  3. 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 ,並知道我們將呼叫它的內容,讓接收應用程式有意義。 共用體驗中的一個用戶端會執行下列步驟來匯出共用錨點:

  1. 建立 WorldAnchorTransferBatch
  2. 新增 WorldAnchors 以傳輸
  3. 開始匯出
  4. 當資料變成可用時,處理 OnExportDataAvailable 事件
  5. 處理 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 座標空間中與其他使用者不同的位置。