View Full Version : optimizing drawing of model

11-26-2002, 07:14 AM
When drawing, I am currently going through the 3ds model's faces in a for loop and retrieving the vertex data, normals, and uv's. Some of this data is shared (like the vertices). This is very, very slow. :-(

Should I pre-process this data and duplicate the vertices, normals, etc. so that I can draw it using Vertex arrays? Is that how it is usually done? It seems like this would defeat the purpose of the 3ds file reusing vertices since I would be duplicating a lot of data for my arrays.

11-26-2002, 09:19 AM
I'm new to OpenGL too, but I'm writing a generic engine for myself ATM...
basically what I did was making three classes:

A Vector/Vertex class
A Plane class
and an Object class

The object class holds three vectors (the container VECTOR, as in #include <vector> )
One Vector holds the plane objects and one vector holds the vertexes. The last one holds 2D coordinates for texture mapping.

The plane class is an array of integers, which contain the INDEXES to the vertexes in the Object class.

So, when I render I first pick my Plane I want to paint, then pick each index, and fetch the right vertex out of the vector...

Plane p;
Vertex v;
int b;

for (as_long_as_we_have_planes; x++)
p = PLANE_VECTOR[x];//get the right plane

glBegin(something);//begin drawing, you might want to set colors/textures too

for (as_long_as_the_plane_has_points; z++)
b = p.INDEX_ARRAY[z];//get the index in out array
v = VERTEX_VECTOR[B];//get the matching vertex
glVertex3f(v.x, v.y, v.z);//and paint it

glEnd();//we stop painting here...

In the Plane object I also stored the normal-vector for lighting, indexes for 2D texture mapping as well as information for texturing and coloring.
I do all intesive calculations when loading the model, like normal calculations.

You might want to choose for another container than a Vector for storing the data. I chose for a vector because it is variable in size, and is easilly accessible while still being reasonably fast.

I'm not quite sure what distiguises your implementation from mine, but here it works fast enough.

11-26-2002, 10:16 AM
I am also no expert and I dont disagree with Structual but instead of having multiple calls to glVertex, glNormal etc, you can use glDrawElements which utilises vertex arrays. It does mean that you will have to duplicate data in your vertex(ie positional, normal, textural etc)arrays; but you should see a speed increase due to the lower number of function calls, as few as one( to glDrawElements).
you may know this but: The duplication is necessary because glDrawElements grabs data from all the enabled vertex arrays, ie the equivalent entry from say the posional vertex array and the normal array(if thos are the only two enabled). So this means that if you have a vertice that is part of two different faces you will have to duplicate that data for the different normals, anf of course the opposite if you have the same normal for more than one vertice.

All this means is that you put more effort in setting up your data.

But check out the red book for all the glDrawElements details if it grabs your fancy.

11-26-2002, 12:15 PM
Thanks for the info.

I always thought that the more you can reuse your data (vertices, normals, etc.), the faster it would run because the data would fit into the cache better. Is this assumption wrong? Is it faster to just duplicate a lot of it and just do glDrawElement many times?

11-26-2002, 02:02 PM
Sorting faces by material and minimize
state changes.

11-26-2002, 02:58 PM
GameMaker: you wrote;

Is it faster to just >duplicate a lot of it and just do >glDrawElement many times?

It is probably easist to illustrate with an example. heres a cube I made.

= static GLfloat vertex[]
=1.0 ,1.0,1.0,
-1.0, 1.0, -1.0,
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,

1.0, 1.0, 1.0, 1.0, -1.0, 1.0,
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,

1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,

1.0, 1.0, -1.0,
-1.0, 1.0, -1.0,
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,

1.0, 1.0, 1.0,
1.0, 1.0, -1.0,
-1.0, 1.0, -1.0,
-1.0, 1.0, 1.0,

1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0 };

static GLfloat normal[] = {-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 0.0, 0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,

0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,

0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,

0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
0.0, -1.0, 0.0};

glVertexPointer (3, GL_FLOAT, 0, vertex);
glNormalPointer (GL_FLOAT, 0, normal);

GLubyte redindices[] = {0, 1, 2, 3};
GLubyte grnindices[] = {4, 5, 6, 7};
GLubyte pnkindices[] = {8, 9, 10, 11};
GLubyte Lblindices[] = {12, 13, 14, 15};
GLubyte yindices[] = {16, 17, 18, 19};
GLubyte blindices[] = {20, 21, 22, 23};

glMaterialfv(GL_FRONT, GL_AMBIENT, rd_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, rd_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, rd_specular);

glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, redindices);

