Is there a simple multiple VBO example?

Is there a simple multiple VBO/IBO example…
say that just draws 2 different triangles … where each is a separate VBO/IBO.

I obviously want to code a more complicated example but my current one only displays the last one so obviously I’m doing something wrong.

I figured a watered down example would illustrate the issue.

Here is what I am currently trying…

Variable initialization:


GLuint vertexbuffer;
GLuint uvbuffer;
GLuint normalbuffer;
GLuint colorbuffer;
GLuint elementbuffer;
GLuint VertexArrayID;

std::vector<unsigned short> indices;
std::vector<glm::vec3> indexed_vertices;
std::vector<glm::vec2> indexed_uvs;
std::vector<glm::vec3> indexed_normals;
std::vector<glm::vec4> indexed_colors;


GLuint vertexbuffer2;
GLuint uvbuffer2;
GLuint normalbuffer2;
GLuint colorbuffer2;
GLuint elementbuffer2;
GLuint VertexArrayID2;

std::vector<unsigned short> indices2;
std::vector<glm::vec3> indexed_vertices2;
std::vector<glm::vec2> indexed_uvs2;
std::vector<glm::vec3> indexed_normals2;
std::vector<glm::vec4> indexed_colors2;

struct PackedVertex{
	glm::vec3 position;
	glm::vec2 uv;
	glm::vec3 normal;
	glm::vec4 color;
	bool operator<(const PackedVertex that) const{
		return memcmp((void*)this, (void*)&that, sizeof(PackedVertex))>0;
	};
};

std::vector<glm::vec3>  in_vertices;
std::vector<glm::vec2>  in_uvs;
std::vector<glm::vec3>  in_normals;
std::vector<glm::vec4>  in_colors;

in_vertices.push_back(glm::vec3(0,0,0));
in_vertices.push_back(glm::vec3(1,0,0));
in_uvs.push_back(glm::vec2(0,0));
in_uvs.push_back(glm::vec2(0,0));

in_normals.push_back(glm::vec3(0,1,0));
in_normals.push_back(glm::vec3(0,1,0));
in_colors.push_back(glm::vec4(1,1,1,1));
in_colors.push_back(glm::vec4(1,0,0,1));


std::vector<glm::vec3>  in_vertices2;
std::vector<glm::vec2>  in_uvs2;
std::vector<glm::vec3>  in_normals2;
std::vector<glm::vec4>  in_colors2;


in_vertices2.push_back(glm::vec3(0,1.3,0));
in_vertices2.push_back(glm::vec3(1,1.3,0));

in_uvs2.push_back(glm::vec2(0,0));
in_uvs2.push_back(glm::vec2(0,0));

in_normals2.push_back(glm::vec3(0,1,0));
in_normals.push_back(glm::vec3(0,1,0));

in_colors2.push_back(glm::vec4(0,0,1,1));
in_colors2.push_back(glm::vec4(0,0,1,1));


void InitializeVertexBuffer(GLuint &theBuffer, GLenum target,  GLenum usage, const void* data,  int size)
{
	glGenBuffers(1, &theBuffer);
	glBindBuffer(target, theBuffer);
	glBufferData(target, size, data, usage);
	glBindBuffer(target, 0);
}

Setting up IBO/VAO/VBO


// For each input vertex
for ( unsigned int i=0; i<2; i++ ){

	// Try to find a similar vertex in out_XXXX
	unsigned short index;
	bool found = getSimilarVertexIndex(in_vertices[i], in_uvs[i], in_normals[i],     indexed_vertices, indexed_uvs, indexed_normals, index);

	if ( found ){ // A similar vertex is already in the VBO, use it instead !
		indices.push_back( index );
	}else{ // If not, it needs to be added in the output data.
		indexed_vertices.push_back( in_vertices[i]);
		indexed_uvs     .push_back( in_uvs[i]);
		indexed_normals .push_back( in_normals[i]);
		indexed_colors .push_back( in_colors[i]);
		indices .push_back( (unsigned short)indexed_vertices.size() - 1 );
	}
}



	size_t colorDataOffset = 0;
InitializeVertexBuffer(vertexbuffer, GL_ARRAY_BUFFER, GL_STATIC_DRAW, &indexed_vertices[0], indexed_vertices.size() * sizeof(glm::vec3)  );
InitializeVertexBuffer(uvbuffer, GL_ARRAY_BUFFER, GL_STATIC_DRAW, &indexed_vertices[0], indexed_vertices.size() * sizeof(glm::vec2)  );
InitializeVertexBuffer(normalbuffer, GL_ARRAY_BUFFER, GL_STATIC_DRAW, &indexed_normals[0], indexed_normals.size() * sizeof(glm::vec3)  );
InitializeVertexBuffer(colorbuffer, GL_ARRAY_BUFFER, GL_STATIC_DRAW, &indexed_colors[0], indexed_colors.size() * sizeof(glm::vec4)  );
InitializeVertexBuffer(elementbuffer, GL_ARRAY_BUFFER, GL_STATIC_DRAW, &indices[0], indices.size() * sizeof(unsigned short)  );

//Generate VAO
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);

// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 );

// 2nd attribute buffer : normals
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 );

// 3nd attribute buffer : UVs
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0 );

