Vue d’ensemble des résolveurs — MRTK2
Les résolveurs sont des composants qui facilitent le calcul de la position d’un objet et l’orientation 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
LinePointer
transformation sur un contrôleur (c’est-à-dire 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 propriété
TrackedHandedness
pour sélectionner la préférence de main (c’est-à-dire Left, Right, Both)
- Utilisez la propriété
- HandJoint : Point de référence est la transformation d’une articulation de 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
- Utilisez la propriété
- CustomOverride : point de référence depuis le/la
TransformOverride
affecté(e)
Remarque
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.
Exemple 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)
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.
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, la définition de la propriété De transformation liée mise à jour sur true indique qu’il Solver
faut enregistrer sa position calculée, son orientation et son échelle sur une variable intermédiaire accessible par tous les solveurs (c’est-à-dire 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.
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.
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 taille qu’une partie du GameObject doit toujours avoir dans la vue.
Les propriétés Min & Max distance déterminent la durée pendant laquelle le GameObject doit être conservé par 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.
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.
Propriétés du suivi
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 SolverHandler
Tracked 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.
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.
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.
Propriétés de l’indicateur directionnel
Exemple de scène de l’indicateur directionnel Assets/MRTK/Examples/Demos/Solvers/Scenes/DirectionalIndicatorSolverExample.unity)
Menu Main avec HandConstraint et HandConstraintPalmUp
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.