Vue d’ensemble des résolveurs — MRTK2

Solver Main

Les résolveurs sont des composants qui facilitent le calcul de la position et l’orientation d’un objet en fonction d’un algorithme prédéfini. Il est par exemple possible de placer un objet sur la surface actuellement visée par le raycast du pointage du regard de l’utilisateur.

En outre, le système de résolveur définit de manière déterministe un ordre des opérations pour ces calculs de transformation, car il n’existe pas de méthode fiable pour indiquer à Unity l’ordre de mise à jour des composants.

Les résolveurs offrent un éventail de comportements pour attacher des objets à d’autres objets ou systèmes. Un autre exemple est un objet tag-along qui pointe vers l’avant de l’utilisateur (en fonction de l’appareil photo). Un résolveur peut également être attaché à un contrôleur et à un objet pour faire de l’objet tag-along le contrôleur. Tous les résolveurs peuvent être empilés en toute sécurité, par exemple un comportement avec objet tag-along + aimantation de surface + dynamisme.

Comment utiliser un résolveur

Le système du résolveur se compose de trois catégories de scripts :

  • Solver : classe abstraite de base de laquelle tous les résolveurs dérivent. Elle fournit le suivi d’état, les paramètres de lissage et l’implémentation, l’intégration du système de résolveur automatique et l’ordre des mises à jour.
  • SolverHandler : définit l’objet de référence selon lequel assurer le suivi (par exemple, la transformation de la caméra principale, le rayon émanant de la main, etc.), gère la collecte des composants du résolveur et exécute leur mise à jour dans l’ordre approprié.

La troisième catégorie est le résolveur lui-même. Les résolveurs suivants fournissent les blocs de construction pour le comportement de base :

  • Orbital : verrouille sur une position et un offset spécifiés à partir de l’objet référencé.
  • ConstantViewSize : met à l’échelle pour conserver une taille constante relative à la vue de l’objet référencé.
  • RadialView : conserve l’objet dans une vue de type cône converti par l’objet référencé.
  • Follow : conserve l’objet dans un ensemble de limites définies par l’utilisateur de l’objet référencé.
  • InBetween : conserve un objet entre deux objets suivis.
  • SurfaceMagnetism : convertit les rayons en surfaces dans le monde et aligne l’objet sur cette surface.
  • DirectionalIndicator : détermine la position et l’orientation d’un objet sous la forme d’un indicateur directionnel. À partir du point de référence de la cible suivie SolverHandler, cet indicateur va orienter vers la DirectionalTarget fournie.
  • Momentum : applique l’accélération/la vélocité/la friction pour simuler le dynamisme et les souplesse d’un objet déplacé par d’autres résolveurs/composants.
  • HandConstraint : limite l’objet pour suivre les mains dans une région qui ne croise pas le GameObject avec les mains. Utile pour le contenu interactif à la main, comme les menus, etc. Ce solveur est conçu pour fonctionner avec IMixedRealityHand , mais il fonctionne également avec IMixedRealityController.
  • HandConstraintPalmUp : dérive de HandConstraint mais comprend une logique permettant de tester si la paume fait face à l’utilisateur avant l’activation. Ce résolveur fonctionne uniquement avec les contrôleurs IMixedRealityHand, avec d’autres types de contrôleur. ce résolveur se comporte comme sa classe de base.

Pour utiliser le système du résolveur, ajoutez simplement l’un des composants repris ci-dessus à un GameObject. Étant donné que tous les résolveurs requièrent un(e) SolverHandler, il y en a un(e) qui est créé(e) automatiquement par Unity.

Remarque

Vous trouverez des exemples d’utilisation du système de résolveurs dans le fichier SolverExamples.scene.

Comment modifier la référence de suivi

La propriété Tracked Target Type du composant SolverHandler définit le point de référence que tous les résolveurs utiliseront pour calculer leurs algorithmes. Par exemple, un type valeur de Head avec un composant SurfaceMagnetism simple se traduira par un raycast à partir de la tête et dans la direction du pointage du regard de l’utilisateur pour déterminer la surface atteinte. Les valeurs potentielles pour la propriété TrackedTargetType sont :

  • Head : le point de référence est la transformation de la caméra principale
  • ControllerRay : le point de référence est la transformation LinePointer sur un contrôleur (c’est-à-dire l’origine du pointeur sur un contrôleur de mouvement ou un contrôleur de main) qui pointe dans la direction du rayon rectiligne.
    • Utilisez la propriété TrackedHandedness pour sélectionner la préférence de main (c’est-à-dire Left, Right, Both)
  • HandJoint : le point de référence est la transformation d’une articulation de la main spécifique
    • Utilisez la propriété TrackedHandedness pour sélectionner la préférence de main (c’est-à-dire Left, Right, Both)
    • Utilisez la propriété TrackedHandJoint pour déterminer la transformation d’articulation à utiliser
  • CustomOverride : point de référence depuis le/la TransformOverride affecté(e)

