Wie kann ich eine Kamera um ihren Zielpunkt kreisen lassen?

18

Ich zeichne eine Szene, in der sich die Kamera frei im Universum bewegt. Die Kameraklasse verfolgt die Ansicht (oder Lesen ) Punkt, um die Position der Kamera, und die Aufwärts - Vektor. Diese Vektoren / Punkte werden dann an gluLookAt übergeben.

Schwenken und Zoomen sind nahezu trivial zu implementieren. Aber ich bin eine Drehung um die Suche nach Blick auf Punkt viel eher ein Problem zu sein. Ich möchte eine Funktion Camera.rotate schreiben , die 2 Winkel nimmt, eine , die sich dreht nach oben / unten und eine , die dreht sich nach links / rechts entlang einer imaginären Kugel , die über die zentriert Blick auf Punkt.

Gibt es eine einfache Möglichkeit, dies zu tun?

Ich habe (kurz) über Quaternionen gelesen, aber ich wollte sehen, ob es angesichts des relativ einfachen Aufbaus meiner Szene eine einfachere Lösung gibt.

Luke
quelle
Haben Sie irgendetwas in Ihrer Toolbox, um einen Punkt um den Ursprung zu drehen, wenn eine Achse und ein Winkel vorgegeben sind?
Sam Hocevar
Nichts anderes als mein loses Verständnis von Quaternions, nein. Je mehr ich mir das anschaue, desto mehr denke ich, dass Quaternions die Antwort sein könnten. Ich bin jedoch nicht sicher , wie die zur Berechnung Achse x, y und z - Werte zu verwenden , in den Formeln Quaternion.
Luke
Ich werde Ihnen nicht sagen, dass Quaternionen nicht der richtige Weg sind. Sie sind eine sehr gute Lösung für Ihr Problem. Sie benötigen jedoch eine Quaternion-Klasse und Möglichkeiten zur Interaktion mit GL und GLU, und ich bin der Meinung, dass Sie zuerst versuchen sollten, sich mit Transformationsmatrizen vertraut zu machen. Andere mögen anderer Meinung sein.
Sam Hocevar
Überlegen Sie, in welcher Reihenfolge Sie die Rotationen ausführen. Das Anwenden von Rotationen für das Bewegen in den Weltraum oder für das Bewegen in den Kameraraum ist unterschiedlich
Charlie

Antworten:

25

Was Sie verlangen, heißt Arcball-Rotation. Quaternionen sind nur dann die einfache Lösung, wenn Sie wissen, wie sie funktionieren. Sie können dies jedoch auch ohne Quaternionen erreichen.

Voraussetzungen

Wissen Sie, wie man Objekte im Allgemeinen dreht? Angenommen, Sie haben ein Objekt am Ursprung. Wissen Sie, wie Sie es drehen (Hinweis: Multiplizieren Sie mit einer Rotationsmatrix)? Wenn ja, dann gehe ich davon aus, dass Sie wissen, was passieren wird, wenn Sie das Objekt zuerst übersetzen und dann drehen?

Sie müssen wissen, wie man eine Rotationsmatrix aus der Winkelachse berechnet.

Lösung

  • Holen Sie sich die Kamera nach oben und die richtigen Vektoren. Beachten Sie, dass sie normalisiert werden sollten.
  • Liefert den Vektor vom Fokuspunkt zur Kamera (camPosition - Focus). Dies ist der Vektor, den Sie drehen werden. Nennen wir diesen camFocusVector .
  • Entscheiden Sie, um wie viel Sie sich in Gier- / Neigungsrichtung in Bezug auf die Kamera drehen möchten
  • Erstellen Sie zwei Rotationsmatrizen. Die erste Rotationsmatrix wird der Einsatz bis der Kamera wie die Achse und Gierwinkel , dass Sie sich entschieden. Die zweite Rotationsmatrix wird die Verwendung direkt von der Kamera wie die Achse und Pitch Winkel dass Sie sich entschieden.
  • Drehen Sie nun den camFocusVector mit den neuen Rotationsmatrizen. Dies ist nun Ihre neue Position der Kamera relativ zum Ursprung. Wir möchten natürlich, dass es relativ zum Fokuspunkt ist ...
  • Fügen Sie die Fokuspunktposition zu camFocusVector hinzu . Dies ist jetzt die neue Position Ihrer Kamera. Übersetzen Sie Ihre Kamera entsprechend.
  • Bitten Sie die Kamera abschließend, sich auf das Fokusmessfeld zu konzentrieren, indem Sie Ihre lookAt () - Funktion aufrufen

