PDA

View Full Version : Problem with gl arrays.



dummstah
04-23-2003, 02:24 AM
I'm having a problem with arrays in OpenGL. Until now I've been drawing everything manually as objects weren't too complex. However, now theyre reaching polygon counts of 500+ so I'm implementing opengl vertex/normal/texture arrays.

All the items are static, so I figured that the fastest way to do this would be to build the vertex/normal/texture buffers in the mesh load function, and store it as an array of vertexes on the mesh object. I'm not too worried on memory optimization right now so it just loads into an array of 1000 vertex's. This is the code I've come up with to do this:

--------------------------

void buildvertexbuffer(mesh *themesh)
{
int l;

memset(&themesh->meshvertbuf, 0, sizeof(vertex) * 1000);
memset(&themesh->meshnormbuf, 0, sizeof(vertex) * 1000);
memset(&themesh->meshtextbuf, 0, sizeof(vertex) * 1000);

for (l = 0; l < themesh->facecount; l++)
{
//Vertices buffer (themesh->vertexlist[themeshfacelist[l].a].x)
themesh->meshvertbuf[(l * 3) + 0].x = themesh->vertexlist [themesh->facelist[l].a] .x;
themesh->meshvertbuf[(l * 3) + 0].y = themesh->vertexlist [themesh->facelist[l].a] .y;
themesh->meshvertbuf[(l * 3) + 0].z = themesh->vertexlist [themesh->facelist[l].a] .z;
themesh->meshvertbuf[(l * 3) + 1].x = themesh->vertexlist [themesh->facelist[l].b] .x;
themesh->meshvertbuf[(l * 3) + 1].y = themesh->vertexlist [themesh->facelist[l].b] .y;
themesh->meshvertbuf[(l * 3) + 1].z = themesh->vertexlist [themesh->facelist[l].b] .z;
themesh->meshvertbuf[(l * 3) + 2].x = themesh->vertexlist [themesh->facelist[l].c] .x;
themesh->meshvertbuf[(l * 3) + 2].y = themesh->vertexlist [themesh->facelist[l].c] .y;
themesh->meshvertbuf[(l * 3) + 2].z = themesh->vertexlist [themesh->facelist[l].c] .z;

//Texture buffer
themesh->meshtextbuf[(l * 3) + 0].x = themesh->uvvertexlist [themesh->uvfacelist[l].a] .x;
themesh->meshtextbuf[(l * 3) + 0].y = themesh->uvvertexlist [themesh->uvfacelist[l].a] .y;
themesh->meshtextbuf[(l * 3) + 0].z = themesh->uvvertexlist [themesh->uvfacelist[l].a] .z;
themesh->meshtextbuf[(l * 3) + 1].x = themesh->uvvertexlist [themesh->uvfacelist[l].b] .x;
themesh->meshtextbuf[(l * 3) + 1].y = themesh->uvvertexlist [themesh->uvfacelist[l].b] .y;
themesh->meshtextbuf[(l * 3) + 1].z = themesh->uvvertexlist [themesh->uvfacelist[l].b] .z;
themesh->meshtextbuf[(l * 3) + 2].x = themesh->uvvertexlist [themesh->uvfacelist[l].c] .x;
themesh->meshtextbuf[(l * 3) + 2].y = themesh->uvvertexlist [themesh->uvfacelist[l].c] .y;
themesh->meshtextbuf[(l * 3) + 2].z = themesh->uvvertexlist [themesh->uvfacelist[l].c] .z;

//Normal buffer (themesh->normal[l].vertexnormals[0].x)
themesh->meshnormbuf[(l * 3) + 0].x = themesh->normal[l].vertexnormals[0].x;
themesh->meshnormbuf[(l * 3) + 0].y = themesh->normal[l].vertexnormals[0].y;
themesh->meshnormbuf[(l * 3) + 0].z = themesh->normal[l].vertexnormals[0].z;
themesh->meshnormbuf[(l * 3) + 1].x = themesh->normal[l].vertexnormals[1].x;
themesh->meshnormbuf[(l * 3) + 1].y = themesh->normal[l].vertexnormals[1].y;
themesh->meshnormbuf[(l * 3) + 1].z = themesh->normal[l].vertexnormals[1].z;
themesh->meshnormbuf[(l * 3) + 2].x = themesh->normal[l].vertexnormals[2].x;
themesh->meshnormbuf[(l * 3) + 2].y = themesh->normal[l].vertexnormals[2].y;
themesh->meshnormbuf[(l * 3) + 2].z = themesh->normal[l].vertexnormals[2].z;
}

}

