Lokale Ankerübertragungen in Unity
In Situationen, in denen Sie Azure Spatial Anchors nicht verwenden können, ermöglichen lokale Ankerübertragungen ein HoloLens-Gerät, einen Anker zu exportieren, der von einem zweiten HoloLens-Gerät importiert wird.
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 räumliche Anker übertragen kann, muss die SpatialPerception-Funktion aktiviert sein.
So aktivieren Sie die SpatialPerception-Funktion :
- Öffnen Sie im Unity-Editor den Bereich "Playereinstellungen" (Projekteinstellungen-Player > bearbeiten>)
- Klicken Sie auf die Registerkarte "Windows Store" .
- 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 Anker einrichten, der übertragen werden soll. Der Benutzer einer HoloLens scannt seine Umgebung und wählt entweder manuell oder programmgesteuert einen Punkt im Raum aus, der als Anker für die freigegebene Erfahrung dienen soll. Die Daten, die diesen Punkt darstellen, können dann serialisiert und an die anderen Geräte übertragen werden, die die Erfahrung teilen. Jedes Gerät de serialisiert dann die Ankerdaten und versucht, diesen Punkt im Raum zu finden. Damit die Anchorübertragung funktioniert, muss jedes Gerät in ausreichender Umgebung gescannt worden sein, sodass der durch den Anker dargestellte Punkt identifiziert werden kann.
Setup
Der Beispielcode auf dieser Seite enthält einige Felder, die initialisiert werden müssen:
- GameObject rootGameObject ist ein GameObject in Unity, das über eine WorldAnchor-Komponente verfügt. Ein Benutzer in der freigegebenen Benutzeroberfläche platziert dieses GameObject und exportiert die Daten in die anderen Benutzer.
- WorldAnchor gameRootAnchor ist der UnityEngine.XR.WSA.WorldAnchor, der sich auf rootGameObject befindet.
- 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 wissen, was wir so nennen werden, 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:
- Erstellen eines WorldAnchorTransferBatch
- Hinzufügen der zu übertragenden WorldAnchors
- Starten des Exports
- Behandeln des OnExportDataAvailable-Ereignisses , wenn Daten verfügbar werden
- Behandeln des OnExportComplete-Ereignisses
Wir erstellen einen WorldAnchorTransferBatch , um zu kapseln, was wir übertragen und dann in Bytes 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, da Datensegmente verfügbar sind und über die gewünschten Mittel gesendet werden:
private void OnExportDataAvailable(byte[] data)
{
TransferDataToClient(data);
}
Sobald der Export abgeschlossen ist, müssen Sie den Client anweisen, die Daten zu verwerfen, wenn wir Daten übertragen und serialisierung fehlgeschlagen sind. Wenn die Serialisierung erfolgreich war, teilen Sie dem Client mit, dass alle Daten übertragen und importiert werden können:
private void OnExportComplete(SerializationCompletionReason completionReason)
{
if (completionReason != SerializationCompletionReason.Succeeded)
{
SendExportFailedToClient();
}
else
{
SendExportSucceededToClient();
}
}
Importieren
Nachdem wir alle Bytes des Absenders empfangen haben, können wir die Daten wieder in ein 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 derselben physischen Position in der Welt hält, aber es kann sich an einer anderen Stelle im Unity-Koordinatenbereich befinden als andere Benutzer.