Wie rotiere ich ein Objekt um weltausgerichtete Achsen?

15

Ich habe einen Vector3, der für jede Achse einen Euler-Winkel hat.

Wenn ich eine Rotationsmatrix erstellen möchte, verwende ich normalerweise Funktionen wie D3DXMatrixRotationX, indem ich den entsprechenden Winkel von meinem Rotationsvektor oben übergebe und die Matrizen (ZXY) multipliziere, um die gesamte Rotationsmatrix zu erstellen, die zur Bildung der vollständigen Objekttransformationsmatrix verwendet wird.

Diese Methode erzeugt jedoch eine Reihe von Rotationen im Objektraum. Das heißt, durch Übergabe eines Vektors von (90, 0, 90) an meine Methode wird effektiv eine Drehung im Weltraum von (90, 90, 0) erzeugt.

Gibt es eine Möglichkeit, sicherzustellen, dass jede Komponente meines Rotationsvektors zu einer Rotation um die jeweiligen Achsen im Weltraum führt?

BEARBEITEN:

Dies ist eine Animation dessen, was gerade passiert - ich möchte eine Möglichkeit, um die blauen Achsen zu drehen, nicht um die roten.

Euler Winkel

EDIT 2:

Nur zur Erinnerung: Ich suche keine Lösung mit Euler-Winkeln, sondern nur eine Möglichkeit, eine Transformation von Mehrfachrotationen um die Weltachsen darzustellen.

Syntac_
quelle
Was ist falsch daran, nur die verschiedenen Funktionen dreimal aufzurufen und die Teile der Vektoren herauszufiltern, die Sie nicht möchten (indem Sie sie vor dem Aufrufen der Funktion auf 0 setzen)? Ansonsten bin ich mir nicht sicher, was Sie erreichen wollen.
TravisG
Was herausfiltern? Ich rufe die 3 separaten Funktionen auf und multipliziere sie dann, um die Transformationsmatrix zu erstellen. Dies führt jedoch zu einer lokalen Rotation.
Syntac_
Möchten Sie Euler-Winkel oder Rotation um Weltachsen? Beachten Sie, dass sich nach der Definition von Euler-Winkeln (z. B. en.wikipedia.org/wiki/Euler_angles ) nur der Alpha-Winkel ausschließlich um eine Weltachse handelt. Die anderen beiden Winkel beziehen sich auf geneigte Achsen, die nicht unbedingt mit den Weltachsen übereinstimmen.
DMGregory
1
Mit Euler-Winkeln multiplizieren Sie alle drei Rotationsmatrizen, bevor Sie sie auf den Scheitelpunkt anwenden. Wenn M, N, O die Rotationsmatrizen sind, lautet die Ergebnisoperation MNO v. Ich habe vorgeschlagen, jede Matrix separat anzuwenden: v1 = O v0, dann v2 = N v1 und schließlich v3 = M v2. Auf diese Weise wird jedes vi in ​​Weltkoordinaten angegeben und Sie müssen nur eine Rotationsmatrix für die aktuelle Achse in Weltkoordinaten verwenden.
dsilva.vinicius
3
@ dsilva.vinicius Deine getrennten Transformationen sind genau die gleichen wie die kombinierten, oder anders ausgedrückt: MNO v == M * (N * (O v))
GuyRT

Antworten:

1

Basierend auf Ihren Kommentaren scheint es, dass Sie die Ausrichtung des Objekts als Satz von Euler-Winkeln speichern und die Winkel beim Drehen des Objekts in / dekrementieren. Das heißt, Sie haben so etwas wie diesen Pseudocode:

// in player input handling:
if (axis == AXIS_X) object.angleX += dir;
else if (axis == AXIS_Y) object.angleY += dir;
else if (axis == AXIS_Z) object.angleZ += dir;

// in physics update and/or draw code:
matrix = eulerAnglesToMatrix(object.angleX, object.angleY, object.angleZ);

Wie Charles Beattie bemerkt , funktioniert dies nicht wie erwartet, da Rotationen nicht pendeln, es sei denn, der Spieler dreht das Objekt in derselben Reihenfolge, in der er eulerAnglesToMatrix()die Rotationen anwendet.

