Fun with glDraw*Elements

Started by
9 comments, last by Kalidor 19 years, 1 month ago
I'm researching vertex arrays and I'm almost ready to pounce. I've done my prep work and now I have a few questions before I start putting some code down. First, the only difference between glDrawRangeElements and glDrawElements is the specified range of indices, right? I'll only have one giant array with something like 800,000 values in it, would it still be worth while to use glDrawRangeElements? Second, am I still going to use the gl*Pointer functions if I'm going to be using glDraw*Elements? I'm only storying normal and vertex data, so if I do should I assemble them both into a big interleved array and then pass the stride and such to glVertex/NormalPointer and then call gl*Elements using the pointer returned from that? Also, I'm thinking about using the glInterleavedArrays function. The only problem is the normal data I have is per plane constructed of three vertices, not per vertex. Is there a way around this, such that I can specify a normal for the triangle and then the three vertices of the triangle, then the next normal and so on? The data is arranged as 3 floats for the normal and 9 floats for the vertex data. Do I specify that I want it to read in the 3 values for the normal, give a stride of 9 so it knows that's where the next one starts, and then have it read in the 9 values for the triangle vertex position? I'm a little confused on that part. Also, the pointer to the array that all the gl*Pointer functions and glInterLeavedArray take, can that just be a dynamically allocated array of type GLfloat of my own creation? It doesn't have to be static, right? I've got all my data stored in a giant dynamic array of floats, it would be real simple to switch those over to GLfloats and pass the pointer to that to the functions. Doable? And finally, would it be worth while to put my vertex arrays in a display list? Thanks in advance!
Without order nothing can exist - without chaos nothing can evolve.
Advertisement
Quote:Original post by CyberSlag5k
First, the only difference between glDrawRangeElements and glDrawElements is the specified range of indices, right? I'll only have one giant array with something like 800,000 values in it, would it still be worth while to use glDrawRangeElements?


Haven't used glDrawRangeElements but if you are looking for speed look at VBO's.
The whole purpose of these calls is to work with giant arrays.

Quote:Original post by CyberSlag5k
Second, am I still going to use the gl*Pointer functions if I'm going to be using glDraw*Elements? I'm only storying normal and vertex data, so if I do should I assemble them both into a big interleved array and then pass the stride and such to glVertex/NormalPointer and then call gl*Elements using the pointer returned from that?


Yes you will still use gl*Pointer functions to specify the stride and pointer info. Better to have them in a structure in such a way that that structure can be passed into an glInterleaved* function in my opinion.

Quote:Original post by CyberSlag5k
Also, I'm thinking about using the glInterleavedArrays function. The only problem is the normal data I have is per plane constructed of three vertices, not per vertex. Is there a way around this, such that I can specify a normal for the triangle and then the three vertices of the triangle, then the next normal and so on? The data is arranged as 3 floats for the normal and 9 floats for the vertex data. Do I specify that I want it to read in the 3 values for the normal, give a stride of 9 so it knows that's where the next one starts, and then have it read in the 9 values for the triangle vertex position? I'm a little confused on that part.


I dont think there is a way around it. You probably have to make a copy of the normals per face.

Quote:Original post by CyberSlag5k
Also, the pointer to the array that all the gl*Pointer functions and glInterLeavedArray take, can that just be a dynamically allocated array of type GLfloat of my own creation? It doesn't have to be static, right? I've got all my data stored in a giant dynamic array of floats, it would be real simple to switch those over to GLfloats and pass the pointer to that to the functions. Doable?


It can be of your own creation provided the info held in it is of the same type and one that is supported by the function. For example :-

struct{    float texCoord[2];    float color[4];    float normal[3];    float vertex[3];} vertices;vertices *vert;.....glInterleavedArrays(GL_T2F_C4F_N3F_V3F, 0, vert);


Quote:Original post by CyberSlag5k
And finally, would it be worth while to put my vertex arrays in a display list?


Yes if you data remains static, no if your data changes over time. If any kind of animation or modification is involved on the data and it required a recompiling it into the display list then display lists are useless.
The more applications I write, more I find out how less I know
Quote:
Haven't used glDrawRangeElements but if you are looking for speed look at VBO's.
The whole purpose of these calls is to work with giant arrays.