and so on for the other faces.

(each face has a different colour but if all sides had the same colour or if you were using textures intead of material properties
then you could crunch those arrays of indices,(grnindices, redindices etc)
into one array and make only one call to

BUt ryo's face sorting idea is good for if u r using material properties.

I fully recommend looking at the red book
on the web though for a more thorough explanation. just type 'OpenGL programming guide' or' red book'into google ,which should give a bunch of sites that keep the red book online.


11-26-2002, 09:53 PM
I have just been introduced to lists (someone linked to NeHe's tutorial: http://nehe.gamedev.net/tutorials/lesson.asp?l=12 ) but don't these work about the same: store all vertex/texture/normal data internally in the list and display it with only one call ???
Or is this less efficient than calling glDrawElements? Or is a combination of these two the *BEST* (ie: building a list with DrawElements instead of building the list with vertexes) ?

11-27-2002, 04:27 AM
Ya, I tried that (display lists) first but it didn't speed things up at all. The first time when drawing the model, I instead compiled it into a display list. Then, every time after that, I use the compiled display list. I don't understand why it didn't speed up at all.

11-27-2002, 10:23 AM
I preprocess the model data now and use glDrawArrays but it only went up by a few frames per second. I must be doing something really wrong. It runs at 230 frames per second when I comment out the glDrawArrays line, so it doesn't seem to be anything dumb that I am doing on the CPU side of things.

I have a P4 2.2 GHZ 512 meg and GEforce4 card 128 meg. And I am only getting 15 frames a second with a 3,000 poly model.

Other peoples demos run fast, so I know it must be something about the way I am drawing or setting up the data.

The vendor information says Nvidia so I am using hardware acceleration.

I tried no lighting, that didn't matter either. I tried 16 color depth, 640 X 480 window.

Help Please, before I go crazy!!! :-O

11-27-2002, 10:34 AM
Wow! I coded a 3ds ASE loader on linux, and it gave me 20-30 FPS with a 17.000 polygons model (an skeleton), with a non-textured material, and using lighting.

The machine was a AMD-k6-III 450MHz, with an ATI 8MB, on a SuSE, with the utah GLX driver.

You are doing something really wrong.

I did nothing of display list or something similar.

My basic "show model" function looks like:

for each face of the model
begin a face with glBegin(GL_POLY)
for each one of the 3 vertex of that face
draw a glVertex
end the face with glEnd


11-27-2002, 11:17 AM
I think that I found the cause of it. I am using a clipping plane and it seems that the clipping plane slows it down A LOT!

Total polys per frame = 9558
Without clip plane = 482 FPS
With clip plane = 62 FPS

Hmmmm....Anybody have any ideas on how to speed up the process of using a clip plane that is always perpendicular to the camera?

11-27-2002, 03:14 PM
I think I answered my own question, I can just push the near clip outward.

Thanks for everyone's help! ;-)

11-28-2002, 07:30 PM
The basic way you want to draw a mesh is to use vertex arrays and glDrawElements.

But before you do that you want to convert your data into your own format.

When you convert them you go through each vertex and copy it for each version of that vertex. Yes, this wastes data. On a cube you'll have three copies of each vertex if you want one with a normal facing each way. It sucks to repeat the position and normal information, but that's life.

Once you've got yourself a "true" mesh get yourself a tristripper such as http://users.pandora.be/tfautre/softdev/
nvidia also has one.

Save your data so you don't have to do this every single time you load your application.

Now just go through each material in your scene, set it up, and draw it. It should fly. Check out the benchmark here: http://www.fl-tw.com/opengl/GeomBench/

It shows what performance you should be getting with that kind of data.

11-28-2002, 08:52 PM
Prove me wrong, but DrawElements uses indices to draw vectors from vertices array, so I can define indices that way - 1,2,3, - (draw v1,v2,v3); 4,5,1 (and then draw v4.v5 and back the first one v1). So there's no need to duplicate vertices, take a look at obj files for example, f lines shows which vectors to use and reuse http://www.opengl.org/discussion_boards/ubb/smile.gif Moreover, this notation should eliminate some intersection problems http://www.opengl.org/discussion_boards/ubb/smile.gif

11-29-2002, 08:32 PM
I wasn't clear about the duplication. A "full vertex", one with a normal, texture coordinates, a colour, a tangent, binormal, etc will not be duplicated.

A vertex that is just a position will be duplicated three times on a cube in order to create an unique "full vertex" with a normal. If you don't have normals this vertex does of course not need to be duplicated.

I was just trying to make the point to think in terms of "full vertexes" instead of vertex==position.