Vorbehalte

Sie müssen nach bestimmten Fällen oder Besonderheiten Ausschau halten, bei denen Ihre Kamera nicht mehr funktioniert. Zum Beispiel gerade nach unten / oben schauen. Ich werde Sie herausfinden lassen, wie Sie damit umgehen sollen.

EDIT1: Neuberechnung der Orthonormalvektoren der Kamera

Sie kennen bereits die Richtung der Kamera ((cameraPos - focusPoint) .normalize ()). Angenommen, Ihre Kamera ist auf + Y (oder die aktuelle Aufwärtsachse Ihrer Welt liegt bei Ihnen). Jetzt einfach die Richtung mit dem Pfeil nach oben kreuzen , um das richtige zu finden . Getan? Nee! Ihr Aufwärtsvektor ist nicht mehr orthogonal zu den beiden anderen. Um das Quer zu beheben rechts mit Richtung und Sie Ihren neuen bekommen oben .

Notiere dass der Gram-Schmidt is really what should be used to orthonormalize vectors.

Beachten Sie auch hier die Vorsichtsmaßnahmen, da dies in einigen Fällen nicht funktioniert (die Richtung ist beispielsweise parallel nach oben ).

Samaursa
quelle
Note that the right vector can be obtained using normalize(up ^ camFocusVector) (or its opposite if left-handed).
sam hocevar
Looking good so far, worked beautifully for left/right rotation (I have the up vector so that's easy). What does the '^' mean in your comment @SamHocevar? Is that cross product? Also, how can I recompute the up vector once I've made the translations?
Luke
@Luke: Check my EDIT1
Samaursa
1
@Samaursa Thank you very much. Your solution works perfectly, and I learned a lot in the process!
Luke
2
this is an EXCELLENT answer, thank you very much for your explanation. In my case, I wanted the camera to only rotate about the target point in the X-Y plane, and so after doing all the calculations, I always set the cameraRight.z to 0 and then calculated the cameraUp vector. This gave the desired effect. Just thought of sharing
codemonkey
1

What you need is a typical ArcBall camera, which is basically a camera that keeps a target location and allows you to move the camera in a "spherical" way around that target.

It's in XNA but IIRC I've used this implementation before, and it worked quite well:

http://roy-t.nl/index.php/2010/02/21/xna-simple-arcballcamera/

David Gouveia
quelle
That implementation appears to only move directly along the right vector, which will approximate an arcball for small values of amount. He's also moving the LookAt point, as where I want to move the camera (close, but subtly different). I believe Samaursa has provided the simplest complete way of achieving this.
Luke
Thank you for your feedback. I must admit that I used this implementation a bit as a "blackbox" but I did not notice any problem. To clarify were you perhaps talking about the MoveCameraRight/MoveCameraForward methods? Those methods were added in order to pan the camera around, but are not part of the Arcball interface. If you want to rotate the camera around the target, you simply change the Yaw or Pitch properties.
David Gouveia
Sorry, you're right, those are panning methods. I didn't notice how he set a dirty flag for the matrix when yaw and pitch were changed.
Luke
0

Here's my code for rotating around a point, found myself reusing it a lot.

float distance;      // Straight line distance between the camera and look at point

// Calculate the camera position using the distance and angles
float camX = distance * -sinf(camAngleX*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));
float camY = distance * -sinf((camAngleY)*(M_PI/180));
float camZ = -distance * cosf((camAngleX)*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));

// Set the camera position and lookat point
gluLookAt(camX,camY,camZ,   // Camera position
          0.0, 0.0, 0.0,    // Look at point
          0.0, 1.0, 0.0);   // Up vector
Stephen Tierney
quelle
1
That's basically the way I did it initially. There are many issues with doing it this way (at least for me). Basically this implementation rotates only about 2 fixed axes. Let's say you rotate up nearly to the north pole. Then rotate right. You'll find yourself spinning in a tiny circle rather than following the right vector of the camera all the way around the globe.
Luke
Now that you mentioned that, I guess there are two different ways to look at the problem. In my application I used the ArcBall camera to rotate around a target island on the sea, and if I used 3 axes of freedom it would look plain wrong (such as seeing the island upside down or sideways).
David Gouveia
How do I get the camera angles here?
rafvasq
0

This very simple algorith to achieve that is pretty awesome:

Being P the center point about you want to rotate (the "look at"or "target" point):

translate(-P)

rotate horizontal
rotate vertical

translate(P)

I used it and its nice.

Source found at sister-site stackoverflow: /programming/287655/opengl-rotating-a-camera-around-a-point

diosney
quelle