PDA

View Full Version : Simple error with glDrawElements(GL_TRIANGLES)



Wasabi
04-29-2011, 04:11 PM
I'm having what seems to be a bit of an odd error which certainly is my own fault. I've just started using OpenGL 3.3, so I'm still feeling my way around.

Here's a code snippet to give an idea of the error:

mesh.vertex = new NVertex[4];
mesh.index = new unsigned int[6];
mesh.vertex[0].Set(-1,0,0,0,0,1);
mesh.vertex[1].Set(0,1,0,0,1,0);
mesh.vertex[2].Set(0,0,0,1,0,0);
mesh.vertex[3].Set(1,0,0,0,0,1);
mesh.index[0]=0;
mesh.index[1]=1;
mesh.index[2]=2;
mesh.index[3]=1;
mesh.index[4]=2;
mesh.index[5]=3;

glGenBuffers(1, &environment.VBO);
glBindBuffer(GL_ARRAY_BUFFER, environment.VBO);
glBufferData(GL_ARRAY_BUFFER, mesh.size(), &mesh.vertex[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0); //VERTEX COORDINATES
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(NVertex), BUFFER_OFFSET(0));
glEnableVertexAttribArray(1); //VERTEX COLORS
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(NVertex), BUFFER_OFFSET(12));

glGenBuffers(1,&environment.VIO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,environment.V IO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*environment.element_num, mesh.index,GL_STATIC_DRAW);
//...
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, BUFFER_OFFSET(0));

If I run this code, only the first triangle appears. However, if I change it for GL_TRIANGLE_STRIP (and make the necessary adjustments), it works and both triangles appear:

mesh.vertex = new NVertex[4];
mesh.index = new unsigned int[4];
mesh.vertex[0].Set(-1,0,0,0,0,1);
mesh.vertex[1].Set(0,1,0,0,1,0);
mesh.vertex[2].Set(0,0,0,1,0,0);
mesh.vertex[3].Set(1,0,0,0,0,1);
mesh.index[0]=0;
mesh.index[1]=1;
mesh.index[2]=2;
mesh.index[3]=3;

glGenBuffers(1, &environment.VBO);
glBindBuffer(GL_ARRAY_BUFFER, environment.VBO);
glBufferData(GL_ARRAY_BUFFER, mesh.size(), &mesh.vertex[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0); //VERTEX COORDINATES
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(NVertex), BUFFER_OFFSET(0));
glEnableVertexAttribArray(1); //VERTEX COLORS
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(NVertex), BUFFER_OFFSET(12));

glGenBuffers(1,&environment.VIO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,environment.V IO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*environment.element_num, mesh.index,GL_STATIC_DRAW);
//...
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, BUFFER_OFFSET(0));

I'm sure this is a stupid, stupid mistake, but I can't figure out what it is. Any help?

mhagain
04-29-2011, 06:23 PM
Reverse the winding order of the second triangle (indexes 3/2/1) and it should work.

Wasabi
04-29-2011, 07:12 PM
Nope. Still only the left triangle. :S

mobeen
04-30-2011, 03:53 AM
Change this line


mesh.index[0]=0;
mesh.index[1]=1;
to


mesh.index[0]=1;
mesh.index[1]=0;
and see if u get the right result.
Reason:
The first triangle is wound clockwise whereas the second one is counterclockwise. This will work for triangle strip but for triangles you need to maintain the same winding for all of the triangles.

Wasabi
04-30-2011, 04:21 AM
Still no change. Making just that alteration or doing it and mhagain's at the same time doesn't change the result. As well, mhagain's was basically the same idea, but just changing the winding of the second triangle instead of the first.

As well, isn't CULL_FACE disabled by default? I haven't enabled it, so the winding order (and thus the definition of front or back faces) shouldn't matter that much, should it?

Dan Bartlett
04-30-2011, 08:18 AM
Is environment.element_num returning the right number of indices? (6 in the first case, 4 in the second case) It could be the case that you aren't uploading enough index data.

GL_CULL_FACE initial value is disabled. It is a common cause of "missing" triangles, although not in your case.

Wasabi
04-30-2011, 03:30 PM
My, don't I feel silly. Since I was just testing things, I hard-coded element_num to be exactly what I wanted it to be. Only I'd hard-coded it to the wrong value for some reason.

As I said in the OP, this was a stupid, stupid mistake. Nevermind me. >.>

Wasabi
04-30-2011, 04:20 PM
Or not. Well, those two triangles are working, but now I've got another problem which I'm fairly certain is related, but I can't point it out.

The code is now

