19
\$\begingroup\$

I'm drawing a scene where the camera freely moves about the universe. The camera class keeps track of the view (or look at) point, the position of the camera, and the up vector. These vectors/points are then passed into gluLookAt.

Pan and zoom are nearly trivial to implement. However, I'm finding rotation about the look at point to be much more of an issue. I want to write a function Camera.rotate that takes 2 angles, one that rotates up/down and one that rotates left/right along an imaginary sphere that is centered about the look at point.

Is there an easy way to do this?

I've (briefly) read about quaternions, but I wanted to see if there was an easier solution given the relatively simple construction of my scene.

\$\endgroup\$
4
  • \$\begingroup\$ Do you have anything in your toolbox to rotate a point around the origin, given an axis and an angle? \$\endgroup\$ Dec 8, 2011 at 15:55
  • \$\begingroup\$ Nothing other than my loose understanding of Quaternions, no. The more I'm looking at this, I think Quaternions might be the answer. However, I'm unsure how to calculate the axis x, y, and z values to use in the Quaternion formulas. \$\endgroup\$
    – Luke
    Dec 8, 2011 at 16:01
  • \$\begingroup\$ I won't tell you that quaternions are not the way to go. They are a very good solution to your problem. But you will need a quaternion class and ways to interact with GL and GLU, and I feel that you should first try to get familiar with transformation matrices. Others may disagree. \$\endgroup\$ Dec 8, 2011 at 16:12
  • \$\begingroup\$ consider what order you do the rotations in. applying rotations for moving to world space or for moving to camera space differs \$\endgroup\$
    – Charlie
    Jun 8, 2018 at 10:35

4 Answers 4

27
\$\begingroup\$

What you are asking for is called Arcball rotation. Quaternions are the easy solution only if you understand how they work. You can achieve the same without quaternions however.

Pre-requisites

Do you know how to rotate objects in general? Let's say you have an object at the origin. Do you know how you rotate it (hint: multiply by some rotation matrix)? If yes, then I am assuming you know what will happen if you translate the object first and then rotate it?

You must know how to calculate a rotation matrix from angle-axis (easy as pie, look at the myriad of equations online, a lot of them give you the code as well)

Solution

  • Get the camera's up and right vectors. Note that they should be normalized.
  • Get the vector from the focus point to the camera (camPosition - Focus). This is the vector that you are going to be rotating. Let's call this camFocusVector.
  • Decide how much you want to rotate in yaw/pitch in relation to the camera
  • Create two rotation matrices. The 1st rotation matrix will use the up of the camera as the axis and yaw angle that you decided. The 2nd rotation matrix will use the right of the camera as the axis and pitch angle that you decided.
  • Now rotate the camFocusVector with the new rotation matrices. This is now your new position of the camera relative to the origin. We of course, want it to be relative to the focus point...
  • Add the focus point position to camFocusVector. This is now your camera's new position. Translate your camera accordingly.
  • Finally, ask the camera to focus on the focus point by calling your lookAt() function

Caveats

You will have to lookout for certain cases or singularities at which your camera will stop working. Looking straight down/up for example. I will let you figure out how to deal with those.

EDIT1: How to recalculate the orthonormal vectors of the camera

You already know the direction of the camera ( (cameraPos - focusPoint).normalize() ). Now assume that your camera's up is +Y (or w/e your world's current up axis is... that is up to you). Now simply cross the direction with the up to get the right. Done? Nope! Your up vector is no longer orthogonal to the other two. To fix that, cross right with direction and you get your new up.

Note that the Gram-Schmidt is really what should be used to orthonormalize vectors.

Again, take a note of the caveats as this will fail to work in some cases (direction is parallel to up for example).

\$\endgroup\$
5
  • \$\begingroup\$ Note that the right vector can be obtained using normalize(up ^ camFocusVector) (or its opposite if left-handed). \$\endgroup\$ Dec 8, 2011 at 17:23
  • \$\begingroup\$ 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? \$\endgroup\$
    – Luke
    Dec 8, 2011 at 21:18
  • \$\begingroup\$ @Luke: Check my EDIT1 \$\endgroup\$
    – Samaursa
    Dec 8, 2011 at 21:35
  • 1
    \$\begingroup\$ @Samaursa Thank you very much. Your solution works perfectly, and I learned a lot in the process! \$\endgroup\$
    – Luke
    Dec 9, 2011 at 12:53
  • 2
    \$\begingroup\$ 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 \$\endgroup\$
    – codemonkey
    Oct 31, 2012 at 15:21
2
\$\begingroup\$

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: https://stackoverflow.com/questions/287655/opengl-rotating-a-camera-around-a-point

\$\endgroup\$
1
\$\begingroup\$

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/

\$\endgroup\$
3
  • \$\begingroup\$ 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. \$\endgroup\$
    – Luke
    Dec 9, 2011 at 12:59
  • \$\begingroup\$ 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. \$\endgroup\$ Dec 9, 2011 at 15:37
  • \$\begingroup\$ 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. \$\endgroup\$
    – Luke
    Dec 12, 2011 at 14:41
0
\$\begingroup\$

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
\$\endgroup\$
3
  • 1
    \$\begingroup\$ 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. \$\endgroup\$
    – Luke
    Dec 9, 2011 at 12:43
  • \$\begingroup\$ 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). \$\endgroup\$ Dec 9, 2011 at 15:46
  • \$\begingroup\$ How do I get the camera angles here? \$\endgroup\$
    – rafvasq
    Nov 11, 2017 at 1:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .