2010-08-09 14 views
12

Wie kann ich den Kamerapitch wirksam begrenzen, wenn nur Kameraquaternion vorhanden ist? Muss ich in Euler-Winkel umwandeln und dann zurück zur Quaternion oder gibt es einen anderen Weg?Kameraposition begrenzen

vector A = [x, y, z] 
Q.x = A.x * sin(theta/2) 
Q.y = A.y * sin(theta/2) 
Q.z = A.z * sin(theta/2) 
Q.w = cos(theta/2) 

Wo A die Position ist und Theta der Winkel der Kamera gedreht werden soll (Einstellung der Tonhöhe):

+0

Wert, ich über eine gute Antwort für die letzten paar Stunden versucht jetzt denken ... Mann, es war seit Jahren beschäftige ich mich mit Quaternionen ... Ich habe jetzt Rauch aus meinen Ohren ... Ich gebe auf ... ;-) – ysap

Antwort

0

Kamera Rotation quaternions kann definiert werden.

Wenn Sie die Quaternion verfügbar haben, können Sie den Tonhöhenwinkel begrenzen, indem Sie jedes Mal überprüfen, ob der Drehwinkel plus/minus des tatsächlichen Winkels in Ordnung ist.

Ich glaube, Sie Umwandlung vermeiden können, wenn Sie Ihre Grenzen als

+cos(supLim/2) < (Q.w + P.w) < -cos(infLim/2) 

gesetzt Als Cosinus eine stetige Funktion ist dies funktionieren soll.

Wenn Sie den Code schreiben könnten, den Sie tatsächlich verwenden, können wir vielleicht ein wenig mehr helfen.

+0

Hmm .. ist nicht A die Achse der Rotation? Wie kann ich dann die Quaternion auf die Tonhöhengrenze setzen, wenn sie die Grenzen überschreitet? – Wert

+0

A ist definitiv die Achse als Einheitsvektor. Selbst wenn "Position" ein Tippfehler wäre, würde die Antwort nur funktionieren, wenn Q bereits nur die Tonhöhendrehung war, nicht die gesamte Kamerarotation C. Wir versuchen, Q aus C zu extrahieren. – SuperElectric

1

Die Tonhöhe ist nur eine Komponente der vollen Rotation. Wenn Sie also über Ihre Rotation nachdenken möchten, sollten Sie die Tonhöhe getrennt speichern, möglicherweise mit Euler-Winkeln.

Die Konvertierung in Euler - Winkel und zurück, wenn Sie die Bewegung beschränken müssen, funktioniert möglicherweise nicht so gut, da Sie sich an das letzte Bild erinnern müssen (falls vorhanden), um zu sehen, ob Sie das Limit überschritten haben welche Richtung.

Wie ich es sehe, ist der Hauptpunkt der Quaternionen, dass Sie sich nicht mit solchen Grenzen herumschlagen müssen. Alles funktioniert einfach ohne Singularitäten. Warum genau willst du die Tonhöhe begrenzen?

2

Wenn die Kamera nie einen Roll hat (wie es in vielen Spielen üblich ist, wie Ego-Shooter), dann ist die Lösung einfach. Wenn es Roll gibt, dann ist ein zusätzlicher Schritt involviert. Ich fange mit dem an, was zu tun ist, wenn es keinen Roll gibt, und generalisiere die Lösung, was zu tun ist, wenn es da ist.

Lassen Sie qc die Kameradrehung sein. Lassen Sie qy eine Drehung mit der gleichen Gier wie qc, aber mit Null-Steigung. Wenn es keine Rolle, ist die Kameradrehung eine Gierdrehung um eine Teilung Drehung folgt:

qc = qp * qy 

Wir können die Tonhöhe Rotation qp als Dreh erholen sich von qy zu qc:

qp = qc * qy^-1 

