Loading Models, Take 2 (Without GLTools)
One of the frustrating aspects of learning 3D programming is that when you do something wrong often you end up with a program that compiles and runs – but leaves you looking at a blank screen. Dropping the immediate mode of earlier versions of OpenGL and moving to using VBOs is much the same – except now there are two things that can happen when you get something wrong:
- The program compiles and runs, but you get a blank screen (as before)
- The program compiles and runs, but crashes when you try to draw something
Bah.
Anyway, as promised, here are some notes on loading and rendering a model without using all the helpful functions that GLTools provides – we’ll be using only the math3d library. In principle it should be easy enough to work through this example and replace the math3d calls and functions with your own preferred math library – the OpenGL Math library, GLM, for instance.
As our model format include a geometry index list, we can take advantage of that in our code. Where the previous version had a part of the model loading function that used the index list to calculate all of the triangles to be drawn, we can now just keep the index list in (yet another) VBO, and let OpenGL figure out what triangles need drawn – using the index list to power through the geometry and normal buffers. While this might entail a bit more processing for OpenGL, it means our vertex and normal buffers will be smaller – saving some memory, and perhaps gaining in memory transfer times what we lost elsewhere. (I’ll leave running exhaustive tests with a profiler as an exercise for the reader!)
Anyway, in the revised code, the globals are mainly there to pass information about the buffers and the data they contain. Obviously this should wrapped in a nice class or struct. But for now, globals will do the job…
// * Global Variables *
GLuint vertexArrayObjID[1]; // Just the one vertex array object
GLuint vertexBufferObjID[3];// 3 vertex buffer objects in this example
GLuint numVerts; // How many vertices in array?
GLfloat angle = 0.0f; // going to animate the object
GLuint program; // Global handle for shader program
Actually drawing the 3D object is not terribly challenging – once the VAO and VBO have the data we need in them, a simple call to glDrawElements will do the job for us. DrawElements is used instead of DrawArray when we are using an index array. This wonderful array tells OpenGL how to make up a load of triangles from an unordered collection of vertices. Say the VBO containing the geometry has 100 vertices. Then if the first three entries in the index array are the numbers 0, 1 and 11, then the 1st, 2nd and 12th vertices in that buffer will be used to draw our triangle. Simple huh? This can vastly reduce the size of the VBOs containing the vertex data.
Here is the drawing code:
// Set up the uniform inputs
glUniformMatrix4fv(glGetUniformLocation(program,"mvMatrix"), 1,GL_FALSE,modelview);
glUniformMatrix4fv(glGetUniformLocation(program,"pMatrix"), 1,GL_FALSE,projection);
glBindVertexArray(vertexArrayObjID[0]); // Bind VAO
glEnableVertexAttribArray(0); // enable position attribue array
glEnableVertexAttribArray(1); // enable normal attribute array
glVertexAttrib3f((GLuint)2, 1.0, 0.0, 0.0); // set constant color attribute
// using index list, so use DrawElements instead of Draw Array
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexBufferObjID[2]);
glDrawElements(GL_TRIANGLES, numVerts, GL_UNSIGNED_INT, 0);
The model loading code itself is actually simpler than the previous code – now we just need to throw all of the position data into the three VBOs in use – one each for the position and normal attributes and one for the indices. Note the final BindBuffer call – the index array is not in a GL_ARRAY_BUFFER type VBO, but a GL_ELEMENT_ARRAY_BUFFER.
Full code on gist as usual… http://gist.github.com/633350
You can also use interleaved buffers – this would allow you to combine the normal and vertex data in a single buffer – see e.g. this Q&A at Stack Overflow.


Hello Daniel, I cant get this code to work. I put the blocks.uwsm file in the project folder and compile it, but it says that my blocks.uwsm is not a .uwsm file for some reason. I’m using the blocks.uwsm from the last load from file post.
Oops, should have updated the uwsm file!
If you inspect the code, you’ll see that there is now a line in the load data function that reads the first string of the uwsm file. If this does not start with the characters “uwsm” then you’ll get that error message.
Edit the uwsm data file to add a new line at the beginning:
uwsm0_2Im actually going back now to edit the original model loading code to use the “uwsmX_X” magic number