Running OpenGL3.0 – part3
In our third installment we are looking into replacing all the matrix math previously built into openGL, what I am going to show you replaces most of it almost exactly like openGL used to work, naturally if your doing something a bit more advanced like a game or so, I would suggest that you use your scene graph to generate new matrices.
It’s really quite simple though, and as with the previous part we have to do some changes a bit here and there, so I am going to start with the most generalized bit and work my way down, and finally end up with the classic rotating cube.
But first the prerequisites, I am assuming that you started where part 2 left off, we will also need the following functions made to work
glGetUniformLocation
glUniformMatrix4fv
Step 1 – the shader
it’s really not that much but after
in vec3 Normal; |
add
uniform mat4 projMat; |
this will be where we send our new matrix to.
Then later in the code you need to do something like this to use our matrix
gl_Position=projMat*pos; |
You could use and I almost recommend that you use two matrices one for the camera and one for the model transformation, but I leave that task to you.
Please note that the order of the multiplication is important.
Step 2 – sending the matrix
This is done in two steps, after you bind the shader but before rendering you call
unsigned int loc1 = glGetUniformLocation(ProgramObject,"projMat"); |
to get the location of the variable, I know what your thinking it’s a bit of an hazzle but my hope is that this will soon change, anyway next step is to send the actual data with glUniformMatrix4fv.
glUniformMatrix4fv(loc1, 1, GL_FALSE, m); |
Step 3 – stacking the matrix
Up to this point there is no difference in how you do things but what comes next can vary, either you do it like I have, or you use the scenegraph or you hand feed it from an animation or any of a thousand ways (well maybe not a thousand, but you get my drift).
So first we have to start a matrix, it’s a simple array of 16 floats.
float m[16] = {0}; |
The we load the identity matrix, I use gld (d as in deprecated) instead of gl and I have a pointer to the matrix but otherwise it’s the same.
gldLoadIdentity(m); |
next I set up a perspective transformation, normaly this would have it’s own matrix in openGL but here we put it first, don’t worry, the end result is the same.
gldPerspective(m, 45.0f, 1.33333f, 1.0f, 100.0f); |
next we move back 6 units with translate
gldTranslatef(m,0,0,-6); |
and finally rotate it (angle is basically just a counter that loops between 0 and 360).
gldRotatef(m,angle,0.0f,1.0f,0.0f); |
couldn’t be simpler, It should work just as well as openGL transformations does.
Step 4 – the rest
What follows is the rest of the code, basically all the transformations we used plus gldScalef and gldMultMatrix, they are pretty simple and I basically just used the openGL reference pages (take a look as many things are explained in there) ,I think you should be able to fill in the rest if you need to.
One more thing before I leave you with a multi page spanning code block you need tho have these defines to make all of it work well.
#define PI 3.1415926535897932384626433832795 #define PI_OVER_180 0.017453292519943295769236907684886 #define PI_OVER_360 0.0087266462599716478846184538424431 |
anyway, that’s it for this time, I don’t know if there will be a part 4, but I don’t think so, maybe if some of you can think of something that needs to be said.
void gldMultMatrix(float *MatrixB,float MatrixA[16]) { float NewMatrix[16]; int i; for(i = 0; i < 4; i++){ //Cycle through each vector of first matrix. memcpy(MatrixB,NewMatrix,64); void gldLoadIdentity(float *m) m[4] = 0; m[8] = 0; m[12] = 0; void gldPerspective(float *m, float fov, float aspect,float zNear, float zFar) float m2[16] = {0}; m2[0] = h / aspect; m2[4] = 0; m2[8] = 0; m2[12] = 0; gldMultMatrix(m,m2); void gldTranslatef(float *m,float x,float y, float z) m2[0] = 1; m2[4] = 0; m2[8] = 0; m2[12] = x; gldMultMatrix(m,m2); void gldScalef(float *m,float x,float y, float z) m2[0] = x; m2[4] = 0; m2[8] = 0; m2[12] = 0; gldMultMatrix(m,m2); void gldRotatef(float *m, float a, float x,float y, float z) m2[0] = 1+(1-cos(angle))*(x*x-1); m2[4] = z*sin(angle)+(1-cos(angle))*x*y; m2[8] = -y*sin(angle)+(1-cos(angle))*x*z; m2[12] = 0; gldMultMatrix(m,m2); |
8 Comments
Other Links to this Post
RSS feed for comments on this post. TrackBack URI
By Peter Wallström, May 4, 2010 @ 17:07
-old comments-
Comment by Overlord on 2009:10:03 17:37
have a gldOrtho here also by popular request
void gldOrtho(float *m, float left, float right, float bottom, float top, float Znear, float Zfar)
{
float m2[16] = {0};
m2[0] = 2/(right-left);
m2[1] = 0;
m2[2] = 0;
m2[3] = -((right+left)/(right-left));
m2[4] = 0;
m2[5] = 2/(top-bottom);
m2[6] = 0;
m2[7] = -((top+bottom)/(top-bottom));
m2[8] = 0;
m2[9] = 0;
m2[10] = 2/(Zfar-Znear);
m2[11] = -((Zfar+Znear)/(Zfar-Znear));
m2[12] = 0;
m2[13] = 0;
m2[14] = 0;
m2[15] = 1;
gldMultMatrix(m,m2);
}
Comment by Øystein on 2009:10:28 18:07
What do you do if you have two objects thath you want to translate/rotate separately? You have only one model/view/projection-matrix, projMat, for the whole scene, right?
Comment by Overlord on 2009:10:29 07:54
no, you make one matrix per object if needed, you upload matrix 1 then draw object 1, then upload matrix 2 then draw object 2 and so on.
Though it would be good to reuse certain base matrices.
By amir, July 13, 2010 @ 18:26
Hey your guides are awesome but one thing is missing and that is the source code i just wonder why you dont publish that ?
By Peter Wallström, July 13, 2010 @ 18:55
for a few simple reasons.
1. these tutorials assume that you already know some of this, either trough nehe or other places.
2. it’s written to be as general as possible as i don’t know what kind of codebase or language any one person is running, especially for the last 5 (VAO to Screenshots)
3. for the ones that are missing code i actually don’t have any specific source code, it’s all integrated into other code which i cant release without cleaning it up
Though the next few might be better on the sourcecode area, at least the final one in a series i am planning.
By Kryten, December 27, 2010 @ 18:04
Hi,
I was just wondering, starting from your code, what would be the best practice to deal with glPushMatrix and glPopMatrix?
Thanks,
Kryten
By Peter Wallström, December 27, 2010 @ 22:14
glPushMatrix and glPopMatrix is mostly just used either to switch between orthographic and perspective rendering or deal with nested transformations/rotations, in both cases we can actually just temporarily save the matrix in question in an float[16] or make the matrix as a part of the object structure.
if you really like you could create your own versions of these functions but it’s probably harder than just copying an array with memcpy(MatrixA,MatrixB,64);
I guess the absolutely best way would be to make a really object class that whenever you select an object for rendering it automatically creates the right matrix and makes sure it’s used.
By Kryten, December 28, 2010 @ 16:31
Hm ok, maybe I didn’t understand correctly what these functions do. I thought OpenGL was some how managing a stack of matrices and these were for adding a new (identity) one to apply specific transformation (that how I use them in my current code).
What I started to code is an implementation of what I described above with final coordinates computed by multiplying all matrices in the stack and finally multiplying with the vertex coordinate.
Is it correct ?
Alexandre
By Peter Wallström, January 5, 2011 @ 14:49
no, well it could work that way (and in some game engines with a strongly hierarchal object tree structure its the preferred way), but openGL before 3.0 sure didn’t, it does things the way i have done here, just “under the hood”.
By Daniel, February 12, 2011 @ 05:24
I used these at first to learn and get some basic design down for my renderer, but I moved to GLM… and my god is it much *much* faster. I’d say for most, GLM is the better alternative if your not looking to roll your own.