Solver-Übersicht — MRTK2

Solver Main

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), die in Richtung des Linienstrahls zeigt.
    • Verwenden Sie die TrackedHandedness-Eigenschaft, um die bevorzugte Händigkeit auszuwählen (d. h. Links, Rechts, beide)
  • HandJoint (Handgelenk): Bezugspunkt ist die Transformation eines spezifischen 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.
  • 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.

Solver Tracked Object (vom Solver verfolgtes Objekt) Beispiel für verschiedene Eigenschaften, die dem jeweiligen TrackedTargetType zugewiesen 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).

Vorwärtsvektor

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.

Zusätzliche Drehung

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 die Solver berechnete Position, Ausrichtung, & Skalierung auf eine zwischengeschaltete Variable gespeichert wird, auf die alle Solver 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.

Solver-Kerneigenschaften
Allgemeine Eigenschaften, die von allen Solver-Komponenten geerbt werden

Orbital

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
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
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.

Eigenschaften folgen
Follow-Eigenschaften

Follow-Beispielszene
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 SolverHandlerTracked Target Type (Typ des verfolgten Ziels) 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.

InBetween-Beispiel
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.

SurfaceMagnetism-Beispiel

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-Eigenschaften (Richtungsindikator)

Directional Indicator-Beispielszene (Richtungsindikator)
Directional Indicator-Beispielszene (Richtungsindikator) (Assets/MRTK/Examples/Demos/Solvers/Scenes/DirectionalIndicatorSolverExample.unity)

Handmenü mit HandConstraint und HandConstraintPalmUp

UX-Beispiel für ein Handmenü

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ü“.

Siehe auch