Skip to main content
GameDev.net gamedev.net
🔒 Locked

glDrawElements Problem

Started by mudrugger Mar 8, 2009 at 7:39 AM 21 replies 10.5k views
Original Post
mudrugger
mudrugger
Hi Everyone, I'm having a problem getting glDrawElements (openGL) to render my vertex buffer objects. Would someone please take a look at what I'm doing and explain to me what I'm doing wrong? The code below works fine

GLfloat flt [] = {	-1.0, 1.0, 0.0,
			1.0, 1.0, 0.0,
			-1.0, -1.0, 0.0
		};
GLubyte indices [] = {
			0, 2, 1
		};
GLuint buffId;

glGenBuffers(1,&buffId);

glBindBuffer(GL_ARRAY_BUFFER, buffId);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*9, flt, GL_STATIC_DRAW);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, 0);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, indices);

glDeleteBuffers(1, &buffId);
However, when I put the indices into a buffer nothing happens. The program doesn't crash...It just gives me a perfectly rendered white screen! And glGetError says that there is not an error so what ever is happening is ignored by openGL.

GLfloat flt [] = {	-1.0, 1.0, 0.0,
			1.0, 1.0, 0.0,
			-1.0, -1.0, 0.0
		};
GLubyte indices [] = {
			0, 2, 1
		};
GLuint buffId;
GLuint buffIndexId;

glGenBuffers(1,&buffId);
glGenBuffers(1, &buffIndexId);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffIndexId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte)*3, indices, GL_STATIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, buffId);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*9, flt, GL_STATIC_DRAW);
glVertexPointer(3, GL_FLOAT, 0, 0);

glEnableClientState(GL_VERTEX_ARRAY);

glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, 0);

glDeleteBuffers(1, &buffId);
glDeleteBuffers(1, &buffIndexId);
Can anyone see what I'm doing wrong? Thanks in advance [Edited by - mudrugger on March 9, 2009 4:36:48 AM]
Badgerr
Badgerr
Can't say for sure but maybe because you have this line:

glVertexPointer(3, GL_FLOAT, 0, 0);

BEFORE this one

glEnableClientState(GL_VERTEX_ARRAY);

so you're trying to give it a vertex array when that state isn't yet enabled.
________________________________Blog...
mudrugger
mudrugger
I moved the glEnableClientState(GL_VERTEX_ARRAY) call to right before the glVertextPointer call but it had the same results.
However, thanks for your suggestion.
broady
broady
Don't you need GLflush() somewhere?
erissian
erissian
I'm completely wrong :D

What stands out immediately is that you don't use your index array. It may not be the problem, but you aren't going to get anywhere without it.

glEnableClientState(GL_VERTEX_ARRAY);glEnableClientState(GL_INDEX_ARRAY);glVertexPointer(3, GL_FLOAT, 0, 0);glIndexPointer(GL_UNSIGNED_BYTE, 0, 0);glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, 0);glDisableClientState(GL_INDEX_ARRAY);glDisableClientState(GL_VERTEX_ARRAY);



[Edited by - erissian on March 9, 2009 8:00:32 AM]
We''re sorry, but you don''t have the clearance to read this post. Please exit your browser at this time. (Code 23)
Brother Bob
Brother Bob
Quote:
Original post by erissian
What stands out immediately is that you don't use your index array. It may not be the problem, but you aren't going to get anywhere without it.

glEnableClientState(GL_VERTEX_ARRAY);glEnableClientState(GL_INDEX_ARRAY);glVertexPointer(3, GL_FLOAT, 0, 0);glIndexPointer(GL_UNSIGNED_BYTE, 0, 0);glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, 0);glDisableClientState(GL_INDEX_ARRAY);glDisableClientState(GL_INDEX_ARRAY);

That's for the color index array (the indexed color mode equivalent to glColorPointer), not the vertex index array which is passed as the last argument to glDrawElements (or in the case of VBO, bound and the parameter specifies the offset).
mudrugger
mudrugger
I will try GLflush after each call, but if that was the case, wouldn't the first example that I provided above not work either?
I may be mistaken but it would seem that that would be the case. I will give it a try and let you know how it turns out.
Thanks for helping
mudrugger
mudrugger
I added glFlush and then glFinish (not at the same time) to the end of the code above and still no luck.
I am using Linux (Ubuntu 7.4) and compiling with g++. Are there any known issues with glDrawElements and the above system?
I highly doubt that that is the problem since I googled and checked the Ubuntu site for any known issues but right now I'm willing to try anything.
I may just try porting my code over to Windows and see if that is case.
What do you guys think?

