Partager via


Résolveurs — MRTK3

Solveur Main

Les solveurs sont des composants qui facilitent le calcul de la position et de l’orientation d’un objet en fonction d’un algorithme prédéfini. Exemple : placer un objet sur la surface avec laquelle le raycast du regard de l’utilisateur croise.

Le système solveur définit de manière déterministe un ordre des opérations pour ces calculs de transformation, car il n’existe aucun moyen fiable de spécifier à Unity l’ordre de mise à jour des composants.

Les solveurs offrent une gamme de comportements pour attacher des objets à d’autres objets ou systèmes. Un autre exemple est un objet tag-along qui pointe devant l’utilisateur en fonction de la caméra. Un solveur peut également être attaché à un contrôleur et un objet pour créer l’étiquette d’objet le long du contrôleur. Tous les résolveurs peuvent être empilés en toute sécurité, par exemple, un comportement tag-along, un magnétisme de surface plus l’impulsion.

Comment utiliser

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

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

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

  • Orbital: verrouille à une position spécifiée et un décalage par rapport à l’objet référencé.
  • ConstantViewSize: met à l’échelle pour conserver une taille constante par rapport à la vue de l’objet référencé.
  • RadialView: conserve l’objet dans un cône d’affichage 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: projette les rayons sur les surfaces du monde et aligne l’objet sur cette surface.
  • DirectionalIndicator: détermine la position et l’orientation d’un objet en tant qu’indicateur directionnel. À partir du point de référence de la cible tracked SolverHandler, cet indicateur s’oriente vers la cible DirectionalTarget fournie.
  • Momentum: applique l’accélération/vitesse/frottement pour simuler l’élan et la springiness d’un objet déplacé par d’autres solveurs/composants.
  • HandConstraint: objet Contraintes pour suivre les mains dans une région qui ne croise pas le GameObject avec les mains. Utile pour le contenu interactif à contrainte manuelle, tel que les menus, etc. Ce solveur est destiné à fonctionner avec XRNode.
  • HandConstraintPalmUp: dérive de HandConstraint, mais inclut une logique pour tester si la paume est face à l’utilisateur avant l’activation. Ce solveur fonctionne uniquement avec XRNode les contrôleurs et se comporte comme sa classe de base avec d’autres types de contrôleurs.
  • Overlap: chevauche l’objet suivi.

Pour utiliser le système solveur, ajoutez l’un des composants répertoriés ci-dessus à un GameObject. Étant donné que tous les solveurs ont besoin d’un SolverHandler, un sera créé automatiquement par Unity.

Remarque

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

Guide pratique pour modifier les informations de référence sur le suivi

La propriété Type de cible suivi du SolverHandler composant 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 simple SurfaceMagnetism entraîne une projection de rayons à partir de la tête et dans la direction du regard de l’utilisateur pour résoudre la surface qui est atteinte. Les valeurs potentielles de la TrackedTargetType propriété sont les suivantes :

  • *Tête : le point de référence est la transformation de la caméra principale
  • ControllerRay : le point de référence est la LinePointer transformation sur un contrôleur (autrement dit, l’origine du pointeur sur un contrôleur de mouvement ou un contrôleur de main) pointant dans la direction du rayon de ligne
    • Utilisez la TrackedHandedness propriété pour sélectionner la préférence de remise (c’est-à-dire, Gauche, Droite, Deux)
  • HandJoint : le point de référence est la transformation d’une articulation spécifique de la main
    • Utilisez la TrackedHandedness propriété pour sélectionner la préférence de remise (c’est-à-dire, Gauche, Droite, Deux)
    • Utilisez la TrackedHandJoint propriété pour déterminer la transformation conjointe à utiliser
  • CustomOverride : point de référence à partir du affecté TransformOverride

Remarque

Pour les types ControllerRay et HandJoint , le gestionnaire du solveur tente de fournir d’abord la transformation de contrôleur/main gauche, puis la droite si le premier n’est pas disponible ou sauf indication contraire de la TrackedHandedness propriété.

Importante

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

Pour surmonter ce problème, mettez à jour la propriété Rotation supplémentaire sur le SolverHandler sur <90, 0, 0>. Cela garantit que le vecteur avant fourni aux résolveurs pointe à travers la paume et vers l’extérieur de la main.

Vous pouvez également utiliser le type de cible suivi par rayon de contrôleur pour obtenir un comportement similaire pour pointer avec les mains.

Guide pratique pour chaîner des résolveurs

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

