OpenGL - Is vertex attribute state bound to specific VBOs? - opengl

As I understand VAOs/VBOs currently, a VAO retains all the attribute information that has been set up since it was bound, eg. the offset, stride, number of components, etc. of a given vertex attribute within a VBO.
What I seem to be unclear on is how VAOs and VBOs work together. A lot of the examples I have seen specify the vertex attributes with respect to the currently bound VBO, and when the VAO is bound the data in the VBO become accessible. One way I can see of using VAOs in this way would be to have one per object (where each object uses its own VBO), but I've read that this is poor performance-wise because of switching between many VAOs unnecessarily. I also would rather like to avoid having to store all my object data in one monolithic VBO because I will need to add and remove objects within my scene at any time - as a 3D editor, I feel the application would be much better suited to having each geometry object own its own buffer, rather than in some large, preallocated VBO. (Is this a correct assumption?)
My question therefore is whether one VAO can store vertex attribute configurations independently of the VBOs? Would I be able to configure a VAO to expect data in a certain format (eg. position, normal, UV) and then "swap in" different VBOs as I draw the different geometry objects, or is the format information essentially bound only to the VBO itself? If the latter, is it worth me using VAOs at all?

ARB_vertex_attrib_binding allows you to separate Vao attribute format and buffer binding.
https://www.opengl.org/wiki/Vertex_Specification#Separate_attribute_format
Internally, when you configure your Vao, Vertex buffer is automatically associated with attribute index. With ARB_vertex_attrib_binding, you have new gl functions to define Attribute formats independently from the bound buffer, which may be switched with VertexBuffer functions.
Here some piece of code in c# with openTK: (full surce: https://github.com/jpbruyere/GGL/tree/ottd/Tetra )
The solution here is to build a VAO with all your meshes concatenated, keeping for each of them only
BaseVertex = the vertice offset in the VAO
IndicesOffset = the offset in the Element buffer (ebo index)
IndicesCount = and the total indice count of the model
protected void CreateVAOs()
{
//normal vao binding
vaoHandle = GL.GenVertexArray();
GL.BindVertexArray(vaoHandle);
GL.EnableVertexAttribArray(0);
GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0);
... other attrib bindings come here
//ARB vertex attrib binding use for fast instance buffers switching
//note that I use 4 attrib indices to bind a matrix
GL.VertexBindingDivisor (instanceBufferIndex, 1);
for (int i = 0; i < 4; i++) {
GL.EnableVertexAttribArray (instanceBufferIndex + i);
GL.VertexAttribBinding (instanceBufferIndex+i, instanceBufferIndex);
GL.VertexAttribFormat(instanceBufferIndex+i, 4, VertexAttribType.Float, false, Vector4.SizeInBytes * i);
}
if (indices != null)
GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle);
GL.BindVertexArray(0);
}
Then, I define Instances of mesh with just a Matrix array for each, that's a normal buffer creation, but not staticaly bound to the vao.
instancesVboId = GL.GenBuffer ();
GL.BindBuffer (BufferTarget.ArrayBuffer, instancesVboId);
GL.BufferData<Matrix4> (BufferTarget.ArrayBuffer,
new IntPtr (modelMats.Length * Vector4.SizeInBytes * 4),
modelMats, BufferUsageHint.DynamicDraw);
GL.BindBuffer (BufferTarget.ArrayBuffer, 0);
To render such vao, I loop inside my instance array:
public void Bind(){
GL.BindVertexArray(vaoHandle);
}
public void Render(PrimitiveType _primitiveType){
foreach (VAOItem item in Meshes) {
GL.ActiveTexture (TextureUnit.Texture1);
GL.BindTexture (TextureTarget.Texture2D, item.NormalMapTexture);
GL.ActiveTexture (TextureUnit.Texture0);
GL.BindTexture (TextureTarget.Texture2D, item.DiffuseTexture);
//Here I bind the Instance buffer with my matrices
//that's a fast switch without changing vao confing
GL.BindVertexBuffer (instanceBufferIndex, item.instancesVboId, IntPtr.Zero,Vector4.SizeInBytes * 4);
//here I draw instanced with base vertex
GL.DrawElementsInstancedBaseVertex(_primitiveType, item.IndicesCount,
DrawElementsType.UnsignedShort, new IntPtr(item.IndicesOffset*sizeof(ushort)),
item.modelMats.Length, item.BaseVertex);
}
}
The final VAO is bound only once.