[Edited by - mudrugger on March 10, 2009 6:06:19 AM]
tksuoran
tksuoran
You could try 16 bit indices. Could be that byte indices are not supported. Have you checked glGetError()?
mudrugger
mudrugger
I originally used 32 bit (int) before changing it to byte. I found some examples using byte so I made the change and never changed it back.
I'll give GLushort a try since I haven't tried that yet.
Thanks
erissian
erissian
Sorry, I tend to use glDrawArrays() instead, so it wasn't clear to me what the problem was.

If you want to use an index array, then you should use glDrawRangeElements(), which takes an array of indices as an argument.

glDrawRangeElements( GL_TRIANGLES, 0, 2, 1, GL_UNSIGNED_BYTE, indices );// Args:// Primitive type// First index to render// Last index to render// Number of primitives to render// Index data type// Pointer to indices


(If I'm wrong again I will be forever shamed) :D
We''re sorry, but you don''t have the clearance to read this post. Please exit your browser at this time. (Code 23)
mudrugger
mudrugger
Rigt or wrong, I appreciate your help. Passing ideas back and forth always helps you learn something!
I believe that both glDrawElements and glDrawRangeElements will use the VBO that is bound with the GL_ELEMENT_BUFFER_ARRAY flag. So the call to either one of those while the "index buffer" is set will use the last argument as a buffer offset rather than the source of the indices.(I hope that made sense)
I have successfully used glDrawElements by commenting out the glBindBuffer call to the index buffer and passing in the indices but not with the Index Buffer (See the first post for this example).
I would use an index array if I have no other choice but every example I read on the web or in a book explains it as if it should work automatically.
However, it is really important for me to draw a large amount of objects as fast as possible and the VBO seems to be the answer I need.
Once again, thanks. If you (or anyone) can think of anything that could help, I would appreciate it.
Badgerr
Badgerr
Quote:
Original post by erissian
Sorry, I tend to use glDrawArrays() instead, so it wasn't clear to me what the problem was.

If you want to use an index array, then you should use glDrawRangeElements(), which takes an array of indices as an argument.

glDrawRangeElements( GL_TRIANGLES, 0, 2, 1, GL_UNSIGNED_BYTE, indices );// Args:// Primitive type// First index to render// Last index to render// Number of primitives to render// Index data type// Pointer to indices


(If I'm wrong again I will be forever shamed) :D


I think if you're using a VBO, you don't need to pass it the indices - it reads them from the VBO if you have bound the GL_ELEMENT_ARRAY_BUFFER.


*Edit* I'd just like to say that I use VBO in pretty much the same way as the OP, and I can't see anything majorly different from my own code that could stop it from working. The only difference is my use of GLushort for the indices, compared to mudrugger's use of GLubyte.
________________________________Blog...
RazzleGames
RazzleGames
It would help to show the rest of your render code. Usually if you are getting a VBO issue, where data is incorrect or the VBO handle is unallocated before rendering, you'll get nifty crashes and/or a very strange looking polygon mess. (Learned this through experience ;) )

Quote:
The only difference is my use of GLushort for the indices, compared to mudrugger's use of GLubyte.


I think this *could* be an issue, if the data is not packed, and also endianess could come into play (but maybe this architecture dependency is accounted for when passing to the data transfer method, I honestly haven't tried this). For instance, if I do this:

GLubyte indices [] = {			0, 2, 1		};


Then Look at memory (neglecting Endianness fun), I could see: 0x000201, or maybe.

0x00000000 ,0x00000002, 0x00000001... Or maybe other variants of this depending on what architecture you are on (16bit anyone?). It all depends on how the compiler packs the data.
mudrugger
mudrugger
Quote:

It would help to show the rest of your render code.


What is it that you would like to see? The only code not showing is the window set up info and a couple of opengl flags such as GL_DEPTH_TEST. Along with a standard while loop that updates and renders the example. If it would help you I will post it.

As far as crashes, the above code doesn't do that. It just doesn't render anything at all when I use the index buffer object (I know there is no actual object called that but it's easier than saying the VBO with the GL_ELELMENT_ARRAY_BUFFER flag set).

I also tried something else that may give everyone some insight. I did the following before calling glDrawElements:

unsigned byte * ibuff = (unsigned byte *)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);printf("%d %d %d\n",ibuff[0],ibuff[1],ibuff[2]);glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);


The values are printed to the stream and the data is correctly displayed, so the vbo does have data.
RazzleGames
RazzleGames
For giggles, try casting to a (unsigned int*) and printing just that (dereferenced), to get an idea of how packed the data is, but I could be barking up the wrong tree on that one.

First thing I do in situations like this: Decrease complexity.

--The reason I suggested showing the render code was just a sanity check (make sure you haven't messed up the state machine). Instead try rendering something simple you know should work, and temp comment out the VBO. A white screen for me usually means I botched the state.

--Try converting your code to a normal vertex array (not stored on card) and see how that goes (should be exactly the same data format, and nearly the same code).

Have you done these things?

If that goes OK, then I'd ask if you've done any checks to see if the hardware supports VBO. I'd say these days chances are pretty good, but I don't really know what you're using.

Also, keep in mind you are doing a draw request and then issuing a delete immediately afterwards. This is kind of like a remote system (if you're using a graphics card) and if that draw command takes longer to complete than the queued glDeleteBuffers(1, &buffId); command, (and they're pipelined somehow) you maybe trying to render a unallocated memory space.

Again, I'm not sure how that's implemented, under the hood. But if rendering as a vert array works, then that would be the first thing I try and comment out (glDeleteBuffers).
mudrugger
mudrugger
Quote:

A white screen for me usually means I botched the state.

That is what I thought it was (still hope it is).

Quote:

--Try converting your code to a normal vertex array (not stored on card) and see how that goes (should be exactly the same data format, and nearly the same code).

I have used the vertices as both vertex array and as a buffered array. When I do not bind the buffered indices and use the index array itself the triangle appears.

Quote:

If that goes OK, then I'd ask if you've done any checks to see if the hardware supports VBO. I'd say these days chances are pretty good, but I don't really know what you're using.

I am using Linux (Ubuntu 7.4) with g++. I am in the middle of porting my code over to Windows using Visual Studio. To see if it may be the system itself.

Quote:

Also, keep in mind you are doing a draw request and then issuing a delete immediately afterwards. This is kind of like a remote system (if you're using a graphics card) and if that draw command takes longer to complete than the queued glDeleteBuffers(1, &buffId); command, (and they're pipelined somehow) you maybe trying to render a unallocated memory space.

This may be but it does render using only the vertex VBO and the index array (w/out VBO).

These are all good points that I will check one by one. Eventhough I may have commented a reason after each of your points saying why I don't think it may be the case, it will be a good excercise in checking myself.

I'll post the results.

Thanks for your time and effort in helping me.


RazzleGames
RazzleGames
I use Linux Mandriva 2008.1, it has similar packages to your distro, I EXTREMELY doubt it's a Linux problem, but you never know I guess. But, about 90% of the time it is "operator error" and not driver bugs etc.

But any-who, I meant "what you are using" in the sense of hardware and software (I mean, there are OpenGL implementations on phones!). Modern PC software should not be much of a limitation here, as modern OpenGL supports VBO, just a question of if using REALLY old hardware.

Quote:

Quote:

Also, keep in mind you are doing a draw request and then issuing a delete immediately afterwards. This is kind of like a remote system (if you're using a graphics card) and if that draw command takes longer to complete than the queued glDeleteBuffers(1, &buffId); command, (and they're pipelined somehow) you maybe trying to render a unallocated memory space.


This may be but it does render using only the vertex VBO and the index array (w/out VBO).


Sorry, I don't understand what you mean exactly.

Do you mean it renders without doing glGenBuffers(1,&buffId); and using what is called a Vertex Array (not VBO)?

If you are using Vertex arrays (what I call bliting the verticies to the card, at each frame, and not storing them on the card) there is no need to delete or allocate graph card buffers (as they are not stored on the card).

So anyhow, you can see how that call to glDeleteBuffers would not do anything important if you were not using memory on the card.

In other words, being able to display Vert Arrays when having the glDeleteBuffers call still uncommented is not relevant in this case. It is VERY relevant to when you are using VBOs on the graphics card, though.

Try removing that delete call when using VBOs, and the other simplification steps and let us know.

Good luck!


EDIT: BTW, I checked on your distro release number, and it looks a bit old. This is ok though, but you should also always make sure you have the latests packages for your distro release number. Check using your package manager.

ALso, if the distro gets too old, support ceases (but usually that is several years later). Anyhow, it's very unlikely to be an issue in this case, but you should know about this to avoid annoying bugs.

[Edited by - RazzleGames on March 11, 2009 2:59:11 PM]
mudrugger
mudrugger
Hi All,
I ported my code over to windows and it works!!!
I'm going to check the drivers on my Linux box and see how why this happened. I know that it uses a restricted driver for my intel video card but I'm shocked that that was the problem.
However, I was able to make the simple triangle in the original post to render so I uncommented some code and loaded up a couple of mesh objects and was able to render over 50,000 vertices every 30 milliseconds without a hiccup on a windows machine with 512MB of ram and way too many applications running in the background (Over 6 years old). OpenGL is a beautiful thing when you get it working properly.
Thanks to everyone who helped me
This web site is a fantastic resource
jackhat25
jackhat25
I have the same problem; but in my case is loading a vertex array from a fila (data.txt). When the program is loading the records from the file; the memory array loss the pointer; and all the time show th first record; the others record don't.


any reference o comment..?
I'm a computer science student; I live in Buenos Aires,Argentina,I like the programming, video games, the Football soccer, the kickboxing and of course the women.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.