I've looked a bit into VBOs since you and someone else have suggested them and I'll definitely implement them. I'll do it right after I get the VA's working as I'd like to observe the speed increase and just to see how pure VA's are done.

Quote:
Yes you will still use gl*Pointer functions to specify the stride and pointer info. Better to have them in a structure in such a way that that structure can be passed into an glInterleaved* function in my opinion.


Actually I do have them in a structure. Sadly, the structure also contains a 2 byte piece of garbage (which is unavoidable). Would I be able to use the stride to get past that?

Quote:
I dont think there is a way around it. You probably have to make a copy of the normals per face.


My structure looks like this:

#pragma pack(1)struct _Facet{	GLfloat normal[3]; //surface normal data 	GLfloat vertex[9]; //vertex data	USHORT dummy;} *triangles;#pragma pack()


Again the dummy has to be there. Now, can I just make two calls:

glNormalPointer(3, GL_FLOAT, 0, *triangles);
glVertexPointer(3, GL_FLOAT, 3*sizeof(GLfloat), *triangles);

But that doesn't let me specify that 3 vertices should be read in, doesn't it. So do these things normally have normal data for each vertex rather than for the surface, as I do? Crap. I don't have vertex normal data, only surface normals...
Without order nothing can exist - without chaos nothing can evolve.
if you use vertex arrays u haveto have a 1to1 colleration between normals and vertices, theres no way around it.
Quote:Original post by CyberSlag5k
But that doesn't let me specify that 3 vertices should be read in, doesn't it. So do these things normally have normal data for each vertex rather than for the surface, as I do? Crap. I don't have vertex normal data, only surface normals...

Yeah you need per-vertex normals to pass to OpenGL. If you want "flat" shading, just copy each of your face normals 3 times (1 per vertex). If you want "smooth" shading, you need to average each of the contributing (adjacent) face normals per-vertex.

Regarding the gl*Pointer calls, make sure that you pass the initial address as the address of the first element IN the structure. ie. if you're calling glNormalPointer, you'll want to pass something like "Vertices[0].Normal". Then for each of them pass a stride of "sizeof(VertexType)" where VertexType is your vertex structure.
Quote:Original post by CyberSlag5k
glNormalPointer(3, GL_FLOAT, 0, *triangles);
glVertexPointer(3, GL_FLOAT, 3*sizeof(GLfloat), *triangles);
It'd be more like:

glNormalPointer(3, GL_FLOAT, sizeof(_Facet), triangles);
glVertexPointer(3, GL_FLOAT, sizeof(_Facet), &(triangles[0].vertex));

I'm not sure whether the pointer in the second line is correct, but the idea is that you need to pass a pointer to where the vertex data actually begins. The stride is the distance between consecutive attributes.
Quote:Original post by CyberSlag5k
Actually I do have them in a structure. Sadly, the structure also contains a 2 byte piece of garbage (which is unavoidable). Would I be able to use the stride to get past that?


Yes. Just use sizeof(structure) in the stride, in that case it will just ignore the dummy. Follow Myopic Rhino's example.

Quote:Original post by CyberSlag5k
My structure looks like this:

#pragma pack(1)
struct _Facet
{
GLfloat normal[3]; //surface normal data
GLfloat vertex[9]; //vertex data
USHORT dummy;
} *triangles;

Again the dummy has to be there. Now, can I just make two calls:

glNormalPointer(3, GL_FLOAT, , *triangles);
glVertexPointer(3, GL_FLOAT, 3*sizeof(GLfloat), *triangles);

But that doesn't let me specify that 3 vertices should be read in, doesn't it. So do these things normally have normal data for each vertex rather than for the surface, as I do? Crap. I don't have vertex normal data, only surface normals...


You should be specifying 1 vertex at a time. Not 3 at a time. So your facet should be like the following.

struct _Facet
{
GLfloat normal[3]; //surface normal data
GLfloat vertex[3]; //vertex data - not vertex[9]
USHORT dummy;
} *triangles;

