Simple OpenGL Keyboard and Mouse FPS Controls

Note: This was written in January 2011 – I just never posted it, but I’d already uploaded the video to YouTube and someone asked for the code, so here it is, in all its fixed-pipeline glory ;)

Update – September 2013: I took these camera controls and wrapped them up into a Camera class in a later post which you can find here: http://r3dux.org/2012/12/a-c-camera-class-for-simple-opengl-fps-controls/. When I did this I wasn’t used to GLM (the OpenGL Mathematics library) so I just rolled my own Vec3 class – you can happily substitute glm::vec3’s if you’d like, and in fact I’d recommend it. Cheers!


I’m working on my OpenGL skills (or lack thereof) at the moment, and wanted to implement some 3D movement controls kinda of like a FPS with clipping off, so I read some chapters of the hallowed OpenGL SuperBible and did some googling, where I came across Swiftless‘ camera tutorials (Part 1, Part 2, Part 3) which gave me a really good start (Thank you, Swiftless!) on how to manipulate the ModelView matrix so we can move around a 3D scene, only it wasn’t quite perfect…

Strange things would happen like you’d look vertically downwards (i.e. directly down the negative Y axis), then you’d push forward – and yeah, you’d move “down”, but you’d also move “forward” at the same time (oh, and I’m putting things like “down” and “forward” in quotes because these concepts are all relative to your viewing orientation – not because I’m trying to be “sarcastic” or anything =P)

Anyways, I had a play with it and sorted it out after spending some time looking at the graphs for trigonometric functions and doing a little bit of off-setting and range-limiting as required. Check it out:

It actually looks quite a lot better running live than in the video due to mis-matched frame-capture rates and the like, but you get the idea =D

Full source code is available after the jump.

Cheers!

Source Code:
Note: Requires the following libraries: GL, GLEE, GLFW, freeGLUT (or GLUT). Also, this code contains a wrong-headed amount of global variables and isn’t in the slightest bit object-oriented. Feel free to encapsulate the camera class and all related functions at your leisure ;)

