Передача локальных привязок в Unity

В ситуациях, когда вы не можете использовать пространственные привязки Azure, передача локальных привязок позволяет одному устройству HoloLens экспортировать привязку для импорта вторым устройством HoloLens.

Примечание

Передача локальных привязок обеспечивает менее надежный отзыв привязки, чем пространственные привязки Azure, и устройства iOS и Android не поддерживаются этим подходом.

Настройка возможности SpatialPerception

Чтобы приложение передавало пространственные привязки, необходимо включить функцию SpatialPerception .

Как включить функцию SpatialPerception :

  1. В редакторе Unity откройте панель "Параметры проигрывателя" (Изменить > параметры > проекта проигрывателя)
  2. Щелкните вкладку "Магазин Windows"
  3. Разверните раздел "Параметры публикации" и проверка возможность SpatialPerception в списке "Возможности".

Примечание

Если вы уже экспортировали проект Unity в решение Visual Studio, необходимо либо экспортировать его в новую папку, либо вручную задать эту возможность в AppxManifest в Visual Studio.

Передача привязки

Пространство имен:UnityEngine.XR.WSA.Sharing
Тип: WorldAnchorTransferBatch

Чтобы передать Объект WorldAnchor, необходимо установить привязку для передачи. Пользователь одного holoLens сканирует свою среду и вручную или программно выбирает точку в пространстве, чтобы быть привязкой для общего интерфейса. Затем данные, представляющие эту точку, можно сериализовать и передать на другие устройства, которые совместно используют интерфейс. Затем каждое устройство десериализует данные привязки и пытается найти точку в пространстве. Чтобы обеспечить работу передачи привязки, каждое устройство должно быть проверено в достаточной среде, чтобы можно было определить точку, представленную привязкой.

Настройка

Пример кода на этой странице содержит несколько полей, которые необходимо инициализировать:

  1. GameObject rootGameObject — это gameObject в Unity с компонентом WorldAnchor . Один пользователь в общем интерфейсе разместит этот GameObject и экспортирует данные другим пользователям.
  2. WorldAnchor gameRootAnchor — это UnityEngine.XR.WSA.WorldAnchor , который находится в rootGameObject.
  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. Создание WorldAnchorTransferBatchch
  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);
}

После блокировки GameObject с помощью вызова LockObject он будет иметь WorldAnchor , который будет держать его в том же физическом положении в мире, но он может находиться в другом месте в пространстве координат Unity, чем другие пользователи.