--------------------------


I'm then replacing my rendering function below:

--------------------------

for (l = 0; l < worldModel[x].facecount; l++)
{

glBegin(GL_TRIANGLES); // Drawing Using Triangles
glNormal3f(worldModel[x].normal[l].facenormal.x, worldModel[x].normal[l].facenormal.y, worldModel[x].normal[l].facenormal.z);

if (worldModel[x].rendertype > 0) glNormal3f (worldModel[x].normal[l].vertexnormals[0].x, worldModel[x].normal[l].vertexnormals[0].y, worldModel[x].normal[l].vertexnormals[0].z);
glTexCoord3f(worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].a)].x, worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].a)].y, worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].a)].z);
glVertex3f (worldModel[x].vertexlist[worldModel[x].facelist[l].a].x, worldModel[x].vertexlist[worldModel[x].facelist[l].a].y, worldModel[x].vertexlist[worldModel[x].facelist[l].a].z);

if (glFlipNormals == FALSE)
{
if (worldModel[x].rendertype > 0) glNormal3f (worldModel[x].normal[l].vertexnormals[1].x, worldModel[x].normal[l].vertexnormals[1].y, worldModel[x].normal[l].vertexnormals[1].z);
glTexCoord3f(worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].b)].x, worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].b)].y, worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].c)].z);
glVertex3f (worldModel[x].vertexlist[worldModel[x].facelist[l].b].x, worldModel[x].vertexlist[worldModel[x].facelist[l].b].y, worldModel[x].vertexlist[worldModel[x].facelist[l].b].z);

if (worldModel[x].rendertype > 0) glNormal3f (worldModel[x].normal[l].vertexnormals[2].x, worldModel[x].normal[l].vertexnormals[2].y, worldModel[x].normal[l].vertexnormals[2].z);
glTexCoord3f(worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].c)].x, worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].c)].y, worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].c)].z);
glVertex3f (worldModel[x].vertexlist[worldModel[x].facelist[l].c].x, worldModel[x].vertexlist[worldModel[x].facelist[l].c].y, worldModel[x].vertexlist[worldModel[x].facelist[l].c].z);
}
else
{
if (worldModel[x].rendertype > 0) glNormal3f (worldModel[x].normal[l].vertexnormals[2].x, worldModel[x].normal[l].vertexnormals[2].y, worldModel[x].normal[l].vertexnormals[2].z);
glTexCoord3f(worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].c)].x, worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].c)].y, worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].c)].z);
glVertex3f (worldModel[x].vertexlist[worldModel[x].facelist[l].c].x, worldModel[x].vertexlist[worldModel[x].facelist[l].c].y, worldModel[x].vertexlist[worldModel[x].facelist[l].c].z);

if (worldModel[x].rendertype > 0) glNormal3f (worldModel[x].normal[l].vertexnormals[1].x, worldModel[x].normal[l].vertexnormals[1].y, worldModel[x].normal[l].vertexnormals[1].z);
glTexCoord3f(worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].b)].x, worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].b)].y, worldModel[x].uvvertexlist[(worldModel[x].uvfacelist[l].c)].z);
glVertex3f (worldModel[x].vertexlist[worldModel[x].facelist[l].b].x, worldModel[x].vertexlist[worldModel[x].facelist[l].b].y, worldModel[x].vertexlist[worldModel[x].facelist[l].b].z);
}

