Transferts d’ancres locales dans Unity

Dans les situations où vous ne pouvez pas utiliser Azure Spatial Anchors, les transferts d’ancre locale permettent à un appareil HoloLens d’exporter une ancre à importer par un deuxième appareil HoloLens.

Notes

Les transferts d’ancres locales fournissent un rappel d’ancre moins robuste que les ancres spatiales Azure, et les appareils iOS et Android ne sont pas pris en charge par cette approche.

Définition de la fonctionnalité SpatialPerception

Pour qu’une application puisse transférer des ancres spatiales, la fonctionnalité SpatialPerception doit être activée.

Comment activer la fonctionnalité SpatialPerception :

  1. Dans l’éditeur Unity, ouvrez le volet « Paramètres du lecteur » (Modifier > le lecteur paramètres > du projet)
  2. Cliquez sur l’onglet « Windows Store »
  3. Développez « Paramètres de publication » et case activée la fonctionnalité « SpatialPerception » dans la liste « Fonctionnalités »

Notes

Si vous avez déjà exporté votre projet Unity vers une solution Visual Studio, vous devez exporter vers un nouveau dossier ou définir manuellement cette fonctionnalité dans AppxManifest dans Visual Studio.

Transfert d’ancre

Espace de noms :UnityEngine.XR.WSA.Sharing
Type : WorldAnchorTransferBatch

Pour transférer un WorldAnchor, il faut établir l’ancre à transférer. L’utilisateur d’un HoloLens analyse son environnement et choisit manuellement ou par programmation un point dans l’espace pour être l’ancre de l’expérience partagée. Les données qui représentent ce point peuvent ensuite être sérialisées et transmises aux autres appareils qui partagent l’expérience. Chaque appareil désérialise ensuite les données d’ancre et tente de localiser ce point dans l’espace. Pour que le transfert d’ancre fonctionne, chaque appareil doit avoir analysé suffisamment de l’environnement pour que le point représenté par l’ancre puisse être identifié.

Programme d’installation

L’exemple de code de cette page comporte quelques champs qui devront être initialisés :

  1. GameObject racineGameObject est un GameObject dans Unity qui a un composant WorldAnchor . Un utilisateur de l’expérience partagée placera ce GameObject et exportera les données vers les autres utilisateurs.
  2. WorldAnchor gameRootAnchor est unityEngine.XR.WSA.WorldAnchor qui se trouve sur rootGameObject.
  3. byte[] importedData est un tableau d’octets pour l’ancre sérialisée que chaque client reçoit sur le réseau.
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>();
    }
}

Exportation

Pour exporter, nous avons juste besoin d’un WorldAnchor et de savoir comment nous l’appellerons afin qu’il soit logique pour l’application de réception. Un client de l’expérience partagée effectue les étapes suivantes pour exporter l’ancre partagée :

  1. Créer un WorldAnchorTransferBatch
  2. Ajouter WorldAnchors au transfert
  3. Commencer l’exportation
  4. Gérer l’événement OnExportDataAvailable à mesure que les données deviennent disponibles
  5. Gérer l’événement OnExportComplete

Nous créons un WorldAnchorTransferBatch pour encapsuler ce que nous allons transférer, puis l’exporter en octets :

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

À mesure que les données deviennent disponibles, envoyez les octets au client ou à la mémoire tampon, car des segments de données sont disponibles et envoyez-les par tous les moyens souhaités :

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

Une fois l’exportation terminée, si nous avons transféré des données et que la sérialisation a échoué, indiquez au client d’ignorer les données. Si la sérialisation a réussi, indiquez au client que toutes les données ont été transférées et que l’importation peut démarrer :

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

Importation en cours

Après avoir reçu tous les octets de l’expéditeur, nous pouvons importer les données dans un WorldAnchorTransferBatch et verrouiller notre objet de jeu racine dans le même emplacement physique. Remarque : l’importation échoue parfois temporairement et doit être retentée :

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

Une fois qu’un GameObject est verrouillé via l’appel LockObject , il dispose d’un WorldAnchor qui le maintient dans la même position physique dans le monde, mais il peut se trouver à un autre emplacement dans l’espace de coordonnées Unity que les autres utilisateurs.