How to add vertices in a VBO

Started by
5 comments, last by TheChubu 8 years, 11 months ago

Hi.

I'm making a voxel world renderer to learn OpenGL. I divided the world in Chunks (group of blocks/voxels) and I thought that the rendering could be optimized if only one draw call was done per chunk, instead of one draw call per block. The problem is that I don't know how to add vertices to the VBO, and I don't think it is possible. I'm learning OpenGL with this wikibook : http://en.wikibooks.org/wiki/OpenGL_Programming but it only shows how to use VBOs for a known number of vertices (a single cube for example). Is there a way to add vertices to a VBO ?

Or if that's not possible, is there a way to create a mesh and add triangles or vertices to it and then display it ?

I'm sorry if this question has already been asked, I couldn't find what I wanted to know.

Thanks a lot.

Advertisement

You can change the content of a buffer in various ways, for example by calling glBufferSubData or by mapping the content to memory with glMapBuffer. If your buffer content can change in size, then start with a large buffer and draw only the necessary part of it so you can expand it later when needed without having to relocate the entire buffer.

Have a look at this article that I wrote: http://www.gamedev.net/page/resources/_/technical/opengl/opengl-batch-rendering-r3900

You can think of a Batch as a VBO that you can add vertices to anytime you want to render things on the screen.

It seems that the OP is asking about resizing a VBO.

Specific example: you have a VBO sized for and containing 8 vertices. You now want to change it's size by adding 2 extra vertices to it, but you want to retain it's existing data.

The short answer is that you can't: that's not how buffer objects are meant to be used.

The long answer is that you can, but OpenGL makes no guarantees that it will be fast. For the example I gave above you would create an array in system meory to hold the new number of vertices, rebuild the first 8 into it, build the new 2 into it, then call glBufferData again.

If you're using GL_ARB_buffer_storage you can't even do that as the buffer size is immutable. Instead you must destroy the original buffer and create a new one at the new size. Note that this is probably what resizing it via a glBufferdata call does behind the scenes anyway.

For one draw call per chunk instead of one per block, look at the glMultiDraw* calls which can help some.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

You can always request a VBO that can hold a lot of vertices and only decide to draw 8 or 9 or whatever amount of vertices in your draw call. The rest of the VBO will just hold useless memory until you add a new vertex at the end and tell GL to draw an extra vertex.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

Thanks a lot everybody, so what I did is that i stock each triangle in a 4D vector (using glm::tvec4<GLbyte>) where the 4th dimension is used for the color of the triangle.

But I have a problem, not with this thing particularly, I think, but nothing is drawn on the screen.

Here's how my code is structured:

main.cpp


int main(int ac, char **av)
{
	g_window = new Renderer;
	g_window->init(ac, av);
	g_window->createWindow(vector2i(500, 0), vector2i(1280, 720), "OpenGL");
	if (g_window->resources())
	{
		glutDisplayFunc(onDisplay);
		glutReshapeFunc(onReshape);
		glutIdleFunc(onIdle);
		glutSpecialFunc(onSpecial);
		glutSpecialUpFunc(onSpecialUp);
		glutIdleFunc(onDisplay);
		glutPassiveMotionFunc(onMotion);
		glutMotionFunc(onMotion);
		glutMainLoop();
	}
	delete (g_window);
	return (0);
}

Renderer.cpp


/* Constructor, destructor and other methods */

void Renderer::createWindow(vector2i winPos, vector2i winSize, const char *winTitle)
{
	this->_winSize = winSize;
	glutInitWindowPosition(winPos.x, winPos.y);
	glutInitWindowSize(this->_winSize.x, this->_winSize.y);
	glutCreateWindow(winTitle);
        this->_chunks.push_back(new Chunk);
	this->_chunks.at(0)->createMesh();
	if (glewInit() != GLEW_OK)
	{
		std::cout << "glewInit failed" << std::endl;
		exit(1);
	}
	if (glewIsSupported("GL_VERSION_4_5"))
		std::cout << "GLEW Version is 4.5" << std::endl;
	else
		std::cout << "GLEW 4.5 not supported" << std::endl;
}

bool Renderer::resources()
{
	this->_program = createProgram("cube.v.glsl", "cube.f.glsl");
	if (this->_program == 0)
		return (false);
	this->_attribute_coord = glGetAttribLocation(this->_program, "coord");
	if (this->_attribute_coord == -1)
	{
		std::cerr << "Could not bind attribute coord3d." << std::endl;
		return (false);
	}
	this->_uniform_mvp = glGetUniformLocation(this->_program, "mvp");
	if (this->_uniform_mvp == -1)
	{
		std::cerr << "Could not bind attribute mvp." << std::endl;
		return (false);
	}
	glUseProgram(this->_program);
	glEnableVertexAttribArray(this->_attribute_coord);
	return (true);
}

void Renderer::beginScene() const
{
	glm::mat4 view = glm::lookAt(this->_position, this->_position + this->_lookAt, glm::vec3(0, 1, 0));
	glm::mat4 projection = glm::perspective(45.0f, 1.0f * this->_winSize.x / this->_winSize.y, 0.01f, 1000.0f);
	glm::mat4 mvp = projection * view;
	glUniformMatrix4fv(this->_uniform_mvp, 1, GL_FALSE, glm::value_ptr(mvp));
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

void Renderer::endScene() const
{
	glutSwapBuffers();
}

void Renderer::onDisplay()
{
	this->beginScene();
	this->renderChunks();
	this->endScene();
}

void Renderer::renderChunks()
{
	int i;

	i = -1;
	while (++i < this->_chunks.size())
	{
		this->_chunks.at(i)->render(this->_attribute_coord);
	}
}
/* And others method for mouse movement etc */

Chunk.cpp


void Chunk::render(GLint attribute_coord)
{
	if (!this->_currentVertex)
		return;
	glBindBuffer(GL_ARRAY_BUFFER, this->_vbo);
	glVertexAttribPointer(attribute_coord, 4, GL_BYTE, GL_FALSE, 0, 0);
	glDrawArrays(GL_TRIANGLES, 0, this->_currentVertex);
}

So Renderer is a class I made that contains everything needed for rendering, such as the program for the shaders etc.

I'm a begginer in OpenGL and I don't know where the problem is.

Thanks for helping me!

EDIT: Sorry if i wasn't clear in the first post, what i wanted wasn't a trick to resize a VBO but just to add vertices to it (just once, at the creation of it).


EDIT: Sorry if i wasn't clear in the first post, what i wanted wasn't a trick to resize a VBO but just to add vertices to it (just once, at the creation of it).
glBufferData to allocate the buffer (and pass data to it if you want). glBufferSubData to update data of it (once it has been already allocated).

You create a VBO with glGenBuffers first. Then use VAO related functions to tell OpenGL how it should be read. So read up on those.

For vertices what you really want is to use a regular 32 bit 'float'. 3 of them per 3D vertex.

If you need to add more vertices than the VBO you allocated will allow, you need to reallocate it with glBufferData then setup all the vertices again (with the parameter of glBufferData or with a glBufferSubData call after reallocating the VBO).

VBO is a bunch of memory, what you do with it is what you do with all chunks of memory, allocate it and put stuff in it. Think of glBufferData as a malloc call and of glBufferSubData as a memcpy call.

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator

This topic is closed to new replies.

Advertisement