glEnd();

}

--------------------------

With this one that utilizes the arrays:

--------------------------

//Enable vertex array so we can stream polygons straight in
glEnable(GL_VERTEX_ARRAY);
glEnable(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_NORMAL_ARRAY);

//Set the pointers to this current model
glVertexPointer (3, GL_FLOAT, 0, worldModel[x].meshvertbuf);
glTexCoordPointer (3, GL_FLOAT, 0, worldModel[x].meshtextbuf);
glNormalPointer (GL_FLOAT, 0, worldModel[x].meshnormbuf);

glDrawArrays(GL_TRIANGLES, 0, worldModel[x].facecount * 3);

--------------------------------

Hopefully I'm not confusing anybody with the code above. The whole thing works perfectly, except now my textures seem to align incorrectly on a few of my objects (so far its just high polygon ones).

Here are before and after shots of the engine. You can clearly see the distortion in the second, after shot:

http://games.paradum.com/before.jpg

http://games.paradum.com/after.jpg


Does anyone know what is causing this, either from looking at my code or from experience?

sanjo
04-23-2003, 03:05 AM
look up how to use the stride param.

dummstah
04-23-2003, 03:40 AM
I did. Theres no stride in my buffers, theyre all packed in together. To me it seems a weird problem as most of the texturing on the mesh is ok, while only certain parts aren't. Also it only seems to happen to high polygon meshs so it seems like its array/memory related, though I can find nothing wrong in the code.

[This message has been edited by dummstah (edited 04-23-2003).]

CAD_Swede
04-23-2003, 04:03 AM
Originally posted by dummstah:
I did. Theres no stride in my buffers, theyre all packed in together. To me it seems a weird problem as most of the texturing on the mesh is ok, while only certain parts aren't. Also it only seems to happen to high polygon meshs so it seems like its array/memory related, though I can find nothing wrong in the code.

[This message has been edited by dummstah (edited 04-23-2003).]

I'm not entirely sure here, but doesn't texture coordinates normally use 2 floats and not 3?

glTexCoordPointer (3, GL_FLOAT, 0, worldModel[x].meshtextbuf);

The first '3' should be a '2', no? It's UV parameters we're talking about? Maybe I didn't read your code right, so take this with a pinch of salt...

Added in Edit:
You're setting X, Y and Z texture coordinates in your "meshtextbuf" setup code.. Is that intentional or an effect of copy-paste programming? :-) UV coordinates are not XYZ coordinates and I think it's good practice to keep those types separated, unless you're using 3D textures. Just my two cents.

/CAD_Swede


[This message has been edited by CAD_Swede (edited 04-23-2003).]

dummstah
04-23-2003, 04:24 AM
The data exported from 3D studio Max does have values for x, y and z texture alignment (UVW?).

I did have it only setting the x and y before, and when I don't set the z it majorly messes up texturing.

I have no idea why 3D studio would be using 3 sets of co-ordinates, as I'm not using 3d textures. It seems to work ok when I manually draw all the triangles, its just when I use glDrawArray it messes up.

CAD_Swede
04-23-2003, 04:33 AM
Originally posted by dummstah:
The data exported from 3D studio Max does have values for x, y and z texture alignment (UVW?).

I did have it only setting the x and y before, and when I don't set the z it majorly messes up texturing.

I have no idea why 3D studio would be using 3 sets of co-ordinates, as I'm not using 3d textures. It seems to work ok when I manually draw all the triangles, its just when I use glDrawArray it messes up.


Ok, another question then: In you "old" code, you have an if-statement for "flipping the normals" and in those cases you send in the coordinates in a different order... I don't see any normal flipping going on in the "new" code.. Could that have something to do with it?

The old code is very difficult to read with the formatting that comes from this web page, so it's tricky and ..well, unfortunately, I've got Real Work to do..ie what my employer pays me to do so i can't spend too much time on this. Sorry. :-)

Good luck!

/CAD_Swede

sanjo
04-23-2003, 04:35 AM
ok. try this:

