Vektor3 um eine Quaternion drehen

25

Ich versuche, einen Vektor3 um eine bestimmte Quaternion zu drehen.

Ich weiß, dass das stimmt

v=qvq1

Ich weiß, dass das Inverse ist, das gerade , aber wie ordne ich die Multiplikation des Vektors der Quaternion zu, um einen Vektor zurückzubekommen?q1qmagnitude(q)

Ich habe festgestellt, dass Sie als Matrix behandeln und und konvertieren könnenvqq in Matrizen konvertieren und dannv von einer Matrix in einen Vektorkonvertieren können, aber dies scheint ein wenig übertrieben, nur um einen Vektor zu erhalten. Gibt es eine sauberere Implementierung, die ich verwenden könnte?

gardian06
quelle

Antworten:

36

Wie Nathan Reed und Teodron herausgestellt haben, lautet das Rezept zum Drehen eines Vektors v um eine Quaternion q von Einheitslänge :

1) Erstellen Sie eine reine Quaternion p aus v . Dies bedeutet einfach, eine vierte Koordinate von 0 hinzuzufügen:

p=(vx,vy,vz,0)p=(v,0)

2) Multipliziere es vorab mit q und postmultipliziere es mit dem Konjugat q * :

p=q×p×q

3) Dies führt zu einer weiteren reinen Quaternion, die in einen Vektor zurückverwandelt werden kann:

v=(px,py,pz)

Dieser Vektor v ist v um q gedreht .


Das funktioniert aber alles andere als optimal . Quaternion-Multiplikationen bedeuten Tonnen und Tonnen von Operationen. Ich war neugierig auf verschiedene Implementierungen wie diese und entschied mich herauszufinden, woher diese kamen. Hier sind meine Erkenntnisse.

Wir können q auch als die Kombination eines dreidimensionalen Vektors u und eines Skalars s beschreiben :

q=(ux,uy,uz,s)q=(u,s)

Durch die Regeln der Quaternion-Multiplikation und da das Konjugat einer Quaternion mit Längeneinheit einfach umgekehrt ist, erhalten wir:

p=qpq=(u,s)(v,0)(u,s)=(sv+u×v,uv)(u,s)=((uv)(u)+s(sv+u× v)+(sv+u×v)×(u),)=((uv)u+s2v+s(u×v)+sv×(u)+(u×v)×(u),)

Der skalare Teil (Ellipsen) ergibt Null, wie hier beschrieben . Interessant ist der Vektorteil, AKA unser gedrehter Vektor v ' . Es kann mit einigen grundlegenden Vektoridentitäten vereinfacht werden :

v=(uv)u+s2v+s(u×v)+s(u×v)+u×(u×v)=(uv)u+s2v+2s(u×v)+(uv)u(uu)v=2(uv)u+(s2uu)v+2s(u×v)

Das ist jetzt viel optimaler ; Zwei-Punkt-Produkte, ein Kreuzprodukt und ein paar Extras: Etwa die Hälfte der Vorgänge. Was im Quellcode so etwas ergeben würde (unter der Annahme einer generischen Vektor-Mathematik-Bibliothek):

