Multiplication
Au moins en termes d'implémentation de Quaternions par Unity, l'ordre de multiplication décrit dans la question n'est pas correct. Ceci est important car la rotation 3D n'est pas commutative .
Donc, si je veux faire pivoter un objet en rotationChange
partant de son, currentOrientation
je l'écrirais comme ceci:
Quaternion newOrientation = rotationChange * currentOrientation;
(c.-à-d. les transformations s'empilent vers la gauche - comme la convention de matrice d'Unity. La rotation la plus à droite est appliquée en premier / à l'extrémité "la plus locale")
Et si je voulais transformer une direction ou un vecteur de décalage par une rotation, je l'écrirais comme ceci:
Vector3 rotatedOffsetVector = rotationChange * currentOffsetVector;
(Unity générera une erreur de compilation si vous faites le contraire)
Mélange
Dans la plupart des cas, vous pouvez vous en tirer avec les rotations Lerping. C'est parce que l'angle utilisé "sous le capot" dans un quaternion est la moitié de l'angle de rotation, ce qui le rend sensiblement plus proche de l'approximation linéaire de Lerp que quelque chose comme une matrice (qui en général ne sera pas bien Lerp!). Découvrez environ 40 minutes dans cette vidéo pour plus d'explications .
Le seul cas où vous avez vraiment besoin de Slerp est lorsque vous avez besoin d'une vitesse constante dans le temps, comme l'interpolation entre les images clés sur une chronologie d'animation. Pour les cas où vous vous souciez simplement qu'une sortie est intermédiaire entre deux entrées (comme le mélange de couches d'une animation), alors Lerp sert généralement assez bien.
Quoi d'autre?
Le produit scalaire de deux quaternions unitaires donne le cosinus de l'angle entre eux, vous pouvez donc utiliser le produit scalaire comme mesure de similitude si vous devez comparer les rotations. C'est un peu obscur cependant, donc pour un code plus lisible, j'utiliserais souvent Quaternion.Angle (a, b) à la place, qui exprime plus clairement que nous comparons les angles, en unités familières (degrés).
Ces types de méthodes pratiques fournies par Unity pour les quaternions sont très utiles. Dans presque tous les projets, j'utilise celui-ci au moins quelques fois :
Quaternion.LookRotation(Vector3 forward, Vector3 up)
Cela construit un quaternion qui:
- fait pivoter l'axe z + local pour pointer exactement le long de l'
forward
argument vecteur
- fait pivoter l'axe y + local pour pointer le plus près possible de l'
up
argument vecteur, s'il est fourni, ou (0, 1, 0)
s'il est omis
La raison pour laquelle le "haut" n'est "aussi proche que possible" est que le système est surdéterminé. Faire face à z + à forward
utilise jusqu'à deux degrés de liberté (c'est-à-dire lacet et tangage), il ne nous reste donc qu'un seul degré de liberté (roulis).
Je trouve assez souvent que je veux quelque chose avec les propriétés d'exactitude opposées: je veux que le y + local pointe exactement le long up
et que le z + local se rapproche le plus possible de forward
la liberté restante.
Cela se produit par exemple lorsque vous essayez de former un cadre de coordonnées relatif à la caméra pour l'entrée de mouvement: je veux que ma direction locale vers le haut reste perpendiculaire au sol ou à une surface inclinée normale, donc mon entrée n'essaie pas de tunneler le personnage dans le terrain ou les léviter.
Vous pouvez également l'obtenir si vous souhaitez que le boîtier de la tourelle d'un char fasse face à une cible, sans décoller du corps du char lorsque vous visez vers le haut / vers le bas.
Nous pouvons construire notre propre fonction de confort pour ce faire, en utilisant LookRotation
pour le levage de charges lourdes:
Quaternion TurretLookRotation(Vector3 approximateForward, Vector3 exactUp)
{
Quaternion rotateZToUp = Quaternion.LookRotation(exactUp, -approximateForward);
Quaternion rotateYToZ = Quaternion.Euler(90f, 0f, 0f);
return rotateZToUp * rotateYToZ;
}
Ici, nous tournons d'abord local y + vers z +, et local z + vers y-.
Ensuite, nous faisons pivoter le nouveau z + dans notre direction vers le haut (de sorte que le résultat net est local y + pointe directement le long exactUp
), et le nouveau y + aussi près que possible de la direction avant négative (de sorte que le résultat net est local z + pointe aussi près que possible le long de approximateForward
)
Une autre méthode pratique est Quaternion.RotateTowards
que j'utilise souvent comme ceci:
Quaternion newRotation = Quaternion.RotateTowards(
oldRotation,
targetRotation,
maxDegreesPerSecond * Time.deltaTime
);
Cela nous permet de nous rapprocher targetRotation
à une vitesse constante et contrôlable quel que soit le framerate - important pour les rotations qui affectent le résultat / l'équité des mécanismes de jeu (comme tourner le mouvement d'un personnage ou avoir une tourelle sur le joueur). Naïvement Lerping / Slerping dans cette situation peut facilement conduire à des cas où le mouvement devient plus vif à des cadences élevées, affectant l'équilibre du jeu. (Cela ne veut pas dire que ces méthodes sont erronées - il existe des moyens de les utiliser correctement sans changer l'équité, cela nécessite simplement des soins. RotateTowards
Donne un raccourci pratique qui s'en occupe pour nous)
n
des orientations différentes (attitudes, poses, etc.). Ensuite, vous pouvez les faire la moyenne en utilisant des poids, généralisant efficacement slerp / lerp. Vous pouvez également convertir un quaternion en rotor, ce qui équivaut à appliquer une vitesse angulaire pendant un certain temps à un corps rigide. Par conséquent, vous pouvez également décrire l'intégration de la vitesse angulaire avec les quaternions. Vous pouvez également estimer la différence entre deux orientations (calculer la longueur de l'arc couvert par les deux quaternions sur l'hypersphère).