Utilisation des quaternions: que puis-je en faire? (sans les maths)

24

Je suis développeur de jeux et je n'ai pas étudié les mathématiques. Je veux donc uniquement utiliser les Quaternions comme outil. Et pour pouvoir travailler avec la rotation 3D, il est nécessaire d'utiliser des quaternions (ou des matrices, mais restons aux quaternions ici dans cette question). Je pense qu'il est important pour de nombreux développeurs de les utiliser. C'est pourquoi je veux partager mes connaissances et, espérons-le, combler les trous que j'ai. À présent....

Donc, pour autant que j'ai compris:

Un Quaternion peut décrire 2 choses:

  1. L'orientation actuelle d'un objet 3D.
  2. Transformation de rotation qu'un objet pourrait effectuer. (rotationChange)

Vous pouvez faire avec un Quaternion:

Multiplications:

  1. Quaternion endOrientation = Quaternion rotationChange * Quaternion currentOrientation;

    Ainsi, par exemple: Mon objet 3D est tourné de 90 ° vers la gauche - et ma rotation que je multiplie est une rotation de 180 ° vers la droite, à la fin mon objet 3D de 90 ° est tourné vers la droite.

  2. Quaternion rotationChange = Quaternion endRotation * Quaternion.Inverse (startRotation);

    Avec cela, vous obtenez un rotationChange, qui peut être appliqué à une autre orientation.

  3. Vector3 endPostion = Quaternion rotationChange * Vector3 currentPosition;

    Ainsi, par exemple: mon objet 3D est en position (0,0,0) et ma rotation que je multiplie est une rotation de 180 ° vers la droite, ma position finale est quelque chose comme (0, -50,0). À l'intérieur de ce Quaternion, il y a un axe - et une rotation autour de cet axe. Vous tournez votre point autour de cet axe Y degrés.

  4. Vector3 rotatedOffsetVector = Quaternion rotationChange * Vector3 currentOffsetVector;

    Par exemple: Ma direction de départ montre UP - (0,1,0), et ma rotation que je multiplie est une rotation de 180 ° vers la droite, ma direction de fin montre vers le bas. (0, -1,0)

Mélange (Lerp et Slerp):

  1. Quaternion currentOrientation = Quaternion.Slerp (startOrientation, endOrientation, interpolateur)

    si l'interpolateur est 1: currentOrientation = endOrientation

    si l'interpolateur est 0: currentOrientation = startOrientation

    Slerp interpole plus précis, Lerp interpole plus performant.

Mes questions):

Tout ce que j'ai expliqué jusqu'à présent est-il correct?

Est-ce "tout" ce que vous pouvez faire avec les Quaternions? (év. pas)

Que pouvez-vous faire d'autre avec eux?

À quoi servent le produit Dot et le produit Cross entre 2 Quaternions?

Modifier:

Question mise à jour avec quelques réponses

OC_RaizW
la source
Disons que vous n'avez pas 2, mais ndes 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).
teodron
Et oui, à première vue, votre justification est correcte (votre compréhension des quaternions est assez bonne pour une personne non technique). C'est inapproprié pour un commentaire, mais bravo! Même les plus doués sur le plan technique ne connaissent pas toutes les utilisations du quaternion, bien qu'ils les utilisent uniquement comme outils d'ingénierie logicielle dans un but précis.
teodron
4
"Et pour pouvoir travailler avec la rotation 3D, il faut utiliser les Quaternions" Je ne saurais trop insister sur la fausseté de cette phrase. Vous pouvez utiliser les angles Euler ou Tait-Bryan pour le développement du jeu, le seul problème est le verrouillage du cardan. Si vous voulez être développeur de jeux, vous aurez besoin de mathématiques à un moment donné, apprenez-le.
Bálint
1
"développeur de jeu" et "ne pas étudier les mathématiques" est un oxymore.
Margaret Bloom
2
J'apprécie ce que vous essayez de faire avec la question, mais les réponses devraient être dans une réponse, pas la question. Faites une réponse «récapitulative» si vous pensez que cela vaut la peine de les rassembler.
Basic

Réponses:

23

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 rotationChangepartant de son, currentOrientationje 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' forwardargument vecteur
  • fait pivoter l'axe y + local pour pointer le plus près possible de l' upargument 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 + à forwardutilise 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 upet que le z + local se rapproche le plus possible de forwardla 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 LookRotationpour 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.RotateTowardsque 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. RotateTowardsDonne un raccourci pratique qui s'en occupe pour nous)

DMGregory
la source
Astuce: ajoutez & t = 40m à la fin de l'URL de la vidéo pour qu'elle y saute directement (par exemple 40m5s en option). Les produits à points Quaternion sont également utiles pour gérer des mondes de jeu sphériques - ou plus largement pour orienter des morceaux de sphères rotatives.
Luke Briggs
@Luke Briggs: Le point de sphère du monde du jeu semble mériter d'être développé dans sa propre réponse (en particulier avec des diagrammes) si vous le souhaitez. :)
DMGregory
Excellente idée - il est 3 heures du matin ici (donc je pense que ça sortirait un peu du charabia!) Mais je serais heureux de rassembler quelque chose demain (si je me souviens!)
Luke Briggs
1
Edit: Je me suis un peu emporté en pensant à une réponse alors défi relevé! Je vais au moins le marquer comme une coupe grossière pour que les gens puissent être conscients de la brûlure tardive qui y est allée: P
Luke Briggs
Et voilà! J'ai essayé de le couvrir dans un sens d'aperçu graphique sur la base que votre réponse couvre déjà très bien les fonctions sous-jacentes. Il est temps de dormir, je pense!
Luke Briggs
14