Notes

Pour les types ControllerRay et HandJoint, le gestionnaire de résolveur tentera de fournir d’abord la transformation de contrôleur/main gauche, puis du droit si le premier n’est pas disponible ou à moins que la propriété TrackedHandedness spécifie autre chose.

Solver Tracked ObjectExemple de différentes propriétés associées à chaque TrackedTargetType

Important

La plupart des résolveurs utilisent le vecteur vers l’avant de la cible de transformation suivie fournie par SolverHandler. Lors de l’utilisation d’un type de cible Articulation de la main suivi, le vecteur avant de l’articulation de la paume peut pointer avec les doigts et non avec la paume. Cela dépend de la plateforme fournissant les données jointes à la main. Pour la simulation d’entrée et Windows Mixed Reality, c’est le vecteur vers le haut qui pointe à travers la paume (le vecteur vert est vers le haut, le vecteur bleu est vers l’avant)

Forward Up vector

Pour remédier à cela, mettez à jour la propriété Additional Rotation sur le SolverHandler avec les valeurs <90, 0, 0>. Cela permet de s’assurer que le vecteur direct fourni aux résolveurs pointe via la paume et vers l’extérieur de la main.

Additional Rotation

Vous pouvez également utiliser le type de cible Ray Controller suivi pour obtenir un comportement similaire pour le pointage avec les mains.

Comment joindre des résolveurs

Il est possible d’ajouter plusieurs composants Solver au même GameObject, et ainsi de joindre leurs algorithmes. Les composants SolverHandler gèrent la mise à jour de tous les résolveurs sur le même GameObject. Par défaut, les SolverHandler appels GetComponents<Solver>() à Start retournent les résolveurs dans l’ordre dans lequel ils apparaissent dans l’inspecteur.

En outre, l’affectation de la valeur true à la propriété Updated Linked Transform indique à ce Solver d’enregistrer sa position calculée, son orientation et son échelle calculées dans une variable intermédiaire accessible par tous les résolveurs (c.-à-d. GoalPosition). Quand la valeur est false, le/la Solver met directement à jour la transformation de GameObject. En enregistrant les propriétés de transformation dans un emplacement intermédiaire, les autres résolveurs sont en mesure d’effectuer leurs calculs à partir de la variable intermédiaire. En effet, Unity ne permet pas aux mises à jour de gameObject.transform de s’empiler dans le même cadre.

Remarque

Les développeurs peuvent modifier l’ordre d’exécution des résolveurs en définissant la propriété SolverHandler.Solvers directement.

Création d'un résolveur

Tous les résolveurs doivent hériter de la classe de base abstraite, Solver . Les exigences principales d’une extension du résolveur impliquent la substitution de la méthode SolverUpdate. Dans cette méthode, les développeurs doivent mettre à jour les propriétés héritées GoalPosition, GoalRotation et GoalScale avec les valeurs souhaitées. En outre, il est généralement utile de tirer parti de SolverHandler.TransformTarget comme cadre de référence souhaité par le consommateur.

Le code fourni ci-dessous donne un exemple d’un nouveau composant de résolveur appelé InFront qui place l’objet attaché à deux mètres devant le/la SolverHandler.TransformTarget . Si le/la SolverHandler.TrackedTargetType est défini(e) par le consommateur en tant que Head, le/la SolverHandler.TransformTarget sera la transformation de la caméra et, par conséquent, ce résolveur placera le GameObject en pièce jointe à deux mètres en face du point de regard de chaque cadre des utilisateurs.

/// <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;
        }
    }
}

Guides d’implémentation du résolveur

Propriétés courantes du résolveur

Chaque composant du résolveur possède un ensemble de propriétés identiques qui contrôlent le comportement du résolveur principal.

Si le lissage est activé, le résolveur met progressivement à jour la transformation du GameObject au fil du temps sur les valeurs calculées. La vitesse de cette modification est déterminée par la propriété LerpTime de chaque composant de transformation. Par exemple, une valeur MoveLerpTime supérieure entraîne des incréments plus lents entre les cadres.

