A Simple Third-Person Camera

Published November 13, 2001 by Andrew Corrigan, posted by Myopic Rhino
Do you see issues with this article? Let us know.
Advertisement
Note: Before reading this article you should understand first-person movement, the kind seen in games like Quake. If you are unfamiliar with what I am talking about, click here to learn from NeHe tutorial #10 on loading and moving through a 3-D world. You only need to know the moving through the 3-D world part.

The third-person camera is used in video games such as Super Mario 64 or Max Payne. When I was trying to figure out how to calculate the camera's position, I remembered back to earlier this year in pre-calculus, when my math teacher described an alternative coordinate system known as the polar coordinate system. It works by specifying the distance from the origin or pole, or [font="Times New Roman"]r[/font], and the angle between the polar axis and the ray that contains the described point, [font="Times New Roman"]q[/font]. Here is an example of a polar graph. The graph is in radians. In the case that you forgot [font="Times New Roman"]p[/font] radians = 180 degrees. The rays coming out of the pole in the middle are different angles. The circles represent the different distances from the pole.

Now think about a third-person camera.
  • It should be a set distance from a certain subject. This set distance could of course change if desired.
  • It should also be a certain amount along the circumference of a circle that has that subject as its center. The position is based on the subject's rotation. Polar graphs happen to perfectly represent where your camera should be. Now that you have realized this, there are four things that you will need to determine:
    1. The camera's distance from the subject, a.k.a. [font="Times New Roman"]r[/font]. You can decide for yourself how far away it is that you want the camera, other variables depend on this value.
    2. The camera's position. We are only worrying about x and z. How you calculate this is too easy. You do need to variables one and four to calculate this though.
    3. The camera's y-axis or yaw rotation.
    4. The amount the camera is around the circumference of the imaginary circle going around the subject. In more mathematical terms, [font="Times New Roman"]q[/font]. This explanation is important so I am putting it in bold and explaining it before any other variable. If the polar axis were in the same place as the positive y-axis (90 degrees) than to find this amount you would just add 180 degrees to the amount of the subject's rotation. However the polar axis is on the positive x-axis. Therefore we must add an additional 90 degrees making the total 270 degrees. Now in OpenGL, you are looking down the negative z-axis. So when you calculate the z-position, you subtract the 270 degrees, rather than adding it.
    Variable number one you decide. It really should just be any number greater than zero. However I am certainly not stopping you from experimentation.

    These next two formulas will calculate variable two, the camera's position. To convert from polar to rectangular coordinates (x, y) you use the incredibly convenient formulas:
    • x = [font="Times New Roman"]r [/font]* cos([font="Times New Roman"]q[/font])
    • y = [font="Times New Roman"]r [/font]* sin([font="Times New Roman"]q[/font]) I could probably explain why this works, but for our purposes it is really not important. If you wish to know look here. These converted to rectangular coordinates, but we are using 3-D coordinates, so we switch y with z.

      Here's some code that calculates the camera's position:

      float camerax = cameradist * cos((yrot + 270.0f) * M_PI / 180) + xpos;
      float cameraz = cameradist * sin((yrot - 270.0f) * M_PI / 180) + zpos;
      There are a few things to note about that code.
      1. The trigonometry functions only take radians, so you must multiply by PI/180 to convert from degrees to radians.
      2. Because the subject moves around, you need to add the respective subject coordinate to the camera's coordinate.
      3. Remember to add or subtract 270 degrees.
      Mathematically when you add 270 degrees to an angle using the cosine function, you are using sine. And when you subtract 270 degrees from an angle using the sine function, you are using cosine. If you don't understand this shortcut, either look at the code below or don't worry about it because it's unimportant.

      (Shortcut)

      float camerax = cameradist * sin((yrot) * M_PI / 180) + xpos;
      float cameraz = cameradist * cos((yrot) * M_PI / 180) + zpos;
      Variable three, in our case, is easy. We are always going to be looking at the subject's rear, so the camera's yaw rotation will be equal to the subject's yaw rotation.

      Variable four was already explained because of how important it was. Now on to drawing using this camera whose position and rotation you just figured out. This section is OpenGL specific.

      Assume that you declared DrawObject() and DrawScenery(). Also assume you defined cameradist, and calculated yaw, camerax, and cameraz.

      // First I like to draw the subject. Basically you are just drawing the subject directly in front of you
      glTranslatef(0.0f, 0.0f, -cameradist);
      DrawObject();

      //You reset the view and now any scenery or world that you want to draw is drawn.
      glLoadIdentity();
      glRotatef(360.0f - yaw, 0.0f, 1.0f, 0.0f);
      glTranslatef(-camerax, 0.0f, -cameraz);
      DrawScenery();
      I think that you now have an idea of how to use polar coordinates. If you have any specific questions please post them to the thread linked at the bottom of this page. For more information on the polar coordinate system check out the resources below. Good luck!

      -Andrew Corrigan
      [email="atcdevil@optonline.net"]atcdevil@optonline.net[/email]
Cancel Save
0 Likes 1 Comments

Comments

Artorias2718

I think your explanation above is starting to make sense. The one thing that seems a bit off is your explanation of the shortcut:

gif.latex?%5Ccos%28%5Cfrac%7B%7D%7B3%5Cpi%7D2%20-%20%5Ctheta%29%20%3D%20%5Csin%28%5Ctheta%29

gif.latex?%5Csin%28%5Cfrac%7B%7D%7B3%5Cpi%7D2%20-%20%5Ctheta%29%20%3D%20%5Ccos%28%5Ctheta%29

I believe this should be:

gif.latex?%5Ccos%28%5Cfrac%7B%7D%7B%5Cpi%7D2%20-%20%5Ctheta%29%20%3D%20%5Csin%28%5Ctheta%29

gif.latex?%5Csin%28%5Cfrac%7B%7D%7B%5Cpi%7D2%20-%20%5Ctheta%29%20%3D%20%5Ccos%28%5Ctheta%29

February 11, 2018 09:26 PM
Artorias2718

Wait... is that why you negate the cameraX and cameraZ values in your glTranslatef call above? Because

gif.latex?%5Ccos%28%5Cfrac%7B3%5Cpi%7D%7B2%7D%20-%20%5Ctheta%29%20%3D%20-%5Csin%28%5Ctheta%29

gif.latex?%5Csin%28%5Cfrac%7B3%5Cpi%7D%7B2%7D%20-%20%5Ctheta%29%20%3D%20-%5Ccos%28%5Ctheta%29

February 11, 2018 10:54 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement