Lokale Ankerübertragungen in Unity

In Situationen, in denen Sie Azure Spatial Anchors nicht verwenden können, ermöglichen lokale Ankerübertragungen, dass ein HoloLens Gerät einen Anker exportieren kann, um von einem zweiten HoloLens Gerät importiert zu werden.

Hinweis

Lokale Ankerübertragungen bieten weniger stabile Ankerrückrufe als Azure Spatial Anchors, und iOS- und Android-Geräte werden von diesem Ansatz nicht unterstützt.

Festlegen der SpatialPerception-Funktion

Damit eine App Raumanker übertragen kann, muss die SpatialPerception-Funktion aktiviert sein.

Aktivieren der SpatialPerception-Funktion :

  1. Öffnen Sie im Unity-Editor den Bereich "Player Einstellungen" (Project Einstellungen > Player bearbeiten > ).
  2. Klicken Sie auf die Registerkarte "Windows Store".
  3. Erweitern Sie "Publishing Einstellungen", und überprüfen Sie die Funktion "SpatialPerception" in der Liste "Funktionen".

Hinweis

Wenn Sie Ihr Unity-Projekt bereits in eine Visual Studio Projektmappe exportiert haben, müssen Sie entweder in einen neuen Ordner exportieren oder diese Funktion im AppxManifest in Visual Studio manuell festlegen.

Ankerübertragung

Namespace:UnityEngine.XR.WSA.Sharing
Typ: WorldAnchorTransferBatch

Um einen WorldAnchor zu übertragen, muss der zu übertragende Anker eingerichtet werden. Der Benutzer eines HoloLens überprüft seine Umgebung und wählt entweder manuell oder programmgesteuert einen Punkt im Raum als Anker für die freigegebene Umgebung aus. Die Daten, die diesen Punkt darstellen, können dann serialisiert und an die anderen Geräte übertragen werden, die in der Benutzeroberfläche freigegeben werden. Jedes Gerät deserialisierungiert dann die Ankerdaten und versucht, diesen Punkt im Raum zu finden. Damit anchor transfer funktioniert, muss jedes Gerät in ausreichender Menge der Umgebung gescannt worden sein, sodass der durch den Anker dargestellte Punkt identifiziert werden kann.

Einrichten

Der Beispielcode auf dieser Seite enthält einige Felder, die initialisiert werden müssen:

  1. GameObject rootGameObject ist ein GameObject in Unity, auf dem eine WorldAnchor-Komponente enthalten ist. Ein Benutzer in der freigegebenen Benutzeroberfläche wird dieses GameObject platzieren und die Daten an die anderen Benutzer exportieren.
  2. WorldAnchor gameRootAnchor ist der UnityEngine.XR.WSA.WorldAnchor auf rootGameObject.
  3. byte[] importedData ist ein Bytearray für den serialisierten Anker, den jeder Client über das Netzwerk empfängt.
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>();
    }
}

Exportieren

Zum Exportieren benötigen wir nur einen WorldAnchor und müssen wissen, wie wir ihn nennen, sodass er für die empfangende App sinnvoll ist. Ein Client in der freigegebenen Benutzeroberfläche führt diese Schritte aus, um den freigegebenen Anker zu exportieren:

  1. Erstellen eines WorldAnchorTransferBatch
  2. Hinzufügen der zu übertragenden WorldAnchors
  3. Starten des Exports
  4. Behandeln des OnExportDataAvailable-Ereignisses , sobald Daten verfügbar werden
  5. Behandeln des OnExportComplete-Ereignisses

Wir erstellen einen WorldAnchorTransferBatch , um die zu übertragenden Daten zu kapseln und diese dann in Bytes zu exportieren:

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

Sobald Daten verfügbar werden, senden Sie die Bytes an den Client oder Puffer, da Datensegmente verfügbar sind, und senden Sie über die gewünschten Mittel:

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

Wenn der Export abgeschlossen ist und die Datenübertragung und die Serialisierung fehlgeschlagen sind, weisen Sie den Client an, die Daten zu verwerfen. Wenn die Serialisierung erfolgreich war, teilen Sie dem Client mit, dass alle Daten übertragen wurden und der Import gestartet werden kann:

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

Importieren

Nachdem wir alle Bytes vom Absender empfangen haben, können wir die Daten wieder in ein WorldAnchorTransferBatch-Objekt importieren und unser Stammspielobjekt an derselben physischen Position sperren. Hinweis: Der Import schlägt manchmal vorübergehend fehl und muss wiederholt werden:

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

Nachdem ein GameObject über den LockObject-Aufruf gesperrt wurde, hat es einen WorldAnchor , der es an der gleichen physischen Position auf der Welt hält, aber es kann sich an einer anderen Position im Unity-Koordinatenraum befinden als andere Benutzer.