Si MaintainScale est activé, le résolveur utilisera l’échelle locale par défaut de GameObject.

Core Solver Properties
Propriétés communes héritées par tous les composants du résolveur

Orbital

La classe Orbital est un composant tag-along qui se comporte comme des planètes dans un système solaire. Ce solveur garantit que le GameObject joint orbite autour de la transformation suivie. Ainsi, si le Tracked Target Type du/de la SolverHandler est défini sur Head, le GameObject orbite autour de la tête de l’utilisateur avec un décalage fixe appliqué.

Les développeurs peuvent modifier ce décalage fixe pour conserver des menus ou d’autres composants de scène au niveau de l’œil ou au niveau de la taille, etc. autour d’un utilisateur. Cela est effectué par la modification des propriétés Local Offset et World Offset . La propriété Orientation Type détermine la rotation appliquée à l’objet s’il doit conserver sa rotation d’origine, ou s’il doit toujours faire face à la caméra ou à la transformation qui dirige sa position, etc.

Orbital Example
Exemple orbital

RadialView

Le/la RadialView est un autre composant tag-along qui conserve une portion spécifique d’un GameObject dans le tronc de cône de la vue de l’utilisateur.

Les propriétés Min & Max View Degrees déterminent la proportion du GameObject qui doit toujours être dans la vue.

Les propriétés Min & Max Distance déterminent la distance à laquelle le GameObject doit se trouver par rapport à l’utilisateur. Par exemple, si vous parcourez le GameObject avec une Distance minimaled’un mètre, vous éloignez le GameObject pour vous assurer qu’il n’est jamais plus proche qu’un mètre par rapport à l’utilisateur.

En règle générale, RadialView est utilisé conjointement avec Tracked Target Type défini sur Head afin que le composant suive le regard de l’utilisateur. Toutefois, ce composant peut fonctionner pour être conservé dans la « vue » de n’importe quel Tracked Target Type.

RadialView Example
Exemple RadialView

Suivi

La classe Follow positionne un élément devant la cible suivie par rapport à son axe de transfert local. L’élément peut être faiblement contraint (« sortie conjointe ») afin de ne pas suivre jusqu’à ce que la cible suivie passe au-delà des limites définies par l’utilisateur.

Il fonctionne de la même façon que le résolveur RadialView, avec des contrôles supplémentaires pour gérer le nombre maximal de niveaux d’affichage verticaux et horizontaux et des mécanismes permettant de modifier l’orientation de l’objet.

Follow properties
Suivre les propriétés

Follow example scene
Suivre l’exemple de scène (Assets/MRTK/Examples/Demos/Solvers/Scenes/FollowSolverExample.unity)

InBetween

La classe InBetween conserve le gameobject joint entre deux transformations. Ces deux points de terminaison de transformation sont définis par le SolverHandlerTracked Target Type propre au GameObject et le composant InBetween de la propriété Second Tracked Target Type. En règle générale, les deux types ont la valeur CustomOverride et les valeurs résultantes SolverHandler.TransformOverride et InBetween.SecondTransformOverride définies sur les deux points de terminaison suivis.

Au moment de l’exécution, le composant InBetween crée un autre composant SolverHandler en fonction des propriétés Second Tracked Target Type et Second Transform Override.

Le/la PartwayOffset définit l’emplacement de l’objet le long de la ligne entre deux transformations. L’objet doit être placé 0,5 à mi-chemin, 1,0 à la première transformation et 0,0 à la deuxième transformation.

InBetween Example
Exemple d’utilisation d’un solveur InBetween pour conserver l’objet entre deux transformations

SurfaceMagnetism

Le/la SurfaceMagnetism fonctionne en effectuant un raycast sur un LayerMask défini de surfaces et en plaçant le GameObject à ce point de contact.

La propriété Surface Normal Offset place le GameObject à une distance définie en mètres à l’extérieur de la surface dans la direction normale par rapport au point d’accès de la surface.

À l’inverse, la propriété Surface Ray Offset place le GameObject à une distance définie en mètres par rapport à la surface, mais dans la direction opposée du raycast effectué. Par conséquent, si le raycast est le pointage du regard de l’utilisateur, le GameObject se rapprochera le long de la ligne du point d’accès de la surface vers la caméra.

La propriété Orientation Mode détermine le type de rotation à appliquer par rapport à la normale sur la surface.

  • None - aucune rotation appliquée
  • TrackedTarget - L’objet va faire face à la transformation suivie qui dirige le raycast
  • SurfaceNormal - L’objet est aligné normalement en fonction du point d’accès sur la surface
  • Blended - L’objet est aligné en fonction de la normale sur le point d’accès sur la surface ET en se basant sur la transformation suivie.