Related

OpenGL shading language best practices

I´m writing a little OpenGL Engine 3D in C++ and Eclipse/Visual C++. In outline, my engine has several objects derived from typical GameObject virtual class. In my hierarchy there is several levels depending if the object has children and parent. For example, the terrain object is in the level 0. A tank loaded from blender is in the level 1, Etc.
The question is what is the best practice for rendering each object depending on the corresponding shader. If I have a list of objects renderer by the same shader program, I should render all objects VAOs between the clausules: glUseProgram(program_id) ... glUseProgram(0) instead of change the program for each object. I.e:
for each object
glUseProgram(object.program)
...
glBindVertexArray(m_pVao->m_vaoHandle);
for (GLuint i = 0; i < (m_iNumIndex / 3); i++)
{
offset = i * 3;
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, &m_Index[offset]);
}
glBindVertexArray(0);
Or:
glUseProgram(object.program)
...
for each object in program.list
glBindVertexArray(object.m_pVao->m_vaoHandle);
for (GLuint i = 0; i < (m_iNumIndex / 3); i++)
{
offset = i * 3;
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, &m_Index[offset]);
}
glBindVertexArray(0);
Sorry the pseudo-pseudocode.
The objects could be stored in std::vector and every shader have a list of objects.
Do the most costly operations (binding programs, shaders, textures, etc.) as little as possible. So, if your design allows it, do binding outside of the loop and reuse the resource. That's one of the most basic performance optimizations you would do later anyway.

Can I call `glDrawArrays` multiple times while updating the same `GL_ARRAY_BUFFER`?

In a single frame, is it "allowed" to update the same GL_ARRAY_BUFFER continuously and keep calling glDrawArrays after each update?
I know this is probably not the best and not the most recommended way to do it, but my question is: Can I do this and expect to get the GL_ARRAY_BUFFER updated before every call to glDrawArrays ?
Code example would look like this:
// setup a single buffer and bind it
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
while (!renderStack.empty())
{
SomeObjectClass * my_object = renderStack.back();
renderStack.pop_back();
// calculate the current buffer size for data to be drawn in this iteration
SomeDataArrays * subArrays = my_object->arrayData();
unsigned int totalBufferSize = subArrays->bufferSize();
unsigned int vertCount = my_object->vertexCount();
// initialise the buffer to the desired size and content
glBufferData(GL_ARRAY_BUFFER, totalBufferSize, NULL, GL_STREAM_DRAW);
// actually transfer some data to the GPU through glBufferSubData
for (int j = 0; j < subArrays->size(); ++j)
{
unsigned int subBufferOffset = subArrays->get(j)->bufferOffset();
unsigned int subBufferSize = subArrays->get(j)->bufferSize();
void * subBufferData = subArrays->get(j)->bufferData();
glBufferSubData(GL_ARRAY_BUFFER, subBufferOffset, subBufferSize, subBufferData);
unsigned int subAttributeLocation = subArrays->get(j)->attributeLocation();
// set some vertex attribute pointers
glVertexAttribPointer(subAttributeLocation, ...);
glEnableVertexAttribArray(subAttributeLocation, ...);
}
glDrawArrays(GL_POINTS, 0, (GLsizei)vertCount);
}
You may ask - why would I want to do that and not just preload everything onto the GPU at once ... well, obvious answer, because I can't do that when there is too much data that can't fit into a single buffer.
My problem is, that I can only see the result of one of the glDrawArrays calls (I believe the first one) or in other words, it appears as if the GL_ARRAY_BUFFER is not updated before each glDrawArrays call, which brings me back to my question, if this is even possible.
I am using an OpenGL 3.2 CoreProfile (under OS X) and link with GLEW for OpenGL setup as well as Qt 5 for setting up the window creation.
Yes, this is legal OpenGL code. It is in no way something that anyone should ever actually do. But it is legal. Indeed, it makes even less sense in your case, because you're calling glVertexAttribPointer for every object.
If you can't fit all your vertex data into memory, or need to generate it on the GPU, then you should stream the data with proper buffer streaming techniques.

