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.
NewMatrix[i*4] = MatrixA[i*4] * MatrixB[0] + MatrixA[i*4+1] * MatrixB[4] + MatrixA[i*4+2] * MatrixB[8] + MatrixA[i*4+3] * MatrixB[12];
NewMatrix[i*4+1] = MatrixA[i*4] * MatrixB[1] + MatrixA[i*4+1] * MatrixB[5] + MatrixA[i*4+2] * MatrixB[9] + MatrixA[i*4+3] * MatrixB[13];
NewMatrix[i*4+2] = MatrixA[i*4] * MatrixB[2] + MatrixA[i*4+1] * MatrixB[6] + MatrixA[i*4+2] * MatrixB[10] + MatrixA[i*4+3] * MatrixB[14];
NewMatrix[i*4+3] = MatrixA[i*4] * MatrixB[3] + MatrixA[i*4+1] * MatrixB[7] + MatrixA[i*4+2] * MatrixB[11] + MatrixA[i*4+3] * MatrixB[15];
}
/*this should combine the matrixes*/

memcpy(MatrixB,NewMatrix,64);
}

void gldLoadIdentity(float *m)
{
m[0] = 1;
m[1] = 0;
m[2] = 0;
m[3] = 0;

m[4] = 0;
m[5] = 1;
m[6] = 0;
m[7] = 0;

m[8] = 0;
m[9] = 0;
m[10] = 1;
m[11] = 0;

m[12] = 0;
m[13] = 0;
m[14] = 0;
m[15] = 1;
}

void gldPerspective(float *m, float fov, float aspect,float zNear, float zFar)
{
const float h = 1.0f/tan(fov*PI_OVER_360);
float neg_depth = zNear-zFar;

float m2[16] = {0};

m2[0] = h / aspect;
m2[1] = 0;
m2[2] = 0;
m2[3] = 0;

m2[4] = 0;
m2[5] = h;
m2[6] = 0;
m2[7] = 0;

m2[8] = 0;
m2[9] = 0;
m2[10] = (zFar + zNear)/neg_depth;
m2[11] = -1;

m2[12] = 0;
m2[13] = 0;
m2[14] = 2.0f*(zNear*zFar)/neg_depth;
m2[15] = 0;

gldMultMatrix(m,m2);
}

void gldTranslatef(float *m,float x,float y, float z)
{
float m2[16] = {0};
float m3[16] = {0};

m2[0] = 1;
m2[1] = 0;
m2[2] = 0;
m2[3] = 0;

m2[4] = 0;
m2[5] = 1;
m2[6] = 0;
m2[7] = 0;

m2[8] = 0;
m2[9] = 0;
m2[10] = 1;
m2[11] = 0;

m2[12] = x;
m2[13] = y;
m2[14] = z;
m2[15] = 1;

gldMultMatrix(m,m2);
}

void gldScalef(float *m,float x,float y, float z)
{
float m2[16] = {0};
float m3[16] = {0};

m2[0] = x;
m2[1] = 0;
m2[2] = 0;
m2[3] = 0;

m2[4] = 0;
m2[5] = y;
m2[6] = 0;
m2[7] = 0;

m2[8] = 0;
m2[9] = 0;
m2[10] = z;
m2[11] = 0;

m2[12] = 0;
m2[13] = 0;
m2[14] = 0;
m2[15] = 1;

gldMultMatrix(m,m2);
}

void gldRotatef(float *m, float a, float x,float y, float z)
{
float angle=a*PI_OVER_180;
float m2[16] = {0};

m2[0] = 1+(1-cos(angle))*(x*x-1);
m2[1] = -z*sin(angle)+(1-cos(angle))*x*y;
m2[2] = y*sin(angle)+(1-cos(angle))*x*z;
m2[3] = 0;

m2[4] = z*sin(angle)+(1-cos(angle))*x*y;
m2[5] = 1+(1-cos(angle))*(y*y-1);
m2[6] = -x*sin(angle)+(1-cos(angle))*y*z;
m2[7] = 0;

m2[8] = -y*sin(angle)+(1-cos(angle))*x*z;
m2[9] = x*sin(angle)+(1-cos(angle))*y*z;
m2[10] = 1+(1-cos(angle))*(z*z-1);
m2[11] = 0;

m2[12] = 0;
m2[13] = 0;
m2[14] = 0;
m2[15] = 1;

gldMultMatrix(m,m2);
}

Part 1 | Part 2


8 Comments

  • 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.

Other Links to this Post

RSS feed for comments on this post. TrackBack URI

Leave a comment

*


WordPress Themes