3. OpenGL 4 Matrices
Introduction
OpenGL 3.x and OpenGl 4.x have since deprecated and started removing all matrix operations as part of the OpenGL library, which I believe is a really good thing for the computer graphics community, but for beginners can make things a little difficult to get up and running at first. What this means if you are coming from the previous OpenGL tutorials, is that you can no longer use calls such as glTranslate or glRotate. Even glLoadIdentity and setting the gluPerspective is now redundant.
When it comes to computer graphics in 3D, you typically have a number of matrices that make up your final scene. They are the projection matrix, model matrix and view matrix. You can also go into the texture matrix and normal matrix, etc, but for simply positioning shapes in the world I will stick with the more basic matrices. OpenGL 2.x and prior combined the model and view matrices into the modelview matrix and used a stack to let us add transformations matrices to the current modelview matrix. We could then pop off the top of the stack to a previous matrix if needed.
Personally I prefer to use the separate matrices so that you don’t have to constantly monitor the one matrix, whilst also making it easier to use scene graphs and other scene management techniques. How you do this is up to you, but I am going to use multiple matrices.
Projection Matrix
The projection matrix is a 4×4 matrix that defines the 2D to 3D projection for a scene. This is often calculated by a pre-defined function, such as gluPerspective in previous versions of OpenGL. The library we are going to be looking at, provides a similar method.
View Matrix
The view matrix, which can also be known as the world matrix determines the position of the ‘camera’ in space. This can be thought of as a global matrix that affects everything and places everything relative to the location of the ‘camera’.
Model Matrix
The model matrix is a local matrix that affects models on a more discrete basis. For example, if you want to translate, rotate or scale a specific object you will use that objects local matrix or model matrix.
Luckily in the wake of OpenGL dropping support for its own matrices, a mathematics library has been developed to replace it, called GLM. GLM is short for OpenGL Mathematics and has been designed to replicate the matrix functions found in GLSL along with giving us the scale, rotate and translate methods we are used to from OpenGL 2.x and lower.
Installation is simple; once you unzip the file you download, find the folder name “glm” and copy it into your IDE’s header directory.
Once you have GLM installed and ready to use, move on to the coding section of this tutorial 😀
Coding
The very first thing we need to do to get GLM working in our OpenGL application is to include the relevant header files. So go and open up main.h and add the following lines at the end of the file:
// GLM include files #include <glm/glm.hpp> #include <glm/gtc/matrix_projection.hpp> #include <glm/gtc/matrix_transform.hpp>
Now we should be able to use glm functions, stored in the glm namespace. To access them will be done similar to glm::function_name unless you add the line:
using namespace glm;
From which you can then just call function_name.
Let’s set up the variables that will hold our matrices now. Open up opengl_3.h and in the private section of our class, created three variables, one for each of our matrices.
glm::mat4 projectionMatrix; // Store the projection matrix glm::mat4 viewMatrix; // Store the view matrix glm::mat4 modelMatrix; // Store the model matrix
Out of these three matrices, the projectionMatrix is the only matrix we will keep consistent throughout the entire application (of course, you can change this during your application if you are after a specific effect). So in our setupScene method, inside of opengl_3.cpp, we are going to create our projectionMatrix. To do so, we call a glm::perspective method, which works virtually identically to gluPerspective. It requires us to specify a fov (field of view) in degrees, followed by the aspect ratio for our window and finally the near and far planes for our scene. To do so, add the following line:
projectionMatrix = glm::perspective(60.0f, (float)windowWidth / (float)windowHeight, 0.1f, 100.f); // Create our perspective projection matrix
Now that isn’t so scary so far. And the following is hopefully just as nice to us. Everything else we will be changing in our C++ code will take place in the renderScene method, followed by modifying our vertex shader. Let’s continue with our opengl_3.cpp file for now. The first thing we are going to do is after we clear our color, depth and stencil buffers, we are going to set our view and model matrices. I am going to set the view matrix, to translate back 5 units into the scene. This is the equivalent to our old glTranslate(0, 0, -5). The view matrix is going to be just for kicks at the moment, as we have no geometry, but it will scale geometry by a half.
viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -5.f)); // Create our view matrix which will translate us back 5 units modelMatrix = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f)); // Create our model matrix which will halve the size of our model
After we have set these matrices, we then have to use them. To do so, we need to send them through to the shader that will be using them. In our code, we first bind our shader, just like we would in the GLSL tutorials. We then need to link to the location of the variables we will be using inside of the shader. This is the locations for the perspectiveMatrix, viewMatrix and modelMatrix.
int projectionMatrixLocation = glGetUniformLocation(shader->id(), "projectionMatrix"); // Get the location of our projection matrix in the shader int viewMatrixLocation = glGetUniformLocation(shader->id(), "viewMatrix"); // Get the location of our view matrix in the shader int modelMatrixLocation = glGetUniformLocation(shader->id(), "modelMatrix"); // Get the location of our model matrix in the shader
Once we have these locations stored, we can go ahead and send through our matrices using glUniformMatrix4fv, just like we would in previous versions of OpenGL if we wanted to play with matrices. GLM allows us to access our matrices to send through to OpenGL easily. So add the following code after our locations.
glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, &projectionMatrix[0][0]); // Send our projection matrix to the shader glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, &viewMatrix[0][0]); // Send our view matrix to the shader glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, &modelMatrix[0][0]); // Send our model matrix to the shader
Shader.vert
Now we will move onto our vertex shader so that we can put these variables to good use. Inside of our vertex shader, we need the three matrix variables. So to create those, we are creating 3 mat4 variables.
uniform mat4 projectionMatrix; uniform mat4 viewMatrix; uniform mat4 modelMatrix;
To use these matrices, you might remember a line similar to:
gl_Position = glModelViewProjectionMatrix * gl_Vertex;
Well in our new code, our line will be similar:
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(in_Position, 1.0);
Where in_Position is the equivalent to gl_Vertex.
To wrap up, that is all that is required to switch from the OpenGL 2.x and lower style of matrix use, to the new developer-managed OpenGL 3.x and higher style of matrix use. I will point out that this tutorial still won’t show anything more than a window on the screen. In the next tutorial we will finally be getting a square rendering on the screen. Well done so far!
Downloads
Visual Studio 2010 Project
PDF version
If you have any questions you can comment below or email me at swiftless@gmail.com
Hi, I would like to ask you, do you know how I could make any loaded model centered in front of camera? I was looking for info but could find decent one
Hello,
It seems that recent versions of GLM no longer include “matrix_projection.hpp” – I will see if I can figure out the resolution. In the mean time, do you happen to know what we need to do to update your tutorial to get it to work with the new versions of GLM?
Regards,
Christopher
Doh, I see earlier comments already address the issue mostly…
Now, to figure out why my square is only white…
I could not get this tutorial to compile until i donwloaded a previous version of glm, matrix_projection.hpp seems to be depreciated, i downloaded the august 2010 version of it to get the tutorial to compile; Just thought you might want to know
Check out some of the old(er) comments. Turns out matrix_projection.hpp was merged (at least partially) with matrix_transform.hpp, so all you need to make this work with the current version is to remove the missing include.
Took me forever to figure this out because I was using the wrong function. (glm::project instead of glm::perspetive… It made sense given the name of the matrix variable :P)
Is it possible to compute the Project * View * Model matrix and send this to the vertex shader ? i am figthing with this concept for few days now and i cannot understand where my error is .
Funny… I copy-pasted’ the shader files together from the page and get loads of compile errors, but downloading and using the shaders from the project, everything works fine.
What encoding do shader files need to be in?
Is there any tutorial/paper/whatever about debugging shader files?
It has to be in plain ascii. So on windows, using (programmer’s) notepad will do the trick just fine.
For debugging shaders i suggest you google for nvidia shader debugger
Hey really nice tutorial – well done!
Very nice tutorials!
One thing i missed myself was to bind my shader before i called glUniformMatrix4fv.
Also in GLM 9.1 the perspective methods have been moved to matrix transform header and the perspective header have been removed. Caused some confusion for me as i downloaded the newest GLM 9.1 but all is good now.
And thanks for introducing me to GLM It seems really nice.
@Jeppe:
The perspective was NOT removed. The headers you need are:
#include
#include
#include
Also, instead of using &modelmatrix[0], use glm::value_ptr(modelmatrix) instead.
Darn it removed the #include’s, its
gtc/matrix_transform.hpp and gtx/projection.hpp
Heya Swiftless,
Thanks for the tutorial. It confirms my implementation with the vertex shader. I’d just like to put in my input and emphasise that the multiplication order of the View matrix and the Model matrix is very important! Otherwise you’ll get weird behaviour with the viewing camera. It works fine with stationary objects, but when moving objects (By changing the model view matrix for each object) the camera rotation goes weird.
Don’t think that ModelView means ModelMatrix * ViewMatrix, and start trying to get your head around it for 3 days like I did.
Hi Hakim,
Yes, the order of the matrix multiplication is extremely important. A*B does not equal B*A and I actually just noticed that it is the complete opposite to how OpenGL named their method.
Cheers,
Swiftless
Current version of glm has removed matrix_projection.hpp and some other things. ^_^;;
0.9.0.7 seems to work
Hi Garet Claborn,
Thanks for that, these tutorials are already out of date, lol. Hopefully people don’t have too much trouble sorting out the differences. GLM is a fairly new library.
Cheers,
Swiftless
Would you mind updating them then, because I don’t want to use any outdated stuff. Sorry to be a bother but I’m a beginner and I just want to make a 2D game engine. Commenting out the include for the matrix_projection makes the application freeze and quit. Nothing else works.
Hi DaSpirit,
A previous commenter mentioned just unincluding that header file should fix the issue as the methods were consolidated into one of the other headers. It would be great to be able to constantly update my tutorial based on library changes, but GLM is a really new library and is going through constant changes. If your program is freezing and quitting, then I wouldn’t be blaming GLM and this tutorial being out of date, as no one else has mentioned an issue. I’d be looking at your application.
Cheers,
Swiftless
Excellent tutorials! – Have been looking at GL 3 / 4 tutorials and these are the ones to follow! – Keep up the great work!
Great tutorial swiftless.
AM i the only one that thinks this is a massive drawback, tho? One of the greatest things in OpenGL back in 2.0~ days was the fact that you could just “ignore” all the matrices things D:
Looking forward for the next tuts. 😀
Hey Vallchrist,
While this is true for beginners (who can still use earlier OpenGL versions if they wish), advanced graphics programmers already use their own matrices to handle everything. This also means that any third party libraries such as OpenCV can be used separately without having to convert it for use in OpenGL.
Cheers,
Swiftless
Hey switft,
Thanks so much for these tutorials. I only have a mac and I wanted to be able to sit on the bed and watch tv with my girlfriend as I made games on my pc laptop, so I could easily port games from one to another.
Opengl is an absolute pain to get set up with a lack of VS extensions and/or msi’s. But you made this as painless as possible, minus the installing to several different folders. Opengl really should make it easier for direct3d guys to make the switch painless.
Thanks for the tuts, i’d be sitting in front of an imac if it wasn’t for you.
Thanks,
Nick
Hi Nick,
I have some bad news for you. OSX comes with everything you need by OpenGL, within Xcode. You don’t need all the external libraries apart from FreeGLUT as OSX has native OpenGL support. It’s definitely not the easiest API to set up on Windows, but once you get it all running it’s a pretty painless experience from then on.
Thanks,
Swiftless
Great OpenGL 3.x/4.x tutorials! Waiting for new tutorials. I need camera tutorial in OpenGL 3.2. I hope here will be a lot of new tutorials, perhaps more than for OpenGL 1.x/2.x 🙂