PDA

View Full Version : indices at glDrawElements(...);



ghostdog
09-14-2003, 11:24 AM
hello,
is right, how i interpret the parameter "indices" in the glDrawElements() Function?

when i have 4 vertices in my floatarray and
indices = 1 2 3 3 2 4 4 2 1 1 3 4
and i use GL_TRIANGLES to draw the VA,
then there will be rendered 4 triangles building up a Tetrahedron.

so the indices correspond to the vertices in
the floatarray. ok, or am i completely wrong?

sorry, i have to ask this basic question
since i'm new to vertex arrays and the information in the OpenGL Specs is not telling me anything.

quote-> "Specifies a pointer to the location where the indices are stored." ... uh ?!?

btw,
i use "GL_EXT_compiled_vertex_array" for drawing a mesh. i know, this method of drawing vertex arrays is nearly obsolete but i thought it would be right to start with this basic one.
which one would be better? i read ARB_EXT_VERTEX_OBJECT is the best one since it is vendor-independent. but my GF2MX doesn't support it. what do you think i should use?

TIA
ghostdog

Obli
09-15-2003, 01:44 AM
so the indices correspond to the vertices in the floatarray. ok, or am i completely wrong?
No, if I understand what you're saying, then you're right.
Consider each vertex to be only a single float, then the indices would be the array indices, in the sense vertex[3] would be the fourth vertex.


quote-> "Specifies a pointer to the location where the indices are stored." ... uh ?!?
I don't know what is confusing you... the indices should be in their own array right? Pass this array here and you're done (this does not apply to vertex buffer objects).


i read ARB_EXT_VERTEX_OBJECT is the best one since it is vendor-independent. but my GF2MX doesn't support it. what do you think i should use?
I guess you're saying ARB_vertex_buffer_object (aka ARB_vbo)
. It is supported by my Geforce2 and Geforce4Ti, I don't see why GeForce2MX should not have it avaiable since it is very similar to my geforce2.
Take care, ARB_vbo changes sligtly the way you think at vertex arrays, take care when trying to use it.

ghostdog
09-15-2003, 04:16 AM
Originally posted by Obli:
I don't know what is confusing you... the indices should be in their own array right? Pass this array here and you're done (this does not apply to vertex buffer objects).


thx, figured it out by myself but i didn't understand it in the first place. sorry, i can't tell you why - at last everything seems to be obvious http://www.opengl.org/discussion_boards/ubb/wink.gif
anyway, i got it to work. but now i have a problem with casting the indices array:

i have the indices in



int *faceIndices = new int[numFaces * 3];

when i cast this to the pointer i'd like to use for my glDrawElements() call



int *pIndices=Mesh->faceIndices;

the array gets corrupted with the effect, that glDrawElements() shows wrong triangles. the data in the array lists only every 3rd index. strange is, the last 3 indices are the right ones.
surprisingly my casting of the vertexpointer



float *vertices = new float[numVertices * 3];
pVertices = (GLfloat *)mesh->getVertices();
...
glVertexPointer(3, GL_FLOAT, 0, pVertices);

shows NO problem. i tried it with casts (int *) or (GLint *), no success. any idea?


I guess you're saying ARB_vertex_buffer_object (aka ARB_vbo)
. It is supported by my Geforce2 and Geforce4Ti, I don't see why GeForce2MX should not have it avaiable since it is very similar to my geforce2.
Take care, ARB_vbo changes sligtly the way you think at vertex arrays, take care when trying to use it.

yeah, sorry. ARB_vertex_buffer_object, that's what i meant. according to GLEW (http://glew.sourceforge.net/) my GF2MX doesn't support it. maybe a driver issue? i'm going to check on this.

what changes do you mean? could you explain it, if you don't mind. maybe i could avoid some pitfalls with your help

TIA
ghostdog



[This message has been edited by ghostdog (edited 09-15-2003).]

Obli
09-15-2003, 05:55 AM
any idea?
I don't have any. Finding how to make other people's code work (from 5 lines of code) has never been my strongest attitude.