All you need to do is make copies of the normal data - each face has a normal data, copy that normal data into the 3 vertex normals for that face. You don't need to recalculate.
The more applications I write, more I find out how less I know
Quote:First, the only difference between glDrawRangeElements and glDrawElements is the specified range of indices, right? I'll only have one giant array with something like 800,000 values in it, would it still be worth while to use glDrawRangeElements?

It's recommended to use glDrawRangeElements instead. There's very little bother involved in doing so, and it can yeild performance benefits on some hardware. It certanly won't slow things down.
Quote:Original post by Nemesis2k2
Quote:First, the only difference between glDrawRangeElements and glDrawElements is the specified range of indices, right? I'll only have one giant array with something like 800,000 values in it, would it still be worth while to use glDrawRangeElements?

It's recommended to use glDrawRangeElements instead. There's very little bother involved in doing so, and it can yeild performance benefits on some hardware. It certanly won't slow things down.


The upper range of indices is easily obtained just by checking the length of my dynamic array, which is all that I'd need to use glDrawRangeElements, correct?
Without order nothing can exist - without chaos nothing can evolve.
I am having problems getting glDrawElements to work with interleaved data. Here is the simple example I'm trying to get to work. The data is packed with two tex coords and three vert positions for each vertex. When I run this example I don't see anything.

static GLushort g_cubeIndicies[] ={    0, 1, 2, 3,    4, 5, 6, 7,    8, 9, 10, 11,    12, 13, 14, 15,    16, 17, 18, 19,    20, 21, 22, 23};float g_cubeVertices[] ={	0.0f,0.0f, -1.0f,-1.0f, 1.0f,	1.0f,0.0f,  1.0f,-1.0f, 1.0f,	1.0f,1.0f,  1.0f, 1.0f, 1.0f,	0.0f,1.0f, -1.0f, 1.0f, 1.0f,	1.0f,0.0f, -1.0f,-1.0f,-1.0f,	1.0f,1.0f, -1.0f, 1.0f,-1.0f,	0.0f,1.0f,  1.0f, 1.0f,-1.0f,	0.0f,0.0f,  1.0f,-1.0f,-1.0f,	0.0f,1.0f, -1.0f, 1.0f,-1.0f,	0.0f,0.0f, -1.0f, 1.0f, 1.0f,	1.0f,0.0f,  1.0f, 1.0f, 1.0f,	1.0f,1.0f,  1.0f, 1.0f,-1.0f,	1.0f,1.0f, -1.0f,-1.0f,-1.0f,	0.0f,1.0f,  1.0f,-1.0f,-1.0f,	0.0f,0.0f,  1.0f,-1.0f, 1.0f,	1.0f,0.0f, -1.0f,-1.0f, 1.0f,	1.0f,0.0f,  1.0f,-1.0f,-1.0f,	1.0f,1.0f,  1.0f, 1.0f,-1.0f,	0.0f,1.0f,  1.0f, 1.0f, 1.0f,	0.0f,0.0f,  1.0f,-1.0f, 1.0f,	0.0f,0.0f, -1.0f,-1.0f,-1.0f,	1.0f,0.0f, -1.0f,-1.0f, 1.0f,	1.0f,1.0f, -1.0f, 1.0f, 1.0f,	0.0f,1.0f, -1.0f, 1.0f,-1.0f};...glEnableClientState( GL_TEXTURE_COORD_ARRAY );glEnableClientState( GL_VERTEX_ARRAY );glBindTexture( GL_TEXTURE_2D, g_textureID );glTexCoordPointer(2, GL_FLOAT, 5*sizeof(float), &g_cubeVertices[0]);glVertexPointer(3, GL_FLOAT, 5*sizeof(float), &g_cubeVertices[2]);glDrawElements(GL_QUADS, 3, GL_UNSIGNED_SHORT, &g_cubeIndicies[0]);glDisableClientState( GL_TEXTURE_COORD_ARRAY );glDisableClientState( GL_VERTEX_ARRAY );


When I replace the glDrawElements call with the following glDrawArrays call, I can see the textured cube just fine.

glDrawArrays(GL_QUADS, 0, 24);


I would like to be able to use glDrawElements for speed and flexibility reasons.
Thank you,
Malachi

This topic is closed to new replies.

Advertisement