Partilhar via


Transferências de âncora local em Unity

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

Nota

As transferências de âncora local fornecem uma recuperação de âncora menos robusta do que as Âncoras Espaciais do Azure, e os dispositivos iOS e Android não são suportados por essa abordagem.

Definindo o recurso SpatialPerception

Para que um aplicativo transfira âncoras espaciais, o recurso SpatialPerception deve ser habilitado.

Como ativar a capacidade SpatialPerception :

  1. No Editor Unity, abra o painel "Configurações do Player" (Editar > Player de Configurações > do Projeto)
  2. Clique no separador "Loja Windows"
  3. Expanda "Configurações de publicação" e verifique o recurso "SpatialPerception" na lista "Recursos"

Nota

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

Transferência de âncora

Espaço de nomes: UnityEngine.XR.WSA.Sharing
Tipo: WorldAnchorTransferBatch

Para transferir uma WorldAnchor, é preciso estabelecer a âncora a ser transferida. O usuário de um HoloLens verifica seu ambiente e, manual ou programaticamente, escolhe um ponto no espaço para ser a âncora para a experiência compartilhada. Os dados que representam esse ponto podem ser serializados e transmitidos para os outros dispositivos que estão compartilhando a experiência. Em seguida, cada dispositivo desserializa os dados de âncora e tenta localizar esse ponto no espaço. Para que a Anchor Transfer funcione, cada dispositivo deve ter escaneado o suficiente do ambiente para que o ponto representado pela âncora possa ser identificado.

Configurar

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

  1. GameObject rootGameObject é um GameObject em 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á em 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, só precisamos de um WorldAnchor e saber como vamos chamá-lo de tal forma que faça sentido para o aplicativo recetor. Um cliente na experiência compartilhada executará estas etapas para exportar a âncora compartilhada:

  1. Criar um WorldAnchorTransferBatch
  2. Adicione o 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, exportamos isso em 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 segmentos de dados estiverem disponíveis e envie através de qualquer meio desejado:

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

Quando a exportação estiver concluída, se tivermos transferido dados e a serialização falhar, diga ao cliente para descartar os dados. Se a serialização for bem-sucedida, informe ao cliente que todos os dados foram transferidos e 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 nosso objeto de jogo raiz no mesmo local físico. Nota: por vezes, a importação falhará transitoriamente e terá de 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 é bloqueado através da chamada LockObject , ele terá um WorldAnchor que o manterá na mesma posição física no mundo, mas pode estar em um local diferente no espaço de coordenadas Unity do que outros usuários.