I know you are all probably terribly angry with me for making this a separate tutorial, but honestly, I just haven’t had time to sit down and redo all of my math work again to get this half of it done until now. Hopefully, the quality and ease of use of this Camera in the future will make up for the long wait you all had to endure
Step 1: Brushing up on your trig
For starters, since this will be the tutorial that uses the most actual math out of almost everything I can think of that will go into this engine (besides particle effects and some more complicated shaders much later), I decided I would put together a bit of a section on trig for those of you who are new to it or a little rusty.
First of all (and forgive me if this seems very Jr. High but it is neccessary to know), all of the concepts of trigonometry start out with some basic ratios that refer to the lengths of the legs on triangles. For our purposes we will only need to use right triangles. These ratios are referred to as sine, cosine, and tangent, and are abbreviated sin, cos, tan respectively. Here is a picture explaining the ratios and which parts of the triangle they talk about.

On our right triangle we label each side (2 legs, and the hypotenuse) with the letters a,b, and c, and we label the angles opposite each side with its corrosponding greek letter alpha for a, beta for b, and gamma for c. Now, with these letters and symbols we can easily take our easy to remember formulas (SOH CAH TOA) and convert them into simple ratios to represent the values of sin, cos, and tan.
Using this knowledge it’s time to start designing some equations that we will use with our camera. Let’s start with the 3rd person equations and then we will move on tho add the 1st person ones later. I will try to put illustrations to this information, but it is slightly difficult to model 3D trig, especially when you aren’t the greatest artist in the world
Step 2: Putting together some 3rd person math
The first thing we must remember about a 3rd person camera is that the object we are looking at is stationary (relative to the camera position anyway) and that the camera simply rotates around it at some set distance (which will also be esaily changed later). Once we realize this, and we have a look at how a sphere is defined, we see that the cameras location around the 3d object can be specified by 3 simple pieces of information: the distance from the object (radius), the location on the circle going around the object (horizontal rotation), and the location on the circle going around in a perpendicular direction to the first one. Here is a picture that will hopefully show this a bit better.

Once the camera has these three pieces of information, we can easily figure out all of the information we need to know to let the engine know what the current state of our camera is. A few things we need to mention here are that the target vector doesn’t need to change for our third person camera unless the object we are looking at moves, in which case we can change it, and that our up vector will only need to ever be (0,1,0) and (0,-1,0) depending on whether our camera is upside down or now (which is easy enough to figure out later.)
So all we have left to figure out is the camera’s position relative to our object which can then be translated by the objects own position in the 3D world to get the camera’s absolute position. To do this, we will need to use our simple trig formulas three times, once for each axis of positioning.
The first axis I started with to figure out these equations in the first place was the y-axis because some of the changes in position moving around that direction causes both the x and z values to be shortened a bit, and we can easily take that into account if we do the y rotation first. The equation for finding the y component of our camera’s position is found as follows: (refer to the image for more explaination)
sin(vRot) = y1/radius cos(vRot) = r1/radius After simple multiplication: y1 = radius*sin(vRot) r1 = radius*cos(vRot)
Now using the vertical rotation stored in our camera class and some simple trig, we have found the y1 component of our camera’s position and r1, which we will use as a new radius for the rest of our math since looking from the top down the camera will have moved closer to the center because of its movement vertically along the circle. All we have to do for the rest of the math is to use the same methods we did for finding the y1 component and get our final x1 and z1.
cos(hRot) = x1/newRadius sin(hRot) = z1/newRadius After simple multiplication: x1 = newRadius*cos(hRot) z1 = newRadius*sin(hRot)
Now if we plug these values into the position vector of our camera class and update the device, the scene will be drawn as if we were looking through this new position at the object in focus. Here is the code we will be adding to accomplish all of this
public void UpdatePosition() { // (radius * Math.Cos(vRotation)) is the temporary radius after the y component shift position.X = (float)(radius * Math.Cos(vRotation) * Math.Cos(hRotation)); position.Y = (float)(radius * Math.Sin(vRotation)); position.Z = (float)(radius * Math.Cos(vRotation) * Math.Sin(hRotation)); // Translate these coordinates by the target objects spacial location position += target; }
A lot shorter than you thought it would be isn’t it? Now that we have a way of converting rotation around an object to 3D position in space, we need a way to change that rotation, and the best way to accomplish this in my opinion is by adding some code to let the movement of the mouse control this. Add a simple rotate function to the camera that looks like this:
public void Rotate(float h, float v) { hRotation += h; vRotation += v; // We will do this after each type of camera movement UpdatePosition(); }
We also need a function to let us zoom in and out, which is actually just as simple as our rotation function and looks like this:
public void Zoom(float dist) { radius += dist; if(radius < .01f) radius = .01f; UpdatePosition(); }
Step 3: Putting it all to work
The very last thing to do to test out our new third person camera is to add a bit of input code to our Demo so the mouse movements will be sent to the camera and we can watch our code in action. Here are the changes that have to be added to the Demo class.
using System.Drawing; public class HMDemo { static Point lastMouseLoc = new Point(); public static void Main() { demo1.MouseMove += new MouseEventHandler(demo1_MouseMove); demo1.MouseWheel += new MouseEventHandler(demo1_MouseWheel); // Existing code } static void demo1_MouseMove(object sender, MouseEventArgs e) { Point delta = new Point(e.X – lastMouseLoc.X, e.Y – lastMouseLoc.Y); lastMouseLoc = new Point(e.X, e.Y); demo1.MyCamera.Rotate((float)delta.X * .05f, -(float)delta.Y * .05f); } static void demo1_MouseWheel(object sender, MouseEventArgs e) { demo1.MyCamera.Zoom(-e.Delta * .01f); } }
With this little snippet added in there you should be able to rotate the mouse around and watch the camera move. You may want to change the default values in the camerea class itself for the target (I made mine (0,0,0) and the radius (10)) just so you can get a better idea of how the camera moves so far.
If you put together and compiled everything we have so far you will notice that the camera seems to be only showing the tiger face up and when we go around where th camera should be upside-down it just switches it. This is because we aren’t also switching the up-vector when the angle of the camera is too great. Here are the lines we will add to UpdatePosition() to fix that:
// Keep all rotations between 0 and 2PI hRotation = hRotation > (float)Math.PI * 2 ? hRotation – (float)Math.PI * 2 : hRotation; hRotation = hRotation < 0 ? hRotation + (float)Math.PI * 2 : hRotation; vRotation = vRotation > (float)Math.PI * 2 ? vRotation – (float)Math.PI * 2 : vRotation; vRotation = vRotation < 0 ? vRotation + (float)Math.PI * 2 : vRotation; // Switch up-vector based on vertical rotation upVector = vRotation > Math.PI / 2 && vRotation < Math.PI / 2 * 3 ? new Vector3(0, -1, 0) : new Vector3(0, 1, 0);
That’s all we really need to create a great third person camera. You will probably notice a slight kick at the beginning of rotating with the mouse like we are, but that is because of our method of input and not the camera itself. Now we have a nice camera we can position and move around to get a better look at what we are playing with in our engine. We will add a lot of functions to this camera in the future, but for now we will just stick with this simple 3rd-Person rotating version.