glVertexPointer (3, GL_FLOAT, 0, worldModel[x].meshvertbuf);
glTexCoordPointer (3, GL_FLOAT, sizeof(float)*3, worldModel[x].meshtextbuf);
glNormalPointer (GL_FLOAT, sizeof(float)*6, worldModel[x].meshnormbuf);

see , i modified the stride param.

sanjo
04-23-2003, 04:37 AM
oops. my fault. should read more carefully next time.

i assumed u used one buffer. sorry.

dummstah
04-23-2003, 04:40 AM
Wow I feel stupid, I just realised the problem. The Arrays weren't large enough.
If a mesh is x triangles, then its gonna need x * 3 vertices. So a mesh with 500 triangles would need 1500 vertices.

I was only allocating 1000 :p That explains why only large polygon meshes messed up.

[This message has been edited by dummstah (edited 04-23-2003).]

CAD_Swede
04-23-2003, 04:59 AM
Originally posted by dummstah:
I think it's something to do with my UVW coordinates being weird. X,Y and Z all have values sometimes (mainly it seems on slopes or flat planes). I'm not sure why this would work drawing each triangle seperately, and not when I use arrays.

Also I isolated the essential parts of my old code:



This is the second call to glTexCoord3f in your code. Notice that for the "w" or "z" component, there's a "uvfacelist[l].c" that I think should be a "uvfacelist[l].b" near the end?

glTexCoord3f(themesh->uvvertexlist[(themesh->uvfacelist[l].b)].x, themesh->themesh->uvvertexlist[(themesh->uvfacelist[l].b)].y, themesh->themesh->uvvertexlist[(themesh->uvfacelist[l].c)].z);

Not that I understand why your old code works with such an error, which I assume it is, but still..:-)

I can't find anything that explains why your "new" code won't work. Sorry.

/CAD_Swede

dummstah
04-23-2003, 05:04 AM
Wow, I didn't notice that old bug in the code. I enlarged the vertbuf array from 1000 to 1500 and it works fine now, I can't believe I made that mistake. Shows I need to sleep more :|

[This message has been edited by dummstah (edited 04-23-2003).]

CAD_Swede
04-23-2003, 05:08 AM
Originally posted by dummstah:
Wow I feel stupid, I just realised the problem. The Arrays weren't large enough.
If a mesh is x triangles, then its gonna need x * 3 vertices. So a mesh with 500 triangles would need 1500 vertices.

I was only allocating 1000 :p That explains why only large polygon meshes messed up.

[This message has been edited by dummstah (edited 04-23-2003).]

haha..Ok.. Saved me from spending more time on this and leaves me with more time to do my Real Job.. *sigh*..You bastard ;-)

Take care!

dummstah
04-23-2003, 05:46 AM
While we're on the topic of arrays, I noticed a funky little command:

glDrawElements()

I've just played around with it and it seems to eliminate the need to prepare the meshes, as if uses a vert and index list.

However, I can't figure out how I'd use this for texture/normals. My UV Texture Coordinates also use an index list, as some vertices may have different UV positions depending on what face theyre draw on.

Any one know If I can do this? Or do I just need to prepare all the buffers before hand.

CAD_Swede
04-23-2003, 06:01 AM
Originally posted by dummstah:
While we're on the topic of arrays, I noticed a funky little command:

glDrawElements()

I've just played around with it and it seems to eliminate the need to prepare the meshes, as if uses a vert and index list.

However, I can't figure out how I'd use this for texture/normals. My UV Texture Coordinates also use an index list, as some vertices may have different UV positions depending on what face theyre draw on.

Any one know If I can do this? Or do I just need to prepare all the buffers before hand.

I don't think you can do this without some preprocessing. Prepare the buffers beforehand and use DrawElements. If you use static objects, you definitely should look up Vertex Buffer Objects too...Nice stuff..;-)

Good luck.

dummstah
04-23-2003, 06:24 AM
I'm only really beginning with advanced opengl games programming. What's the standard method for rendering animated model in games? Is it preparing the buffer every frame, or is there a less cpu intensive method?