according to GLEW (http://glew.sourceforge.net/) my GF2MX doesn't support it. maybe a driver issue?
Not sure, but I guess you need at least 44.something nvidia drivers.


what changes do you mean? could you explain it, if you don't mind. maybe i could avoid some pitfalls
Most pitfalls has been ironed out by the API. The only thing that you may find strange is that when you use vertex buffers, you usually pass NULL as vertexPointer or something like that.
This is because every vertex array pointer will be extrapolated from the buffer object which was actually bound when the the pointer was specified.
Another way to think at it is that pointers are usually expressed as <pointer> while when you use a buffer object, the GL accesses data ad <bufferObjectAddress> + <pointer>, figuring out another address (which you don't know since you don't know <bufferObjectAddress>. So, the pointer you pass is used as an offset and since you can easily use a buffer object for every small bit of geometry you want, you usually can pass NULL and pull out directly from <bufferObjectAddress> + 0.

Take care however, buffer object offsets are in **bytes** and not in elements, float, vertices or stuff like that.

Deiussum
09-15-2003, 06:58 AM
In the following code:




float *vertices = new float[numVertices * 3];
pVertices = (GLfloat *)mesh->getVertices();
...
glVertexPointer(3, GL_FLOAT, 0, pVertices);


I don't see vertices used at all. Did you mean?




float *pVertices = new float[numVertices * 3];
pVertices = (GLfloat *)mesh->getVertices();
...
glVertexPointer(3, GL_FLOAT, 0, pVertices);


If that is the case, you have a memory leak. You allocate memory to pVertices, but then you immediately replace the pointer with mesh->getVertices(); You now have no pointer to the memory you allocated, and therefore no way to clean it up.

In any case, the problem with your code probably lies withing mesh->getVertices(); What does it return? Showing a little code for that method might be helpful.

Edit: You seem to have this same memory leak problem with your indices.

[This message has been edited by Deiussum (edited 09-15-2003).]

Deiussum
09-15-2003, 07:03 AM
I just re-read your posts a bit more. You say it works when you cast mesh->getVertices() to a float* but not to an int*?

If that is what you are saying then, duh. The memory layout for ints and floats is totally different so if you just try to cast a float* to an int* and then access the individual elements of the int*, you will get totally different values from the individual elements of the float*. It won't be a simple truncation/rounding either. Floats are stored in IEEE format for floating point numbers and ints are stored in a more direct manner.

Edit: To clarify, casting a float* to an int* is not like casting a float to an int. It will not cast every element of the float array to an int. Instead, it merely casts the float pointer to an int pointer. It still points to the same memory location, and the memory is still layed out exactly like it was for the float pointer, it's just interpretted a bit different when reading the array.


[This message has been edited by Deiussum (edited 09-15-2003).]

ghostdog
09-15-2003, 07:38 AM
In the following code <posted code>
I don't see vertices used at all. Did you mean?


what do you mean? my vertex data (3 floats for x, y and z-coords per vertex) ist sequencially stored in "CMesh.faceIndices".
faceIndices points to an array: v1x , v1y, v1z, v2x, v2y, v2z, ....
CMesh.faceIndices[0] is v1x
CMesh.faceIndices[1] is v1y
CMesh.faceIndices[2] is v1z
and so on...




If that is the case, you have a memory leak. You allocate memory to pVertices, but then you immediately replace the pointer with mesh->getVertices(); You now have no pointer to the memory you allocated, and therefore no way to clean it up.

You seem to have this same memory leak problem with your indices.


i allocate memory within my CMesh-Object. for the opengl drawing i need a pointer to the indices and vertices, so i create new pointers (int *pIndices and float *pVertices) and let them point too to the certain arrays.

i see no leak here.



In any case, the problem with your code probably lies withing mesh->getVertices(); What does it return? Showing a little code for that method might be helpful.


sorry, here is more code.




void render(CMesh *mesh){
...
float *pVertices;
int *pIndices;
pVertices = (GLfloat *)mesh->getVertices(); //A, works
pIndices = (int *)mesh->getFaceIndices(); //B, works NOT

...
}

int *CMesh::getFaceIndices() const{
return faceIndices;
}

float *CMesh::getVertices() const{
return vertices;
}

Class CMesh
{
...
float *vertices;
int *faceIndices;
...
}

ghostdog
09-15-2003, 08:08 AM
Originally posted by Obli:

Most pitfalls has been ironed out by the API. The only thing that you may find strange is that when you use vertex buffers, you usually pass NULL as vertexPointer or something like that.
This is because every vertex array pointer will be extrapolated from the buffer object which was actually bound when the the pointer was specified.
Another way to think at it is that pointers are usually expressed as <pointer> while when you use a buffer object, the GL accesses data ad <bufferObjectAddress> + <pointer>, figuring out another address (which you don't know since you don't know <bufferObjectAddress>. So, the pointer you pass is used as an offset and since you can easily use a buffer object for every small bit of geometry you want, you usually can pass NULL and pull out directly from <bufferObjectAddress> + 0.

Take care however, buffer object offsets are in **bytes** and not in elements, float, vertices or stuff like that.

thank you for these infos, i'm going to give ARB_vbo a try http://www.opengl.org/discussion_boards/ubb/wink.gif

ghostdog
09-15-2003, 08:22 AM
Originally posted by Deiussum:
I just re-read your posts a bit more. You say it works when you cast mesh->getVertices() to a float* but not to an int*?

If that is what you are saying then, duh. The memory layout for ints and floats is totally different so if you just try to cast a float* to an int* and then access the individual elements of the int*, you will get totally different values from the individual elements of the float*. It won't be a simple truncation/rounding either. Floats are stored in IEEE format for floating point numbers and ints are stored in a more direct manner.

Edit: To clarify, casting a float* to an int* is not like casting a float to an int. It will not cast every element of the float array to an int. Instead, it merely casts the float pointer to an int pointer. It still points to the same memory location, and the memory is still layed out exactly like it was for the float pointer, it's just interpretted a bit different when reading the array.

[This message has been edited by Deiussum (edited 09-15-2003).]

hmm, i think you get me totally wrong. i don't want to cast floats to ints nor the other way round. i think you misunderstood something because of the lack of code. sorry, i posted it above.

for using glDrawElements() (for drawing vertex arrays) i need a pointer to the vertex data (which are is an array of sequential floats-coordinates: x,y,z,x,y,z,...) and a pointer to the indices-array.
these data is stored in the member variables of my objectclass "CMesh".

so my main attempt is to get 2 pointers. one pointing to the int-array (indices)and one to the float-array (vertices). and therefore is my cast. but the cast only works for the float pointer, not for the int.

so when i run my app. the triangles of the mesh are connected wrong because the indices are wrong. but when i draw only the vertex data (with GL_POINTS) i get the correct vertices.

so i conclude there is something wrong with the cast because the data is correct on the CMesh-side, but not with the pointer finally pass to the glDrawElements()-call.

EDIT: now i got, what you misunderstood. sorry for posting such stupid code... damn...
of course those lines are totally separated. hope it's clear from my new posted, completer code.
sorry if my post before was not at all understandable!

regards,
ghostdog


[This message has been edited by ghostdog (edited 09-15-2003).]

Deiussum
09-15-2003, 09:40 AM
Ok, there's no need to even do a cast there. You're returning an int* and storing it in an int*, so why is a cast needed at all?

Maybe the problem lies in the way you fill your index array? glDrawArrays itself only takes the pointer to the index array. You use the vertex array in glVertexPointer. Maybe you should also post some code around this area so we can see what you are doing.

Basically, you should have something like so:




//Simple example, just using static allocation
//but that shouldn't matter.
float pVertices[] = {0.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0};
unsigned int pIndices[] = {0, 1, 2};
glVertexArray(3, GL_FLOAT, 0, pVertices);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, pIndices);



[This message has been edited by Deiussum (edited 09-15-2003).]

ghostdog
09-15-2003, 03:35 PM
void CMesh::handleFace(vector<string> *words, int offset){
int i;
char buffer[MAX_STRINGLENGTH];
char seperator[] = "/";
char *token;

//3 (+1 for 'f') entries means face = triangle
if( words->size() == 4 ){
//faces[offset].texindex = ti;

for(i = 0; i < 3; i++){
//copies first couple after "f" into buffer
strcpy(buffer, words->at(i+1).c_str());

//if first char != / and offset < numFaces
if(buffer[0]!='/' &amp;&amp; offset < numFaces){
token = strtok( buffer, seperator ); //get first part
faceIndices[offset+i]=(int)atoi(token); //get first nummber (till first '/')
} else {
std::cout << "OBJ_ERROR: face invalid" << endl;
}
}
} else {
std::cout << "OBJ_ERROR: face is no triangle" << endl;
}
}


explanation:
i'm loading an wavefront OBJ file. these files are ASCII txt-files. so i read line by line and parse them.

after loading every vertex sequentially from the file in an array, i have to load the indices of the faces. faces are defined in lines that look like that:

"f v7/vt7/vn7 v46/vt46/vn46 v83/vt83/vn83"

v ... vertex index
vt ... texture coordinate index
vn ... vertex normal index

i.e. this face(triangle) consists of v7, v46, v83

so my parsing-function divides a line into chunks (which are separated by whitespaces) and pushes them on a string-vector (words).

-> words[0]='f'
-> words[1]='v7/vt7/vn7'
-> words[2]='v46/vt46/vn46'
-> words[4]='v83/vt83/vn83'

then i call the function handleFace() and i pass my string vector as an argument.
i only need the indices of the vertices for now, so i have to split those 'v7/vt7/vn7' up again to get only the integer at v7. this value is written into the array.

i debugged this loading code step by step and i printed it out on the console. it seemed to be correct (at least at the beginning and at the end, ist quite difficult to compare very much values). but i printed them out right before the glDrawElements-call (but after the cast) and they are changed. the vertices are right, only the indices are false...

hope the code and explanation is more or less easy to understand.
thx for your help and patience.

ghostdog



[This message has been edited by ghostdog (edited 09-15-2003).]

ghostdog
09-16-2003, 10:02 AM
uuups. it actually was the loading code. found 3 bugs with the indices in there. thank you for the tip.

so finally i am able to draw my obj-models.
thank you for you help.

br,
ghostdog