Sign in to follow this  

OpenGL Camera and Viewing Transformations

Recommended Posts

First of all, I am aware that there is no such entity called camera in OpenGL. The eye is located at the origin looking down the negative z-axis with the up vector being the positive y-axis (please correct me if I am wrong here or anywhere).

So here's the deal, I am trying to make a class that will handle the view of the scene using keyboard input. Just like in an aircraft, there is thrust which causes the camera to move forward(if we are sitting in a cockpit). Let us say, I am using W and S keys to control the thrust of this hypothetical camera and A and D keys to control my heading(the direction at which I am looking) and Up and Down keys to control the Pitch and Left and Right to control Roll.

If you have ever played Descent, there are actually ten ways to control the ship. Thrust forward, backward.. slide left, right, slide up and down, Pitch up and down, and roll left and right.

This is what I am trying to do here. By using basic opengl transformation functions I want to build my own camera class that I can control the view the scene very easily and how I want to view it.

Here is the code so far that I was able to do:
#include <SDL.h>
#include <GLEW\glew.h>
#include <math.h>
#include "Misc.h"
const GLfloat INCREMENT_HEADING = 0.1f;
const GLfloat INCREMENT_PITCH = 0.1f;
const GLfloat INCREMENT_ROLL = 0.1f;
const GLfloat INCREMENT_FORWARD = 1.0f;
// From Right to Left, in Bits, the keys are
// right left down up d a s w
class EyeCam
GLfloat Angle_Heading;
GLfloat Angle_Pitch;
GLfloat Angle_Roll;
Uint8 KeyState;
GLfloat eyeX, eyeY, eyeZ;
EyeCam(GLfloat eyeX, GLfloat eyeY, GLfloat eyeZ, GLfloat aimX, GLfloat aimY, GLfloat aimZ);
void onEvent(SDL_Event* event);
void update();


#include "EyeCam.h"
#include <iostream>
EyeCam::EyeCam(GLfloat eyeX, GLfloat eyeY, GLfloat eyeZ, GLfloat aimX, GLfloat aimY, GLfloat aimZ)
this->eyeX = eyeX;
this->eyeY = eyeY;
this->eyeZ = eyeZ;
Angle_Heading = Misc::toDegrees(atan2f((eyeX - aimX), (eyeZ - aimZ)));
GLfloat base = sqrt(pow(eyeZ-aimZ, 2) + pow(eyeX - aimX, 2));
Angle_Pitch = Misc::toDegrees(atan2f( -(eyeY - aimY), base));
//Angle_Roll = 0.0;
KeyState = 0x00;

void EyeCam::onEvent(SDL_Event* event)
if (event->type == SDL_KEYDOWN)
if (event->key.keysym.sym == SDLK_RETURN)
std::cout << "X: " << eyeX << '\n';
std::cout << "Y: " << eyeY << '\n';
std::cout << "Z: " << eyeZ << "\n\n";
std::cout << "Heading: " << Angle_Heading << '\n';
std::cout << "Pitch: " << Angle_Pitch << '\n';
//std::cout << "Roll: " << Angle_Roll << '\n';
if (event->key.keysym.sym == SDLK_w)
KeyState = KeyState | 0x01;
if (event->key.keysym.sym == SDLK_s)
KeyState = KeyState | 0x02;
if (event->key.keysym.sym == SDLK_a)
KeyState = KeyState | 0x04;
if (event->key.keysym.sym == SDLK_d)
KeyState = KeyState | 0x08;
if (event->key.keysym.sym == SDLK_UP)
KeyState = KeyState | 0x10;
if (event->key.keysym.sym == SDLK_DOWN)
KeyState = KeyState | 0x20;
if (event->key.keysym.sym == SDLK_LEFT)
KeyState = KeyState | 0x40;
if (event->key.keysym.sym == SDLK_RIGHT)
KeyState = KeyState | 0x80;
else if (event->type == SDL_KEYUP)
if (event->key.keysym.sym == SDLK_w)
KeyState = KeyState & 0xFE;
if (event->key.keysym.sym == SDLK_s)
KeyState = KeyState & 0xFD;
if (event->key.keysym.sym == SDLK_a)
KeyState = KeyState & 0xFB;
if (event->key.keysym.sym == SDLK_d)
KeyState = KeyState & 0xF7;
if (event->key.keysym.sym == SDLK_UP)
KeyState = KeyState & 0xEF;
if (event->key.keysym.sym == SDLK_DOWN)
KeyState = KeyState & 0xDF;
if (event->key.keysym.sym == SDLK_LEFT)
KeyState = KeyState & 0xBF;
if (event->key.keysym.sym == SDLK_RIGHT)
KeyState = KeyState & 0x7F;
void EyeCam::update()
if (KeyState & 0x01) // w
eyeX = eyeX - INCREMENT_FORWARD * sin(Misc::toRadians(Angle_Heading));
eyeY = eyeY + INCREMENT_FORWARD * sin(Misc::toRadians(Angle_Pitch));
eyeZ = eyeZ - INCREMENT_FORWARD * cos(Misc::toRadians(Angle_Heading));
if (KeyState & 0x02) // s
eyeX = eyeX + INCREMENT_FORWARD * sin(Misc::toRadians(Angle_Heading));
eyeY = eyeY - INCREMENT_FORWARD * sin(Misc::toRadians(Angle_Pitch));
eyeZ = eyeZ + INCREMENT_FORWARD * cos(Misc::toRadians(Angle_Heading));
if (KeyState & 0x04) // a
Angle_Heading = Angle_Heading + INCREMENT_HEADING;
if (KeyState & 0x08) // d

