3D DirectX10 Free Look Camera (Timer based)

Introduction:

Okay so I promised I’d write a tutorial on writing a simple free look vector based camera, this tutorial doesn’t only apply to DirectX10 but to pretty much any graphics API. We want to keep things simple initially so the simplest possible camera we can implement short of a first person style camera is a free look camera (without roll) so basically only two degrees of freedom: left/right and up/down, we are also going to implement some basic movement controls forwards/backwards and Strafe Left/Right.

Now the shape of this frustum is controlled by the projection that we we to employ, there are several types of projective but chances are you will end up using a perspective projection. Now the projection is attached to our virtual camera (think of the projection as a camera lens), to orient ourselves in a scene we need to know the position that we are viewing the scene from, the direction in which we’re looking and which way is up (shown in figure 2), now this up direction is very important for movement calculations and obviously to display the scene the right way up 😉 These three parameters are called the eye position, the view vector and the up vector.

Figure 2 - Virtual Camera

For a free look camera, we need the up vector to be in the direction of the camera top, if we were doing a first person camera where the viewer is stuck on the ground then the up direction will always be towards the sky. So in conclusion to view a scene, you need a virtual camera positioned somewhere in a scene (pos/up/view) with some sort of lens (projection).

Now I need to quickly explain what happens to an object’s vertices when it travels through the rendering pipeline. When a object’s vertex gets sent down the rendering pipeline it has a position in its own model space, this position is now moved to wherever the object is required to be in the world by multiplying the vertex by the world matrix for the object. Now if you run through the world you would think of it as the world standing still and the camera moving, but for now it is beneficial to think of it in the opposite way, that the camera is stationary and its the world that’s moving. Cause mathematically that is exactly whats happening.

The camera never moves, the worlds position is just adjusted to give that impression. So we’ve positioned our object in the world, the next step it move it according to our view point, if we want to looking to the left of the object, we need to move the entire world to the right, so we multiply the vertex position with the view matrix to move it as necessary. Remember that even though each object will have its own world matrix, they will all use the exact same view matrix. The last step that needs to be applied to each vertex is the projection matrix. In a real camera, the lens affect the image displayed and can possible apply distortion to the scene (e.g. a fisheye lens), our virtual lens (the projection matrix) does exactly that, the vertices get transformed into clip space according to the view frustum we have set. After our vertices are completely transformed they are then sent to the rasterization stage of the pipeline, where they are assembled into primitives and flattened into a 2D image.

Order of vertex transformations that occur in the Vertex Shader

The Camera Body: The Container Class

Figure 4 - Camera Class

Figure 4 shows the class structure for our camera, source code is below, we have the two matrices: view and projection, we have function to position the camera, change the view and so on…

The Camera Lens: Creating the Projection Matrix

Lets do the easiest thing first, creating the camera lens or projection matrix. Almost all graphical APIs have a helper functions to create this matrix for you. To create a left handed perspective projection in D3D10, the function you need is: D3DXMatrixPerspectiveFovLH( outputMatrix, FOV, aspectRatio, nearPlane, farPlane)… The code to create this matrix is:

I’m setting the projection matrix’s FOV using a degree parameter, since I only do it once and its easier to visualize a degree based FOV its fine, the helper function requires radians, so I simply convert to radians using the constant defined in the class header file. The aspect ratio is the ratio of width:height for your display window. If your window is 640×480 then the aspect ratio is 640:480 -> 4:3 or numerically 1.3333333333…

The Camera: Creating the View Matrix

Since we are using a camera with only 2 degree of freedom (axes of movement) ->heading (left/right) and pitch (up/down), we store the direction in which we’re facing as a angle on each axis. These angles are stored as radians. The final view vector is calculated from these two variables and original position of the view and the up vector is adjusted accordingly. This mean that to get an accurate up vector we need to initialize the camera with correct values when we create it, so that the up vector is valid once the view changes. so the constructor for the camera class is:

This always initializes our camera at the position (0,0,0), facing the positive z axis. *NOTE: we will discuss the movement toggles later on.We also set our default view and up vectors to (0,0,1) and (0,1,0) respectively. We will use these default vectors to calculate the new view vector from the heading and pitch parameters when the view changes. So how do we adjust the view? Well we simple modify the heading and pitch parameters and run the updateView() function which we’ll define later. Just to be safe we add hard limits to the values of the heading and pitch (0~2pi) just so over the course of the program we don’t overflow the variables.

We also said we would be adding movement controls: forwards, backwards and strafing. To move we will need to know which direction is forward ( hint: the view vector 😉 ) and which way is directly right, backwards and left are obviously in the direct opposite direction. We now have the two unit vectors forward and strafeRight which also need to be updated as soon as the view changes. As we said forward is easy as it is the view vector and backward is the negative forward vector. How do we calculate the right vector? Well we have the forward direction and the up direction so right should be ortogonal (90 degrees) to both of them (ie the x axis, if forward is the z axis and u is the y axes), hm, we have two vectors and need to get another vector orthogonal to them, if we think back to basic calculas and we suddenly remember that the cross product of two vectors gives us an orthogonal vector, wiki the cross product for more details. We also need to unsure that the movement vectors are unit vectors to ensure consistant movement.

To create the new view and up vectors, we first create a rotation matrix which will rotate any point/vector by the degrees on each axis that we specify, we then rotate the default view and up vectors (du & dv) to get the new view and up vectors. Easy Peasy…

We now have all the info necessary to create our updateView() function.

This simply positions the camera on a location and set the view according to the heading/pitch params specified.

Moving our Camera

There are two ways to move the camera, incrementally step by by, i.e. on each update (frame) we move the camera by a fixed amount but there is a massive problem with this, variable framerates! Imagine if we moved the camera by 1 unit every frame, on a midrange PC getting around 45 frames per second we will be moving at 45units a second, but now comes a guy with a monster machine and runs the game at 75 frames per second and our movement speed has increased as well, this is unacceptable and would ruin any game. I dont know if any of you remember how quake3’s physics was reliant on the FPS, and so guys getting higher FPS rates could run faster and jump further than guys with lower FPS rates. So how do we correct this? We need to ensure a fixed movement rate based on time and not frames, so we do just that, we make movement timer based! We firstly add movement toggles, which get activated when a player pushes a movement key, and deactivated when he releases it, this is necessary to ensure that if a player pushes both forward and back the camera doesnt move and then when he releases a single key it immediately starts moving in the still active direction.

The to work out the distance moved between updates, we create a simple timer and check the elapsed time in seconds, we then multiply this time by the movement rate per second. Both of these functions are shown below:

This update function is what gets called from the main game loop, also the reason why updateView() is declared private. On each frame update, you will process input, set the movement toggles appropriately, run the adjustHeadingPitch() function and then run the update() function to create the new view matrix.

NOTE: The timer used is based on my silly encapsulation of the tick timers in the windows API, look at my High Resolution Timers entry.

Conclusion

So there we have it, a super simple super basic free look camera implementation in less than a 100 lines of code. In the next blog entry I will be covering how to give the camera mouse control using Windows Raw Input. With those two tutorials you will have all the tools to create a basic input system for your game!!!

Hey, I tried following your tutorial and implementing what you’ve taught me into a small program; on start, the camera seems to shake and the rotation becomes uncontrollable. Do you know why this is happening? How do I fix it?

Hi there! This is my first visit to your blog!
We are a group of volunteers and starting a new project in a community in the same niche.
Your blog provided us valuable information to work on.
You have done a wonderful job!