En outre, la définition de la propriété Transformation liée mise à jour sur true indique que Solver pour enregistrer sa position calculée, son orientation et sa mise à l’échelle dans une variable intermédiaire accessible par tous les solveurs (autrement dit, GoalPosition). Si la valeur est false, met Solver directement à jour la transformation du GameObject. En enregistrant les propriétés de transformation dans un emplacement intermédiaire, d’autres solveurs peuvent effectuer leurs calculs à partir de la variable intermédiaire. Cela est dû au fait que Unity n’autorise pas les mises à jour de gameObject.transform à s’empiler dans le même cadre.

Remarque

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

Comment créer un résolveur

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

Le code fourni ci-dessous donne un exemple de nouveau composant solveur appelé InFront qui place l’objet attaché 2 m devant .SolverHandler.TransformTarget Le consommateur définit SolverHandler.TrackedTargetType comme Head, puis sera SolverHandler.TransformTarget la transformation de caméra, et donc ce solveur placera le GameObject 2 m attaché devant le regard des utilisateurs à chaque image.

/// <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 solveur

Propriétés courantes du solveur

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

Si le lissage est activé, le solveur met progressivement à jour la transformation du GameObject au fil du temps en fonction des valeurs calculées. La propriété LerpTime de chaque composant de transformation détermine la vitesse de cette modification. Par exemple, une valeur MoveLerpTime plus élevée entraîne des incréments plus lents dans le mouvement entre les images.

Si MaintainScale est activé, le solveur utilise l’échelle locale par défaut du GameObject.

Orbitale

La Orbital classe est un composant tag-along qui se comporte comme des planètes dans un système solaire. Ce solveur garantit que le GameObject attaché orbite autour de la transformation suivie. Par conséquent, si le type de cible suivi du SolverHandler est défini sur Head, le GameObject tourne 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 des yeux ou de la taille, etc., autour d’un utilisateur. Pour ce faire, modifiez les propriétés Décalage local et Décalage mondial . La propriété Type d’orientation détermine la rotation appliquée à l’objet s’il doit conserver sa rotation d’origine ou toujours faire face à l’appareil photo ou au visage, quelle que soit la transformation qui détermine sa position.

RadialView

Est RadialView un autre composant tag-along qui conserve une partie particulière d’un GameObject dans le frustum de la vue de l’utilisateur.

Les propriétés Min & Max View Degrees déterminent la quantité d’une partie du GameObject qui doit toujours être visible.

Les propriétés Min & Max Distance déterminent dans quelle mesure le GameObject doit être conservé par rapport à l’utilisateur. Par exemple, si vous vous dirigez vers le GameObject avec une distance minimale de 1 m, le GameObject est repoussé pour s’assurer qu’il n’est jamais plus proche de 1 m de l’utilisateur.

En règle générale, le RadialView est utilisé avec le type de cible suivi défini Head sur 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 type de cible suivi.

Suivre

La Follow classe positionne un élément devant la cible suivie par rapport à son axe vers l’avant local. L’élément peut être faiblement limité (également appelé « tag-along ») afin qu’il ne suive pas tant que la cible suivie ne dépasse pas les limites définies par l’utilisateur.

Il fonctionne de la même façon que le solveur RadialView, avec des contrôles supplémentaires pour gérer les degrés de vue max horizontal & vertical et les mécanismes pour modifier l’orientation de l’objet.

InBetween

La InBetween classe conserve le GameObject attaché entre deux transformations. Le type SolverHandler de cible suivi du GameObject et la InBetween propriété Second Tracked Target Type du composant définissent ces deux points de terminaison de transformation. En règle générale, les deux types sont définis sur CustomOverride et les valeurs résultantes SolverHandler.TransformOverride et InBetween.SecondTransformOverride sont définies sur les deux points de terminaison suivis.

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

Le long de la ligne entre deux transformations, le PartwayOffset définit où l’objet sera placé avec 0,5 à mi-chemin, 1,0 à la première transformation et 0,0 à la deuxième transformation.

SurfaceMagnetism

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

Le décalage normal de surface place le GameObject à une distance définie en mètres de la surface dans la direction de la normale au point de contact sur la surface.

À l’inverse, le décalage de rayon de surface place le GameObject à une distance définie en mètres de la surface, mais dans la direction opposée du raycast effectué. Ainsi, si le raycast est le regard de l’utilisateur, le GameObject se rapproche le long de la ligne, du point de frappe sur la surface à la caméra.