// 4th attribute buffer : colors
glEnableVertexAttribArray(3);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 0, (void*)0 );

// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);	


//****Second one*****//

		// For each input vertex
	for ( unsigned int i=0; i<2; i++ ){

		// Try to find a similar vertex in out_XXXX
		unsigned short index;
		bool found = getSimilarVertexIndex(in_vertices2[i], in_uvs2[i], in_normals2[i],     indexed_vertices2, indexed_uvs2, indexed_normals2, index);

		if ( found ){ // A similar vertex is already in the VBO, use it instead !
			indices2.push_back( index );
		}else{ // If not, it needs to be added in the output data.
			indexed_vertices2.push_back( in_vertices2[i]);
			indexed_uvs2     .push_back( in_uvs2[i]);
			indexed_normals2 .push_back( in_normals[i]);
			indexed_colors2 .push_back( in_colors2[i]);
			indices2.push_back( (unsigned short)indexed_vertices2.size() - 1 );
		}
	}

size_t colorDataOffset = 0;
InitializeVertexBuffer(vertexbuffer2, GL_ARRAY_BUFFER, GL_STATIC_DRAW, &indexed_vertices2[0], indexed_vertices2.size() * sizeof(glm::vec3)   );
InitializeVertexBuffer(uvbuffer2, GL_ARRAY_BUFFER, GL_STATIC_DRAW, &indexed_vertices2[0], indexed_vertices2.size() * sizeof(glm::vec2)  );
InitializeVertexBuffer(normalbuffer2, GL_ARRAY_BUFFER, GL_STATIC_DRAW, &indexed_normals2[0], indexed_normals2.size() * sizeof(glm::vec3)  );
InitializeVertexBuffer(colorbuffer2, GL_ARRAY_BUFFER, GL_STATIC_DRAW, &indexed_colors2[0], indexed_colors2.size() * sizeof(glm::vec4)  );
InitializeVertexBuffer(elementbuffer2, GL_ARRAY_BUFFER, GL_STATIC_DRAW, &indices2[0], indices2.size() * sizeof(unsigned short)  );

//Generate VAO
glGenVertexArrays(1, &VertexArrayID2);
glBindVertexArray(VertexArrayID2);


	// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer2);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0  );

// 2nd attribute buffer : normals
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer2);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 );

// 3nd attribute buffer : UVs
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0 );

// 4th attribute buffer : colors
glEnableVertexAttribArray(3);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer2);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 0, (void*)0 );

// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer2);				

Now Drawing


do{
glUseProgram(programID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
// Draw the primatives !
glDrawElements(GL_POINTS, 2, GL_UNSIGNED_SHORT, (void*)0);


glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer2);
glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, (void*)0);

glUseProgram(0); 
glfwSwapBuffers();
..}

So when I init the 2nd VBO it over and I only get 2 blue dots and not 2 dots and a line

That happens because you have to redefine the vertex attribute arrays. You have to draw your elementbuffer directly after you setup your buffer’s layout via glVertexAttribPointer().

Basic example:


//draw the points
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

//set up other buffers that belong to your point-setup

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
glDrawElements(GL_POINTS, 2, GL_UNSIGNED_SHORT, (void*)0);

//draw the lines
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer2);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

//set up other buffers that belong to your line-setup

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer2);
glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, (void*)0);

When you do your glDrawElements() call the data is read from the addresses that you set by glVertexAttribPointer(), so you have to setup your pointers via glVertexAttribPointer() each time before you do your draw-call (unless you want to draw the same things or different things but from the same VBO’s).

So does that mean I always have to interleave draw calls?

So I cannot bind different VBOs for each attribute, and A Vertex Array Object or VAO to store the state of all the glVertexAttribPointer calls and the VBOs that were targeted when each of the glVertexAttribPointer calls were made?

I would think I could use something to store the state of the glVertexAttribPointer(s) when I init the buffers so that I could call them later than reset them in the draw loop especially for static geometry.

[QUOTE=JohnMarkem;1252194]That happens because you have to redefine the vertex attribute arrays. You have to draw your elementbuffer directly after you setup your buffer’s layout via glVertexAttribPointer().

When you do your glDrawElements() call the data is read from the addresses that you set by glVertexAttribPointer(), so you have to setup your pointers via glVertexAttribPointer() each time before you do your draw-call (unless you want to draw the same things or different things but from the same VBO’s).[/QUOTE]

Just use a few VAOs and the problem is solved

Where should I put the few VAOs… and how do I store that to work so I can use it for multiple meshes… interleving the draw calls like that and binds in that fashion still just seems wrong in practice even if it might work.

I would think you could set that all up in an initialization somewhere ahead of time and it would work out

No. You can choose whether to interleave or not. Further, if you don’t interleave, you can choose whether to put all of the vertex attribs in separate buffers per attrib, the same buffer for all attribs, or anywhere in between.

So I cannot bind different VBOs for each attribute,

Sure you can.

…and A Vertex Array Object or VAO to store the state of all the glVertexAttribPointer calls and the VBOs that were targeted when each of the glVertexAttribPointer calls were made?

Sure, no problem.

See Example 5.3 here: Chapter 5. Objects in Depth

BTW, I don’t understand the comment about using a few VAOs.