Wie kann ich zwei Quaternionen auf logische Gleichheit vergleichen?

9

Ich versuche einige Unit-Tests zu schreiben und stelle fest, dass ich nicht weiß, wie man Quaternionen vergleicht. Ich muss wissen, ob zwei Quaternionen dieselbe Ausrichtung darstellen (das Objekt würde in dieselbe Richtung weisen). Mit einer vektorähnlichen Position würde ich einfach die Teile vergleichen und prüfen, ob sie nahe genug sind, aber für Quaternionen können die Werte sehr unterschiedlich sein.

Wie kann ich zwei Quaternionen vergleichen?

edA-qa mort-ora-y
quelle
Ich bin nicht sicher, ob dies Standard ist, aber in z. B. Java und Unity werden die Quaternionen als vier Float-Werte gespeichert. Vergleichen Sie diese einfach miteinander, wie in diesen Beiträgen beschrieben: answers.unity3d.com/questions/288338/… stackoverflow.com/questions/5803627/quaternion-comparision
Tholle
1
@Tholle Der Benutzer befasst sich auch mit den Auswirkungen der Anwendung der Quaternion auf die Transformation / Drehung einer 3D-Entität (dh in Bezug auf die Pose). Zwei verschiedene Quaternionen können dieselbe Rotation erzielen (z . B. qund -q). Der naive (rechnerisch) Weg wäre, beide Quaternionen auf denselben Vektor anzuwenden und zu
prüfen,

Antworten:

7

Wenn Ihre beiden Quaternionen q1und sind q2, stellen sie dieselbe Rotation dar, wenn eine dieser beiden Bedingungen gilt:

  1. q1ist komponentenweise ungefähr gleich q2OR
  2. q1 ist komponentenweise ungefähr gleich -q2

Wenn Sie dies wissen, können Sie einen ziemlich simplen Gleichheitstester schreiben, der Ihrem Ziel entspricht.

Teodron
quelle
9
+1, ein Nitpick, qund -qrepräsentieren die gleiche Ausrichtung (die angefordert wurde), aber nicht die gleiche Drehung. Dies ist beim Interpolieren von entscheidender Bedeutung.
Falstro
@falstro, ich glaube ich verstehe was du meinst: Die Rotationsachsen sind invers, aber der Argumentwinkel wird auch zwischen qund -qals Winkelachsen-Rotationsoperator negiert . Technisch gesehen ist der Effekt dieser Rotationen also der gleiche, obwohl dies bei den Bedienern nicht der Fall ist. Und, ja, wenn SLERPING, muss man sicherstellen, q1und q2liegen auf derselben Hemisphäre des S3 Hypershäre , um für die Slerp den kürzesten Weg zu nehmen.
Teodron
1
Wenn Sie eine der beiden Rotationen ausführen, erhalten Sie genau dieselbe Ausrichtung, aber wenn Sie sie interpolieren (egal ob Sie lerp oder slerp oder eine andere ausgefallene Interpolation), werden Sie feststellen, dass sie sich unterschiedlich dreht. Und ja, das Winkelargument wird negiert, aber das ist das gleiche wie 2pi-angle, also dreht es den langen Weg um die negierten Achsen. Manchmal ist es das, was Sie wollen; Es ist nur etwas, das man beachten muss, q1 dot q2 > 0das zu einer kurzen Kurve q1 dot q2 < 0führt und zu einer langen Kurve führt.
Falstro
12

Nur weil es nicht erwähnt wurde. Da Quaternionen, die für die räumliche Orientierung verwendet werden, immer die Einheitslänge haben (oder sein sollten), funktioniert auch das Folgende.

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

Dabei ist EPS ein Fudge-Faktor, um kleine Fehler aufgrund der begrenzten Gleitkommapräzision zu berücksichtigen. Wenn (und nur wenn) beide Quaternionen dann q1 = +- q2und damit die gleiche Ausrichtung haben q1.dot(q2) = +- 1. Wenn Sie sicherstellen möchten, dass sie die gleiche Drehung haben (und nicht nur die Ausrichtung), entfernen Sie dieabs .

falstro
quelle
@ Bogglez wahr. War im Text versteckt. :)
Falstro
+1, ziemlich elegant und vielleicht sogar numerisch effizienter als meine Antwort (vorausgesetzt, SIMD-Operationen werden verwendet :)).
Teodron
Was ist die mathematische Rechtfertigung dafür?
fabian789
"Mathematisch" (in Anführungszeichen, weil ich kein Mathematiker bin :)) Begründung: Zwei Einheitslängenvektoren haben ein Punktprodukt (auch bekannt als inneres Produkt), das 0 ist, wenn sie vertikal zueinander sind, 1 * 1 = 1, wenn sie genau auf das zeigen gleiche Richtung und 1 * 1 * cos (phi) im allgemeinen Fall, mit phi ihren Winkel ...
ntg
2

Quaternionen werden als 4 Floats oder Doubles gespeichert, die oft als x, y, z und w bezeichnet werden, wobei die ersten drei eine Achse und w den Rotationsgrad um diese Achse darstellen.

Ein naiver Ansatz wäre, nur diese Zahlen von zwei Quaternionen auf Gleichheit zu vergleichen. Da Gleitkommaberechnungen jedoch einen Fehler beinhalten, sollten Sie mindestens einen Fehler verwenden, der häufig als eps (für epsilon) bezeichnet wird, und jede Komponente wie vergleichen

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

Ein besserer Test wäre, das Punktprodukt der beiden Quaternionen zu berechnen und zu testen, ob es nahe bei 1,0 liegt. Sie sollten die Gleichung der Quaternionen mit sin und cos nachschlagen und nur zwei Quaternionen punktieren, dann sollten Sie leicht erkennen, warum dies funktioniert.

bogglez
quelle
0

Basierend auf all den Vorschlägen zur Verwendung von Dot und eps fand ich, dass using (in unit):

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

hat gut funktioniert, ohne dass ich mich für die Größe des EPS entscheiden musste.

Sakull284
quelle