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:
void Update() {
float speed = lookSpeed * Time.deltaTime;
transform.Rotate(0f, Input.GetAxis("Horizontal") * speed, 0f, Space.World);
transform.Rotate(-Input.GetAxis("Vertical") * speed, 0f, 0f, Space.Self);
}
Wenn Sie Ihre Rotationen mithilfe der Multiplikation kombinieren, müssen Sie die Links- / Rechtsreihenfolge einer der Multiplikationen umkehren, um den gleichen Effekt zu erzielen:
// Yaw happens "over" the current rotation, in global coordinates.
Quaternion yaw = Quaternion.Euler(0f, Input.GetAxis("Horizontal") * speed, 0f);
transform.rotation = yaw * transform.rotation; // yaw on the left.
// Pitch happens "under" the current rotation, in local coordinates.
Quaternion pitch = Quaternion.Euler(-Input.GetAxis("Vertical") * speed, 0f, 0f);
transform.rotation = transform.rotation * pitch; // pitch on the right.
(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):
// Construct a new orientation quaternion or matrix from Euler/Tait-Bryan angles.
var newRotation = Quaternion.Euler(totalPitch, totalYaw, 0f);
// Apply it to our object.
transform.rotation = newRotation;
oder äquivalent...
// Form a view vector using total pitch & yaw as spherical coordinates.
Vector3 forward = new Vector3(
Mathf.cos(totalPitch) * Mathf.sin(totalYaw),
Mathf.sin(totalPitch),
Mathf.cos(totalPitch) * Mathf.cos(totalYaw));
// Construct an orientation or view matrix pointing in that direction.
var newRotation = Quaternion.LookRotation(forward, new Vector3(0, 1, 0));
// Apply it to our object.
transform.rotation = newRotation;
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.