Wie kann ich mich in 3D um einen beliebigen Punkt drehen (anstelle des Ursprungs)?

15

Ich habe einige Modelle, die ich mithilfe von Quaternionen auf normale Weise drehen möchte, außer dass ich sie nicht um den Ursprung drehen möchte, sondern leicht versetzen möchte. Ich weiß, dass Sie im 3D-Raum nicht sagen, dass Sie sich um einen Punkt drehen. Sie sagen, Sie drehen sich um eine Achse. Ich stelle es mir also so vor, als würde es sich um einen Vektor drehen, dessen Schwanz nicht am lokalen Ursprung positioniert ist.

Alle affinen Transformationen in meiner Rendering- / Physik-Engine werden mithilfe von SQT (Maßstab, Quaternion, Übersetzung; eine Idee aus dem Buch Game Engine Architecture ) gespeichert . Daher erstelle ich aus diesen Komponenten für jeden Frame eine Matrix und übergebe sie an den Vertex-Shader. In diesem System wird zuerst die Translation, dann die Skalierung und dann die Rotation angewendet.

In einem bestimmten Fall muss ich ein Objekt im Weltraum verschieben, skalieren und um einen Scheitel drehen, der nicht am lokalen Ursprung des Objekts zentriert ist.

Frage: Wie kann ich unter Berücksichtigung der oben beschriebenen Einschränkungen meines aktuellen Systems eine lokale Rotation erzielen, die um einen anderen Punkt als den Ursprung zentriert ist? Automatisches Upvote für alle, die beschreiben können, wie dies auch nur mit Matrizen gemacht wird :)

notlesh
quelle
Quaternionen beschreiben bereits eine Rotation um eine beliebige Achse; Sie haben Probleme konstruieren so eine Quaternion aus den Daten , die Sie haben?
Martin Sojka
3
Könnten die Leute, die die Antworten positiv bewertet haben, sie tatsächlich lesen ? Ich gab eine Methode, eine effiziente Formel und sogar eine Demonstration. Die einzige Antwort mit Gegenstimmen enthält zwar einige wertvolle Informationen (und auch einige eindeutig falsche Informationen), jedoch keine davon und beantwortet nicht einmal die Frage!
Sam Hocevar
@MartinSojka, das ist ein beliebiger Punkt, keine beliebige Achse.
notlesh
@SamHocevar Beide Ihre Antworten waren hilfreich. Ich habe Ihre ausgewählt, weil sie gründlicher war und mir geholfen hat, eine Lösung zu finden. Danke euch beiden.
notlesh
Ah, tut mir leid - ich hatte es mit Dual Quaternions verwechselt (bei denen bekommst du auch die Übersetzung "kostenlos"). Ich schreibe später auf, was ich damit gemeint habe. Vielleicht finden es andere nützlich, zumal Sie Ihre drei Komponenten auf eine reduzieren können - wenn auch etwas komplexer.
Martin Sojka

Antworten:

17

Zusamenfassend

Sie müssen nur T in Ihrem SQT-Formular ändern.

Ersetzen Sie den Translationsvektor vmit v' = v-invscale(p-invrotate(p))dem vdie anfängliche Translationsvektor, pist der Punkt , um die Sie die Rotation stattfinden soll, und invrotateund invscalesind die Umkehrungen Ihrer Drehung und Skalierung.

Schnelle Demonstration

Sei pder Punkt, um den Sie die Drehung anwenden r. Seien Sie sIhre Skalierungsparameter und vIhr Übersetzungsvektor. Die endgültige Matrixtransformation findet T(p)R(r)T(-p)S(s)T(v)statt R(r)S(s)T(v).

Was Sie wollen, sind neue Transformationsparameter v', r'und s'so, dass die endgültige Matrixtransformation ist R(r')S(s')T(v')und wir haben:

