Ich habe zwei Vektoren u und v. Gibt es eine Möglichkeit, ein Quaternion zu finden, das die Rotation von u nach v darstellt?
math
vector
quaternions
sdfqwerqaz1
quelle
quelle
crossproduct
ist in diesen Fällen nicht gültig, daher müssen Sie zuerst überprüfendot(v1, v2) > 0.999999
unddot(v1, v2) < -0.999999
entweder ein Identitätsquat für parallele Vektoren zurückgeben oder eine 180-Grad-Drehung (um eine beliebige Achse) für entgegengesetzte Vektoren zurückgeben.sqrt((v1.Length ^ 2) * (v2.Length ^ 2))
vereinfacht sichv1.Length * v2.Length
. Ich konnte keine Variation davon bekommen, um vernünftige Ergebnisse zu erzielen.Half-Way-Vektorlösung
Ich kam auf die Lösung, die Imbrondir meiner Meinung nach zu präsentieren versuchte (wenn auch mit einem kleinen Fehler, weshalb Sinisterchipmunk wahrscheinlich Probleme hatte, sie zu überprüfen).
Vorausgesetzt, wir können ein Quaternion konstruieren, das eine Drehung um eine Achse wie folgt darstellt:
Und dass das Punkt- und Kreuzprodukt zweier normalisierter Vektoren sind:
Da eine Drehung von u nach v durch Drehen um Theta (den Winkel zwischen den Vektoren) um den senkrechten Vektor erreicht werden kann, sieht es so aus, als könnten wir aus den Ergebnissen der Punkt- und Kreuzprodukte direkt eine Quaternion konstruieren, die eine solche Drehung darstellt ;; So wie es aussieht, ist Theta = Winkel / 2 , was bedeutet, dass dies zu der doppelten gewünschten Drehung führen würde.
Eine Lösung besteht darin, einen Vektor auf halbem Weg zwischen u und v zu berechnen und das Punkt- und Kreuzprodukt von u und dem halben Vektor zu verwenden, um eine Quaternion zu konstruieren, die eine Drehung um den doppelten Winkel zwischen u und dem halben Vektor darstellt. das bringt uns den ganzen Weg nach v !
Es gibt einen Sonderfall, in dem u == -v und ein eindeutiger Halbwertsvektor nicht mehr berechnet werden können. Dies wird angesichts der unendlich vielen "kürzesten Bogen" -Drehungen erwartet, die uns von u nach v führen können , und wir müssen uns einfach um 180 Grad um jeden Vektor drehen, der orthogonal zu u (oder v ) ist, als unsere Sonderfalllösung. Dies geschieht, indem das normalisierte Kreuzprodukt von u mit einem anderen Vektor genommen wird, der nicht parallel zu u ist .
Es folgt ein Pseudocode (in der Realität müsste der Sonderfall natürlich Gleitkomma-Ungenauigkeiten berücksichtigen - wahrscheinlich durch Überprüfen der Punktprodukte anhand eines bestimmten Schwellenwerts anstelle eines absoluten Werts).
Beachten Sie auch, dass es keinen Sonderfall gibt, wenn u == v (die Identitätsquaternion wird erstellt - überprüfen Sie und überzeugen Sie sich selbst).
Die
orthogonal
Funktion gibt jeden Vektor zurück, der orthogonal zum angegebenen Vektor ist. Diese Implementierung verwendet das Kreuzprodukt mit dem orthogonalsten Basisvektor.Quaternion-Lösung auf halbem Weg
Dies ist tatsächlich die Lösung, die in der akzeptierten Antwort dargestellt ist, und sie scheint geringfügig schneller zu sein als die Vektorlösung auf halbem Weg (~ 20% schneller durch meine Messungen, obwohl ich nicht mein Wort dafür nehme). Ich füge es hier hinzu, falls andere wie ich an einer Erklärung interessiert sind.
Anstatt ein Quaternion mit einem Halbwertsvektor zu berechnen, können Sie im Wesentlichen das Quaternion berechnen, das zu der doppelten erforderlichen Rotation führt (wie in der anderen Lösung beschrieben), und das Quaternion auf halbem Weg zwischen diesem und null Grad ermitteln.
Wie ich zuvor erklärt habe, lautet die Quaternion für die doppelte erforderliche Rotation:
Und die Quaternion für die Nullrotation lautet:
Die Berechnung der Quaternion auf halbem Weg ist einfach eine Frage der Summierung der Quaternionen und der Normalisierung des Ergebnisses, genau wie bei Vektoren. Wie auch bei Vektoren müssen die Quaternionen jedoch dieselbe Größe haben, da sonst das Ergebnis in Richtung der Quaternion mit der größeren Größe verschoben wird.
Ein Quaternion, das aus dem Punkt- und Kreuzprodukt zweier Vektoren aufgebaut ist, hat die gleiche Größe wie diese Produkte :
length(u) * length(v)
. Anstatt alle vier Komponenten durch diesen Faktor zu teilen, können wir stattdessen die Identitätsquaternion vergrößern. Und wenn Sie sich gefragt haben, warum die akzeptierte Antwort die Sache scheinbar kompliziert machtsqrt(length(u) ^ 2 * length(v) ^ 2)
, liegt dies daran, dass die quadratische Länge eines Vektors schneller zu berechnen ist als die Länge, sodass wir einesqrt
Berechnung speichern können . Das Ergebnis ist:Und dann normalisieren Sie das Ergebnis. Pseudocode folgt:
quelle
Das angegebene Problem ist nicht genau definiert: Es gibt keine eindeutige Drehung für ein bestimmtes Vektorpaar. Betrachten Sie zum Beispiel den Fall, in dem u = <1, 0, 0> und v = <0, 1, 0> . Eine Umdrehung von u nach v wäre eine pi / 2- Umdrehung um die z-Achse. Eine andere Drehung von u nach v wäre eine pi- Drehung um den Vektor <1, 1, 0> .
quelle
Warum nicht den Vektor mit reinen Quaternionen darstellen? Es ist besser, wenn Sie sie vielleicht zuerst normalisieren.
q 1 = (0 u x u y u z ) '
q 2 = (0 v x v y v z )'
q 1 q rot = q 2
Vormultiplizieren mit q 1 -1
q rot = q 1 -1 q 2
wobei q 1 -1 = q 1 konj / q Norm
Dies kann als "linke Teilung" angesehen werden. Die rechte Teilung, die Sie nicht wollen, ist:
q rot, rechts = q 2 -1 q 1
quelle
Ich bin nicht sehr gut in Quaternion. Ich hatte jedoch stundenlang Probleme damit und konnte die Polaris878-Lösung nicht zum Laufen bringen. Ich habe versucht, v1 und v2 vornormalisieren. Normalisierung q. Normalisierung von q.xyz. Trotzdem verstehe ich es nicht. Das Ergebnis hat mir immer noch nicht das richtige Ergebnis gebracht.
Am Ende fand ich jedoch eine Lösung, die es tat. Wenn es jemand anderem hilft, ist hier mein Arbeitscode (Python):
Ein Sonderfall muss gemacht werden, wenn v1 und v2 wie v1 == v2 oder v1 == -v2 (mit einer gewissen Toleranz) parallel sind, wobei ich glaube, dass die Lösungen Quaternion (1, 0,0,0) sein sollten (keine Rotation) oder Quaternion (0, * v1) (180-Grad-Drehung)
quelle
quat = diffVectors(v1, v2); assert quat * v1 == v2
.angle
seinen Wert von einem Punktprodukt erhält.Einige der Antworten scheinen die Möglichkeit nicht in Betracht zu ziehen, dass das Kreuzprodukt 0 sein könnte. Unter dem Snippet wird die Winkelachsendarstellung verwendet:
Das
toQuaternion
kann wie folgt implementiert werden:Wenn Sie die Eigenbibliothek verwenden, können Sie auch einfach Folgendes tun:
quelle
toQuaternion(axis, ang)
-> Sie haben vergessen anzugeben, was istang
angle
Teil der Achsenwinkeldarstellung des Quaternions, gemessen im Bogenmaß.Aus Sicht des Algorithmus sieht die schnellste Lösung im Pseudocode aus
Stellen Sie sicher, dass Sie Einheitenquaternionen benötigen (normalerweise ist dies für die Interpolation erforderlich).
HINWEIS: Nicht-Einheiten-Quaternionen können bei einigen Vorgängen schneller als Einheiten verwendet werden.
quelle