Angle_Heading = Angle_Heading - INCREMENT_HEADING;
if (KeyState & 0x10) // Up
Angle_Pitch = Angle_Pitch + INCREMENT_PITCH;
if (KeyState & 0x20)
Angle_Pitch = Angle_Pitch - INCREMENT_PITCH;
if (KeyState & 0x40) // Left
Angle_Roll = Angle_Roll + INCREMENT_ROLL;
if (KeyState & 0x80) // Right
Angle_Roll = Angle_Roll - INCREMENT_ROLL;
glRotatef(-Angle_Pitch, 1.0, 0, 0);
glRotatef(-Angle_Heading, 0, 1.0, 0);
glTranslatef(-eyeX, -eyeY, -eyeZ);
glRotatef(-Angle_Roll, 0.0, 0.0, 1.0);


The constructor of the class takes the same arguments as gluLookAt() function, except for the Up vector (I've not implemented it yet in my class). The position of the eye in x, y, z coordinates and a point of aim in x, y, z coordinates.

In the constructor, I am calculating two angles, the Heading and the Pitch by using spherical trigonometry and then using these angles to rotate the view accordingly. Please note that, I am not using gluLookAt() function at all in my class.

Then, by using keyboard commands, I am just making changes to the angles to adjust my aim and calculating eye coordinates to adjust my position.

Now, the problem I am having here is that, If I am originally looking down the -ve z- axis and my up is +ve y axis. then I know to adjust my heading I have to Rotate the scene around the y - axis, if I want to adjust pitch I have to Rotate around the x - axis and if I want to adjust roll I have to Rotate around the z-axis. Hence, I am using equation of circle with heading angle to calculate my eyeX and eyeZ and pitch angle to calculate y - axis. But unfortunately, this will only work till I stay in the XZ plane. Any change in the plane, I will not get the desired results.

For example, at the start if I make a 90 degree Roll such that my up now is -ve x-axis, then if I want to Pitch up relative to the camera, I have rotate around the y-axis. Originally I was rotating about the x-axis when roll was 0. Similarly, If I am looking down the -ve z-axis and then roll will perfectly fine because I am rotating around the +ve z axis, however, If I move the camera to aim at the +ve x-axis and then roll it will not work, in that case I have to rotate on the -ve x-axis to make the roll work. I was able to solve this problem by changing the glRotate function for Roll

glRotatef(Angle_Roll, 0, 0, 1);
glRotatef(Angle_Roll, sin(toRadians(Angle_Heading), 0, cos(toRadians(Angle_Heading));

but what if I am looking down the -ve or +ve y-axis, this again will not work as desired and also I try to change the heading then it will automatically affect the roll transformation.

I hope that I am not confusing you guys too much with the my description, please correct me if I am wrong in my assumptions.

So, the bottom line question is, what I need to do make this camera work in every orientation so that it pitchs, rolls, and turns correctly relative to its orientation.

I am not very skilled with mathematics, but I have studied trigonometry and equations of curves and shapes. Please let me know If I need to cover more mathematics in order to implement what I want.

Any input will be appreciated, Thanks.

Share this post

Link to post
Share on other sites
If you are up for it, I recommend storing and manipulating your camera's orientation as a [url=""]quaternion[/url]. Especially if you are also implementing a roll for rotation, this will save you quite a bit of trouble. There are a few benefits of using quaternions:
- You gain the ability to Interpolate between two orientations, which is very valuable if you want to move your camera along a spline for instance.
- By not having separate angles, there are no "duplicate" poses (look up, and either rotate by yaw or roll).
- Concatenating rotations (say you want a camera fixed to an object, and you rotate the object) becomes a lot easier.

Regardless of what method of orientation you use, camera's will have some position and orientation in space. Combining them will give you the camera's transformation. To apply this to the scene, you will need to use the inverse of this transformation on the whole scene.
First imagine doing several rotations and translations on your camera. Then, as you "undo" each of those in the inverse order, but also apply them to your scene, you will end up with your camera back where it was, but your scene has moved back along with it. This is exactly what you want to achieve.

Let's take Euler angles as an example. In matrix form, you can view it like this:
Camera Transform = Txyz * Ry * Rp * Rr
where Txyz is the translation, and R denotes Rotation, yaw, pitch and roll. The inverse of this, is the following:
Inverse Transform = Rr[sup]-1[/sup] * Rp[sup]-1[/sup] * Ry[sup]-1[/sup] * Txyz[sup]-1[/sup].
Apply that to your scene, and you are done.

Share this post

Link to post
Share on other sites
IMHO one has to understand the concept of spaces. Statements like "looking along the negative z-axis", " rotating around the y axis", and "you'll end up with your camera back where it was" are somewhat meaningless without knowing the reference in use. Sometimes it becomes clear from the context, but often enough it doesn't do so.

E.g. when one applies the said inverse camera transformation (a.k.a. view transformation) to the entirety of objects including your camera, the scene doesn't really change. Instead, one is switching over to another reference system (usually called the view space) in which the camera is located at the origin and orientated normally. (Whether looking is done along the negative z-axis in view space or something else belongs to the projection matrix and clipping.)

When considering the concept of space, the questions of when to apply which transformation at what position in the pipeline becomes clear.

[quote name='Ignifex' timestamp='1345366628' post='4971044']
If you are up for it, I recommend storing and manipulating your camera's orientation as a [url=""]quaternion[/url]. ...
Only unit quaternions represent ure rotations, to be precise. This is important insofar that one need to normalize quaternions from time to time (not so often as rotation matrices need to be normalized, I agree).

[quote name='Ignifex' timestamp='1345366628' post='4971044']
- By not having separate angles, there are no "duplicate" poses (look up, and either rotate by yaw or roll).
A unit quaternion has 2 representations for each orientation, namely q and -q, so it isn't unique as well. Especially when doing interpolation one has the choice of following the short or the long arc (ignoring pathological cases here).

[quote name='Ignifex' timestamp='1345366628' post='4971044']
- Concatenating rotations (say you want a camera fixed to an object, and you rotate the object) becomes a lot easier.
Why this? Concatenation means to multiply quaternions on the one or matrices on the other hand. Spaces and order play their role regardless whether one uses quaternions or matrices.

IMHO especially the example "you want a camera fixed to an object" is less intuitive when using quaternions, because "fixed to an object" implies a fixed position, too. This can be expressed as a single homogenous matrix and a simple matrix product. Edited by haegarr

Share this post

Link to post
Share on other sites
I agree the concept of spaces is essential for a good understanding of how transformations work, especially in the case of view transformations where there are quite a few distinct spaces you have to understand (object space, world space, view/eye space, clip space).
IMO, there are many ways in which to view transformations. As you progress in your understanding of how these work, your view will likely change.
You might well be right that one should start by understanding spaces. How about reading something like [url=""]this[/url].

My earlier post was mainly an attempt to intuitively explain some of the core mechanics of transformations, without diving too deep into the maths behind it.
[quote name='haegarr' timestamp='1345371483' post='4971060']
Why this? Concatenation means to multiply quaternions on the one or matrices on the other hand. Spaces and order play their role regardless whether one uses quaternions or matrices.
This is mainly a comparison between quaternions and euler angles. Finding the euler angles of a concatination from two rotations is not very optimal. I couldn't think of a proper use case where concatenating euler angles makes sense though, instead of the matrices derived from them.

Euler angles are good for allowing a user to specify an angle, but are far less useful when applying these angles as transformations.
Matrices are the default approach for applying transformations.
Quaternions are useful for manipulating rotation, such as interpolation.

Share this post

Link to post
Share on other sites

As you suggested, I will take a look at quaternions, I never heard this term before.

As far as camera and inverse transformations are concerned, this is what I am trying to do here already, the knowledge that I have with Opengl and viewing transformations come from the red book.

From what I understand, there is no such thing called a 'Camera' in Opengl library. If you want view an object that is drawn and centered at the origin, then you can either use the gluLookAt(0, 0, +z, 0, 0, 0, 0, 1, 0) or insted you can use glTranslatef(0, 0, -z), both of these will have the same effect (for this case at least).

From what I have studied and understand, the function name " LookAt " is like a false advertisement. You are not actually looking somewhere in the scene, it just applies inverse transformations to the whole scene and you think that you are moving a camera in the scene when you are acutally just transforming the scene. But then again, I might be incorrect here and its a completely different debate.

In my class, I am doing a similar thing, taking vector input in euclidean space and then finding the appropriate angle of rotations of heading and pitch, and then apply the inverse of this when I am rotating about an axis and it works fine as I please.

The problem I am having, is that if you take a look at my code, as long you give the initial arguments such that your hypothetical camera is located at the XZ plane, the heading will work fine, however, If I pitch or Roll to 180 degrees, and then I apply my heading calculation, then they will seem to work in reverse order. If I give the input to turn left, it will turn right and vice versa, because I am still rotating around this +ve y-axis.

Please note that, when I was trying to implement this class, I was not thinking in terms of matrices, I was thinking in terms of these transformation commands (glRotatef and glTranslatef). Edited by uzipaz

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Announcements

  • Forum Statistics

    • Total Topics
    • Total Posts
  • Similar Content

    • By test opty
      Hi all,
      I'm starting OpenGL using a tut on the Web. But at this point I would like to know the primitives needed for creating a window using OpenGL. So on Windows and using MS VS 2017, what is the simplest code required to render a window with the title of "First Rectangle", please?
    • By DejayHextrix
      Hi, New here. 
      I need some help. My fiance and I like to play this mobile game online that goes by real time. Her and I are always working but when we have free time we like to play this game. We don't always got time throughout the day to Queue Buildings, troops, Upgrades....etc.... 
      I was told to look into DLL Injection and OpenGL/DirectX Hooking. Is this true? Is this what I need to learn? 
      How do I read the Android files, or modify the files, or get the in-game tags/variables for the game I want? 
      Any assistance on this would be most appreciated. I been everywhere and seems no one knows or is to lazy to help me out. It would be nice to have assistance for once. I don't know what I need to learn. 
      So links of topics I need to learn within the comment section would be SOOOOO.....Helpful. Anything to just get me started. 
      Dejay Hextrix 
    • By mellinoe
      Hi all,
      First time poster here, although I've been reading posts here for quite a while. This place has been invaluable for learning graphics programming -- thanks for a great resource!
      Right now, I'm working on a graphics abstraction layer for .NET which supports D3D11, Vulkan, and OpenGL at the moment. I have implemented most of my planned features already, and things are working well. Some remaining features that I am planning are Compute Shaders, and some flavor of read-write shader resources. At the moment, my shaders can just get simple read-only access to a uniform (or constant) buffer, a texture, or a sampler. Unfortunately, I'm having a tough time grasping the distinctions between all of the different kinds of read-write resources that are available. In D3D alone, there seem to be 5 or 6 different kinds of resources with similar but different characteristics. On top of that, I get the impression that some of them are more or less "obsoleted" by the newer kinds, and don't have much of a place in modern code. There seem to be a few pivots:
      The data source/destination (buffer or texture) Read-write or read-only Structured or unstructured (?) Ordered vs unordered (?) These are just my observations based on a lot of MSDN and OpenGL doc reading. For my library, I'm not interested in exposing every possibility to the user -- just trying to find a good "middle-ground" that can be represented cleanly across API's which is good enough for common scenarios.
      Can anyone give a sort of "overview" of the different options, and perhaps compare/contrast the concepts between Direct3D, OpenGL, and Vulkan? I'd also be very interested in hearing how other folks have abstracted these concepts in their libraries.
    • By aejt
      I recently started getting into graphics programming (2nd try, first try was many years ago) and I'm working on a 3d rendering engine which I hope to be able to make a 3D game with sooner or later. I have plenty of C++ experience, but not a lot when it comes to graphics, and while it's definitely going much better this time, I'm having trouble figuring out how assets are usually handled by engines.
      I'm not having trouble with handling the GPU resources, but more so with how the resources should be defined and used in the system (materials, models, etc).
      This is my plan now, I've implemented most of it except for the XML parts and factories and those are the ones I'm not sure of at all:
      I have these classes:
      For GPU resources:
      Geometry: holds and manages everything needed to render a geometry: VAO, VBO, EBO. Texture: holds and manages a texture which is loaded into the GPU. Shader: holds and manages a shader which is loaded into the GPU. For assets relying on GPU resources:
      Material: holds a shader resource, multiple texture resources, as well as uniform settings. Mesh: holds a geometry and a material. Model: holds multiple meshes, possibly in a tree structure to more easily support skinning later on? For handling GPU resources:
      ResourceCache<T>: T can be any resource loaded into the GPU. It owns these resources and only hands out handles to them on request (currently string identifiers are used when requesting handles, but all resources are stored in a vector and each handle only contains resource's index in that vector) Resource<T>: The handles given out from ResourceCache. The handles are reference counted and to get the underlying resource you simply deference like with pointers (*handle).  
      And my plan is to define everything into these XML documents to abstract away files:
      Resources.xml for ref-counted GPU resources (geometry, shaders, textures) Resources are assigned names/ids and resource files, and possibly some attributes (what vertex attributes does this geometry have? what vertex attributes does this shader expect? what uniforms does this shader use? and so on) Are reference counted using ResourceCache<T> Assets.xml for assets using the GPU resources (materials, meshes, models) Assets are not reference counted, but they hold handles to ref-counted resources. References the resources defined in Resources.xml by names/ids. The XMLs are loaded into some structure in memory which is then used for loading the resources/assets using factory classes:
      Factory classes for resources:
      For example, a texture factory could contain the texture definitions from the XML containing data about textures in the game, as well as a cache containing all loaded textures. This means it has mappings from each name/id to a file and when asked to load a texture with a name/id, it can look up its path and use a "BinaryLoader" to either load the file and create the resource directly, or asynchronously load the file's data into a queue which then can be read from later to create the resources synchronously in the GL context. These factories only return handles.
      Factory classes for assets:
      Much like for resources, these classes contain the definitions for the assets they can load. For example, with the definition the MaterialFactory will know which shader, textures and possibly uniform a certain material has, and with the help of TextureFactory and ShaderFactory, it can retrieve handles to the resources it needs (Shader + Textures), setup itself from XML data (uniform values), and return a created instance of requested material. These factories return actual instances, not handles (but the instances contain handles).
      Is this a good or commonly used approach? Is this going to bite me in the ass later on? Are there other more preferable approaches? Is this outside of the scope of a 3d renderer and should be on the engine side? I'd love to receive and kind of advice or suggestions!
    • By nedondev
      I 'm learning how to create game by using opengl with c/c++ coding, so here is my fist game. In video description also have game contain in Dropbox. May be I will make it better in future.
  • Popular Now