void rotate_vector_by_quaternion(const Vector3& v, const Quaternion& q, Vector3& vprime)
{
    // Extract the vector part of the quaternion
    Vector3 u(q.x, q.y, q.z);

    // Extract the scalar part of the quaternion
    float s = q.w;

    // Do the math
    vprime = 2.0f * dot(u, v) * u
          + (s*s - dot(u, u)) * v
          + 2.0f * s * cross(u, v);
}
Laurent Couvidou
quelle
Hut ab vor einer besseren schriftlichen Antwort. Und wenn man bedenkt, dass die meisten Performance-Freaks dazu neigen, für Vektoroperationen Intrinsics zu verwenden, erhalten Sie eine erhebliche Beschleunigung (selbst bei einfacher Quaternion-Multiplikation, insbesondere bei Intel-Architekturen).
Teodron
Das Endergebnis ähnelt der Rotationsformel von Rodrigues - es hat ohnehin die gleichen Basisvektoren; Ich müsste mich mit einigen Trigger-Identitäten auseinandersetzen, um zu sehen, ob die Koeffizienten übereinstimmen.
Nathan Reed
@ NathanReed Dies scheint ein anderer Weg zu sein, um zum selben Ergebnis zu kommen. Ich würde auch gerne wissen, ob dies passt. Vielen Dank für den Hinweis!
Laurent Couvidou
1
Ich habe die Implementierung von GLM überprüft und es scheint ein bisschen anders implementiert zu sein, nämlich wie folgt: vprime = v + ((cross(u, v) * s) + cross(u, cross(u, v)) * 2.0fHandelt es sich um eine ähnliche Optimierung? Es sieht etwas ähnlich aus, ist aber nicht dasselbe - es werden nur Kreuzprodukte verwendet, keine Punktprodukte. Der ursprüngliche Quellcode kann in die gefunden werden offizielle GLM Repository type_quat.inl Datei in dem operator*die eine Quaternion und einen Vektor nimmt ( vec<3, T, Q> operator*(qua<T, Q> const& q, vec<3, T, Q> const& v))
j00hi
7

Erstens ist q ^ (- 1) nicht -q / Betrag (q); es ist q * / (Betrag (q)) ^ 2 (q * ist das Konjugat; das negiert alle Komponenten mit Ausnahme der realen). Natürlich können Sie die Division durch die Größe weglassen, wenn alle Ihre Quaternionen bereits normalisiert sind, was normalerweise in einem Rotationssystem der Fall ist.

Bei der Multiplikation mit einem Vektor erweitern Sie den Vektor einfach zu einem Quaternion, indem Sie die Realkomponente eines Quats auf Null und seine IJK-Komponenten auf das XYZ des Vektors setzen. Dann führen Sie die Quaternion-Multiplikationen durch, um v 'zu erhalten, und extrahieren dann die ijk-Komponenten erneut. (Der Realteil von v 'sollte immer Null plus oder minus eines Gleitkommafehlers sein.)

Nathan Reed
quelle
5

Erste Beobachtung: Das Gegenteil von qist nicht -q/magnitude(q), das ist völlig falsch. Rotationen mit Quaternionen implizieren, dass diese 4D-Äquivalente für komplexe Zahlen eine einheitliche Norm haben und daher auf der S3-Einheitenkugel in diesem 4D-Raum liegen. Die Tatsache, dass ein Quat einheitlich ist, bedeutet, dass seine Norm ist norm(q)^2=q*conjugate(q)=1und dass das Inverse des Quats sein Konjugat ist.

Wenn ein Einheitsquaternion als q=(w,x,y,z)= (cos (t), sin (t) v ) geschrieben wird, dann ist sein Konjugat conjugate(q)=(w,-x,-y,-z)= (cos (t), - sin (t) v ), wobei t die Hälfte des Drehwinkels und v ist ist die Rotationsachse (natürlich als Einheitsvektor).

Als dieser Hamilton-Typ beschloss, mit komplexen Zahlenäquivalenten in höheren Dimensionen herumzuspielen, stieß er auch auf einige nette Eigenschaften. Wenn Sie zum Beispiel eine vollständig reine Quaternion verwenden q=(0,x,y,z)(kein skalarer Teil w !), Können Sie diesen Mist als Vektor betrachten (es ist tatsächlich eine Quat auf dem Äquator der S3-Kugel, die eine S2-Kugel ist!). ! - Wenn man bedenkt, wie technisch behindert die Menschen im 19. Jahrhundert sind, scheint uns eyePhone Cowboys heutzutage). Also nahm Hamilton diesen Vektor in seiner Quat-Form: v=(0,x,y,z)und führte eine Reihe von Experimenten durch, in denen die geometrischen Eigenschaften von Quats untersucht wurden.

INPUT: _v=(x,y,z)_ a random 3D vector to rotate about an __u__ unit axis by an angle of _theta_

OUTPUT: q*(0,_v_)*conjugate(q)

woher

 q = (cos(theta/2), sin(theta/2)*u)
 conjugate(q) = inverse(q) = (cos(theta/2), -sin(theta/2)*u)
 norm(q)=magnitude(q)=|q|=1

