1
votes

I have written a simple graphic engine using OpenGL and GLSL. Until here, when I needed to create a new mesh scene node I created a VAO, a VBO and an IBO for each mesh. I loaded my vertex attributes for each mesh this way:

glBufferData(GL_ARRAY_BUFFER, this->GetVerticesByteSize(VERTEX_POSITION)
        + this->GetVerticesByteSize(VERTEX_TEXTURE) + this->GetVerticesByteSize(VERTEX_NORMAL), NULL, this->m_Usage);
    glBufferSubData(GL_ARRAY_BUFFER, 0, this->GetVerticesByteSize(VERTEX_POSITION), &this->m_VertexBuffer[VERTEX_POSITION][0]);
    if (!this->m_VertexBuffer[VERTEX_TEXTURE].empty())
        glBufferSubData(GL_ARRAY_BUFFER, this->GetVerticesByteSize(VERTEX_POSITION),
            this->GetVerticesByteSize(VERTEX_TEXTURE), &this->m_VertexBuffer[VERTEX_TEXTURE][0]);
    if (!this->m_VertexBuffer[VERTEX_NORMAL].empty())
        glBufferSubData(GL_ARRAY_BUFFER, this->GetVerticesByteSize(
            VERTEX_POSITION) + this->GetVerticesByteSize(VERTEX_TEXTURE),
                this->GetVerticesByteSize(VERTEX_NORMAL), &this->m_VertexBuffer[VERTEX_NORMAL][0]);

But if the scene is composed by a lot of meshes it's not correct for the performance (too many state changes). So, I decided to create a unique VAO, VBO and IBO (singleton classes) for all the geometry of my scene.

The way to do this is the following :

Load all the vertex attributes in a specific class (let's call it 'VertexAttributes') for each mesh. After all the meshes are loaded we can allocate the big vertex buffer in a unique VBO. So like above I call in first the function 'glBufferData' to allocate the whole memory with the size of all the vertex attributes in my scene and after that call the function 'glBufferSubData' for each kind of vertex attribute in a loop.

But is it possible to call glBufferData several times (for each mesh) and fill the VBO during the scene loading (step by step for each mesh). So it looks like a realloc. Is it possible to do this with OpenGL or my first method is the good one ?

1
Just allocate a buffer thats big enough and use glMapBufferRange to update parts of it?paulm
Yes, it's a good idea. I didn't think this function. But with this technique I'm obliged to allocate my buffer using 'glBufferData' with a sufficient size even my scene is composed of just a little mesh. But I think it's clearer and faster than my first proposition (loading all the vertex attributes and after make unique call of the function 'glBufferData' to allocate this time all the geometry of my scene). But maybe there is a way to realloc the VBO. 'glMapBuffer' or 'glMapBufferRange' only map allocated memory (I believe). But maybe another function could reallocate the whole buffer...user1364743
Not reallocate in the sense of the C stdlib function: realloc (...). There is no such feature in OpenGL, you can easily allocate new storage for a buffer object (and have the previous storage freed when there is no pending command in the pipeline that references it), but this new storage will have undefined contents.Andon M. Coleman

1 Answers

3
votes

But is it possible to call glBufferData several times (for each mesh) and fill the VBO during the scene loading (step by step for each mesh). So it looks like a realloc. Is it possible to do this with OpenGL or my first method is the good one ?

No. Whenever you call glBufferData, a new data storage (with the new size is created, and the previous contents are lost.

However, combining multiple objects in the same VBO is still a valid strategy in many cases, especially if many of those objects are likely to be drawn together.

You cannot dynamically resizes buffer objects. What you can do is pre-allocate bigger buffers and update parts of it. Having a bunch of reasonably-sized buffers available and dynamically fill can be a viable strategy. Note that there is also GL_ARB_copy_buffer (in core since GL 3.1, so widely available) which will allow you quite efficient server-side copies, and you can even emulate the "realloc" behavior by allocating a new buffer and copying the old contents over.

Which strategy is best will always depend on the situation. If you often load or destroy objects dynamically, using some complex buffer allocation and management strategies might pay off.