Transferências de âncora local no Unity

Em situações em que você não pode usar âncoras espaciais do Azure, as transferências de âncora local permitem que um dispositivo HoloLens exporte uma âncora para ser importada por um segundo dispositivo HoloLens.

Observação

As transferências de âncora local fornecem um recall de âncora menos robusto do que as Âncoras Espaciais do Azure, e os dispositivos iOS e Android não são compatíveis com essa abordagem.

Definindo a funcionalidade SpatialPerception

Para que um aplicativo transfira âncoras espaciais, a funcionalidade SpatialPerception deve ser habilitada.

Como habilitar a funcionalidade SpatialPerception :

  1. No Editor do Unity, abra o painel "Configurações do Player" (Editar > Player de Configurações > do Projeto)
  2. Clique na guia "Windows Store"
  3. Expanda "Configurações de Publicação" e marcar a funcionalidade "SpatialPerception" na lista "Funcionalidades"

Observação

Se você já exportou seu projeto do Unity para uma solução do Visual Studio, precisará exportar para uma nova pasta ou definir manualmente essa funcionalidade no AppxManifest no Visual Studio.

Transferência de Âncora

Namespace:UnityEngine.XR.WSA.Sharing
Tipo: WorldAnchorTransferBatch

Para transferir um WorldAnchor, é necessário estabelecer a âncora a ser transferida. O usuário de um HoloLens examina seu ambiente e escolhe manual ou programaticamente um ponto no espaço para ser a Âncora para a experiência compartilhada. Os dados que representam esse ponto podem então ser serializados e transmitidos para os outros dispositivos que estão compartilhando na experiência. Cada dispositivo des serializa os dados de âncora e tenta localizar esse ponto no espaço. Para que a Transferência de Âncora funcione, cada dispositivo deve ter verificado o suficiente no ambiente, de modo que o ponto representado pela âncora possa ser identificado.

Instalação

O código de exemplo nesta página tem alguns campos que precisarão ser inicializados:

  1. GameObject rootGameObject é um GameObject no Unity que tem um Componente WorldAnchor nele. Um usuário na experiência compartilhada colocará este GameObject e exportará os dados para os outros usuários.
  2. WorldAnchor gameRootAnchor é o UnityEngine.XR.WSA.WorldAnchor que está no rootGameObject.
  3. byte[] importedData é uma matriz de bytes para a âncora serializada que cada cliente está recebendo pela rede.
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>();
    }
}

Exportação

Para exportar, precisamos apenas de um WorldAnchor e saber como vamos chamá-lo de modo que faça sentido para o aplicativo receptor. Um cliente na experiência compartilhada executará estas etapas para exportar a âncora compartilhada:

  1. Criar um WorldAnchorTransferBatch
  2. Adicionar os WorldAnchors para transferir
  3. Iniciar a exportação
  4. Manipular o evento OnExportDataAvailable à medida que os dados ficam disponíveis
  5. Manipular o evento OnExportComplete

Criamos um WorldAnchorTransferBatch para encapsular o que vamos transferir e, em seguida, exportá-lo para bytes:

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

À medida que os dados ficam disponíveis, envie os bytes para o cliente ou buffer à medida que os segmentos de dados estiverem disponíveis e enviem por todos os meios desejados:

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

Depois que a exportação for concluída, se estivermos transferindo dados e a serialização falhar, diga ao cliente para descartar os dados. Se a serialização tiver sido bem-sucedida, informe ao cliente que todos os dados foram transferidos e que a importação pode iniciar:

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

Importação

Depois de receber todos os bytes do remetente, podemos importar os dados de volta para um WorldAnchorTransferBatch e bloquear nosso objeto de jogo raiz no mesmo local físico. Observação: às vezes, a importação falhará transitóriamente e precisará ser repetida:

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

Depois que um GameObject for bloqueado por meio da chamada LockObject , ele terá um WorldAnchor que o manterá na mesma posição física do mundo, mas pode estar em um local diferente no espaço de coordenadas do Unity do que outros usuários.