T(p)R(r)T(-p)S(s)T(v) = R(r')S(s')T(v')

Verhalten im Unendlichen zeigt an, dass sich Rotationsparameter und Skalierungsparameter nicht ändern können (dies könnte demonstriert werden). Wir haben also r = r'und s = s'. Der einzige fehlende Parameter ist daher v'Ihr neuer Übersetzungsvektor:

T(p)R(r)T(-p)S(s)T(v) = R(r)S(s)T(v')

Wenn diese Matrizen gleich sind, sind ihre Umkehrungen gleich:

T(-v)S(-s)T(p)R(-r)T(-p) = T(-v')S(-s)R(-r)

Dies gilt insbesondere für die Herkunft O:

T(-v)S(-s)T(p)R(-r)T(-p)O = T(-v')S(-s)R(-r)O

Skalieren und Drehen des Ursprungs ergibt den Ursprung, womit erhalten Sie:

T(-v)S(-s)T(p)R(-r)(-p) = -v'

v'ist der neue Übersetzungsvektor, nach dem Sie suchen, um Ihre Transformation in SQT-Form zu speichern. Es ist wahrscheinlich möglich, die Berechnung zu vereinfachen; Zumindest aber wird der benötigte Speicherplatz nicht erhöht.

sam hocevar
quelle
Danke für die Erklärung. Übrigens, kennen Sie Ressourcen, in denen ich mehr über SQT-Darstellungstricks lesen kann?
Pachanga
Korrigieren Sie mich, wenn ich falsch liege, aber es scheint, dass eine andere Lösung darin besteht, Ihre Quaternion wie gewohnt zu speichern. Wenn Sie die Verschiebung um einen beliebigen Punkt / eine beliebige Achse berücksichtigen müssen, erstellen Sie die Q-Matrix mit dieser Angabe. Extrahieren Sie einfach den Verschiebungsvektor aus dieser Matrix (normalerweise letzte Spalte) und fügen Sie sie dem Übersetzungsvektor des Objekts hinzu, dann werfen Sie Ihre temporäre Matrix heraus.
Johnbakers
15

Alle kanonischen Rotationsformeln, die zum Ableiten Ihrer Rotationsmatrizen verwendet werden, dienen der Rotation um den Ursprung. Wenn Sie diese Drehung stattdessen um einen bestimmten Punkt anwenden möchten, müssen Sie zuerst den Ursprung versetzen oder das Objekt entsprechend so verschieben, dass sich der Punkt, um den Sie drehen möchten, am Ursprung befindet.

Betrachten Sie zuerst den 2D-Fall, da er einfacher ist und die Technik skaliert. Wenn Sie einen Würfel der Breite 2 auf dem Ursprung zentriert hätten und ihn um 45 Grad um seinen Mittelpunkt drehen möchten, wäre dies eine triviale Anwendung der 2D-Rotationsmatrix .

Wenn Sie es stattdessen um die rechte obere Ecke (befindet sich bei 1,1) drehen möchten, müssen Sie es zuerst so übersetzen, dass sich die Ecke am Ursprung befindet. Dies kann mit einer Übersetzung von erreicht werden -1,-1. Anschließend können Sie das Objekt wie zuvor drehen, müssen dies jedoch durch Zurückübersetzen (von 1,1) nachholen . Um also im Allgemeinen die Rotationsmatrix Rfür eine Rotation rum einen Punkt zu erhalten, gehen PSie wie folgt vor:

R = translate(-P) * rotate(r) * translate(P)

wo translateund rotatesind die kanonischen Translations- / Rotationsmatrizen. Dies skaliert trivial auf 3D, mit der Ausnahme, dass Sie der Rotation auch eine Achse zuweisen müssen - Sie könnten einfach immer die kanonischen Rotationsmatrizen für die X-, Y- oder Z-Achse auswählen, aber das wäre langweilig. Sie möchten die willkürliche Achsenwinkel-Rotationsmatrix verwenden . Dein Finale Rin 3D ist also:

R = translate(-P) * rotate(a,r) * translate(P)

Dabei asteht ein Einheitsvektor für die Rotationsachse und Pist jetzt ein 3D-Punkt im Modellraum, der den Rotationspunkt darstellt.

Quaternionen können zufällig in und aus Matrixdarstellungen konvertiert werden , sodass Sie Ihre Verkettung auf diese Weise durchführen können, falls Sie dies wünschen. Oder Sie können einfach alles als Matrizen belassen (Quaternionen haben einige nette Vorteile, wie zum Beispiel eine einfachere Interpolation, aber ob Sie das brauchen oder nicht, liegt bei Ihnen).

Ebenfalls:

Ich stelle es mir also so vor, als würde es sich um einen Vektor drehen, dessen Schwanz nicht am lokalen Ursprung positioniert ist.

Streng genommen können Vektoren zur Darstellung von Positionen verwendet werden, indem sie als Verschiebungen von einem Ursprung betrachtet werden. Vektoren haben selbst keine Positionen, daher ist es etwas ungewöhnlich, eine Position als solche zu visualisieren.


quelle
Danke, das ist eine gute Antwort. Es entspricht jedoch nicht den Einschränkungen meines Systems. Ich hätte in meine Frage aufnehmen sollen: "Ist es möglich, dies angesichts dieser Einschränkungen zu tun?", Und ich denke, die Antwort ist, dass dies nicht der Fall ist, da dies zwei Übersetzungen erfordert und ich nur eine zur Verfügung stelle. Ist dies ein unvermeidlicher Mangel bei der Verwendung von SQT als Repräsentation affiner Transformationen?
notlesh
Es passt perfekt in Ihre Grenzen. Die Matrix R (erzeugt als translate-rotate-translate-back) ist Ihre Rotationsmatrix. Ersetzen Sie Q durch R in Ihrem "SQT" -System, damit Sie das üblichere Paradigma für Skalieren, Drehen und Übersetzen haben und fertig sind. Diese letzte Verschiebung ist unabhängig von den zwei Zwischenverschiebungen, die durchgeführt werden, um die gewünschte Drehung zu erzeugen.
Sie schlagen vor, das Quaternion durch eine Matrix zu ersetzen? Das sind 12 Bytes mehr pro Objekt (8, wenn ich es als 4x3-Matrix speichere)! Ich werde jedoch den Optimisten in mir zum Schweigen bringen und das Ganze in Schwung bringen. (Das wird wahrscheinlich nicht einmal eine Erhöhung der Stellfläche um 2 KB bedeuten ...) Vielen Dank für Ihre Antworten.
notlesh
Sie könnten - Sie könnten auch zwischen ihnen konvertieren, die Rotationsquaternion auf diese Weise konstruieren und sie wieder in Ihr bestehendes System einbinden.
1
@SamHocevar: Alternativ kann jede Kombination davon als einzelne Schraube ausgedrückt werden .
Martin Sojka