OpenGL render multiple objects using single VBO and updata object's matrices using another VBO

So, I need the way to render multiple objects(not instances) using one draw call. Actually I know how to do this, just to place data into single vbo/ibo and render, using glDrawElements.
The question is: what is efficient way to update uniform data without setting it up for every single object, using glUniform...?
How can I setup one buffer containing all uniform data of dozens of objects, include MVP matrices, bind it and perform render using single draw call?
I tried to use UBOs, but it's not what I need at all.
For rendering instances we just place uniform data, including matrices, at another VBO and set up attribute divisor using glVertexAttribDivisor, but it only works for instances.
Is there a way to do that I want in OpenGL? If not, what can I do to overcome overheads of setting uniform data for dozens of objects?
For example like this:
{
// setting up VBO
glGenBuffers(1, &vbo);
glBindBuffer(vbo);
glBufferData(..., data_size);
// setup buffer
for(int i = 0; i < objects_num; i++)
glBufferSubData(...offset, size, &(objects[i]));
// the same for IBO
.........
// when setup some buffer, that will store all uniforms, for every object
.........
glDrawElements(...);
}
Thanks in advance for helping.
If you're ok with requiring OpenGL 4.3 or higher, I believe you can render this with a single draw call using glMultiDrawElementsIndirect(). This allows you to essentially make multiple draw calls with a single API call. Each sub-call is defined by values in a struct of the form:
typedef struct {
GLuint count;
GLuint instanceCount;
GLuint firstIndex;
GLuint baseVertex;
GLuint baseInstance;
} DrawElementsIndirectCommand;
Since you do not want to draw multiple instances of the same vertices, you use 1 for the instanceCount in each draw call. The key idea is that you can still use instancing by specifying a different baseInstance value for each one. So each object will have a different gl_InstanceID value, and you can use instanced attributes for the values (matrices, etc) that you want to vary per object.
So if you currently have a rendering loop:
for (int k = 0; k < objectCount; ++k) {
// set uniforms for object k.
glDrawElements(GL_TRIANGLES, object[k].indexCount,
GL_UNSIGNED_INT, object[k].indexOffset * sizeof(GLuint));
}
you would instead fill an array of the struct defined above with the arguments:
DrawElementsIndirectCommand cmds[objectCount];
for (int k = 0; k < objectCount; ++k) {
cmds[k].count = object[k].indexCount;
cmds[k].instanceCount = 1;
cmds[k].firstIndex = object[k].indexOffset;
cmds[k].baseVertex = 0;
cmds[k].baseInstance = k;
}
// Rest of setup.
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, 0, objectCount, 0);
I didn't provide code for the full setup above. The key steps include:
Drop the cmds array into a buffer, and bind it as GL_DRAW_INDIRECT_BUFFER.
Store the per-object values in a VBO. Set up the corresponding vertex attributes, which includes specifying them as instanced with glVertexAttribDivisor(1).
Set up the per-vertex attributes as usual.
Set up the index buffer as usual.
For this to work, the indices for all the objects will have to be in the same index buffer, and the values for each attribute will have to be in the same VBO across all objects.

Properly update vertex buffer objects [duplicate]

