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);
}

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

Other Links to this Post

RSS feed for comments on this post. TrackBack URI

Leave a comment


WordPress Themes