Ich sehe, dass häufig Fragen auftauchen, die dieses zugrunde liegende Problem haben, aber sie sind alle in den Einzelheiten eines bestimmten Features oder Tools gefangen. Hier ist ein Versuch, eine kanonische Antwort zu erstellen, auf die wir Benutzer verweisen können, wenn dies eintritt - mit vielen animierten Beispielen! :)
Nehmen wir an, wir machen eine First-Person-Kamera. Die Grundidee ist, nach links und rechts zu schauen und nach oben und unten zu schauen. Also schreiben wir ein bisschen Code wie diesen (am Beispiel von Unity):
void Update() {
float speed = lookSpeed * Time.deltaTime;
// Yaw around the y axis using the player's horizontal input.
transform.Rotate(0f, Input.GetAxis("Horizontal") * speed, 0f);
// Pitch around the x axis using the player's vertical input.
transform.Rotate(-Input.GetAxis("Vertical") * speed, 0f, 0f);
}
oder vielleicht
// Construct a quaternion or a matrix representing incremental camera rotation.
Quaternion rotation = Quaternion.Euler(
-Input.GetAxis("Vertical") * speed,
Input.GetAxis("Horizontal") * speed,
0);
// Fold this change into the camera's current rotation.
transform.rotation *= rotation;
Und es funktioniert meistens, aber mit der Zeit wird der Blick schief. Die Kamera scheint sich um ihre Rollachse (z) zu drehen, obwohl wir ihr nur befohlen haben, sich auf x und y zu drehen!
Dies kann auch passieren, wenn wir versuchen, ein Objekt vor der Kamera zu manipulieren - sagen wir, es ist ein Globus, den wir drehen möchten, um uns umzusehen:
Das gleiche Problem - nach einer Weile beginnt der Nordpol nach links oder rechts zu wandern. Wir geben Input auf zwei Achsen, aber wir bekommen diese verwirrende Rotation auf einer dritten. Und es passiert, ob wir alle unsere Rotationen um die lokalen Achsen des Objekts oder die globalen Achsen der Welt anwenden.
In vielen Motoren sehen Sie dies auch im Inspektor - drehen Sie das Objekt in der Welt, und plötzlich ändern sich die Zahlen auf einer Achse, die wir nicht einmal berührt haben!
Also, ist das ein Motorfehler? Wie können wir dem Programm mitteilen, dass es keine zusätzliche Rotation hinzufügen soll?
Hat es etwas mit Eulerwinkeln zu tun? Soll ich stattdessen Quaternionen oder Rotationsmatrizen oder Basisvektoren verwenden?
quelle
Antworten:
Nein, dies ist kein Motorfehler oder ein Artefakt einer bestimmten Rotationsdarstellung (dies kann auch passieren, aber dieser Effekt gilt für jedes System, das Rotationen darstellt, einschließlich Quaternionen).
Sie haben eine reale Tatsache darüber entdeckt, wie Rotation im dreidimensionalen Raum funktioniert, und es weicht von unserer Intuition über andere Transformationen wie das Übersetzen ab:
Wenn wir Rotationen auf mehr als einer Achse erstellen, erhalten wir nicht nur den Gesamt- / Nettowert, den wir auf jede Achse angewendet haben (wie wir es für die Übersetzung erwarten würden). Die Reihenfolge, in der wir die Drehungen anwenden, ändert das Ergebnis, da jede Drehung die Achsen bewegt, auf die die nächsten Drehungen angewendet werden (wenn sie sich um die lokalen Achsen des Objekts drehen), oder die Beziehung zwischen dem Objekt und der Achse (wenn sie sich um die Welt drehen) Achsen).
Die Veränderung der Achsenbeziehungen im Laufe der Zeit kann unsere Intuition darüber verwirren, was jede Achse "tun" soll. Insbesondere bestimmte Kombinationen von Gier- und Nickrotationen führen zum gleichen Ergebnis wie eine Rollrotation!
Sie können überprüfen, ob sich jeder Schritt korrekt um die von uns angeforderte Achse dreht. In unserer Notation gibt es keine Motorstörungen oder Artefakte, die unsere Eingabe beeinträchtigen oder nachträglich erraten herum "aufeinander. Sie mögen lokal orthogonal sein, für kleine Rotationen, aber wenn sie sich aufstapeln, stellen wir fest, dass sie nicht global orthogonal sind.
Dies ist am dramatischsten und klarsten für 90-Grad-Kurven wie oben, aber die wandernden Achsen kriechen auch über viele kleine Umdrehungen ein, wie in der Frage gezeigt.
Also, was machen wir dagegen?
Wenn Sie bereits über ein Pitch-Yaw-Rotationssystem verfügen, können Sie unerwünschte Rollbewegungen am schnellsten beseitigen, indem Sie eine der Rotationen so ändern, dass sie auf der globalen oder übergeordneten Transformationsachse und nicht auf der lokalen Achse des Objekts ausgeführt werden. Auf diese Weise können Sie keine Kreuzkontamination zwischen den beiden erhalten - eine Achse bleibt absolut kontrolliert.
Hier ist dieselbe Sequenz von Nick-Gier-Nick, die im obigen Beispiel zu einer Rolle wurde, aber jetzt wenden wir unser Gieren um die globale Y-Achse an, anstatt um die des Objekts
So können wir die First-Person-Kamera mit dem Mantra "Pitch Local, Yaw Globally" reparieren:
Wenn Sie Ihre Rotationen mithilfe der Multiplikation kombinieren, müssen Sie die Links- / Rechtsreihenfolge einer der Multiplikationen umkehren, um den gleichen Effekt zu erzielen:
(Die genaue Reihenfolge hängt von den Multiplikationskonventionen in Ihrer Umgebung ab, aber left = globaler / right = lokaler ist eine häufige Wahl.)
Dies ist gleichbedeutend mit dem Speichern der gewünschten Nettogier- und Gesamtsteigung als Float-Variablen und dem gleichzeitigen Anwenden des Nettoergebnisses, wobei nur aus diesen Winkeln eine einzelne neue Orientierungsquaternion oder -matrix erstellt wird (vorausgesetzt, Sie halten
totalPitch
sie fest):oder äquivalent...
Bei dieser globalen / lokalen Aufteilung haben die Rotationen keine Chance, sich zu verbinden und zu beeinflussen, da sie auf unabhängige Achsensätze angewendet werden.
Die gleiche Idee kann helfen, wenn es sich um ein Objekt in der Welt handelt, das wir drehen möchten. Bei einem Beispiel wie dem Globus möchten wir ihn oft umkehren und unser Gieren lokal anwenden (damit er sich immer um seine Pole dreht) und global neigen (damit er in Richtung / weg von unserer Sicht und nicht in Richtung / weg von Australien kippt , wohin es zeigt ...)
Einschränkungen
Diese globale / lokale Hybridstrategie ist nicht immer die richtige Lösung. In einem Spiel mit 3D-Flug / Schwimmen möchten Sie möglicherweise direkt nach oben / unten zeigen und trotzdem die volle Kontrolle haben. Aber mit diesem Setup werden Sie auf Gimbal Lock klicken - Ihre Gierachse (global aufwärts) wird parallel zu Ihrer Rollachse (lokal vorwärts), und Sie haben keine Möglichkeit, nach links oder rechts zu schauen, ohne sich zu drehen.
In solchen Fällen können Sie stattdessen reine lokale Rotationen verwenden, wie wir sie in der obigen Frage beschrieben haben (damit sich Ihre Steuerelemente gleich anfühlen, egal wohin Sie schauen), wodurch sich zunächst ein wenig Roll einschleichen kann - aber dann wir korrigieren es.
Zum Beispiel können wir lokale Rotationen verwenden, um unseren "Vorwärts" -Vektor zu aktualisieren, und dann diesen Vorwärtsvektor zusammen mit einem Referenz- "Auf" -Vektor verwenden, um unsere endgültige Orientierung zu konstruieren. (Verwenden Sie zum Beispiel die Unity- Methode Quaternion.LookRotation oder konstruieren Sie manuell eine orthonormale Matrix aus diesen Vektoren.) Durch Steuern des Aufwärtsvektors steuern Sie die Roll- oder Verdrehung.
Für das Flug- / Schwimmbeispiel möchten Sie diese Korrekturen im Laufe der Zeit schrittweise anwenden. Wenn es zu abrupt ist, kann die Sicht störend schwanken. Stattdessen können Sie den aktuellen Aufwärtsvektor des Players verwenden und ihn Frame für Frame vertikal ausrichten, bis die Ansicht ausgeglichen ist. Das Anwenden dieser Option in einer Runde kann manchmal weniger Übelkeit verursachen als das Drehen der Kamera, während die Bedienelemente des Players inaktiv sind.
quelle
TCVector::calcRotationMatrix(totalPitch, totalYaw, identity)
- dies entspricht dem obigen Beispiel "Alles auf einmal Euler".Nach 16 Stunden Erziehung und Rotationsfunktionen lol.
Ich wollte nur, dass Code ein leeres hat, das sich im Grunde genommen im Kreis dreht und sich auch von vorne dreht.
Mit anderen Worten, das Ziel ist es, Gieren und Nicken ohne Auswirkung auf das Rollen zu drehen.
Hier sind die wenigen, die in meiner Anwendung tatsächlich funktioniert haben
In der Einheit:
Führen Sie nun die Skripterstellung in Visual Studio durch, und führen Sie die folgenden Schritte in Update aus:
Beachten Sie, dass alles für mich kaputt ging, als ich versuchte, die Reihenfolge der Elternschaft zu ändern. Oder wenn ich Space.World für das untergeordnete Pitch- Objekt ändere (es macht dem übergeordneten Yaw nichts aus, durch Space.Self gedreht zu werden). Verwirrend. Ich könnte definitiv eine Erklärung gebrauchen, warum ich eine lokale Achse nehmen musste, aber sie durch den Weltraum anwenden musste - warum ruiniert Space.Self alles?
quelle
me.Rotate(me.right, angle, Space.World)
ist es dasselbe wieme.Rotate(Vector3.right, angle, Space.Self
und Ihre verschachtelten Transformationen entsprechen den Beispielen "Pitch Local, Yaw Global" in der akzeptierten Antwort.