Beachten Sie insbesondere die folgende Abfolge von Drehungen:

  1. Objekt um x Grad um die X-Achse drehen ;
  2. Objekt um y Grad um die Y-Achse drehen ;
  3. Objekt um - x Grad um die X-Achse drehen ;
  4. Objekt um - y Grad um die Y-Achse drehen .

In der naiven Euler-Winkeldarstellung, wie im obigen Pseudocode implementiert, heben sich diese Rotationen auf und das Objekt kehrt in seine ursprüngliche Ausrichtung zurück. In der realen Welt passiert das nicht - wenn du mir nicht glaubst, nimm einen sechsseitigen Würfel oder einen Zauberwürfel, lass x = y = 90 ° und probiere es selbst aus!

Wie Sie in Ihrer eigenen Antwort bemerken , besteht die Lösung darin, die Ausrichtung des Objekts als Rotationsmatrix (oder Quaternion) zu speichern und diese Matrix basierend auf Benutzereingaben zu aktualisieren. Das heißt, anstelle des obigen Pseudocodes würden Sie Folgendes tun:

// in player input handling:
if (axis == AXIS_X) object.orientation *= eulerAnglesToMatrix(dir, 0, 0);
else if (axis == AXIS_Y) object.orientation *= eulerAnglesToMatrix(0, dir, 0);
else if (axis == AXIS_Z) object.orientation *= eulerAnglesToMatrix(0, 0, dir);

// in physics update and/or draw code:
matrix = object.orientation;  // already in matrix form!