39 thoughts on “Simple OpenGL Keyboard and Mouse FPS Controls”

  1. Hi,

    Thanks for the code. I used your keyboard and mouse input code in my program but the mouse is stationary in the middle of the screen and won’t move way up or down. Nothing happens when I press the keyboard too. Any pointers as to what I might be doing wrong and how I can tweak your code to work for me?

    1. It sounds like something’s off with the mouse and keyboard callback registration, which should occur with these lines in the main:

      The mouse cursor is supposed to be in the dead-centre of the screen and invisible, because the way we handle mouse movement is to calc how far from the centre of the screen the mouse has moved per frame (i.e. + or – horizontally (x-axis) and + or – vertically (y-axis) ), and then modify the ModelView matrix accordingly so you actually “look” in different directions. The mouse cursor then gets set back to the dead-centre of the window after each frame where we detect some cursor movement.

      I’ve dug out some example code from when I was learning keyboard and mouse handlers for you. Once you can get those to work, you should be fine for the FPS controls:
      GLFWKeyboardHandlerTest.zip
      GLFWMouseHandlerTest.zip

      Hope this helps.

      Update: I should add that as far as I’m concerned these mouse and keyboard handlers work perfectly. I just don’t know if they’ll work for you. They should, but who knows… Could be something specific to your setup causing issues.

      1. Thank you so much for your prompt response and detailed explanations. It helps me learn more. Thank you. I’ll take a look at the sample codes and revisit this code again. Hopefully, I will be able to sort it out. Thanks again.

        1. Hi,
          I managed to get the keyboard code working in my program. As it turns out, there were some changes I needed to make in my code which I over looked. I’m working on the mouse code now but I have a question. I know you can use both glut and glfw functions in one program. That is how mine is. Is it possible for me to use glut functions for the keyboard and mouse interactions instead of glfw functions? Will my program work or I have to stick with glfw functions?

          1. I can’t say I’ve tried it, but you should be able to use GLUT keyboard & mouse handlers without any issues – certainly sounds reasonable. Give it a whirl! =D

    1. I can give you my Linux Code::Blocks project if that’s what you mean, but the OpenGL library (libGL.so etc) comes as part of the graphics driver package.

      If you really want the C::B project let me know and I’ll upload it.

  2. @r3dux, I wonder about glfwSwapInterval() (apparently I just see that there’re just two options to set 1, 0 not merely a number or some other values, Am i right about this ?) whether how can we’re sure it will be lock down to 60Hz or 60 fps. I believe it’s too much for the system with this restriction. If I want the game to run only at 30fps (i don’t think it will relate with Hz no more, 30Hz no good for monitor), how can I do that ?

    I found Glut really flexible on this as its underlying system won’t strict automatically to some setting of fps.

    1. When glfwSwapInterval is enabled (1), then drawing is locked to the vertical refresh rate of your screen, whether that’s 50Hz, 60Hz, 75Hz, 85H or whatever. So if your program draws a frame, then it has time to spare before the next frame, it’ll just wait.

      When glfwSwapInterval is disabled (0), then the program will run as fast as it possibly can – once the program has drawn a frame, it moves right onto to the next frame without worrying about weather drawing at this point in the display’s refresh might cause page-tearing or anything.

      These are your two built-in options.

      The third option, which we need to implement ourselves, can be to lock our program to a specified refresh rate by working out how many milliseconds we want each frame to take (i.e. 60fps = 1000 / 60 = 16.6667ms), and then in our main loop we:

      1. Get the current system time (frameStart time)
      2. Do stuff and draw the frame,
      3. Get the current system time (frameEnd time),
      4. Calculate the frameDraw time (which is frameEnd – frameStart),
      5. If the frameDraw time is > 16.667ms draw the next frame, otherwise, if the frameDraw time is < 16.667ms, sleep for (16.667 - frameDraw time)ms

      To do this, you can use code like this:

      Hope this helps.

  3. Firstly – thanks for this post, it’s helped me understand a lot of what’s involved :)

    However, as Glee no longer seems to be available, how would I go about running this code without it?

    Any help would be greatly appreciated!

    1. You’re welcome =D

      GLee’s still alive and kicking as far as I’m aware – you can get it from the GLee site at: http://elf-stone.com/glee.php

      I actually stopped using GLee a little while after this as some aspects were a little bit buggy and instead changed to GLEW (GL Extension Wrangler), which you can find at: http://glew.sourceforge.net/. There are examples on how to use it on the site, or if you wanted you could take a look at any of the projects I’ve used GLEW in (http://r3dux.org/tag/glew/), for example this one: http://r3dux.org/2010/11/2d-c-openglglfw-basecode/ (take a look near the bottom of the post).

      Hope this helps!

      1. Thanks again for your reply. I ended up comment out some code and things are running (for now!) so happy days :)

        I’m now attempting to implement a simple ray picking system into my game. I’m following this guide: http://schabby.de/picking-opengl-ray-tracing/

        “Note that cameraLookAt is the 3D point where the camera looks at (as used on glLookat), cameraPosition is the current position of the camera in world space and cameraUp is the up vector of the camera.”

        I know what to use as cameraPosition, but what variables in your code should I use for the camera’s focus? (cameraLookAt)?

        Thanks again!

  4. #include // No need to link to GL/gl.h
    #include // Include OpenGL Framework library
    #include // Include FreeGLUT so we can easily draw spheres and calculate our viewing frustrum

    Can I ask where can i get this library?

      1. ya~ i look up to the internet and add some header files already, then i got a new problem :

        1>d:\my documents\documents\visual studio 2010\projects\hw3\hw3\counter_strike\counter_strike\main.cpp(612): error C2065: ‘GLEE_GLX_SGI_swap_control’ : undeclared identifier

        if (GLEE_GLX_SGI_swap_control)
        {
        cout << "Extension found: GLX_SGI_swap_control (vsync can be used)." << endl;
        glfwSwapInterval(1);
        }
        else
        {
        cout << "Extension NOT found: GLX_SGI_swap_control (vsync cannot be used)." << endl;
        glfwSwapInterval(0);
        }

        what is the problem?\

        tks for helping

        1. All that code’s doing is checking whether there’s an extension available which will allow us to use vsync, and then setting vsync to be on or off. I wouldn’t worry about it – just remove the code entirely, or just call glfwSwapInterval(0); or gfwSwapInterval(1); to try to disable/enable vsync to your chosen setting.

          Also, I probably wouldn’t use GLee, so just strip out everything GLee related (just the stuff in the GLee init section). If you really need OpenGL extensions, which this code doesn’t, use GLEW instead.

  5. Hello again,

    Got ray picking working in the end :)

    A (hopefully more simple!) question: I’m making a simple portal remake using your FPS controls as above. Lets say portal “a” is the one you walk into, and “b” is the one you walk out of. I’ve drawn 4 walls in my game. I’ve attached a value to each as a “centerPoint”. When I emerge from portal b, I set the rotation of the camera to the same rotation as the nearest wall (really the nearest centerPoint). However, the limit of the camera to 180 and -180 seems to be affecting this and it doesn’t work sometimes.

    I would really appreciate it if you had the time to get back to me.

    Thanks again for putting your time into this site!

    1. Sorry for the delay in getting back to you – eventful weekend (unfortunately not in a good way).

      Okay, so we’re setting camera rotations (really, the camera yaw around the Y axis) – so when you hit one portal and are teleported to the location of the linked portal, you’ll want to set the camera position to be the target portal coordinates, and the cam rotation to be the rotation of the portal (assuming the front of the portal is “facing outwards” – otherwise add or remove 180 degrees to the portal rotation and set as the new cam rotation).

      You say that it “doesn’t work sometimes” – like how? What happens? Post some snippets of code if it’ll help.

      To be honest, the camera controls as implemented were never meant to be used for anything too flash, which is why they weren’t encapsulated into a class or anything. But I knackered my foot last Friday so had to take it easy for the day, which gave me a change to write the FPS controls as a proper Camera class. I’ll post that up shortly – maybe it’ll help.

      1. Thanks again for your reply. Sorry to hear your weekend didn’t go too well!

        My wall class constructor is: (xPos,yPos,zPos,xRot,yRot,zRot,width,height). I have 4 walls:
        //”Front” wall (in front of camera at spawn)
        -600.0f , -50.0f, -600.0f, 0.0f, 0.0f,0.0f, 1200.0f,200.0f
        //”Back” Wall
        600.0f, -50.0f, 600.0f, 0.0f, 180, 0.0f, 1200.0f,200.0f
        //”Left” Wall
        -600.0f, -50.0f, 600.0f, 0.0f, 90, 0.0f, 1200.0f,200.0f
        //”Right” Wall
        600.0f, -50.0f, -600.0f, 0.0f, 270, 0.0f, 1200.0f,200.0f

        Player walks into portalA. The following code is executed (pseudo-code for the sake of your eyes!):
        camPos = portalB.pos;
        camRot = nearestWall(portalB.pos).rot //NearestWall returns the nearest Wall object to portalB, and the rotation of this wall is assigned to the camera.

        This works fine for “left” and “right” walls, but portals on the “front” and “back” walls don’t function correctly (my camera ends up staring 180 degrees the wrong way)

        Thanks again, I look forward to the Camera class :)

        1. Murphy’s law – I have solved the problem after all :) Here is what I used:

          camPos = portalB.pos;
          Vector3f newRot = nearestWall(portalB).rot;
          if (newRot.y == 180.0){
          newRot.y = 360.0;
          }
          if (newRot.y == 0.0){
          newRot.y = 180.0;
          }
          camRot = newRot;

    1. Thanks!

      The source highlighting plugin I use updated not so long ago and it’s become sluggish, but I don’t see how you can struggle to copy and paste a few pages of text, let along needing regex to do it. This is actually a bug in the Firefox rendering engine (as there’s no such slowdown in Chrome or IE), but as I wasn’t particularly keen on the colour-banding anyway I’ve added some CSS to disable it.

      Also, “#sthash.XSmg9l2h.dpuf”? This doesn’t appear anywhere on this page, or on the YouTube video page – so I can only imagine it must be something to do with your machine.

      Hope you found the code useful, even if it might have been a pain to copy and paste.

      1. Oh wow, I see what you mean now… I just went to copy and paste a snippet of code from an article I wrote ages back and I got the exact same stupid-ass behavior putting all the code on the same line and with that #sthash.blah.dpuf stuff…

        Turns out the ShareThis plugin is trying to keep track of all text copied and pasted from the site – which is fucked up and bullshit. Disabled.
        Source: http://www.mybloggingtricks.com/2013/03/fix-for-text-ending-with-sthash.html

        Sorry about that, I had no idea a plugin update had introduced that new ‘feature’.

  6. Hey, Im having trouble when running this code. Everything works fine except mouse handling. When I move with my mouse to rotate the camera scene is rendered somehow laggy, its not smooth as in the video. Do you have any idea why?

    1. Not really, no – it should be nice and smooth. Maybe try tweaking the vertMouseSensitivity and horizMouseSensitivity values in the handleMouseMove function and see if that helps (higher values mean less sensitive – so you have to move the mouse a greater distance to look around). If that doesn’t work try modifying the following code:

      To read:

      Maybe that’ll help…

      1. That did not help. The problem is that if I move my mouse as fast as I usually do, scene renders strangely. It looks like camera does not move continuously and its movement is snatchy. But if I move mouse really slow and sensitive theres no problem. Well except the fact that its annoying and view angle is changin slow.

  7. Hi there! Just wanted to pop in and say *thank you* for this example, it was precisely what I needed to get my bearings with cameras. Keep up the great work!

    1. Glad you found it useful!

      GLFW 2 was the most recent version when I wrote this a few years back, GLFW3 is now the current version so I’ve ported it to that. Can post if you’re interested.

      Also, if you port to GLUT feel free to sling a link here in case it’ll help out anyone looking for simple camera controls w/ GLUT.

      Cheers! =D

  8. > Can post if you’re interested.

    Yes, that could be useful, thanks. What I attached in mouse.cpp would actually be enough, don’t really care about the planets that much, simplicity is more important here.

    1. GLFW3 mouse and keyboard handling example:

  9. Hi,

    I use your code exactly the same way but when I move it moves only so far. It turns out that

    is failed for me.

Leave a Reply

Your email address will not be published.