Simple error with glDrawElements(GL_TRIANGLES)

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.VIO);
	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.VIO);
	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?

Reverse the winding order of the second triangle (indexes 3/2/1) and it should work.

Nope. Still only the left triangle. :S

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.

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?

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.

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. >.>

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.VIO);
	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.

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.

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).

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.

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

Alfonse, to quote you in this thread:

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.

Any help please?

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.

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.