Comment comparer deux quaternions pour une égalité logique?

9

J'essaie d'écrire des tests unitaires et je réalise que je ne sais pas comparer les quaternions. J'ai besoin de savoir si deux quaternions représentent la même orientation (l'objet serait orienté de la même manière). Avec une position de type vecteur, je comparerais simplement les pièces et vérifierais qu'elles sont suffisamment proches, mais pour les quaternions, les valeurs peuvent être très différentes.

Comment comparer deux quaternions?

edA-qa mort-ora-y
la source
Je ne sais pas si c'est une pratique standard, mais par exemple dans Java et Unity, les quaternions sont stockés sous forme de quatre valeurs flottantes. Comparez-les simplement les uns aux autres comme indiqué dans ces articles: answers.unity3d.com/questions/288338/… stackoverflow.com/questions/5803627/quaternion-comparision
Tholle
1
@Tholle, l'utilisateur est également concerné par l'impact de l'application du quaternion pour transformer / faire pivoter une entité 3D (c'est-à-dire en termes de pose). Deux quaternions différents peuvent réaliser la même rotation (par exemple qet -q). La manière naïve (en termes de calcul) serait d'appliquer les deux quaternions au même vecteur et de voir si leurs résultats vectoriels sont différents.
teodron

Réponses:

7

Si vos deux quaternions sont q1et q2, ils représentent la même rotation si l'une de ces deux conditions est vérifiée:

  1. q1est sage à peu près égal à q2OU
  2. q1 est sage composant environ égal à -q2

Sachant cela, vous pouvez écrire un testeur d'égalité assez simpliste qui convient à votre objectif.

teodron
la source
9
+1, un nitpick cependant, qet -qreprésentent la même orientation (qui était demandée), mais pas la même rotation. Ceci est crucial lors de l'interpolation.
falstro
@falstro, je pense que je comprends ce que vous voulez dire: les axes de rotation sont inversés, mais l'angle d'argument est également annulé entre qet -qlorsqu'il est représenté comme un opérateur de rotation axe-axe. Donc, en effet, techniquement, l'effet de ces rotations est le même, bien que les opérateurs ne le soient pas. Et, oui, lorsque SLERPING, il faut s'assurer q1et q2se coucher sur le même hémisphère de l'hypersphère S3 afin que le slerp prenne le chemin le plus court.
teodron
1
Exactement, lorsque vous exécutez l'une ou l'autre rotation, vous vous retrouverez avec la même orientation, mais l'interpolez (que vous lerpiez ou slerpiez ou que vous ayez une autre interpolation de fantaisie), vous verrez que cela tourne différemment. Et oui, l'argument angle est nié, mais c'est la même chose que 2pi-angle, donc il tourne le long chemin autour des axes niés. Parfois, c'est ce que vous voulez; c'est juste quelque chose dont il faut être conscient, q1 dot q2 > 0entraîne le virage court, q1 dot q2 < 0prend le virage long.
falstro
12

Tout simplement parce que cela n'a pas été mentionné. Étant donné que les quaternions utilisés pour l'orientation spatiale ont toujours une longueur unitaire (ou devraient l'être), les éléments suivants fonctionneront également.

abs(q1.dot(q2)) > 1-EPS

où EPS est un facteur de fudge pour permettre de petites erreurs dues à une précision limitée en virgule flottante. Si (et seulement si) les deux quaternions représentent la même orientation alors q1 = +- q2, et donc q1.dot(q2) = +- 1. Si vous souhaitez vous assurer qu'il s'agit bien de la même rotation (plutôt que de la seule orientation), supprimez le abs.

falstro
la source
@bogglez true. A été caché dans le texte tl; dr. :)
falstro
+1, assez élégant et, peut-être encore plus efficace numériquement que ma réponse (à condition que les opérations SIMD soient utilisées :)).
teodron
Quelle est la justification mathématique de cela?
fabian789
"Mathématique" (entre guillemets parce que je ne suis pas un mathématicien :)) justification: Deux vecteurs de longueur unitaire ont un produit scalaire (aka produit interne) qui est 0 s'ils sont verticaux l'un par rapport à l'autre, 1 * 1 = 1 s'ils pointent exactement le même direction, et 1 * 1 * cos (phi) dans le cas général, avec phi leur angle ...
ntg
2

Les quaternions sont stockés sous forme de 4 flotteurs ou doubles, souvent appelés x, y, z et w, où les trois premiers représentent un axe et w le degré de rotation autour de cet axe.

Une approche naïve serait de simplement comparer ces nombres de deux quaternions pour l'égalité. Cependant, comme les calculs en virgule flottante impliquent une erreur, vous devez au moins utiliser une erreur, souvent appelée eps (pour epsilon) et comparer chaque composant comme

    double const eps = 1e-12; // some error threshold
    abs(quat1_x - quat2_x) < eps // similar enough?
    // repeat for other values..

Un meilleur test serait de calculer le produit scalaire des deux quaternions et de tester s'il est proche de 1,0. Vous devriez rechercher l'équation des quaternions avec sin et cos et juste parsemer deux quaternions, alors vous devriez facilement voir pourquoi cela fonctionne.

bogglez
la source
0

Sur la base de toutes les suggestions d'utilisation de Dot et eps, j'ai trouvé qu'en utilisant (à l'unité):

Mathf.Approximately(Mathf.Abs(Quaternion.Dot(transform.rotation, to)), 1.0f)

a bien fonctionné sans que je doive prendre une décision pour la taille de eps.

Sakull284
la source