Wie verhindere ich, dass meine mit Quaternion arbeitende FPS-Kamera kippt und durcheinander kommt?

17

Ich verwende eine FPS-ähnliche Kamera, die Quaternionen verwendet. Aber wenn ich versuche, nach oben und dann zur Seite zu schauen, kippt es, und manchmal kann es auf den Kopf gestellt werden. Wie kann ich das beheben?

Aeodyn
quelle
3
(Wird sich in 7 Stunden selbst beantworten)
Aeodyn

Antworten:

16

Sie könnten Ihr Quaternion in ein Gieren / Neigen / Rollen-Winkel-Set zerlegen, aber das ist normalerweise übertrieben.

Anstatt deine Quaternionen wie folgt zu komponieren:

cameraOrientation = cameraOrientation * framePitch * frameYaw;

Versuche dies:

cameraOrientation = framePitch * cameraOrientation * frameYaw;

Es wird dann niemals Kippen / Rollen erzeugen und ist gleichbedeutend damit, Gieren und Neigen getrennt zu speichern

ltjax
quelle
3
Dies. Genau das habe ich gesucht. Löste mein Problem in einem Einzeiler. Nett!
Aardvarkk
1
Sind framePitchund frameYaw floatTypen? Ich wäre Ihnen auch dankbar, wenn Sie Ihren ersten Satz näher erläutern würden.
sirdank
1
@sirdank cameraOrientation, framePitchund frameYawsind alle Quaternionen (jede Quaternion besteht aus 4 Floats oder Doubles).
Dan
8

Dies ist ein Problem, das ich seit einiger Zeit hatte und für das ich keine Antworten finden konnte. Deshalb dachte ich, ich würde es hier posten.

Es ist eigentlich ganz einfach. Wie Sie höchstwahrscheinlich die Rotationen ausführen, ist wie folgt:

currentDirection * newRotation;

Aber es so zu machen, funktioniert auch nicht.

newRotation * currentDirection;

Was Sie tun müssen, ist, es in der ersten Reihenfolge für die Aufwärts- und Abwärtsdrehungen und in der zweiten Reihenfolge für die Seitwärtsdrehungen zu tun.

Für mich war es so:

        if (keyboard.IsKeyDown(Keys.Up))
            Direction = Direction * Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), TurnSpeed);
        if (keyboard.IsKeyDown(Keys.Down))
            Direction = Direction * Quaternion.CreateFromAxisAngle(new Vector3(-1, 0, 0), TurnSpeed);
        if (keyboard.IsKeyDown(Keys.Left))
            Direction = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, 1), TurnSpeed) * Direction;
        if (keyboard.IsKeyDown(Keys.Right))
            Direction = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, -1), TurnSpeed) * Direction;

Aus einem Grund hat der erste Weg die Rotation relativ zur aktuellen seitlichen Richtung, die Sie für Auf- und Abwärtsbewegungen wünschen, aber Sie wollen das nicht für die seitlichen Rotationen, weshalb die zweite Ordnung benötigt wird.

Aeodyn
quelle
Ich musste 7 Stunden warten, um meine eigenen Fragen zu beantworten ...
Aeodyn
Entschuldigung, kannst du das mit ein paar Screenshots erklären? "erste Bestellung" und "zweite Bestellung" ist etwas verwirrend - danke!
Atav32
Bei der Arbeit mit Quaternions spielt die Reihenfolge eine Rolle, wie es bei 3D-Rotationen immer der Fall ist. In meinem Beispiel ist "Direction * = newRotation" dasselbe wie "Direction = Direction * newRotation". Aber mit Links- und Rechtsdrehung wollen wir es umgekehrt. Dies macht es nicht abhängig von der Auf- und Abwärtsneigung, die ein Wegrollen verursacht.
Aeodyn
Oh, ich glaube, es ging darum, dass Kardansperren vermieden wurden und die Rotationen unabhängig voneinander abliefen, aber ich habe das Lehrbuch möglicherweise falsch gelesen. Wollen Sie damit klarstellen, dass Sie verhindern können, dass die Kamera kippt, wenn Sie die Reihenfolge der Rotationstransformationen umkehren? Oder setzen Sie die Roll- und Pitch-Transformationen manuell auf 0, wenn Sie das Gieren drehen?
Atav32
5

Bei einer FPS-Kamera möchten Sie normalerweise nicht rollen und sind auf +/- 90 Grad Neigung beschränkt. Daher würde ich den aktuellen Zustand nur mit Gier- und Neigungswinkeln verfolgen. Die volle Kraft der Quaternionen ist dafür nicht wirklich hilfreich.

Sie können die Gier- / Nickwinkel weiterhin in und aus Quaternionen konvertieren, falls Sie mithilfe der Quaternion-Keyframe-Interpolation oder ähnlichem zwischen der FPS-Kamera und animierten Kameras wechseln möchten.

Nathan Reed
quelle
0

Ein weiterer einfacher Trick besteht darin, die Kamera in ein GameObject einzufügen und die Gierrotation das Spielobjekt steuern zu lassen, während die untergeordnete Kamera mit den Pitch-Koordinaten konfiguriert ist:

playerCameraHolder.transform.Rotate(0, rotationYaw, 0);
playerCamera.transform.Rotate(rotationPitch, 0, 0);
Victor S
quelle