This question already has answers here:
What is the proper way to modify OpenGL vertex buffer?
(3 answers)
Closed 2 years ago.
I've got a training app written in winapi
So, I've got GL initialized there and I've got node-based system, that can be described by couple of classes
class mesh
{
GLuint vbo_index; //this is for having unique vbo
float *vertex_array;
float *normal_array;
unsigned int vertex_count;
etc.. //all those mesh things.
....
}
class node
{
bool is_mesh; //the node may or may not represent a mesh
mesh * mesh_ptr; //if it does then this pointer is a valid address
}
I've also got 2 global variables for keeping record of renderable mesh..
mesh **mesh_table;
unsigned int mesh_count;
Right now I'm experimenting on 2 objects. So I create 2 nodes of type mesh::cube with customizable number of x y and z segments. Expected behaviour of my app is let the user click between 2 of the nodes CUBE0, CUBE1 and show their customizable attributes - segments x, segments y, segments z. The user tweaks both objecs' parameters and they are being rendered out on top of each other in wireframe mode, so we can see the changing in their topology in real time.
When the node is being created for the first time, if the node type is mesh, then the mesh object is generated and it's mesh_ptr is written into the mesh_table and mesh_count increments. After that my opengl window class creates a unique vertex buffer object for the new mesh and stores it's index in the mesh_ptr.vbo_index
void window_glview::add_mesh_to_GPU(mesh* mesh_data)
{
glGenBuffers(1,&mesh_data->vbo_index);
glBindBuffer(GL_ARRAY_BUFFER ,mesh_data->vbo_index);
glBufferData(GL_ARRAY_BUFFER ,mesh_data->vertex_count*3*4,mesh_data->vertex_array,GL_DYNAMIC_DRAW);
glVertexAttribPointer(5,3,GL_FLOAT,GL_FALSE,0,NULL);//set vertex attrib (0)
glEnableVertexAttribArray(5);
}
After that the user is able to tweak the parameters and each time the parameter value changes the object's mesh information is being re-evaluated based on the new parameter values, while still being the same mesh instance, after that VBO data is being updated by
void window_glview::update_vbo(mesh *_mesh)
{
glBindBuffer(GL_ARRAY_BUFFER,_mesh->vbo_vertex);
glBufferData(GL_ARRAY_BUFFER,_mesh->vertex_count*12,_mesh->vertex_array,GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER,0);
}
and the whole scene redrawn by
for (unsigned short i=0;i<mesh_count;i++)
draw_mesh(mesh_table[i],GL_QUADS,false);
SwapBuffers(hDC);
The function for a single mesh is
bool window_glview::draw_mesh(mesh* mesh_data,unsigned int GL_DRAW_METHOD,bool indices)
{
glUseProgram(id_program);
glBindBuffer(GL_ARRAY_BUFFER,mesh_data->vbo_index);
GLuint id_matrix_loc = glGetUniformLocation(id_program, "in_Matrix");
glUniformMatrix4fv(id_matrix_loc,1,GL_TRUE,cam.matrixResult.get());
GLuint id_color_loc=glGetUniformLocation(id_program,"uColor");
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glUniform3f(id_color_loc,mesh_color[0],mesh_color[1],mesh_color[2]);
glDrawArrays(GL_DRAW_METHOD,0,mesh_data->vertex_count);
glBindBuffer(GL_ARRAY_BUFFER,0);
glUseProgram(0);
return true;
}
The problem is that only the last object in stack is being drawn that way, and the other object's points are all in 0 0 0, so in the viewport it's rendered one cube with proper parameters and one cube just as a DOT
QUESTION: Where did I go wrong?
You have a fundamental misunderstanding of what glBindBuffer(GL_ARRAY_BUFFER,mesh_data->vbo_vertex); does.
That sets the bound array buffer, which is actually only used by a handful of commands (mostly glVertexAttrib{I|L}Pointer (...)), binding the buffer itself is not going to do anything useful.
What you need to do is something along the lines of this:
bool window_glview::draw_mesh(mesh* mesh_data,unsigned int GL_DRAW_METHOD,bool indices)
{
glUseProgram(id_program);
//
// Setup Vertex Pointers in addition to binding a VBO
//
glBindBuffer(GL_ARRAY_BUFFER,mesh_data->vbo_vertex);
glVertexAttribPointer(5,3,GL_FLOAT,GL_FALSE,0,NULL);//set vertex attrib (0)
glEnableVertexAttribArray(5);
GLuint id_matrix_loc = glGetUniformLocation(id_program, "in_Matrix");
glUniformMatrix4fv(id_matrix_loc,1,GL_TRUE,cam.matrixResult.get());
GLuint id_color_loc=glGetUniformLocation(id_program,"uColor");
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glUniform3f(id_color_loc,mesh_color[0],mesh_color[1],mesh_color[2]);
glDrawArrays(GL_DRAW_METHOD,0,mesh_data->vertex_count);
glBindBuffer(GL_ARRAY_BUFFER,0);
glUseProgram(0);
return true;
}
Now, if you really want to make this simple and be able to do this just by changing a single object binding, I would suggest you look into Vertex Array Objects. They will persistently store the vertex pointer state.
in your draw glBindBuffer(GL_ARRAY_BUFFER,mesh_data->vbo_index); doesn't actually do anything; the information about the vertex attribute is not bound to the buffer at all. it is set in the glVertexAttribPointer(5,3,GL_FLOAT,GL_FALSE,0,NULL); call which gets overwritten each time a new mesh is uploaded.
either create and use a VAO or move that call from add_mesh_to_GPU to draw_mesh:
for the VAO you would do:
void window_glview::add_mesh_to_GPU(mesh* mesh_data)
{
glGenVertexArrays(1, &mesh_data->vao_index);//new GLInt field
glBindVertexArray(mesh_data->vao_index);
glGenBuffers(1,&mesh_data->vbo_index);
glBindBuffer(GL_ARRAY_BUFFER ,mesh_data->vbo_index);
glBufferData(GL_ARRAY_BUFFER ,mesh_data->vertex_count*3*4,mesh_data->vertex_array,GL_DYNAMIC_DRAW);
glVertexAttribPointer(5,3,GL_FLOAT,GL_FALSE,0,NULL);//set vertex attrib (0)
glEnableVertexAttribArray(5);
glBindVertexArray(0);
}
bool window_glview::draw_mesh(mesh* mesh_data,unsigned int GL_DRAW_METHOD,bool indices)
{
glBindVertexArray(mesh_data->vao_index);
glUseProgram(id_program);
GLuint id_matrix_loc = glGetUniformLocation(id_program, "in_Matrix");
glUniformMatrix4fv(id_matrix_loc,1,GL_TRUE,cam.matrixResult.get());
GLuint id_color_loc=glGetUniformLocation(id_program,"uColor");
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glUniform3f(id_color_loc,mesh_color[0],mesh_color[1],mesh_color[2]);
glDrawArrays(GL_DRAW_METHOD,0,mesh_data->vertex_count);
glUseProgram(0);
glBindVertexArray(0);
return true;
}

Draw array of VBOs in OpenGL ES

I have an array of Vertex Array Objects, that each contain a VBO reference, and and array of matrices, of the same size, such as:
unsigned int vaoArray[128];
matrix_t matrixArray[128];
rather than
for (i = 0; i < 128; i++)
{
glBindVertexArray(vaoArray[i]);
glUniformMatrix4fv(U_MVP_MATRIX_SLOT, 1, GL_FALSE, &matrixArray[i]);
glDrawArrays(BGL_TRIANGLE_FAN, 0, 4);
}
Is there a way I can push the entire array of VAOs and matrices to the GPU at once? Maybe using the instancing extension somehow?
I can't combine them all in one VAO/VBO, because the combination can change (this is drawing text, with each character having its own VAO/VBO combo).
And yes, I realize this all involves using ES 2.0 extensions. That's OK.
BTW, All of the VAOs for each character are identical except for the VBO id, if that helps.