Solver-Übersicht — MRTK2
Solver sind Komponenten, die die Berechnung der Position und Ausrichtung eines Objekts gemäß einem vordefinierten Algorithmus erleichtern. Ein Beispiel hierfür ist das Platzieren eines Objekts auf der Oberfläche, auf die der Raycast des Anvisierens durch den Benutzer aktuell trifft.
Darüber hinaus definiert das Solver-System deterministisch eine Reihenfolge von Vorgängen für diese Transformationsberechnungen, da es keine zuverlässige Möglichkeit gibt, Unity die Aktualisierungsreihenfolge für Komponenten anzugeben.
Solver bieten eine Reihe von Verhaltensweisen zum Anfügen von Objekten an andere Objekte oder Systeme. Ein weiteres Beispiel wäre ein mitwanderndes Objekt, das vor dem Benutzer schwebt (basierend auf der Kamera). Ein Solver könnte auch an einen Controller und ein Objekt angefügt werden, damit das Objekt dem Controller folgt. Alle Solver können sicher gestapelt werden, z. B. ein Folgeverhalten + Oberflächenmagnetismus + Momentum.
Verwenden eines Solvers
Das Solver-System besteht aus drei Kategorien von Skripts:
Solver
: Die abstrakte Basisklasse, von der alle Solver abgeleitet werden. Sie bietet Zustandsverfolgung, Glättungsparameter und Implementierung, automatische Solver-Systemintegration und Aktualisierungsreihenfolge.SolverHandler
: Legt das zu verfolgende Bezugsobjekt fest (z. B. die Hauptkameratransformation, Handstrahl usw.), verarbeitet das Sammeln von Solver-Komponenten und führt deren Aktualisierung in der richtigen Reihenfolge aus.
Die dritte Kategorie ist der Solver selbst. Die folgenden Solver stellen die Bausteine für das grundlegende Verhalten bereit:
Orbital
: Wird an einer angegebenen Position und mit einem Offset vom Bezugszobjekt verankert.ConstantViewSize
: Wird so skaliert, dass eine konstante Größe relativ zur Ansicht des Bezugsobjekts beibehalten wird.RadialView
: Hält das Objekt innerhalb eines Sichtkegels, der vom Bezugsobjekt geworfen wird.Follow
: Hält das Objekt innerhalb einer Gruppe benutzerseitig definierter Grenzen vom Bezugsobjekt.InBetween
: Hält ein Objekt zwischen zwei verfolgten Objekten.SurfaceMagnetism
: Wirft Strahlen auf Oberflächen in der Welt und richtet das Objekt an dieser Oberfläche aus.DirectionalIndicator
: Bestimmt die Position und Ausrichtung eines Objekts als Richtungsindikator. Ab dem Bezugspunkt des vom SolverHandler verfolgten Ziels richtet sich dieser Indikator auf das angegebene DirectionalTarget aus.Momentum
: Wendet Beschleunigung/Geschwindigkeit/Reibung an, um Momentum und Elastizität für ein Objekt zu simulieren, das von anderen Solvern/Komponenten bewegt wird.HandConstraint
: Schränkt das Objekt auf die Verfolgung von Händen in einem Bereich ein, in dem sich das GameObject nicht mit den Händen überschneidet. Nützlich für auf Hände eingeschränkte interaktive Inhalte wie Menüs usw. Dieser Solver ist für die Verwendung mit IMixedRealityHand vorgesehen, funktioniert aber auch mit IMixedRealityController.HandConstraintPalmUp
: Wird von HandConstraint abgeleitet, umfasst aber Logik zum Testen vor der Aktivierung, ob die Handfläche dem Benutzer zugewandt ist. Dieser Solver funktioniert nur mit IMixedRealityHand-Controllern. Mit anderen Controllertypen verhält sich dieser Solver genau wie seine Basisklasse.
Um das Solver-System zu verwenden, fügen Sie einem GameObject einfach eine der oben aufgeführten Komponenten hinzu. Da alle Solver einen SolverHandler
erfordern, wird einer automatisch von Unity erstellt.
Hinweis
Beispiele für die Verwendung des Solver-Systems finden Sie in der Datei SolverExamples.scene.
Ändern des Verfolgungsbezugs
Die Eigenschaft Tracked Target Type (Typ des verfolgten Ziels) der SolverHandler
-Komponente definiert den Bezugspunkt, den alle Solver verwenden, um ihre Algorithmen zu berechnen. Beispielsweise führt ein Werttyp von Head
mit einer einfachen SurfaceMagnetism
-Komponente zu einem Raycast vom Kopf des Benutzers aus und in dessen Anvisierrichtung, um aufzulösen, welche Oberfläche getroffen wird. Potenzielle Werte für die TrackedTargetType
-Eigenschaft sind:
- Head (Kopf): Bezugspunkt ist die Transformation der Hauptkamera.
- ControllerRay: Bezugspunkt ist die
LinePointer
Transformation auf einem Controller (d. h. Zeigerursprung auf einem Bewegungscontroller oder Handcontroller), der in Richtung des Linienstrahls zeigt- Verwenden Sie die
TrackedHandedness
-Eigenschaft, um die bevorzugte Händigkeit auszuwählen (d. h. Links, Rechts, beide)
- Verwenden Sie die
- HandJoint: Bezugspunkt ist die Transformation eines bestimmten Handgelenks
- Verwenden Sie die
TrackedHandedness
-Eigenschaft, um die bevorzugte Händigkeit auszuwählen (d. h. Links, Rechts, beide) - Verwenden Sie die
TrackedHandJoint
-Eigenschaft, um die zu verwendende Gelenktransformation zu bestimmen.
- Verwenden Sie die
- CustomOverride (benutzerdefinierte Außerkraftsetzung): Bezugspunkt von der zugewiesenen
TransformOverride
aus.
Hinweis
Für beide Typen, also ControllerRay und HandJoint, versucht der Solver-Handler zuerst, die linke Controller-/Handtransformation bereitzustellen, und dann die rechte, wenn die erste nicht verfügbar ist, oder wenn die TrackedHandedness
-Eigenschaft etwas anderes angibt.
Beispiel für verschiedene Eigenschaften, die den einzelnen TrackedTargetType zugeordnet sind
Wichtig
Die meisten Solver verwenden den Vorwärtsvektor des verfolgten Transformationsziels, das vom SolverHandler
bereitgestellt wird. Bei Verwendung des Typs Handgelenk für ein verfolgtes Ziel kann es sein, dass der Vorwärtsvektor des Hand(flächen)gelenks durch die Finger und nicht durch die Handfläche zeigt. Dies hängt von der Plattform ab, die die Handgelenksdaten liefert. Für die Eingabesimulation und Windows Mixed Reality ist es der Nach-oben-Vektor, der durch die Handfläche nach oben zeigt (d. h. grüner Vektor bedeutet aufwärts, blauer Vektor vorwärts).
Um dies zu umgehen, aktualisieren Sie die Eigenschaft Additional Rotation (Zusätzliche Drehung) des SolverHandler
auf <90, 0, 0>. Dadurch wird sichergestellt, dass der an Solver übergebene Vorwärtsvektor durch die Handfläche und nach außen, von der Hand weg verweist.
Alternativ können Sie den Typ Controller Ray (Controllerstrahl) für ein verfolgtes Ziel verwenden, um ein ähnliches Verhalten für das Zeigen mit den Händen zu erhalten.
Verketten von Solvern
Es ist möglich, dem selben GameObject mehrere Solver
-Komponenten hinzuzufügen und so deren Algorithmen zu verketten. Die SolverHandler
-Komponenten aktualisieren alle Solver desselben GameObject. Standardmäßig ruft der SolverHandler
beim Starten GetComponents<Solver>()
auf, wodurch die Solver in der Reihenfolge zurückgegeben werden, in der sie im Inspektor vorkommen.
Darüber hinaus weist das Festlegen der Updated Linked Transform-Eigenschaft auf "true" an, dass Solver
die berechnete Position, Ausrichtung und Skalierung auf eine zwischengeschaltete Variable gespeichert werden soll, auf die alle Solvers zugreifen können (d. h GoalPosition
. ). „false“ gibt an, dass der Solver
die Transformation des GameObject direkt aktualisiert. Durch das Speichern der Transformationseigenschaften an einem Zwischenspeicherort können andere Solver ihre Berechnungen ab der Zwischenvariablen ausführen. Dies liegt daran, dass Unity nicht zulässt, dass Aktualisierungen von „gameObject.transform“ innerhalb desselben Frames gestapelt werden.
Hinweis
Entwickler können die Ausführungsreihenfolge von Solvern ändern, indem sie die SolverHandler.Solvers
-Eigenschaft direkt festlegen.
Erstellen eines neuen Solvers
Alle Solver müssen von der abstrakten Basisklasse Solver
erben. Die primären Anforderungen einer Solver-Erweiterung umfassen das Außerkraftsetzen der SolverUpdate
-Methode. Bei dieser Methode sollten Entwickler die geerbten Eigenschaften GoalPosition
, GoalRotation
und GoalScale
auf die gewünschten Werte aktualisieren. Darüber hinaus ist es im Allgemeinen nützlich, SolverHandler.TransformTarget
als Bezugsframe zu nutzen, der vom Consumer gewünscht wird.
Der unten angegebene Code enthält ein Beispiel für eine neue Solver-Komponente namens InFront
, die das angefügte Objekt 2 m vor dem SolverHandler.TransformTarget
platziert. Wenn der SolverHandler.TrackedTargetType
vom Consumer als Head
festgelegt wird, ist SolverHandler.TransformTarget
die Kameratransformation, weshalb dieser Solver dann das angefügte GameObject in jedem Frame 2 m vor dem Anvisieren des Benutzers platziert.
/// <summary>
/// InFront solver positions an object 2m in front of the tracked transform target
/// </summary>
public class InFront : Solver
{
...
public override void SolverUpdate()
{
if (SolverHandler != null && SolverHandler.TransformTarget != null)
{
var target = SolverHandler.TransformTarget;
GoalPosition = target.position + target.forward * 2.0f;
}
}
}
Richtlinien für die Solver-Implementierung
Allgemeine Solver-Eigenschaften
Jede Solver-Komponente verfügt über einen Kernsatz identischer Eigenschaften, die das Kernverhalten des Solvers steuern.
Wenn Smoothing (Glättung) aktiviert ist, aktualisiert der Solver die Transformation des GameObject im Laufe der Zeit schrittweise auf die berechneten Werte. Die Geschwindigkeit dieser Änderung wird durch die Eigenschaft LerpTime der jeweiligen Transformationskomponente bestimmt. Ein höherer MoveLerpTime-Wert führt beispielsweise zu langsameren Inkrementen bei der Bewegung zwischen Frames.
Wenn MaintainScale aktiviert ist, verwendet der Solver die lokale Standardskalierung des GameObject.
Allgemeine Eigenschaften, die von allen Solver-Komponenten geerbt werden
Orbitale
Die Orbital
-Klasse ist eine Komponente mit Folgeverhalten, die sich wie Planeten in einem Sonnensystem verhält. Dieser Solver stellt sicher, dass das angefügte GameObject die verfolgte Transformation umkreist. Wenn also der Tracked Target Type (Typ des verfolgten Ziels) des SolverHandler
auf Head
festgelegt ist, umkreist das GameObject den Kopf des Benutzers mit einem festen Offset.
Entwickler können diesen festen Offset ändern, um Menüs oder andere Szenenkomponenten auf Augen- oder Hüfthöhe usw. um einen Benutzer herum zu halten. Dies erfolgt durch Ändern der Eigenschaften Local Offset (Lokaler Offset) und World Offset (Weltoffset). Die Eigenschaft Orientation Type (Ausrichtungstyp) bestimmt auf das Objekt angewendete Drehung, ob es seine ursprüngliche Drehung beibehalten oder immer der Kamera oder dem Gesicht zugewandt sein soll, egal welche Transformation seine Position bestimmt usw.
Orbital-Beispiel
RadialView
RadialView
ist eine weitere Komponente mit Folgeverhalten, die einen bestimmten Teil eines GameObject im Frustum des Sichtfelds des Benutzers hält.
Die Eigenschaften Min & Max View Degrees (Mindest-/Maximalsichtgrad) bestimmen die Größe des Teils des GameObject, der immer im Sichtfeld sein muss.
Die Eigenschaften Min & Max Distance (Mindest-/Maximalabstand) bestimmen, wie weit das GameObject vom Benutzer entfernt bleiben soll. Wenn Sie beispielsweise mit einer Min Distance (Mindestabstand) von 1 m auf das GameObject zugehen, wird das GameObject weggestoßen, um sicherzustellen, dass es dem Benutzer nie näher als 1 m kommt.
Im Allgemeinen wird die RadialView
in Verbindung mit dem auf Head
festgelegten Tracked Target Type (Typ des verfolgten Ziels) verwendet, damit die Komponente dem Anvisieren des Benutzers folgt. Diese Komponente kann jedoch so funktionieren, dass sie immer im "Sichtfeld" jedes Tracked Target Type (Typ des verfolgten Ziels) gehalten wird.
RadialView-Beispiel
Follow
Die Follow
-Klasse positioniert ein Element vor dem verfolgten Ziel, relativ zu seiner lokalen Vorwärtsachse. Das Element kann lose eingeschränkt werden (auch als Tag-Along bezeichnet), sodass es erst nachverfolgt wird, wenn das nachverfolgte Ziel die benutzerdefinierten Grenzen überschreitet.
Es funktioniert ähnlich wie der RadialView-Solver mit zusätzlichen Steuerelementen zum Verwalten von Max Horizontal & Vertical View Degrees (Max. horizontale/vertikaler Sichtgrad) und Mechanismen zum Ändern der Ausrichtung des Objekts.
Follow-Eigenschaften
Follow-Beispielszene (Assets/MRTK/Examples/Demos/Solvers/Scenes/FollowSolverExample.unity)
InBetween
Die InBetween
-Klasse hält das angefügte GameObject zwischen zwei Transformationen. Diese zwei Transformationsendpunkte werden durch den eigenen Tracked Target Type (Typ des verfolgten Ziels) SolverHandler
des GameObject und die Eigenschaft Second Tracked Target Type (Zweiter Typ des verfolgten Ziels) der InBetween
-Komponente definiert. Im Allgemeinen werden beide Typen auf CustomOverride
und die resultierenden SolverHandler.TransformOverride
- und InBetween.SecondTransformOverride
-Werte auf die zwei verfolgten Endpunkte festgelegt.
Zur Laufzeit erstellt die InBetween
-Komponente eine weitere SolverHandler
-Komponente, die auf den Eigenschaften Second Tracked Target Type (Zweiter Typ des verfolgten Ziels) und Second Transform Override (Zweite Transformationsaußerkraftsetzung) basiert.
Der PartwayOffset
definiert, wo entlang der Linie zwischen zwei Transformationen das Objekt platziert werden soll, wobei 0,5 auf halber Strecke, 1,0 bei der ersten Transformation und 0,0 bei der zweiten Transformation ist.
Beispiel für die Verwendung des InBetween-Solvers, um ein Objekt zwischen zwei Transformationen zu halten
SurfaceMagnetism
SurfaceMagnetism
funktioniert, indem ein Raycast auf eine festgelegte LayerMask von Oberflächen ausgeführt und das GameObject an diesem Kontaktpunkt platziert wird.
Der Surface Normal Offset (Offset zur Oberflächennormale) platziert das GameObject in einem festgelegten Abstand in Metern von der Oberfläche in Richtung der Normalen am Punkt des Auftreffens auf der Oberfläche.
Umgekehrt platziert der Surface Ray Offset (Offset zum Oberflächenstrahl) das GameObject in einem festgelegten Abstand in Metern von der Oberfläche weg, aber in entgegengesetzter Richtung des ausgeführten Raycasts. Wenn der Raycast also das Anvisieren des Benutzers ist, bewegt sich das GameObject näher entlang der Linie vom Punkt des Auftreffens auf der Oberfläche zur Kamera.
Der Orientation Mode (Ausrichtungsmodus) bestimmt den Typ der Drehung, die in Bezug auf die Normale auf der Oberfläche angewendet werden soll.
- None (Keine): Keine Drehung angewendet.
- TrackedTarget (Verfolgtes Ziel): Das Objekt wird der verfolgten Transformation, die den Raycast steuert, zugewandt.
- SurfaceNormal (Oberflächennormale): Das Objekt wird auf Grundlage der Normalen am Punkt des Auftreffens auf der Oberfläche ausgerichtet.
- Blended (Gemischt): Das Objekt wird basierend auf der Normalen am Punkt des Auftreffens auf der Oberfläche UND der verfolgten Transformation zugewandt ausgerichtet.
Um zu erzwingen, dass das zugeordnete GameObject in jedem anderen Modus als None vertikal bleibt, aktivieren Sie Keep Orientation Vertical (Ausrichtung vertikal halten).
Hinweis
Verwenden Sie die Eigenschaft Orientation Blend (Gemischte Ausrichtung), um das Gleichgewicht zwischen Drehfaktoren zu steuern, wenn der Orientation Mode (Ausrichtungsmodus) auf Blended (Gemischt) festgelegt ist. Beim Wert 0,0 wird die Ausrichtung vollständig vom TrackedTarget-Modus gesteuert, und beim Wert 1,0 wird die Ausrichtung vollständig von SurfaceNormal gesteuert.
Bestimmen, welche Oberflächen erreicht werden können
Beim Hinzufügen einer SurfaceMagnetism
-Komponente zu einem GameObject ist es wichtig, die Ebene des GameObject und seine untergeordneten Elemente zu berücksichtigen, sofern diese Collider aufweisen. Die Komponente funktioniert so, dass sie verschiedene Arten von Raycasts ausführt, um zu bestimmen, an welcher Oberfläche sie sich selbst „magnetisch anheften“ soll. Wenn das Solver GameObject über einen Collider auf einer der Ebenen verfügt, die in der MagneticSurfaces
-Eigenschaft von SurfaceMagnetism
aufgeführt sind, trifft sich der Raycast wahrscheinlich selbst, was dazu führt, dass das GameObject an seinen eigenen Colliderpunkt angefügt wird. Dieses seltsame Verhalten kann vermieden werden, indem das Haupt-GameObject und alle seine untergeordneten Elemente auf die Ignore Raycast-Eben (Raycast ignorieren) festgelegt werden oder das MagneticSurfaces
LayerMask-Array entsprechend geändert wird.
Umgekehrt wird ein SurfaceMagnetism
GameObject nicht mit Oberflächen auf einer Ebene kollidieren, die nicht in der MagneticSurfaces
-Eigenschaft aufgeführt ist. Es wird generell empfohlen, alle gewünschten Oberflächen auf einer dedizierten Ebene zu platzieren (d. h. Surfaces (Oberflächen)) und die MagneticSurfaces
-Eigenschaft auf eben diese Ebene festzulegen. Die Verwendung von default (Standard) oder everything (alles) kann dazu führen, dass Benutzeroberflächenkomponenten oder Cursor zum Solver beitragen.
Schließlich werden Oberflächen, die weiter als die Einstellung der Eigenschaft MaxRaycastDistance
entfernt liegen, von den SurfaceMagnetism
-Raycasts ignoriert.
DirectionalIndicator
Die DirectionalIndicator
-Klasse ist eine Komponente mit Folgeverhalten, die sich selbst an der Richtung eines gewünschten Punkts im Raum orientiert.
Wird am häufigsten verwendet, wenn der Tracked Target Type (Typ des verfolgten Ziels) des SolverHandler
auf Head
festgelegt ist. Auf diese Weise weist eine UX-Komponente einen Benutzer mit dem DirectionalIndicator
-Solver an, auf den gewünschten Punkt im Raum zu sehen.
Der gewünschte Punkt im Raum wird über die Eigenschaft Directional Target (Gerichtetes Ziel) bestimmt.
Wenn das gerichtete Ziel für den Benutzer sichtbar ist, oder egal welcher Bezugsframe im SolverHandler
festgelegt ist, deaktiviert dieser Solver alle darunter liegenden Renderer
-Komponenten. Wenn es nicht sichtbar ist, wird alles für den Indikator aktiviert.
Der Indikator wird immer kleiner, je näher der Benutzer dem Erfassen des Directional Target in seinem Sichtfeld (FOV) kommt.
Min Indicator Scale (Minimale Indikatorskala): Die minimale Skalierung für das Indikatorobjekt.
Max Indicator Scale (Maximale Indikatorskala): Die maximale Skalierung für das Indikatorobjekt.
Visibility Scale Factor (Skalierungsfaktor für Sichtbarkeit): Multiplikator zum Erhöhen oder Verringern des Sichtfelds, der bestimmt, ob der Punkt des Directional Target sichtbar ist oder nicht.
View Offset (Sichtoffset): Vom Blickpunkt des Bezugsrahmens (d. h. möglicherweise Kamera) definiert diese Eigenschaft, wie weit sich das Objekt in Indikatorrichtung von der Mitte des Viewports entfernt befinden soll.
Directional Indicator-Eigenschaften (Richtungsindikator)
Directional Indicator-Beispielszene (Richtungsindikator) (Assets/MRTK/Examples/Demos/Solvers/Scenes/DirectionalIndicatorSolverExample.unity)
Handmenü mit HandConstraint und HandConstraintPalmUp
Das HandConstraint
-Verhalten stellt einen Solver bereit, der das verfolgte Objekt auf einen Bereich beschränkt, der für auf Hand eingeschränkte Inhalte sicher ist (z. B. Handbenutzeroberfläche, Menüs usw.). Als sichere Regionen gelten Bereiche, die sich nicht mit der Hand überschneiden. Eine abgeleitete Klasse von HandConstraint
namens HandConstraintPalmUp
ist ebenfalls enthalten, um ein allgemeines Verhalten der Aktivierung des vom Solver verfolgten Objekts zu veranschaulichen, wenn die Handfläche dem Benutzer zugewandt ist.
Die Beispiele für die Verwendung des Handeinschränkungs-Solvers zum Erstellen von Handmenüs finden Sie auf der Seite „Handmenü“.