dare
04-23-2003, 08:51 PM
You should definitely use glDrawElements; and some preparation is also needed.
I also use export from 3D Max (ASE). Vertices, normals and texcoords you can store in one large array, reference them all with glInterleavedArrays and call glDrawElements. The thing that you must resolve, and I'm currently working on it, is that one model can have more than one material; see post 'optimization issue'.

dummstah
04-25-2003, 03:15 AM
Is there any possibility you could post an example of the code, or point me in the direction of finding one?

I'm real stuck on using glDrawElements to render models which have seperate vertex and UV index lists. I've looked up glInterleavedArrays on MSDN and online, but can't find any good sample code of it.

dare
04-25-2003, 07:35 PM
What you mean by separate vertex and UV index list? If you tend to use glDrawElements, than indices must be indexing appropriate coords-texcoords pair. They don't have to be in the same array, but indices must match! So you need only one index list. Here some example :
struct Vertex{
GLfloat UV[2];
GLfloat coords[3];
};
Vertex* vertices;
GLuint* indices;
GLuint count; //size of the indices array;
//and you fill it with your data...
//now, rendering sequence :
glInterleavedArrays(GL_T2F_V3F, 0, vertices);
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, indices);

Remark : it is important that order in Vertex struct declaration corresponds to type in glInterleavedArrays function (GL_T2F_V3F); first tex coords, then vert coords.

jwatte
04-27-2003, 07:51 AM
I'm real stuck on using glDrawElements to render models which have seperate vertex and UV index lists.


Modeling programs use separate index lists for convenience of the modeling program programmers.

Hardware does not understand separate index lists.

You gotta turn one into the other before you can render. InterleavedArrays doesn't really help, and is really somewhat of an anachronism (VertexPointer, NormalPointer, TexCoordPointer etc are better ways of specifying arrays)

For a short explanation of how to normalize geometry for rendering, see:
http://www.mindcontrol.org/~hplus/graphics/vertex-arrays.html

dare
04-27-2003, 10:19 PM
I don't see the reason not to use InterleavedArrays. In my experience, it is pretty the same as to state every array separate... except, you must have all in one large array. Can't see that can hurt?
Also I saw that code about saparating arrays.
Struct 'vert' are almost the same as I wrote in previous post, i.e. position and UV coords are in the same array...

knackered
04-27-2003, 11:47 PM
Interleaved are fine until you want to do a second render pass which, for instance, doesn't require the vertex normals (or primary/secondary colours). Then you're transferring redundant data.

dare
04-28-2003, 04:10 AM
knackered, I can see now why it would be better to have them in separate arrays...
But you can also transfer all to HW and then just extract what you need, right? So data on card will be resistant. Or am I talking nonsense?

Korval
04-28-2003, 08:34 AM
I don't see the reason not to use InterleavedArrays. In my experience, it is pretty the same as to state every array separate... except, you must have all in one large array. Can't see that can hurt?

Using the explicit InterleavedArrays call is not a great idea, as it doesn't support the ARB_vertex_program attribute arrays (or any other extension-defined *pointer call). However, manually interleving your arrays is just fine.

Of course, as others have pointed out, if you do something like a shadow map or shadow volume pass (that only needs vertex data), you're going to use up lots of extra bandwidth.

dare
04-29-2003, 04:07 AM
If it is the fact about those extensions, I'm with you guys. But I have some other thoughts :
first, what is the difference between these two calls :
InterleavedArrays(GL_V3F, stride1, vertices);
and
VertexPointer(size, GL_FLOAT, stride2, vertices); ?
second, if, for instance, coordinates are not packed tightly, someone (OpenGL or driver) must extract them from agregate array, either before or after sending them to graphic HW; so if this is true, what is the big differece anyway?
Of course, if all arrays are tight (i.e. they occupies different but consecutive memory range), it can speed up transfering data to HW. Maybe I just guessing, but what you think?