Trasferimenti di ancoraggio locali in UnityLocal anchor transfers in Unity

Nei casi in cui non è possibile usare gli ancoraggi spaziali di Azure, i trasferimenti di ancoraggio locali consentono a un dispositivo HoloLens di esportare un ancoraggio per l'importazione da parte di un secondo 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

I trasferimenti di ancoraggio locali forniscono un richiamo di ancoraggio meno affidabile rispetto agli ancoraggi spaziali di Azuree i dispositivi iOS e Android non sono supportati da questo approccio.Local anchor transfers provide less robust anchor recall than Azure Spatial Anchors, and iOS and Android devices are not supported by this approach.

Impostazione della funzionalità SpatialPerceptionSetting the SpatialPerception capability

Per consentire a un'app di trasferire ancoraggi spaziali, è necessario abilitare la funzionalità SpatialPerception .In order for an app to transfer spatial anchors, the SpatialPerception capability must be enabled.

Come abilitare la funzionalità SpatialPerception :How to enable the SpatialPerception capability:

  1. Nell'editor di Unity aprire il riquadro "Impostazioni lettore" (modificare > impostazioni progetto > lettore)In the Unity Editor, open the "Player Settings" pane (Edit > Project Settings > Player)
  2. Fare clic sulla scheda "Windows Store"Click on the "Windows Store" tab
  3. Espandere "impostazioni di pubblicazione" e selezionare la funzionalità "SpatialPerception" nell'elenco "funzionalità"Expand "Publishing Settings" and check the "SpatialPerception" capability in the "Capabilities" list

Nota

Se il progetto Unity è già stato esportato in una soluzione di Visual Studio, sarà necessario eseguire l'esportazione in una nuova cartella o impostare manualmente questa funzionalità in appxmanifest in 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.

Trasferimento di ancoraggioAnchor Transfer

Spazio dei nomi: UnityEngine. XR. WSA. sharingNamespace: UnityEngine.XR.WSA.Sharing
Tipo: WorldAnchorTransferBatchType: WorldAnchorTransferBatch

Per trasferire un WorldAnchor, è necessario stabilire l'ancoraggio da trasferire.To transfer a WorldAnchor, one must establish the anchor to be transferred. L'utente di un HoloLens analizza l'ambiente e sceglie manualmente o a livello di codice un punto nello spazio come ancoraggio per l'esperienza condivisa.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. I dati che rappresentano questo punto possono quindi essere serializzati e trasmessi agli altri dispositivi che condividono nell'esperienza.The data that represents this point can then be serialized and transmitted to the other devices that are sharing in the experience. Ogni dispositivo deserializza quindi i dati di ancoraggio e tenta di individuare il punto nello spazio.Each device then de-serializes the anchor data and attempts to locate that point in space. Per il corretto funzionamento del trasferimento di ancoraggio, è necessario che ogni dispositivo abbia eseguito una scansione sufficiente dell'ambiente, in modo che sia possibile identificare il punto rappresentato dall'ancoraggio.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.

ConfigurazioneSetup

Il codice di esempio in questa pagina contiene alcuni campi che dovranno essere inizializzati:The sample code on this page has a few fields that will need to be initialized:

  1. GameObject rootGameObject è un GameObject in Unity in cui è presente un componente WorldAnchor .GameObject rootGameObject is a GameObject in Unity that has a WorldAnchor Component on it. Un utente nell'esperienza condivisa inserisce questo GameObject ed Esporta i dati negli altri utenti.One user in the shared experience will place this GameObject and export the data to the other users.
  2. WorldAnchor gameRootAnchor è UnityEngine. XR. WSA. WorldAnchor che si trova in rootGameObject.WorldAnchor gameRootAnchor is the UnityEngine.XR.WSA.WorldAnchor that is on rootGameObject.
  3. byte [] importedData è una matrice di byte per l'ancoraggio serializzato che ogni client riceve sulla rete.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>();
    }
}

EsportazioneExporting

Per eseguire l'esportazione, è sufficiente un WorldAnchor e per sapere cosa verrà chiamato in modo da renderlo utile per l'app ricevente.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 client nell'esperienza condivisa eseguirà questa procedura per esportare l'ancoraggio condiviso:One client in the shared experience will perform these steps to export the shared anchor:

  1. Creare un WorldAnchorTransferBatchCreate a WorldAnchorTransferBatch
  2. Aggiungere il WorldAnchors da trasferireAdd the WorldAnchors to transfer
  3. Inizia l'esportazioneBegin the export
  4. Gestisci l'evento OnExportDataAvailable quando i dati diventano disponibiliHandle the OnExportDataAvailable event as data becomes available
  5. Gestisci evento OnExportCompleteHandle the OnExportComplete event

Viene creato un WorldAnchorTransferBatch per incapsulare gli elementi che verranno trasferiti e quindi esportati in byte: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);
}

Quando i dati diventano disponibili, inviare i byte al client o al buffer perché i segmenti di dati sono disponibili e inviarli con qualsiasi mezzo: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);
}

Al termine dell'esportazione, se i dati sono stati trasferiti e la serializzazione non è riuscita, indicare al client di rimuovere i dati.Once the export is complete, if we have been transferring data and serialization failed, tell the client to discard the data. Se la serializzazione ha avuto esito positivo, indicare al client che tutti i dati sono stati trasferiti e che è possibile avviare l'importazione: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();
    }
}

ImportazioneImporting

Dopo aver ricevuto tutti i byte dal mittente, è possibile importare di nuovo i dati in un WorldAnchorTransferBatch e bloccare l'oggetto del gioco radice nella stessa posizione fisica.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: l'importazione a volte avrà esito negativo e deve essere riprovata: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);
}

Dopo che un GameObject è stato bloccato tramite la chiamata lockobject , avrà un WorldAnchor che lo manterrà nella stessa posizione fisica del mondo, ma potrebbe trovarsi in una posizione diversa nello spazio delle coordinate di Unity rispetto ad altri utenti.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.