Pour forcer le GameObject associé à rester vertical dans n’importe quel mode autre que None, activez Keep Orientation Vertical.

Remarque

Utilisez la propriété Orientation Blend pour contrôler l’équilibre entre les facteurs de rotation lorsque le mode d’orientation a la valeur Blended. La valeur 0,0 aura une orientation entièrement pilotée par le mode TrackedTarget et la valeur 1,0 aura une orientation entièrement pilotée par SurfaceNormal.

SurfaceMagnetism Example

Détermination des surfaces qui peuvent être atteintes

Lorsque vous ajoutez un composant SurfaceMagnetism à un GameObject, il est important de tenir compte de la couche du GameObject et de ses enfants, en présence de colliders. Le composant fonctionne en exécutant différents types de raycasts pour déterminer la surface sur laquelle il peut agir comme un « aimant ». Si le résolveur GameObject a un collider sur l’une des couches répertoriéez dans la propriété MagneticSurfaces de SurfaceMagnetism, le raycast sera probablement atteint, ce qui entraînera un attachement de GameObject à son propre point de collider. Ce comportement étrange peut être évité en définissant le GameObject principal et tous les enfants sur la couche Ignore Raycast ou en modifiant le tableau LayerMask MagneticSurfaces de manière appropriée.

À l’inverse, un GameObject SurfaceMagnetism n’entrera pas en conflit avec des surfaces sur une couche non répertoriée dans la propriété MagneticSurfaces. Il est généralement recommandé de placer toutes les surfaces souhaitées sur une couche dédiée (par exemple Surfaces) et de définir la propriété MagneticSurfaces seulement sur cette couche. L’utilisation de la default ou de everything peut entraîner des composants de l’interface utilisateur ou des curseurs contribuant au résolveur.

Enfin, les surfaces plus éloignées que le paramètre de propriété MaxRaycastDistance seront ignorées par les raycasts SurfaceMagnetism.

DirectionalIndicator

La classe DirectionalIndicator est un composant tag-along qui s’oriente vers la direction d’un point souhaité dans l’espace.

La plus couramment utilisée lorsque la propriété Tracked Target Type du/de la SolverHandler est défini(e) sur Head. De cette manière, un composant d’expérience utilisateur avec le résolveur DirectionalIndicator indiquera à l’utilisateur de regarder le point souhaité dans l’espace.

Le point souhaité dans l’espace est déterminé par la propriété Directional Target.

Si la cible directionnelle est affichable par l’utilisateur, ou quel que soit le cadre de référence défini dans le/la SolverHandler, ce résolveur désactive tous les composants Renderer qui le précèdent. S’il n’est pas visible, tout sera activé sur l’indicateur.

La taille de l’indicateur diminuera à mesure que l’utilisateur est proche de capturer la Directional Target dans son champ de vue.

  • Min Indicator Scale - L’échelle minimale pour l’objet indicateur

  • Max Indicator Scale - L’échelle maximale pour l’objet indicateur

  • Visibility Scale Factor - Multiplicateur pour augmenter ou diminuer le champ de vue qui détermine si le point Directional Target est affichable ou non

  • View Offset - Depuis le point de vue de la trame de référence (c’est-à-dire possiblement la caméra), cette propriété définit la distance à laquelle l’objet doit être éloigné du centre de la fenêtre d’affichage dans la direction de l’indicateur.

Directional Indicator properties
Propriétés de l’indicateur directionnel

Directional Indicator example scene
Exemple de scène de l’indicateur directionnel Assets/MRTK/Examples/Demos/Solvers/Scenes/DirectionalIndicatorSolverExample.unity)

Menu Main avec HandConstraint et HandConstraintPalmUp

Hand Menu UX Example

Le comportement HandConstraint fournit un résolveur qui limite l’objet suivi à une région sécurisée pour le contenu contraint à la main (par exemple, l’interface utilisateur manuelle, les menus, etc.). Les régions sécurisées sont considérées comme des zones qui ne se croisent pas avec la main. Une classe dérivée de HandConstraint appelée HandConstraintPalmUp est également incluse pour illustrer un comportement courant de l’activation de l’objet suivi du résolveur lorsque la paume est orientée vers l’utilisateur.

Pour obtenir des exemples d’utilisation du résolveur Hand Constraint pour créer des menus manuels, consultez la page du menu Main.

Voir aussi