共用方式為


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 中手動設定此功能。

錨點傳輸

命名空間:UnityEngine.XR.WSA.Sharing
類型WorldAnchorTransferBatch

若要轉移 WorldAnchor,必須建立要轉移的錨點。 一個 HoloLens 的用戶會掃描其環境,並以手動或程式設計方式選擇空間點做為共用體驗的錨點。 然後,表示此點的數據可以串行化並傳輸至體驗中共用的其他裝置。 然後,每個裝置都會取消串行化錨點數據,並嘗試在空間中找出該點。 為了讓錨點傳輸能夠運作,每個裝置都必須在環境中掃描足夠的位置,以便識別錨點所代表的點。

設定

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

  1. GameObject rootGameObject 是 Unity 中的 GameObject其上有 WorldAnchor 元件。 共享體驗中的一位使用者會放置此 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 坐標空間中的不同位置,而不是其他使用者。