Le mode d’orientation détermine le type de rotation à appliquer par rapport à la normale sur la surface.

  • Aucun : aucune rotation appliquée
  • TrackedTarget : l’objet sera confronté à la transformation suivie qui pilote le raycast
  • SurfaceNormal : l’objet s’aligne en fonction de la normale au point d’accès sur la surface
  • Blended : l’objet s’aligne en fonction de la normale au point d’accès sur la surface ET en fonction de la transformation suivie.

Pour forcer le GameObject associé à rester vertical dans un mode autre que Aucun, activez Conserver l’orientation verticale.

Remarque

Utilisez la propriété Orientation Blend pour contrôler l’équilibre entre les facteurs de rotation lorsque le mode d’orientation est défini sur Blended. Une valeur de 0.0 aura une orientation entièrement pilotée par le mode TrackedTarget , et une valeur de 1.0 aura une orientation entièrement pilotée par SurfaceNormal.

Overlap

le Overlap est un résolveur simple qui maintient la transformation de l’objet à la même position et à la même rotation que la cible de transformation SolverHandler's .

Déterminer quelles surfaces peuvent être atteintes

Lors de l’ajout d’un SurfaceMagnetism composant à un GameObject, il est important de prendre en compte la couche du GameObject et de ses enfants, s’il existe des collisionneurs. Le composant fonctionne en effectuant différents raycasts pour déterminer sur quelle surface se « aimanter » lui-même. Supposons que le solveur GameObject a un collisionneur sur l’une des couches répertoriées dans la MagneticSurfaces propriété de SurfaceMagnetism. Dans ce cas, le raycast se heurtera probablement lui-même, ce qui entraînera l’attachement du GameObject à son propre point de collisionneur. Ce comportement étrange peut être évité en définissant le GameObject principal et tous les enfants sur la couche Ignore Ray cast ou en modifiant le MagneticSurfaces tableau LayerMask de manière appropriée.

À l’inverse, un SurfaceMagnetism GameObject n’entre pas en collision avec des surfaces sur une couche non répertoriée dans la MagneticSurfaces propriété . Nous vous recommandons de placer toutes les surfaces souhaitées sur une couche dédiée (c’est-à-dire, Surfaces) et de définir la MagneticSurfaces propriété uniquement sur cette couche. L’utilisation de la valeur par défaut ou de tout peut entraîner la contribution de composants ou de curseurs d’interface utilisateur au solveur.

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

DirectionalIndicator

La DirectionalIndicator classe est un composant tag-along qui s’oriente vers la direction du point souhaité dans l’espace. Il est le plus couramment utilisé lorsque le type de cible suivi du SolverHandler est défini sur Head. De cette façon, un composant d’expérience utilisateur avec le DirectionalIndicator solveur indique à l’utilisateur d’examiner le point souhaité dans l’espace. Ce point est déterminé par la propriété Cible directionnelle .

Si la cible directionnelle est visible par l’utilisateur ou si le cadre de référence est défini dans , SolverHandlerce solveur désactive tous les Renderer composants sous-jacents. S’il n’est pas visible, tout est activé sur l’indicateur.

La taille de l’indicateur est réduite, plus l’utilisateur est proche de la capture de la cible directionnelle dans son FOV.

  • Échelle minimale de l’indicateur : échelle minimale de l’objet indicateur

  • Échelle maximale de l’indicateur : échelle maximale pour l’objet indicateur

  • Facteur d’échelle de visibilité : multiplicateur pour augmenter ou diminuer l’objet FOV qui détermine si le point cible directionnel est visible ou non

  • Décalage de la vue : à partir du point de vue du cadre de référence (c’est-à-dire, éventuellement, caméra) et dans le sens de l’indicateur, cette propriété définit la distance entre l’objet et le centre de la fenêtre d’affichage.

Exemple de scène d’indicateur directionnel (assets/MRTK/Examples/Demos/Solvers/Scenes/DirectionalIndicatorSolverExample.unity)

Menu Main avec HandConstraint et HandConstraintPalmUp

Le HandConstraint comportement fournit un solveur qui limite l’objet suivi à une région sûre pour le contenu à contrainte manuelle (par exemple, l’interface utilisateur de la main, les menus, etc.) Les régions sûres 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 d’activation de l’objet suivi du solveur lorsque la paume est face à l’utilisateur.

Consultez la documentation menu main pour obtenir des exemples d’utilisation du solveur Hand Constraint pour créer des menus de main.