Der Trick Dann soll qy konstruiert werden, damit wir es in die obige Gleichung einfügen können, um nach qp zu suchen. Sei vc der Einheitsvektor, der aus dem Objektiv der Kamera oder dem "Vorwärtsvektor" hervorgeht. Sei vy derselbe Vektor, aber projiziert auf die horizontale Ebene und normalisiert. Schließlich sei v0 der Vorwärtsvektor, wenn die Kameradrehung qc die Identitätsdrehung ist. Die Drehung, die v0 in vy dreht, ist die Gierdrehung. Der Winkel kann gegeben werden als:

yaw = asin(Norm(cross(v0, vy))) 

Die entsprechende Gierdrehung ist:

qy = { cos(yaw/2), up * sin(yaw/2) } 

Wo „oben“ ist der Einheitsvektor in der Aufwärtsrichtung, auch bekannt als die Achse für Gierrotationen. Stecke dies in qp = qy^-1 * qc oben, um die Tonhöhenquaternion qp zu erhalten.Schließlich erhält die Steigungswinkel von qp als:

pitch = 2*asin(Dot(right, [qp[1], qp[2], qp[3]])) 

Wo „rechts“ ist der Einheitsvektor in der richtigen Richtung, auch bekannt als die Achse für die Pitch-Rotationen.

Wie gesagt, die Dinge werden komplizierter, wenn die Kamera auch Roll hat, aber die allgemeine Strategie ist die gleiche. Sie formulieren die Kameradrehung als Produkt von Rotationskomponenten und isolieren dann die gewünschte Komponente (in diesem Fall die Tonhöhe). Sie können beispielsweise wenn die Eulersche Sequenz zu definieren, verwenden „Pitch“ die gemeinsame Gier Nick-Roll-Sequenz ist, definieren Sie qc wie:

qc = qr * qp * qy 

wir eine Variable qx definieren können die kombinierte Nick- und Roll Drehungen sein :

qx = qr * qp 

wir schreiben jetzt qc wie:

qc = qx * qy 

wir wissen bereits, wie durch zurückzuverfolgen die Schritte für qx in dieser Form zu lösen, die wir oben für qp zu lösen verwendet. Neufestlegung der Definition für qx, erhalten wir:

qp = qr^-1 * qx 

Wir haben gerade für qx gelöst, so dass für das Feld Drehung qp zu lösen, brauchen wir nur die Rolle qr. Wir können es wie zuvor mit Vektoren konstruieren. Sei vc wieder der Vorwärtsvektor. Die Rolle wird eine Rotation um diesen Vektor sein. Sei vu der Aufwärtsvektor der Kamera (in Weltkoordinaten) und vu0 sei der Aufwärtsvektor der Kamera mit Null-Roll. Wir können vu0 konstruieren, indem wir den globalen up-Vektor auf die Ebene senkrecht zu vc projizieren und dann normalisieren. Die Rolldrehung qr ist dann die Drehung von vu0 nach vu. Die Achse dieser Drehung ist der Vorwärtsvektor vc. Der Rollwinkel ist

roll = asin(Dot(vc, cross(vu0, vu))) 

Die entsprechende Quaternion ist:

qr = { cos(roll/2), forward * sin(roll/2) } 

Wo "Vorwärts" ist die Achse der Walzenumdrehungen.

0

kann ich ein wenig spät, um die Partei sein, aber das ist, wie ich es gelöst:

 // "Up" = local vector -> rotation * Vector3.UnitY 
     // "Forward" = local vector -> rotation * Vector3.UnitZ 
     // "Right" = local vector -> rotation * Vector3.UnitX 

    public void Rotate(Vector3 axis, float angle) 
    { 
     if (LerpRotation) 
     { 
      RotationTarget *= Quaternion.FromAxisAngle(axis, angle); 
     } 
     else 
     { 
      Rotation *= Quaternion.FromAxisAngle(axis, angle); 
     } 
     //Locking the Pitch in 180° 
     float a = Vector3.CalculateAngle(Vector3.UnitY, Up); 
     float sign = Math.Sign(Forward.Y); 
     float delta = (float)Math.PI/2 - a; 
     if(delta < 0) 
      Rotation *= Quaternion.FromAxisAngle(Right, delta * sign); 
    }