Поделиться через


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

Локальная передача привязки позволяет одному устройству HoloLens экспортировать привязку, импортируемую вторым устройством HoloLens.

Примечание.

Устройства 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. Создание WorldAnchorTransferBatch
  2. Добавление WorldAnchors для передачи
  3. Начало экспорта
  4. Обработка события OnExportDataAvailable по мере того, как данные становятся доступными
  5. Обработка события OnExportComplete

Мы создадим WorldAnchorTransferBatchch , чтобы инкапсулировать то, что мы передаем, а затем экспортируем их в байты:

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, чем другие пользователи.