Beobachtung: Das q * (0, v) * Konj (q) muss ein anderes Quat der Form (0, v ') sein. Ich werde die scheinbar komplizierte Erklärung, warum dies geschieht, nicht durchgehen, aber wenn Sie eine rein imaginäre Quaternion (oder in unserem Fall einen Vektor!) Durch diese Methode drehen, müssen Sie eine ähnliche Art von Objekt erhalten: reines imaginäres Quat. und du nimmst seinen imaginären Teil als Ergebnis. Da haben Sie es, die wunderbare Welt der Rotationen mit Quaternionen in einer Nussschale.

ANMERKUNG : zu wem auch immer mit dieser überbeanspruchten Phrase einspringt: Quats sind gut, weil sie Kardansperren vermeiden. Sollten ihre Fantasie zuerst freisetzen !! Quats sind ein bloß "eleganter" mathematischer Apparat und können durch die Verwendung anderer Ansätze insgesamt vermieden werden, wobei derjenige, den ich als vollständig geometrisch äquivalent empfinde, der Achsenwinkelansatz ist.

CODE : Die C ++ - Bibliothek, die ich mir vorstelle, ist recht simpel, verfügt jedoch über alle Matrix-, Vektor- und Quat-Operationen, die ein 3D-Grafiker benötigen sollte, ohne mehr als 15 Minuten zum Erlernen zu verschwenden. Sie können die hier geschriebenen Dinge damit testen in 15 Minuten, wenn Sie kein C ++ - Neuling sind. Viel Glück!

Teodron
quelle
+1 für deine Notiz. Ich wette, die meisten Leute könnten kein echtes Gimbal Lock erreichen, wenn sie es versuchen. Es ist zu einem Schlagwort für unerwartetes Verhalten beim Ausführen von Rotationen geworden.
Steve H
Die meisten Menschen können keinen richtigen Kardanmechanismus bauen und denken, wenn sie 3 Rotationsmatrizen miteinander verketten, erhalten sie automatisch die Darstellung "Euler-Winkel". Das Kardan-Ding ist nur eine der einfachsten Rotationsarten für Roboterarme Gelenke, bei denen Redundanz auftreten kann, wenn versucht wird, eine inverse Kinematik durchzuführen (es verfügt über mehr Freiheitsgrade, als tatsächlich zur Herstellung der gewünschten Ausrichtung erforderlich sind). Na ja, das ist ein anderes Thema, aber ich fand es schön, mich von dem Hype fernzuhalten, den diese "legendäre" Ausgabe unter CG-Programmierern hervorgerufen hat.
teodron
Nitpickery: Während der Achsenwinkel insofern äquivalent ist, als beide Darstellungen alle Umdrehungen in SO (3) eindeutig darstellen können (okay, modulo die übliche doppelte Abdeckung) und natürlich eine fast triviale Transformation zwischen ihnen besteht, haben Quaternionen eine der Vorteil, dass es viel einfacher zu komponieren ist als alle anderen Nicht-Matrix-Darstellungen.
Steven Stadnicki
Sie haben den Vorteil, dass sie aufgrund ihres netten Verhaltens in jeder objektorientierten Programmiersprache einfacher zu komponieren sind, insbesondere bei Verwendung der Operatorüberladung. Ich bin mir nicht sicher, aber vielleicht bleiben sogar ihre sphärischen Interpolationseigenschaften für den Achsenwinkel erhalten (außer für SQUAD vielleicht ?!).
Teodron
2

Hier ist eine alternative Möglichkeit, einen Vektor durch eine Quaternion zu transformieren. Es ist die Art und Weise, wie MS es im xna-Framework tut. http://pastebin.com/fAFp6NnN

Steve H
quelle
-1

Ich habe versucht, dies von Hand herauszufinden und fand die folgende Gleichung / Methode:

// inside quaterion class
// quaternion defined as (r, i, j, k)
Vector3 rotateVector(const Vector3 & _V)const{
    Vector3 vec();   // any constructor will do
    vec.x = 2*(r*_V.z*j + i*_V.z*k - r*_V.y*k + i*_V.y*j) + _V.x*(r*r + i*i - j*j - k*k);
    vec.y = 2*(r*_V.x*k + i*_V.x*j - r*_V.z*i + j*_V.z*k) + _V.y*(r*r - i*i + j*j - k*k);
    vec.z = 2*(r*_V.y*i - r*_V.x*j + i*_V.x*k + j*_V.y*k) + _V.z*(r*r - i*i - j*j + k*k);
    return vec;
}

Ich würde mich freuen, wenn sich jemand die MT-Ableitung ansieht, die ich unter http://pastebin.com/8QHQqGbv verwendet habe

In meiner Notation habe ich q ^ (- 1) verwendet, um konjugiert und nicht invers und verschiedene Bezeichner zu bedeuten, aber ich hoffe, dass es nachvollziehbar ist. Ich denke, dass die Mehrheit Recht hat, vor allem, wenn der reale Teil des Vektors verschwinden würde.

gardian06
quelle