(Technisch gesehen , da jede Rotationsmatrix oder Quaternion kann als ein Satz von Euler - Winkeln dargestellt werden, es ist möglich , sie zu verwenden , um die Orientierung des Objekts zu speichern. Aber die physikalisch korrekte Regel zwei aufeinanderfolgende Drehungen zu kombinieren, die jeweils dargestellt als Euler - Winkel, Die Umwandlung in eine einzelne Umdrehung ist ziemlich kompliziert und läuft im Wesentlichen darauf hinaus, die Umdrehungen in Matrizen / Quaternionen umzuwandeln, sie zu multiplizieren und das Ergebnis dann wieder in Euler-Winkel umzuwandeln.

Ilmari Karonen
quelle
Ja, Sie haben Recht, das war die Lösung. Ich bin der Meinung, dass dies etwas besser ist als die Antwort von concept3d, da er den Eindruck erweckt, dass eine Quaternion erforderlich ist, aber das stimmt nicht. Solange ich die aktuelle Drehung als Matrix und nicht die drei Euler-Winkel gespeichert habe, war es in Ordnung.
Syntac_
14

Das Problem bei Rotationen ist, dass die meisten Leute es in Euler-Winkeln sehen, da sie leicht zu verstehen sind.

Die meisten Menschen vergessen jedoch den Punkt, dass Euler-Winkel drei aufeinanderfolgende Winkel sind . Das bedeutet, dass die Drehung um die erste Achse die nächste Drehung relativ zur ersten ursprünglichen Drehung bewirkt. Daher können Sie einen Vektor nicht unabhängig voneinander mit Euler-Winkeln um jede der drei Achsen drehen.

Dies wird direkt in Matrizen übersetzt, wenn Sie zwei Matrizen multiplizieren. Sie können sich diese Multiplikation als Transformation einer Matrix in den Raum der anderen Matrix vorstellen.

Dies soll mit 3 aufeinanderfolgenden Rotationen geschehen, auch wenn Quaternionen verwendet werden.

Bildbeschreibung hier eingeben

Ich möchte die Tatsache betonen, dass Quaternionen keine Lösung für Gimble Lock sind. Tatsächlich passiert Gimble Lock immer, wenn Sie Euler-Winkel mit Quaternionen dargestellt haben. Das Problem ist nicht die Darstellung, das Problem sind die 3 aufeinander folgenden Schritte.

Die Lösung?

Die Lösung für das unabhängige Drehen eines Vektors um 3 Achsen besteht darin , ihn in eine einzige Achse und einen einzigen Winkel zu kombinieren. Auf diese Weise können Sie den Schritt beseitigen, bei dem Sie eine sequentielle Multiplikation durchführen müssen. Dies führt effektiv zu:

Meine Rotationsmatrix repräsentiert das Ergebnis der Rotation um X und Y und Z.

eher als die Euler - Interpretation von

Meine Rotationsmatrix repräsentiert die Rotation um X, Y und Z.

Um dies zu verdeutlichen, zitiere ich aus Wikipedia Eulers Rotationssatz:

Nach dem Rotationssatz von Euler entspricht jede Rotation oder Folge von Rotationen eines starren Körpers oder Koordinatensystems um einen festen Punkt einer einzelnen Rotation um einen gegebenen Winkel θ um eine feste Achse (Euler-Achse genannt), die durch den festen Punkt verläuft. Die Euler-Achse wird typischerweise durch einen Einheitsvektor dargestellt. Daher kann jede Drehung in drei Dimensionen als eine Kombination eines Vektors u → und eines Skalars θ dargestellt werden. Quaternionen bieten eine einfache Möglichkeit, diese Achsenwinkel-Darstellung in vier Zahlen zu codieren und die entsprechende Drehung auf einen Positionsvektor anzuwenden, der einen Punkt relativ zum Ursprung in R3 darstellt.

Beachten Sie, dass das Multiplizieren von 3 Matrizen immer 3 aufeinanderfolgende Rotationen darstellt.

Um nun Rotationen um 3 Achsen zu kombinieren, müssen Sie eine einzelne Achse und einzelne Winkel ermitteln, die die Rotation um X, Y, Z darstellen. Mit anderen Worten, Sie müssen eine Achsen- / Winkel- oder Quaternionendarstellung verwenden, um die sequentiellen Rotationen zu beseitigen.

Dies erfolgt normalerweise, indem Sie mit einer anfänglichen Ausrichtung (Ausrichtung kann als Achsenwinkel betrachtet werden) beginnen, die normalerweise als Quaternion oder Achsenwinkel dargestellt wird, und diese Ausrichtung dann ändern, um Ihre Zielausrichtung darzustellen. Sie beginnen beispielsweise mit dem Identitäts-Quaterion und drehen dann um den Unterschied, um die Zielausrichtung zu erreichen. Auf diese Weise verlieren Sie keinen Freiheitsgrad.

concept3d
quelle
Als Antwort markiert, da dies aufschlussreich erscheint.
Syntac_
Ich habe einige Probleme herauszufinden, was Sie mit dieser Antwort sagen wollen. Ist es einfach "die Ausrichtung eines Objekts nicht als Euler-Winkel speichern"? Und wenn ja, warum nicht einfach so?
Ilmari Karonen,
@IlmariKaronen Es könnte klarer formuliert werden, aber ich denke, concept3d fördert die Darstellung des Achsenwinkels. Siehe Abschnitt 1.2.2 dieses Dokuments für die Beziehung zwischen Achsenwinkel und Quaternionen. Die Achs-Winkel-Darstellung ist aus den oben genannten Gründen einfacher zu implementieren, sie leidet nicht unter Gimbal-Lock und ist (zumindest für mich) genauso leicht zu verstehen wie Euler-Winkel.
NauticalMile
@ concept3d, das ist sehr interessant und ich mag deine Antwort wirklich. Mir fehlt jedoch eine Sache: Menschen interagieren mit dem Computer über eine Tastatur und eine Maus. Wenn wir an die Maus denken, dann sprechen wir über x- und y-Maus-Deltas. Wie können diese x, y-Deltas mit einer einzelnen Quaternion dargestellt werden, mit der wir die Rotationsmatrix generieren können, um beispielsweise eine Objektorientierung zu ändern?
Dienstag,
@gmagno Der Ansatz besteht normalerweise darin, die Mausbewegung auf die Objekte oder die Szene zu projizieren und die Deltas in diesem Raum zu berechnen. Dazu wird ein Strahl geworfen und die Schnittmenge berechnet. Suche nach Ray Casting, Projekt und Unprojekt, ich bin grob im Detail, da ich seit Jahren nicht mehr in CG gearbeitet habe. Ich hoffe, das hilft.
concept3d
2

Das Umschalten einer Rotationskombination vom Objektraum in den Weltraum ist trivial: Sie müssen lediglich die Reihenfolge umkehren, in der die Rotationen angewendet werden.

In Ihrem Fall müssen Z × X × YSie nur berechnen , anstatt Matrizen zu multiplizieren Y × X × Z.

Ein Grund dafür ist auf Wikipedia zu finden: Umrechnung zwischen intrinsischer und extrinsischer Rotation .

sam hocevar
quelle
Wenn dies wahr wäre, wäre die folgende Aussage aus Ihrer Quelle nicht wahr, da die Rotationen unterschiedlich wären: "Jede extrinsische Rotation entspricht einer intrinsischen Rotation um die gleichen Winkel, jedoch mit umgekehrter Reihenfolge der Elementrotationen und umgekehrt . "
Syntac_
1
Ich sehe hier keinen Widerspruch. Sowohl meine Antwort als auch diese Aussage sind wahr. Und ja, Rotationen im Objektraum und im Weltraum ergeben unterschiedliche Rotationen. das ist genau der Punkt, nicht wahr?
Sam Hocevar
Diese Aussage besagt, dass das Ändern der Reihenfolge immer zur gleichen Rotation führt. Wenn ein Auftrag die falsche Drehung erzeugt, wird auch der andere Auftrag ausgeführt, was bedeutet, dass dies keine Lösung ist.
Syntac_
1
Du liest falsch. Das Ändern der Reihenfolge führt nicht zur gleichen Drehung. Das Ändern der Reihenfolge und das Umschalten von intrinsischen Rotationen zu extrinsischen Rotationen führt zu derselben Rotation.
Sam Hocevar
1
Ich glaube nicht, dass ich deine Frage verstehe. Ihr GIF zeigt eine Drehung von ungefähr 50 Grad um Z(Objektraum), dann 50 Grad um X(Objektraum) und dann 45 Grad um Y(Objektraum). Dies entspricht einer Drehung um 45 Grad Y( Weltraum ), dann um 50 Grad X( Weltraum ) und dann um 50 Grad Z( Weltraum ).
Sam Hocevar
1

Ich werde meine Lösung als Antwort bereitstellen, bis jemand erklären kann, warum dies funktioniert.

Bei jedem Rendern habe ich meine Quaternion mit den in meinem Rotationsvektor gespeicherten Winkeln neu erstellt und die Quaternion dann auf meine endgültige Transformation angewendet.

Um es jedoch um die Weltachsen zu halten, musste ich das Quaternion über alle Frames hinweg beibehalten und Objekte nur mit einem Winkelunterschied drehen, d. H.

// To rotate an angle around X - note this is an additional rotation.
// If currently rotated 90, apply this function with angle of 90, total rotation = 180.
D3DXQUATERNION q;
D3DXQuaternionRotation(&q, D3DXVECTOR3(1.0f, 0.0f, 0.0f), fAngle);
m_qRotation *= q; 

//...

// When rendering rebuild world matrix
D3DXMATRIX mTemp;
D3DXMatrixIdentity(&m_mWorld);

// Scale
D3DXMatrixScaling(&mTemp, m_vScale.x, m_vScale.y, m_vScale.z);
m_mWorld *= mTemp;

// Rotate
D3DXMatrixRotationQuaternion(&mTemp, m_qRotation);
m_mWorld *= mTemp;

// Translation
D3DXMatrixTranslation(&mTemp, m_vPosition.x, m_vPosition.y, m_vPosition.z);
m_mWorld *= mTemp;

(Ausführlich für die Lesbarkeit)

Ich glaube, dsilva.vinicius hat versucht, an diesen Punkt zu gelangen.

Syntac_
quelle
1

Sie müssen die Reihenfolge der Rotationen speichern.

Rotating around x 90 then rotate around z 90 !=
Rotating around z 90 then rotate around x 90.

Speichern Sie Ihre aktuelle Rotationsmatrix und multiplizieren Sie jede Rotation vorab.

Charles Beattie
quelle
0

Zusätzlich zu @ concept3d answer können Sie 3 extrinsische Rotationsmatrizen verwenden, um sich in Weltkoordinaten um die Achse zu drehen. Zitat aus Wikipedia :

Extrinsische Rotationen sind elementare Rotationen, die um die Achsen des festen Koordinatensystems xyz auftreten. Das XYZ-System dreht sich, während xyz festgelegt ist. Beginnend mit XYZ, das xyz überlappt, kann eine Komposition aus drei extrinsischen Rotationen verwendet werden, um eine beliebige Zielorientierung für XYZ zu erreichen. Die Euler- oder Tait-Bryan-Winkel (α, β, γ) sind die Amplituden dieser Elementrotationen. Beispielsweise kann die Zielorientierung wie folgt erreicht werden:

Das XYZ-System dreht sich um die z-Achse um α. Die X-Achse steht nun im Winkel α zur X-Achse.

Das XYZ-System dreht sich wieder um die x-Achse um β. Die Z-Achse steht nun im Winkel β zur z-Achse.

Das XYZ-System dreht sich ein drittes Mal um γ um die z-Achse.

Rotationsmatrizen können verwendet werden, um eine Folge von extrinsischen Rotationen darzustellen. Zum Beispiel,

R = Z (γ) Y (β) X (α)

stellt eine Zusammensetzung von extrinsischen Rotationen um die Achsen xyz dar, wenn sie zum Vormultiplizieren von Spaltenvektoren verwendet werden

R = X (α) Y (β) Z (γ)

stellt genau die gleiche Zusammensetzung dar, wenn sie zum Nachmultiplizieren von Zeilenvektoren verwendet wird.

Sie müssen also die Reihenfolge der Rotationen im Verhältnis zu dem, was Sie mit intrinsischen (oder lokalen) Rotationen tun würden, umkehren. @Syntac hat nach einer zxy-Rotation gefragt, daher sollten wir eine extrinsische yxz-Rotation durchführen, um das gleiche Ergebnis zu erzielen. Der Code ist unten:

Erklärung der Matrixwerte hier .

// Init things.
D3DXMATRIX *rotationMatrixX = new D3DXMATRIX();
D3DXMATRIX *rotationMatrixY = new D3DXMATRIX();
D3DXMATRIX *rotationMatrixZ = new D3DXMATRIX();
D3DXMATRIX *resultRotationMatrix0 = new D3DXMATRIX();
D3DXMATRIX *resultRotationMatrix1 = new D3DXMATRIX();

D3DXMatrixRotationX(rotationMatrixX, angleX);
D3DXMatrixRotationY(rotationMatrixY, angleY);
D3DXMatrixRotationZ(rotationMatrixZ, angleZ);

// yx extrinsic rotation matrix
D3DXMatrixMultiply(resultRotationMatrix0, rotationMatrixY, rotationMatrixX);
// yxz extrinsic rotation matrix
D3DXMatrixMultiply(resultRotationMatrix1, resultRotationMatrix0, rotationMatrixZ);

D3DXVECTOR4* originalVector = // Original value to be transformed;
D3DXVECTOR4* transformedVector = new D3DXVECTOR4();

// Applying matrix to the vector.
D3DXVec4Transform(transformedVector, originalVector, resultRotationMatrix1);

// Don't forget to clean memory!

Dieser Code ist didaktisch und nicht optimal, da Sie mehrere D3DXMATRIX-Matrizen wiederverwenden können.

dsilva.vinicius
quelle
1
sorry mann das ist nicht korrekt Matrix / Vektor-Multiplikation ist assoziativ. Dies ist genau das gleiche wie die kombinierte Matrixmultiplikation.
concept3d
Du hast recht. Ich habe die Konzepte von extrinsischen und intrinsischen Rotationen gemischt.
dsilva.vinicius
Ich werde diese Antwort reparieren.
dsilva.vinicius
Die Antwort ist jetzt festgelegt.
dsilva.vinicius