Tricks zur Persistenz
Persistenz ist verfügbar, wenn sie von der zugrunde liegenden Plattform unterstützt wird. Derzeit beschränkt sich dies auf die HoloLens-Gerätefamilie, die die integrierte VR-Unterstützung von Unity (Legacy XR) nutzt.
Grundlegende Persistenz
Für World Locking Tools ist standardmäßig grundlegende Persistenz aktiviert. Diese Aktivierung erfolgt über zwei Optionen.
Relevant sind hier die Kontrollkästchen „Auto Load“ (Automatisch laden) und „Auto Save“ (Automatisch speichern). Sie werden feststellen, dass diese Optionen abgeblendet dargestellt werden. Dies liegt daran, dass sie Teil der Auswahl „Use Defaults“ (Standardwerte verwenden) sind. Wenn Sie die Option „Use Defaults“ deaktivieren, können Sie beliebige Kombinationen der Automatisierungsoptionen auswählen.
Es stehen weitere Informationen zu diesen Einstellungen und zu deren Manipulation über ein Skript zur Verfügung.
AutoSave
Die Option „AutoSave“ weist WLT an, den Zustand während der Ausführung der Anwendung häufig und regelmäßig zu speichern. Die Anwendung kann jederzeit mit minimalem Zustandsverlust beendet werden.
AutoLoad
Über die Option „AutoLoad“ wird WLT angewiesen, alle zuvor gespeicherten Zustände beim Start zu laden. Dies ermöglicht es der Anwendung, eine neue Sitzung dort fortzusetzen, wo sie (in Bezug auf WLT) bei der vorangegangenen Sitzung beendet wurde.
Vollständige Persistenz
Wenn sowohl „AutoSave“ als auch „AutoLoad“ aktiviert sind, funktioniert WLT nahtlos über mehrere Sitzungen hinweg. Während die Position und die Ausrichtung des globalen Raums beim ersten Durchlauf willkürlich sind (da kein vorheriger Zustand gespeichert wurde, wird die Kopfposition beim Start als Ursprung verwendet), wird für nachfolgende Durchläufe derselbe Koordinatenrahmen verwenden.
Dies führt zu einem interessanten Verhalten, wenn die Anwendung eine neue Sitzung in einem Raum startet, der nicht mit dem Raum der vorherigen Sitzung verbunden ist. Weitere Informationen finden Sie im Abschnitt Persistenz nach Standort weiter unten.
Hinweis
Die Einstellungen „AutoSave“ und „AutoLoad“ gelten auch für globale SpacePins. Einzelheiten dazu finden Sie weiter unten.
Anwendungssteuerung über Persistenz
Die standardmäßige vollständige Persistenz eignet sich für eine Vielzahl von Anwendungen.
Einige Anwendungen benötigen jedoch möglicherweise eine präzisere Kontrolle über den Prozess.
Es mag ungewöhnlich erscheinen, dass die Aktivierung der automatischen WLT-Persistenz in zwei Eigenschaften unterteilt ist, nämlich in „AutoSave“ und „AutoLoad“. Eine Untersuchung von Fällen, in denen die beiden Einstellungen unabhängig voneinander verwendet werden, kann Aufschluss über das Persistenzsystem insgesamt geben.
„AutoSave“, aber keine Verwendung von „AutoLoad“
Mit dieser Konfiguration wird WLT angewiesen, den Zustand regelmäßig zu speichern. Beim Start wird jedoch nicht automatisch ein persistierter Zustand geladen.
Vielmehr wird das System in einem Anfangszustand gestartet, so als ob es das erste Mal auf diesem Gerät ausgeführt würde. Erst durch eine explizite Anforderung von Load() wird der Zustand der vorherigen Sitzung wiederhergestellt.
Dadurch kann die Anwendung entscheiden, ob die Wiederherstellung des früheren Sitzungszustands sinnvoll ist oder nicht, und bei Bedarf sogar die wiederherzustellenden Daten ändern.
Der allgemeine WLT-Speicherzustand befindet sich in der Datei „LocalState/frozenWorldState.hkfw“. Sobald die Datei von WLT erstellt wurde, kann sie an einen anderen Speicherort kopiert und nach Ermessen der Anwendung wiederhergestellt werden.
Die Speicherdatei für Ausrichtungsdaten (SpacePin) lautet standardmäßig „LocalState/Persistence/Alignment.fwb“. Diese kann jedoch von der Anwendung mithilfe der AlignmentManager-Eigenschaft SaveFileName überschrieben werden.
Die Entscheidung zum Laden des Zustands der vorherigen Sitzung mit dieser Konfiguration muss beim Start getroffen werden. Sobald die Ausführung beginnt, wird der gespeicherte Zustand der vorherigen Sitzung mit dem Zustand der aktuellen Sitzung überschrieben. Informationen zu einer flexibleren Einrichtung finden Sie weiter unten im Abschnitt Manuelles Speichern und Laden.
Manuelles Speichern, aber Verwendung von „AutoLoad“
In dieser Konfiguration lädt WLT beim Start jeden verfügbaren Zustand aus einer vorherigen Sitzung. Der Zustand wird jedoch nicht automatisch gespeichert. So kann die Anwendung entscheiden, ob und wann der Zustand durch einen Aufruf von Save() gespeichert werden sollte.
„AutoLoad“ weist WLT nur an, beim Start einen beliebigen verfügbaren Zustand zu laden. Es steht der Anwendung frei, jeden gespeicherten Zustand jederzeit durch einen expliziten Aufruf von „Load()“ wiederherzustellen.
Manuelles Speichern und Laden
Die Anwendung erhält die Möglichkeit, die vollständige Kontrolle über den Speicher- und Ladevorgang zu behalten.
Der Zustand wird hierbei nur durch einen expliziten Aufruf von Save() durch die Anwendung gespeichert und nur mit einem expliziten Aufruf von Load() geladen.
Der über den Aufruf von „Load()“ geladene Zustand kann zu einem früheren Zeitpunkt in dieser Sitzung oder in einer vorherigen Sitzung gespeichert worden sein.
Deaktivieren der Persistenz
Wie oben erläutert, steht die Persistenz der Anwendung jederzeit über das Skript zur Verfügung. Die automatische Persistenz kann über ein Skript oder über den WorldLockingContext im Inspector aktiviert und deaktiviert werden. Wenn die automatische Persistenz deaktiviert ist, versucht WLT nicht, den Zustand ohne ausdrückliche Aufforderung durch die Anwendung zu speichern oder zu laden.
Da sich die AutoLoad-Anweisung nur darauf auswirkt, ob der Zustand beim Start geladen wird oder nicht, hat eine Änderung des Werts im Skript nach dem Start keinerlei Auswirkungen.
Vorsicht bei der Entwicklung
Wie bereits erwähnt, gelten die Speicherorte der Dateien für WLT und Ausrichtung für die gesamte Anwendung. Insbesondere werden die Ausrichtungsknoten, auch als SpacePins bezeichnet, nach Namen persistiert (siehe unten). Wenn eine Anwendung den Zustand mit einem Satz von SpacePins aus einer Szene speichert und dann den Zustand mit einem Satz von SpacePins aus einer anderen Szene lädt und beide SpacePins-Sätze gleiche Namen verwenden, dann ist das Verhalten undefiniert.
Es gibt mehrere Möglichkeiten, dieses Problem zu umgehen. Am besten ist es, wenn Sie die Wiederverwendung von SpacePin-Namen innerhalb eines Projekts einfach vermeiden. Wenn Sie nach einer erneuten Bereitstellung ein unerwartetes Verhalten beim Szenenübergang feststellen, löschen Sie den WLT-Speicherzustand. Ebenso können Sie bei einer umfassenden Änderung der Anwendung als Vorsichtsmaßnahme entweder die WLT-Speicherdateien vom Gerät löschen oder die Anwendung einfach deinstallieren, bevor Sie die neue Version installieren.
Persistenz nach Standort
Szenario
Es gibt eine interessante Klasse von Anwendungen, die an verschiedenen physischen Standorten ausgeführt werden. Beispiel: Eine Anwendung wird in Raum A ausgeführt, dann wird das Gerät ausgeschaltet, an einen anderen Ort gebracht und anschließend in Raum B neu gestartet. Hierbei kann sich Raum B in der Nähe von Raum A oder auf einem anderen Kontinent befinden. Die Anwendung und das Gerät haben keine Möglichkeit, dies zu erkennen.
Der Einfachheit halber nehmen wir an, dass die Anwendung für manuelle WLT-Persistenz konfiguriert ist.
Exemplarische Vorgehensweise
Stellen Sie sich zwei nicht miteinander verbundene Räume A und B vor.
Die Anwendung wird in Raum A gestartet. Nachdem ein zusammenhängender, festgeschriebener Koordinatenraum innerhalb des Raums eingerichtet wurde, wird der gesamte Raum Fragment 1 zugeordnet. Ein persistentes Hologrammobjekt X wird im Raum platziert. Anschließend speichert die Anwendung den Zustand und wird beendet.
Das Gerät wird ausgeschaltet, in Raum B gebracht und neu gestartet.
Da das Gerät erkennt, dass es sich nicht um Raum A handelt, deshalb weist WLT dem Inhalt eine neue Fragment-ID zu, beispielsweise ID == 29. Warum 29? Weil es ein anderer Wert ist als 1. Fragment-IDs können beliebige Werte aufweisen, allerdings darf die ID eines Fragments nicht „FragmentId.Invalid“ oder „FragmentId.Unknown“ lauten oder mit einem anderen bekannten Fragment identisch sein.
Jetzt gibt es zwei Fragmente und keine Möglichkeit, sie zusammenzuführen (da keine Informationen über ihre relative Position verfügbar sind).
Der interessierte Anwendungsentwickler könnte sich Folgendes fragen: Ich habe ein persistentes Objekt X in Raum A platziert. Was geschieht, wenn Objekt X geladen wird, wenn die Anwendung in Raum B startet?
Die Antwort ist, dass es dem Anwendungsentwickler überlassen ist, das Verhalten zu bestimmen. Die aktuelle Fragment-ID bei Platzierung des Objekts X in Raum A ist verfügbar und kann persistiert werden. Die Anwendung kann dann beim Start entscheiden, ob Objekt X angezeigt werden soll oder nicht, und zwar abhängig davon, ob das aktuelle Fragment dasselbe ist wie bei der Objekterstellung oder nicht.
Hier beschließt (und implementiert) der Entwickler, dass Objekt X nur geladen wird, wenn die aktuelle Fragment-ID 1 lautet, und dass Objekt Y aus Raum B nur dann geladen wird, wenn die aktuelle Fragment-ID 29 lautet.
Die Persistenz der Fragment-ID, die mit einem Raum verbunden ist, wird im Rahmen der WLT-Persistenz gespeichert. Die Persistenz der mit einem Objekt verbundenen Fragment-ID sowie die darauf basierenden Aktionen bleiben jedoch der Anwendung überlassen.
Zusammen mit der zugeordneten Fragment-ID des Objekts kann seine Position im globalen Raum gespeichert werden. Wenn dann die Fragment-ID übereinstimmt, kann nach dem Laden des Objekts seine Position wiederhergestellt werden, sodass sie mit der Position in der physischen Welt während der letzten Sitzung übereinstimmt. Dank World Locking Tools-Persistenz bleibt eine Position sitzungsübergreifend und relativ zu den Merkmalen der physischen Welt um sie herum fixiert.
Persistenz von SpacePins
SpacePins können als anwendungsseitige Wrapper für AlignmentAnchors betrachtet werden. Während SpacePins (und abgeleitete Klassen) Unity-Komponenten sind, sind AlignmentAnchors rein konzeptionell. Es gibt keine Klassen oder Typen, die einem AlignmentAnchor entsprechen. Daher werden in dieser Erläuterung SpacePins und AlignmentAnchors austauschbar verwendet, wobei SpacePins generell bevorzugt werden.
Allerdings könnte es etwas verwirrend sein, dass ein AlignmentManager SpacePins persistieren kann, obwohl er über kein Konzept für SpacePins verfügt. Dies liegt daran, dass der AlignmentManager den konzeptionellen AlignmentAnchor verwaltet, der das Prinzip eines SpacePins verkörpert und aus dem ein SpacePin gebildet werden kann.
Es gibt im Vergleich zum allgemeinen WLT-Persistenzsystem mehr Steuerungsmöglichkeiten auf Anwendungsebene für die Persistenz von SpacePins, da SpacePins grundsätzlich stärker durch Anwendungseingaben gesteuert werden als die übrigen World Locking Tools-Elemente.
Es ist wichtig zu beachten, dass SpacePins (und AlignmentAnchors) nach Namen persistiert werden. Dies ist eine etwas strengere Anforderung als die allgemeine Vorgabe, dass zwei aktive SpacePins in einem IAlignmentManager nicht denselben Namen verwenden dürfen. Beim Persistieren von SpacePins dürfen zwei SpacePins in derselben Datenbank niemals identische Namen aufweisen, unabhängig davon, ob sie aktiv sind oder nicht.
AlignmentManager-Datenbanken
Jeder IAlignmentManager verfügt über eine Datenbank mit SpacePins nach Namen, wie durch seine Implementierung von RestoreAlignmentAnchor(string uniqueName, Pose virtualPose) impliziert.
Datenbank für die globale Ausrichtung
Es gibt einen globalen IAlignmentManager, der sich im Besitz von „WorldLockingManager.GetInstance()“ befindet. Wie bereits erwähnt, wird der Standardspeicherort der Datei durch die Eigenschaft SaveFileName bestimmt. Beachten Sie, dass „SaveFileName“ eine Eigenschaft der AlignmentManager-Klasse ist, nicht der Schnittstelle IAlignmentManager. Eine IAlignmentManager-Implementierung kann die Persistenz ohne ein Konzept für Dateien oder Dateinamen implementieren. „SaveFileName ist ein Artefakt“ für die Umsetzung der Persistenz durch den AlignmentManager und somit auf den AlignmentManager beschränkt.
Datenbanken für die lokale Ausrichtung
Es kann eine beliebige Anzahl von AlignmentManager-Instanzen für untergeordnete Räume geben, jeweils einen pro AlignSubtree und angezeigt als Feld „AlignSubtree.alignmentManager“. Darüber hinaus kann die Anwendung eigene AlignmentManager-Instanzen oder sogar eigene Klassen erstellen, die von IAlignmentManager abgeleitet sind.
Der AlignmentManager jeder AlignSubtree-Komponente verfügt über einen eigenen Dateispeicherort. Dieser ist standardmäßig auf den GameObject-Namen mit der Erweiterung „.fwb“ festgelegt. Wenn es sich beispielsweise um eine AlignSubtree-Komponente für ein GameObject mit dem Namen „MyRoot“ handelt, erhält die Speicherdatei den Namen „MyRoot.fwb“. Mithilfe eines Schrägstrichs („/“) kann die Datei in einem Unterordner abgelegt werden. Es wäre wahrscheinlich ungünstig, wenn zwei AlignSubtree-Komponenten denselben Dateispeicherort verwenden würden.
Umsetzung
Langfristig gesehen ist es einfacher und robuster, SpacePins/AlignmentAnchors mit global eindeutigen Namen zu versehen – anstatt zu versuchen, die weniger strengen Anforderungen an die lokale Eindeutigkeit zu erfüllen. Daher wird dieser Ansatz dringend empfohlen. Die tatsächliche Vorgehensweise bleibt aber natürlich Ihnen überlassen.