Transferencias de delimitadores locales en UnityLocal anchor transfers in Unity

En situaciones en las que no se pueden usar delimitadores espaciales de Azure, las transferencias de delimitadores locales permiten que un dispositivo hololens exporte un delimitador para que lo importe un segundo dispositivo hololens.In situations where you cannot use Azure Spatial Anchors, local anchor transfers enable one HoloLens device to export an anchor to be imported by a second HoloLens device.

Nota

Las transferencias de delimitadores locales proporcionan una recuperación de delimitador menos sólida que los delimitadores espaciales de Azurey los dispositivos iOS y Android no se admiten en este enfoque.Local anchor transfers provide less robust anchor recall than Azure Spatial Anchors, and iOS and Android devices are not supported by this approach.

Establecimiento de la funcionalidad SpatialPerceptionSetting the SpatialPerception capability

Para que una aplicación transfiera los anclajes espaciales, se debe habilitar la funcionalidad SpatialPerception .In order for an app to transfer spatial anchors, the SpatialPerception capability must be enabled.

Cómo habilitar la funcionalidad SpatialPerception :How to enable the SpatialPerception capability:

  1. En el editor de Unity, abra el panel de configuración del reproductor (editar > configuración del proyecto > Player).In the Unity Editor, open the "Player Settings" pane (Edit > Project Settings > Player)
  2. Haga clic en la pestaña "tienda Windows"Click on the "Windows Store" tab
  3. Expanda "configuración de publicación" y seleccione la funcionalidad "SpatialPerception" en la lista "funcionalidades" .Expand "Publishing Settings" and check the "SpatialPerception" capability in the "Capabilities" list

Nota

Si ya ha exportado el proyecto de Unity a una solución de Visual Studio, deberá exportar a una nueva carpeta o establecer manualmente esta funcionalidad en el AppxManifest de Visual Studio.If you have already exported your Unity project to a Visual Studio solution, you will need to either export to a new folder or manually set this capability in the AppxManifest in Visual Studio.

Transferencia de delimitadorAnchor Transfer

Espacio de nombres: UnityEngine. XR. WSA. SharingNamespace: UnityEngine.XR.WSA.Sharing
Tipo: WorldAnchorTransferBatchType: WorldAnchorTransferBatch

Para transferir un WorldAnchor, debe establecer el delimitador que se va a transferir.To transfer a WorldAnchor, one must establish the anchor to be transferred. El usuario de un HoloLens examina su entorno y, de forma manual o mediante programación, elige un punto en el espacio para que sea el delimitador de la experiencia compartida.The user of one HoloLens scans their environment and either manually or programmatically chooses a point in space to be the Anchor for the shared experience. Los datos que representan este punto se pueden serializar y transmitir a los otros dispositivos que compartan la experiencia.The data that represents this point can then be serialized and transmitted to the other devices that are sharing in the experience. Después, cada dispositivo deserializa los datos de delimitador e intenta buscar ese punto en el espacio.Each device then de-serializes the anchor data and attempts to locate that point in space. Para que la transferencia de delimitador funcione, cada dispositivo debe haber explorado en el entorno suficiente, de modo que se pueda identificar el punto representado por el delimitador.In order for Anchor Transfer to work, each device must have scanned in enough of the environment such that the point represented by the anchor can be identified.

ConfigurarSetup

El código de ejemplo de esta página tiene algunos campos que se deben inicializar:The sample code on this page has a few fields that will need to be initialized:

  1. GameObject rootGameObject es un GameObject en Unity que tiene un componente WorldAnchor en él.GameObject rootGameObject is a GameObject in Unity that has a WorldAnchor Component on it. Un usuario de la experiencia compartida colocará esta GameObject y exportará los datos a los demás usuarios.One user in the shared experience will place this GameObject and export the data to the other users.
  2. WorldAnchor gameRootAnchor es UnityEngine. XR. WSA. WorldAnchor que se encuentra en rootGameObject.WorldAnchor gameRootAnchor is the UnityEngine.XR.WSA.WorldAnchor that is on rootGameObject.
  3. Byte [] importedData es una matriz de bytes para el delimitador serializado que recibe cada cliente a través de la red.byte[] importedData is a byte array for the serialized anchor each client is receiving over the network.
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>();
    }
}

ExportadorExporting

Para exportar, solo necesitamos un WorldAnchor y para saber lo que le llamaremos de modo que tenga sentido para la aplicación receptora.To export, we just need a WorldAnchor and to know what we will call it such that it makes sense for the receiving app. Un cliente de la experiencia compartida realizará estos pasos para exportar el delimitador compartido:One client in the shared experience will perform these steps to export the shared anchor:

  1. Creación de un WorldAnchorTransferBatchCreate a WorldAnchorTransferBatch
  2. Agregar WorldAnchors para transferirAdd the WorldAnchors to transfer
  3. Inicio de la exportaciónBegin the export
  4. Controlar el evento OnExportDataAvailable a medida que los datos estén disponiblesHandle the OnExportDataAvailable event as data becomes available
  5. Controlar el evento OnExportCompleteHandle the OnExportComplete event

Creamos un WorldAnchorTransferBatch para encapsular lo que se va a transferir y exportarlo en bytes:We create a WorldAnchorTransferBatch to encapsulate what we will be transferring and then export that into bytes:

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

A medida que los datos estén disponibles, envíe los bytes al cliente o búfer a medida que los segmentos de datos estén disponibles y envíe los medios que desee:As data becomes available, send the bytes to the client or buffer as segments of data is available and send through whatever means desired:

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

Una vez completada la exportación, si se ha producido un error en la transferencia de datos y en la serialización, indique al cliente que descarte los datos.Once the export is complete, if we have been transferring data and serialization failed, tell the client to discard the data. Si la serialización se realizó correctamente, indique al cliente que se han transferido todos los datos y que se puede iniciar la importación:If the serialization succeeded, tell the client that all data has been transferred and importing can start:

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

ImportaciónImporting

Después de recibir todos los bytes del remitente, se pueden volver a importar los datos en un WorldAnchorTransferBatch y bloquear el objeto de juego raíz en la misma ubicación física.After receiving all of the bytes from the sender, we can import the data back into a WorldAnchorTransferBatch and lock our root game object into the same physical location. Nota: la importación a veces producirá un error temporal y se debe volver a intentar:Note: import will sometimes transiently fail and needs to be retried:

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

Después de que un GameObject se bloquee a través de la llamada de LockObject , tendrá un WorldAnchor que lo mantendrá en la misma posición física del mundo, pero puede estar en una ubicación diferente en el espacio de coordenadas de Unity que otros usuarios.After a GameObject is locked via the LockObject call, it will have a WorldAnchor which will keep it in the same physical position in the world, but it may be at a different location in the Unity coordinate space than other users.