environment.vertex_num = 5;
environment.index_num = 9;
mesh.vertex = new NVertex[environment.vertex_num];
mesh.index = new unsigned int[environment.index_num];
mesh.vertex[0].Set(-1,0,0,0,0,1);
mesh.vertex[1].Set(0,1,0,0,1,0);
mesh.vertex[2].Set(0,-0.5,0,1,0,0);
mesh.vertex[3].Set(1,0,0,0,0,1);
mesh.vertex[4].Set(0.5,-1,0,1,1,1);

mesh.index[0]=0;
mesh.index[1]=1;
mesh.index[2]=2;

mesh.index[3]=1;
mesh.index[4]=2;
mesh.index[5]=3;

mesh.index[6]=4;
mesh.index[7]=3;
mesh.index[8]=1;

glGenBuffers(1, &environment.VBO);
glBindBuffer(GL_ARRAY_BUFFER, environment.VBO);
glBufferData(GL_ARRAY_BUFFER, mesh.size(), &mesh.vertex[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0); //VERTEX COORDINATES
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(NVertex), BUFFER_OFFSET(0));
glEnableVertexAttribArray(1); //VERTEX COLORS
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(NVertex), BUFFER_OFFSET(12));

glGenBuffers(1,&environment.VIO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,environment.V IO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*environment.index_num, mesh.index,GL_STATIC_DRAW);
//...
glDrawElements(GL_TRIANGLES, environment.index_num, GL_UNSIGNED_INT, BUFFER_OFFSET(0));

Notice how I do not even have a (0,0,0) coordinate. However, if I now run the program, both of the now-working triangles appear, but the third triangle seems to lose its last vertex, which is drawn as a (0,0,0) point. This time, vertex_num and index_num are right there so that any mistakes become quickly evident.

Dan Bartlett
04-30-2011, 08:33 PM
It could be an issue with how NVertex is declared, the compiler might be putting in extra bytes of padding after the position + color fields for alignment reasons, so you might need to override this somehow, to force NVertex to be tightly packed. Alternatively, if you have other float values that need to be included, you could pack them into the spaces.

Wasabi
04-30-2011, 09:10 PM
This is the NVertex class:

class NVertex
{
float x, y, z;
float r,g,b;
public:
NVertex();
NVertex(float x, float y, float z, float r=1, float g=1, float b=1);
void Set(float _x, float _y, float _z, float _r=1, float _g=1, float _b=1);
void SetColor(float _r, float _g, float _b);
void SetPos(float _x, float _y, float _z);
};

It's just floats, which are 4-byte chunks, and some functions with the same privacy setting, which I've been told do not increase the memory footprint of the class in any modern compiler (I'm using VC++2008Express, which I take to be a pretty modern compiler. Can't use 2010 because this project is eventually going to be merged with Qt, which isn't VC++2010-portable yet).

Alfonse Reinheart
04-30-2011, 09:46 PM
The C++ specification's definition for "plain old data" types specifically excludes types with member functions or with non-public members. It may just work, but C++ doesn't say it will.

Dan Bartlett
05-01-2011, 03:13 AM
There's some more information about this at:
http://en.wikipedia.org/wiki/C++_classes
http://en.wikipedia.org/wiki/Plain_old_data_structure

A simple check would be to test whether sizeof(NVertex) = 24

Wasabi
05-01-2011, 07:40 AM
Alfonse, to quote you in this thread (http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=290337#Post2903 37):


According to the Standard for Programming Language C++, doing what you are doing is not guaranteed to work as you expect it to. The next version of the C++ standard will allow what you're doing to work because...

According to pretty much every actual C++ compiler on the planet, what you're doing will be just fine. As long as you don't have inheritance or virtual functions (and all member variables have the same protection class), a class/struct with members will work exactly like a class/struct without members.

I'd seen the first part that stated what I was doing was non-standard, but took the second part to be more relevant, since I'm using a pretty famous compiler and my class fits the description (same protection for all variables, no virtual functions, no inheritance).

As well, sizeof(NVertex) does indeed return 24. And, just to be sure, I changed NVertex to an all-public struct and still have the same problem.

Wasabi
05-05-2011, 11:22 AM
Any help please?

Dan Bartlett
05-06-2011, 05:56 AM
Does mesh.size() return vertex_count * sizeof(NVertex)? I assume strides + offsets are working ok now, or the second triangle wouldn't show up properly.
Are the positions used what you expect them to be? Currently the third triangle overlaps the 2nd triangle.

Wasabi
05-06-2011, 12:32 PM
Another silly mistake. Made a beginner mistake and used sizeof(mesh.vertex) to get the number of elements in mesh.vertex, which obviously doesn't work. Altered the code and now it's working. Lets hope my streak of stupid mistakes is over.