Où est utilisé le produit scalaire?

Dans Unity, l'un des utilisateurs les plus courants du produit scalaire est chaque fois que vous vérifiez si deux quaternions sont égaux via ==ou !=. Unity calcule le produit scalaire pour vérifier la similitude plutôt que de comparer directement les valeurs internes x, y, z, w. Cela vaut la peine de garder celui-ci à l'esprit car cela rend l'appel plus cher que vous ne le pensez.

Nous l'utilisons également dans un cas d'utilisation intéressant.

Amusez-vous avec les produits à points quaternion - Mondes sphériques et orbitales

Les simulations de planètes entières et même de systèmes solaires entiers deviennent de plus en plus courantes. Afin de réussir cela en temps réel, nous avons également besoin du produit scalaire quaternion. Beaucoup d'entre eux. Le produit quaternion dot est très sous-utilisé mais il a certainement ses utilisations - Jetons un coup d'œil!

Premièrement, nous avons toute une série de rotations à considérer:

  1. (Facultatif) L'étoile autour du centre galactique
  2. La planète autour de l'étoile
  3. L'inclinaison de la planète
  4. Le tour de la planète
  5. La position des cellules de grille voisines (tournées autour du noyau des planètes) *
  6. Plans orbitaux multiples

Combinez-les tous ensemble et vous vous retrouvez avec beaucoup de complexité (et beaucoup de nombres énormes!). Lorsque le spectateur se tient à la surface de la planète, nous ne voulons pas qu'il se précipite à une vitesse folle à travers notre espace de jeu. Nous préférons en fait qu'ils soient stationnaires et quelque part près de l'origine - déplacez plutôt l'univers autour du joueur.

Planète en rotation

Surtout, pour que nous puissions obtenir le spin et l'inclinaison de la planète correctement dans ce scénario, nous devons verrouiller l'axe du pôle de sorte qu'il ne puisse que basculer vers le haut / bas sur l'image ci-dessus (c'est-à-dire basculer "vers le haut" pendant que le joueur voyage Nord). C'est là qu'intervient un produit scalaire quaternion. Si nous n'utilisions pas de produit scalaire ici et que nous multiplions plutôt l'inclinaison, cela se produirait:

«Planètes» mal inclinées

Remarquez comment les pôles de nos «planètes» en orbite sont toujours inclinés vers l'étoile. Ce n'est pas ce qui se passe en réalité - l'inclinaison est dans une direction fixe .

Sans aller trop loin, voici un bref résumé:

  • Sur une sphère, une orientation décrit également parfaitement une position de surface.
  • Nous avons beaucoup de rotations à combiner ensemble.
  • Décrivez tout comme rotation; la position du spectateur aussi. Cela aide à améliorer les performances, car nous finissons par faire moins d'opérations.
  • L'angle entre les rotations (notre produit scalaire) permet alors de mesurer la longitude et fonctionne particulièrement bien pour gérer les inclinaisons.

En obtenant uniquement l'angle, nous supprimons une partie de cette rotation indésirable . Dans le même temps, nous nous sommes également retrouvés avec une mesure de longitude qui est utile pour la navigation ainsi que le climat local.

* Les planètes sont construites à partir de nombreuses cellules de la grille . Seuls les plus proches sont affichés.

Luke Briggs
la source
2
Cela fait un excellent travail pour mettre en scène et motiver le problème, mais je suis toujours un peu flou sur la façon dont les mathématiques du produit scalaire quaternion (c'est-à-dire le produit scalaire dot(a, b) = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.wpar opposition à la composition quaternion que nous utiliserions pour enchaîner) rotations) nous aiderait à résoudre ce problème. Je serais ravi de voter si vous êtes en mesure de développer cela un peu plus tard (je ne veux pas vous garder de votre slerp ... je veux dire dormir!)
DMGregory
@DmGregory la réponse courte est que l'inclinaison est l'intrus; tout se compose bien sauf celui-là (la planète semblerait osciller autour de son étoile autrement). Je vais (espérons-le!) Ajouter un peu plus de contexte demain!
Luke Briggs
@DMGregory J'ai ajouté quelques informations supplémentaires (je n'ai pas pu dormir!) - j'espère que cela le rend plus clair.
Luke Briggs
1
Désolé si je suis un peu dense, mais après avoir relu plusieurs fois, je ne sais toujours pas comment j'utiliserais le produit scalaire dans une formule pour réaliser la transformation que vous décrivez. Seriez-vous en mesure d'ajouter un petit pseudocode présentant explicitement les opérations que vous effectuez?
DMGregory
@DMGregory Je ne connais pas les quaternions mais s'il s'agit de rotations sur une sphère, ce ne sont pas des compositions de rotation. C'est en utilisant la géométrie sphérique avec des vecteurs pour calculer le vecteur normal pour une "ligne" sur la surface d'une sphère AKA toute circonférence. Encore une fois, la réponse n'a pas beaucoup de sens, pas plus que cette question, mais je pense qu'ils utilisent la géométrie sphérique.
The Great Duck