Transferências de âncora locais na Unidade

Em situações em que não é possível utilizar âncoras espaciais Azure,as transferências de âncora locais permitem que um dispositivo HoloLens exportar uma âncora seja importado por um segundo dispositivo HoloLens.

Nota

As transferências de âncora locais fornecem uma recolha de âncora menos robusta do que as âncoras espaciais Azure, e os dispositivos iOS e Android não são suportados por esta abordagem.

Definição da capacidade de Perceção Espacial

Para que uma aplicação transfira âncoras espaciais, a capacidade de Ordenamento espacial deve ser ativada.

Como ativar a capacidade de Perceção Espacial:

  1. No Editor de Unidade, abra o painel "Player Definições" (Editar Project Definições > Player)
  2. Clique no separador "Windows Store"
  3. Expanda a "Publicação Definições" e verifique a capacidade "EspacialPerception" na lista de "Capacidades"

Nota

Se já exportou o seu projeto Unidade para uma solução Visual Studio, terá de exportar para uma nova pasta ou definir manualmente esta capacidade no AppxManifest em Visual Studio.

Transferência de Âncora

Espaço de nome:UnityEngine.XR.Wsa.sharing
Tipo: WorldAnchorTransferBatch

Para transferir um WorldAnchor,é preciso estabelecer a âncora a transferir. O utilizador de um HoloLens digitaliza o seu ambiente e, manualmente ou programáticamente, escolhe um ponto no espaço para ser o Âncora para a experiência partilhada. Os dados que representam este ponto podem então ser serializados e transmitidos para os outros dispositivos que estão a partilhar na experiência. Cada dispositivo, em seguida, des-serializa os dados da âncora e tenta localizar esse ponto no espaço. Para que a Anchor Transfer funcione, cada dispositivo deve ter digitalizado em ambiente suficiente para que o ponto representado pela âncora possa ser identificado.

Configuração

O código de amostra desta página tem alguns campos que terão de ser inicializados:

  1. GameObject rootGameObject é um GameObject in Unitity que tem um Componente WorldAnchor nele. Um utilizador na experiência partilhada colocará este GameObject e exportará os dados para os outros utilizadores.
  2. WorldAnchor gameRootAnchor é o UnityEngine.XR.WSA.WorldAnchor que está no rootGameObject.
  3. byte[] importadoData é um conjunto byte para a âncora serializada que cada cliente está recebendo através da 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, só precisamos de um WorldAnchor e saber o que lhe vamos chamar de tal que faz sentido para a app recetora. Um cliente na experiência partilhada irá realizar estes passos para exportar a âncora partilhada:

  1. Criar um WorldAnchorTransferBatch
  2. Adicione os WorldAnchors à transferência
  3. Inicie a exportação
  4. Lide com o evento OnExportData Disponível à medida que os dados se tornem disponíveis
  5. Lidar com o evento OnExportComplete

Criamos um WorldAnchorTransferBatch para encapsular o que vamos transferir e depois 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 se tornam disponíveis, envie os bytes para o cliente ou tampão à medida que segmentos de dados estão disponíveis e envie através dos meios desejados:

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

Uma vez concluída a exportação, se tivermos vindo a transferir dados e a serialização falhar, diga ao cliente para descartar os dados. Se a serialização tiver sido bem sucedida, diga ao cliente que todos os dados foram transferidos e que a importação pode começar:

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 o nosso objeto de jogo de raiz no mesmo local físico. Nota: a importação por vezes falha transitoriamente e precisa de ser novamente julgada:

// 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 de um GameObject ser bloqueado através da chamada LockObject, terá um WorldAnchor que irá mantê-lo na mesma posição física do mundo, mas pode estar em um local diferente no espaço de coordenadas Unidade do que outros utilizadores.