OpenGL FPS Camera

Welcome back to our 3rd chapter in this OpenGL tutorial series. If you followed our tutorials up to this point I’m pretty sure you asked yourself when are we going to move around in our virtual scene. In this tutorial we will learn how to do a basic FPS (First Person Shooter) camera style.

Here are the keypoints of this tutorial:

  1. Yaw, Pitch, Roll.
  2. Get view matrix from rotations and translation
  3. Get direction and strafe from the view matrix.
  4. Get mouse and keyboard input
  5. Using quaternions.

Note 1: Although it’s written in  C++, you should be able to write this camera code in any language or engine.

Note 2: I used GLM library for math, but these concepts works with any math library / your own math library.

We will use the following methods in our code:

  • UpdateView
  • GetViewMatrix
  • KeyPressed
  • MouseMove

1. Yaw, Pitch, Roll

Yaw, pitch, and roll (also called Euler angles) can be seen as elemental rotations about the axes of a coordinate system in a 3D environment. By combining these three rotations, any orientation can be achieved.

Yaw Pitch Roll

Yaw Pitch Roll (source)

  • Yaw is the rotation around the Y-axis (0 , 1,  0). Imagine that your head is the camera right now, yaw is the rotation from left to right of your head. Just turn your head from left to right and experiment :).
  • Pitch is the rotation around the X-axis (1, 0, 0). Imagine that you head is the camera right now, pitch is the up and down rotation.
  • Roll is the rotation around the Z-axis (0, 0, 1). This is when you tilt your head. Usually roll is not used in a FPS camera. However you can find it in some games or applications. You can find it in free camera scenarios like flight simulators.

Equations for each rotation are presented in this tutorial


2. Get view matrix from rotations and translation

Until now we knew how to create the view matrix using just the LookAt function. I wrote about the view matrix in this tutorial. However we can create the view matrix from rotations and translation. Keep in mind that we are using GLM library which is Row Major, meaning that translation is going to be on the last row. The view matrix will look something like this:

View Matrix

View Matrix created with rotations and translation using GLM library. Note that order of multiplication matters. In FPS camera, roll can be omitted.

We can create a method called UpdateView to compute our View Matrix. Let’s imagine that we have a class called CameraFPSEuler where: viewMatrix, eyeVector, roll, pitch, and yaw are member variables. We will see later the whole implementation for this.

//this method is used in our class to update the view
void CameraFPSEuler::UpdateView()

 //roll can be removed from here. because is not actually used in FPS camera
 glm::mat4 matRoll  = glm::mat4(1.0f);//identity matrix; 
 glm::mat4 matPitch = glm::mat4(1.0f);//identity matrix
 glm::mat4 matYaw   = glm::mat4(1.0f);//identity matrix

 //roll, pitch and yaw are used to store our angles in our class
 matRoll  = glm::rotate(matRoll,  roll,  glm::vec3(0.0f, 0.0f, 1.0f));
 matPitch = glm::rotate(matPitch, pitch, glm::vec3(1.0f, 0.0f, 0.0f));
 matYaw   = glm::rotate(matYaw,  yaw,    glm::vec3(0.0f, 1.0f, 0.0f));
 //order matters
 glm::mat4 rotate = mattRoll * matPitch * matYaw;

 glm::mat4 translate = glm::mat4(1.0f);
 translate = glm::translate(translate, -eyeVector);

 viewMatrix = rotate * translate;

In this method we create our main rotation matrix by multiplying 3 rotation matrices given by angles and axis as discussed above. After that we get the translation matrix from eyeVector. Finally we multiply rotation matrix with translation matrix to get our View matrix. Roll is not used in FPS camera so you can remove it from equation.

3. Get direction and strafe from the view matrix

Now that we know a few things about rotations we need WASD keys to move the camera around in our scene.

  • We need to keep track of the direction of the camera to walk forward and backward (W and S keys).
  • We need to find strafe direction to go left and right (A and D keys)

Luckily the view matrix, presented in this tutorial, makes our lives simple by keeping all the information we need to get direction and strafe.


We can take the view matrix created by UpdateView method from above and extract forward and strafe vectors to compute the new camera postion (eyeVector) and update the view matrix once again.

//Just return the view matrix
glm::mat4 CameraFPSEuler::GetViewMatrix() const
  return viewMatrix;

//when we press key
void CameraFPSEuler::KeyPressed(const unsigned char key)
  float dx = 0; //how much we strafe on x
  float dz = 0; //how much we walk on z
  switch (key)
    case 'w':
      dz = 2;

    case 's':
      dz = -2;
    case 'a':
      dx = -2;

    case 'd':
      dx = 2;
  //get current view matrix
  glm::mat4 mat = GetViewMatrix();
  //row major
  glm::vec3 forward(mat[0][2], mat[1][2], mat[2][2]);
  glm::vec3 strafe( mat[0][0], mat[1][0], mat[2][0]);
  const float speed = 0.12f;//how fast we move

  //forward vector must be negative to look forward. 
  //read :
  eyeVector += (-dz * forward + dx * strafe) * speed;
  //update the view matrix


4. Get mouse input

We already dealt with WASD input in the above method. Now we need to rotate our camera using the mouse input. Everytime we move the mouse, we have to update pitch and yaw angles and of course update our view matrix. But let’s update this only when mouse is pressed, to have some control over our application. Based on rotations definitions for this FPS camera :

  • When we move the mouse left and right we have to upgrade the Yaw angle.
  • When we move the mose up and down we have to upgrade the Pitch angle.

We need only two methods for mouse movement. One to update yaw and pitch when the mouse is moved (drag), and another one to see when the mouse is pressed and released:

void CameraFPSEuler::MouseMove(int x, int y, int width, int height)
  if (isMousePressed == false)
  //always compute delta
  //mousePosition is the last mouse position
  glm::vec2 mouse_delta = glm::vec2(x, y) - mousePosition;

  const float mouseX_Sensitivity = 0.25f;
  const float mouseY_Sensitivity = 0.25f;
  //note that yaw and pitch must be converted to radians.
  //this is done in UpdateView() by glm::rotate
  yaw   += mouseX_Sensitivity * mouse_delta.x;
  pitch += mouseY_Sensitivity * mouse_delta.y;

  mousePosition = glm::vec2(x, y);
void CameraFPSEuler::MousePressed(int button, int state, int x, int y)

 if (state == GLUT_UP)
   isMousePressed = false;
 if (state == GLUT_DOWN)
   isMousePressed = true;
   mousePosition.x = x;
   mousePosition.y = y;

That’s all. I think that you should be able to write this code in any language or engine you want. This is just a basic FPS camera however you can make it more fancy by adding acceleration, constrain it by angle to look only 180 degrees, etc.  Next we will see how to integrate this camera in our engine.

5. Using Quaternions

To keep our tutorials short, quaternions are presented in the next tutorial. See you there.

Follow me on Twitter and stay tuned for next tutorials.

Tagged under:
blog comments powered by Disqus