Unity でのローカルアンカー転送Local anchor transfers in Unity

Azure 空間アンカーを使用できない場合、ローカルアンカー転送では、1つの hololens デバイスが2つ目の hololens デバイスによってインポートされるアンカーをエクスポートできるようにします。In situations where you cannot use Azure Spatial Anchors, local anchor transfers enable one HoloLens device to export an anchor to be imported by a second HoloLens device.

注意

ローカルアンカー転送は、 Azure 空間アンカーよりも堅牢なアンカーの再呼び出しを提供します。この方法では、iOS デバイスと Android デバイスはサポートされていません。Local anchor transfers provide less robust anchor recall than Azure Spatial Anchors, and iOS and Android devices are not supported by this approach.

SpatialPerception 機能の設定Setting the SpatialPerception capability

アプリで空間アンカーを転送するには、 SpatialPerception機能を有効にする必要があります。In order for an app to transfer spatial anchors, the SpatialPerception capability must be enabled.

SpatialPerception機能を有効にする方法:How to enable the SpatialPerception capability:

  1. Unity エディターで、 [プレーヤーの設定] ウィンドウを開きます (> プロジェクトの設定を編集し > player)In the Unity Editor, open the "Player Settings" pane (Edit > Project Settings > Player)
  2. [Windows ストア] タブをクリックします。Click on the "Windows Store" tab
  3. [発行の設定] を展開し、 [機能] ボックスの一覧の "SpatialPerception" 機能を確認します。Expand "Publishing Settings" and check the "SpatialPerception" capability in the "Capabilities" list

注意

Unity プロジェクトを Visual Studio ソリューションに既にエクスポートしている場合は、新しいフォルダーにエクスポートするか、 Visual studio の package.appxmanifest でこの機能を手動で設定する必要があります。If you have already exported your Unity project to a Visual Studio solution, you will need to either export to a new folder or manually set this capability in the AppxManifest in Visual Studio.

アンカー転送Anchor Transfer

名前空間: UnityEngine.XR.WSA.SharingNamespace: UnityEngine.XR.WSA.Sharing
種類:WorldAnchorTransferBatchType: WorldAnchorTransferBatch

WorldAnchorを転送するには、転送するアンカーを設定する必要があります。To transfer a WorldAnchor, one must establish the anchor to be transferred. 1つの HoloLens のユーザーが自分の環境をスキャンし、共有エクスペリエンスのアンカーとなるポイントを手動またはプログラムによって選択します。The user of one HoloLens scans their environment and either manually or programmatically chooses a point in space to be the Anchor for the shared experience. その後、このポイントを表すデータをシリアル化し、エクスペリエンスで共有している他のデバイスに転送できます。The data that represents this point can then be serialized and transmitted to the other devices that are sharing in the experience. 各デバイスは、アンカーデータを逆シリアル化し、そのポイントの位置を特定しようとします。Each device then de-serializes the anchor data and attempts to locate that point in space. アンカー転送を機能させるには、各デバイスが、アンカーで表されるポイントを識別できるように、十分な環境でスキャンする必要があります。In order for Anchor Transfer to work, each device must have scanned in enough of the environment such that the point represented by the anchor can be identified.

セットアップSetup

このページのサンプルコードには、初期化する必要があるいくつかのフィールドがあります。The sample code on this page has a few fields that will need to be initialized:

  1. WorldAnchor オブジェクトがある場合、このオブジェクトは Unity のオブジェクトです。GameObject rootGameObject is a GameObject in Unity that has a WorldAnchor Component on it. 共有エクスペリエンスの1人のユーザーがこのユーザーオブジェクトを配置し、他のユーザーにデータをエクスポートします。One user in the shared experience will place this GameObject and export the data to the other users.
  2. WorldAnchor gameRootAnchorは、 root オブジェクトにあるUnityengine. XR. WorldAnchorです。WorldAnchor gameRootAnchor is the UnityEngine.XR.WSA.WorldAnchor that is on rootGameObject.
  3. byte [] importedDataは、各クライアントがネットワーク経由で受信するシリアル化されたアンカーのバイト配列です。byte[] importedData is a byte array for the serialized anchor each client is receiving over the network.
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>();
    }
}

エクスポートExporting

エクスポートするには、 WorldAnchorが必要なだけで、受信側のアプリにとって意味のある情報を知ることができます。To export, we just need a WorldAnchor and to know what we will call it such that it makes sense for the receiving app. 共有操作の1つのクライアントは、次の手順を実行して共有アンカーをエクスポートします。One client in the shared experience will perform these steps to export the shared anchor:

  1. WorldAnchorTransferBatchを作成するCreate a WorldAnchorTransferBatch
  2. 転送するWorldAnchorsを追加するAdd the WorldAnchors to transfer
  3. エクスポートを開始しますBegin the export
  4. データが使用可能になったときにOnExportDataAvailableイベントを処理するHandle the OnExportDataAvailable event as data becomes available
  5. Onexportcompleteイベントの処理Handle the OnExportComplete event

ここでは、転送する対象をカプセル化してからバイトにエクスポートするWorldAnchorTransferBatchを作成します。We create a WorldAnchorTransferBatch to encapsulate what we will be transferring and then export that into bytes:

private void ExportGameRootAnchor()
{
    WorldAnchorTransferBatch transferBatch = new WorldAnchorTransferBatch();
    transferBatch.AddWorldAnchor("gameRoot", this.gameRootAnchor);
    WorldAnchorTransferBatch.ExportAsync(transferBatch, OnExportDataAvailable, OnExportComplete);
}

データが使用可能になったら、データのセグメントが使用可能であり、必要な方法で送信されるので、クライアントまたはバッファーにバイトを送信します。As data becomes available, send the bytes to the client or buffer as segments of data is available and send through whatever means desired:

private void OnExportDataAvailable(byte[] data)
{
    TransferDataToClient(data);
}

エクスポートが完了したら、データを転送し、シリアル化に失敗した場合は、データを破棄するようにクライアントに指示します。Once the export is complete, if we have been transferring data and serialization failed, tell the client to discard the data. シリアル化が成功した場合は、すべてのデータが転送され、インポートを開始できることをクライアントに通知します。If the serialization succeeded, tell the client that all data has been transferred and importing can start:

private void OnExportComplete(SerializationCompletionReason completionReason)
{
    if (completionReason != SerializationCompletionReason.Succeeded)
    {
        SendExportFailedToClient();
    }
    else
    {
        SendExportSucceededToClient();
    }
}

込んImporting

送信元からバイトをすべて受信した後、データをWorldAnchorTransferBatchにインポートして、ルートゲームオブジェクトを同じ物理的な場所にロックすることができます。After receiving all of the bytes from the sender, we can import the data back into a WorldAnchorTransferBatch and lock our root game object into the same physical location. 注: インポートに失敗する場合があり、再試行が必要になることがあります。Note: import will sometimes transiently fail and needs to be retried:

// 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);
}

WorldAnchor オブジェクトは、 lockobject呼び出しによってロックされた後に、世界の同じ物理的な位置に保持されますが、Unity 座標空間内の他のユーザーとは異なる場所にある可能性があります。After a GameObject is locked via the LockObject call, it will have a WorldAnchor which will keep it in the same physical position in the world, but it may be at a different location in the Unity coordinate space than other users.