Lokale Ankerübertragungen in Unity

In Situationen, in denen Sie Azure Spatial Anchors nicht verwenden können, ermöglichen lokale Ankerübertragungen einem HoloLens-Gerät das Exportieren eines Ankers, der von einem zweiten HoloLens-Gerät importiert werden kann.

Hinweis

Lokale Ankerübertragungen bieten weniger robuste 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 "Playereinstellungen" (Projekteinstellungen > bearbeiten > Player)
  2. Klicken Sie auf die Registerkarte "Windows Store" .
  3. Erweitern Sie "Veröffentlichungseinstellungen", 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 manuell im AppxManifest in Visual Studio festlegen.

Ankerübertragung

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

Um einen WorldAnchor zu übertragen, muss man den zu übertragenden Anker einrichten. Der Benutzer einer HoloLens scannt seine Umgebung und wählt entweder manuell oder programmgesteuert einen Punkt im Raum als Anker für die gemeinsame Benutzeroberfläche 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 de serialisiert dann die Ankerdaten und versucht, diesen Punkt im Raum zu finden. Damit die Ankerübertragung funktioniert, muss jedes Gerät in ausreichender 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 mit einer WorldAnchor-Komponente . Ein Benutzer in der freigegebenen Benutzeroberfläche platziert dieses GameObject und exportiert die Daten an die anderen Benutzer.
  2. WorldAnchor gameRootAnchor ist die UnityEngine.XR.WSA.WorldAnchor , die sich auf rootGameObject befindet.
  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 um zu wissen, wie wir es nennen, so dass es für die empfangende App sinnvoll ist. Ein Client in der freigegebenen Umgebung führt die folgenden 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 , wenn Daten verfügbar werden
  5. Behandeln des OnExportComplete-Ereignisses

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

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

Wenn Daten verfügbar werden, senden Sie die Bytes an den Client oder Puffer, wenn Datensegmente verfügbar sind, und senden Sie über beliebige Mittel:

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

Wenn der Export abgeschlossen ist, bitten Sie den Client, die Daten zu verwerfen, wenn daten übertragen und die Serialisierung fehlgeschlagen ist. 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 einen WorldAnchorTransferBatch importieren und unser Stammspielobjekt an demselben physischen Speicherort 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, verfügt es über einen WorldAnchor , der es an der gleichen physischen Position in der Welt behält, sich aber möglicherweise an einem anderen Ort im Unity-Koordinatenraum als andere Benutzer befindet.