Reputation: 7594
According to http://www.opengl.org/wiki/Vertex_Specification_Best_Practices, Under the dynamic VBO section, it is recommended that you set the VBO type to GL_DYNAMIC_DRAW if your scene changes frequently. In addition, if you have to update the entire buffer you don't use glBufferSubData alone. Instead you use glBufferData, and then you can set its data pointer to NULL followed by calls to glBufferSubData to load the data into the VBO.
I am doing exactly that in a Qt program I am writing which allows the user to resize the OpenGL drawable area (QGLWidget), which forces a set of lines (a wireframe of sorts) to be redrawn based on if more or less data is displayed in the given QGLWidget. I have an initial working example which works after the first initial resize. The program looking like:
Now when I go to resize it a second time the application looks like:
I have narrowed down the problem to re-loading the VBO associated with the lines. The code for loading the vertex attributes associated with the lines is:
bool batch_renderer::load_data(render_data_type &data, GLsizei buffer_count)
{
if (_vbo_id) {
glBindBuffer(GL_ARRAY_BUFFER, _vbo_id);
glDeleteBuffers(_byte_count, &_vbo_id);
_vbo_id = 0;
_vertex_count = 0;
_byte_count = 0;
_byte_count1 = 0;
_byte_count2 = 0;
_byte_count3 = 0;
_byte_count4 = 0;
}
_vertex_count = data._data_1.size();
_byte_count = data.size_of();
glGenBuffers(buffer_count, &_vbo_id);
if (bind()) {
glBufferData(GL_ARRAY_BUFFER, _byte_count, NULL, GL_DYNAMIC_DRAW);
switch (data._type_count) {
case (4): {
_byte_count4 = data.data4_size_of();
size_t offset = data.t4_offset();
glBufferSubData(GL_ARRAY_BUFFER, offset, _byte_count4,
data._data_4.data());
}
case (3): {
_byte_count3 = data.data3_size_of();
size_t offset = data.t3_offset();
glBufferSubData(GL_ARRAY_BUFFER, offset, _byte_count3,
data._data_3.data());
}
case (2): {
_byte_count2 = data.data2_size_of();
size_t offset = data.t2_offset();
glBufferSubData(GL_ARRAY_BUFFER, offset, _byte_count2,
data._data_2.data());
}
case (1): {
_byte_count1 = data.data1_size_of();
size_t offset = data.t1_offset();
glBufferSubData(GL_ARRAY_BUFFER, offset, _byte_count1,
data._data_1.data());
}
break;
default: {
return false;
}
}
} else {
return false;
}
return true;
}
If I comment out the source which re-loads the VBO then the progam looks as follows after ANY resize event:
What am I doing wrong here with the VBO to cause the lines to go wrong, and the texture to be all messed up?
Upvotes: 1
Views: 568
Reputation: 162164
The point of calling glBufferData
when updating the whole buffer is to reuse an existing buffer object, telling the driver to discard the old data. Which means that you don't have to do this
if (_vbo_id) {
glBindBuffer(GL_ARRAY_BUFFER, _vbo_id);
glDeleteBuffers(_byte_count, &_vbo_id);
_vbo_id = 0;
_vertex_count = 0;
_byte_count = 0;
_byte_count1 = 0;
_byte_count2 = 0;
_byte_count3 = 0;
_byte_count4 = 0;
}
So before generating the ID, just check if that's unset
if(!_vbo_id)
glGenBuffers(buffer_count, &_vbo_id);
Note that I found the difference between total buffer object reallocation with glBufferData
and updating the whole thing glBufferSubData
to be neglectible. But you have to profile your own program to make an informed decision.
Upvotes: 2