OpenGL get currently bound vertex buffer and index buffer - c++

I'm currently working with OpenGL in C++, and I'm trying to debug by identifying what the currently bound vertex buffer and index buffer are. I have three functions.
GLint getBoundVAO()
{
GLint id = 0;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &id);
return id;
};
GLint getBoundVBO()
{
GLint id = 0;
// ???
return id;
};
GLint getBoundIBO()
{
GLint id = 0;
// ???
return id;
};
How would I go about getting the vertex buffer and index buffer in a similar way to how I am getting the VAO? I've looked at the OpenGL page https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGet.xhtml and am not seeing a value which will allow me to get the index or vertex buffers.

See the "Parameters" section here. The symbolic constants used for binding the buffers match the ones used for glGet* (but with a _BINDING suffix).
For the vertex buffer object, use:
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &id);
For the index buffer, use:
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &id);

Related

GLSL Error : Undefined layout buffer variable in compute shader, though it is defined

I'm trying to make a simple compute shader using a Shader Storage Buffer (SSBO) to pass data to the shader. I'm coding in C++ with GLFW3 and GLEW. I'm passing an array of integers into an SSBO, binding it to the index 0, and expecting to retrieve the data in the shader from a layout buffer variable (as explained on various websites). However, I get an unexpected "undefined variable" error on shader compilation concerning this layout buffer variable, though it is clearly declared.
Here is the GLSL code of the compute shader (this script is only at its beginning) :
#version 430
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout (std430, binding = 0) buffer params
{
ivec3 dims;
};
int index(ivec3 coords){
ivec3 dims = params.dims;
return coords.x + dims.y * coords.y + dims.x * dims.y * coords.z;
}
void main() {
ivec3 coords = ivec3(gl_GlobalInvocationID);
int i = index(coords);
}
I get the error : 0(12) : error C1503: undefined variable "params"
Here is the C++ script that setups and runs the compute shader :
int dimensions[] {width, height, depth};
GLuint paramSSBO;
glGenBuffers(1, &paramSSBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, paramSSBO);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(dimensions), &dimensions, GL_STREAM_READ);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, paramSSBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
GLuint computeShaderID;
GLuint csProgramID;
char* computeSource;
loadShaderSource(computeSource, "compute.glsl");
computeShaderID = glCreateShader(GL_COMPUTE_SHADER);
compileShader(computeShaderID, computeSource);
delete[] computeSource;
csProgramID = glCreateProgram();
glAttachShader(csProgramID, computeShaderID);
glLinkProgram(csProgramID);
glDeleteShader(computeShaderID);
glUseProgram(csProgramID);
glDispatchCompute(width, height, depth);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
glUseProgram(0);
glDeleteBuffers(1, &paramSSBO);
width, height and depth are int variables defined earlier in the program. I'm binding the dimensions array to the index 0 and I expect to retrieve it in the ivec3 params.dims variable in the shader. However the params variable is said to be undefined when used in the index() function.
This script is just the beginning and I wanted to add a second buffer where the shader would actually write its result, but I'm stuck here. For clarification : in the complete script I expect not to write in any texture (as all online examples show), but write the results in the second buffer from which I will get the data back into a C++ array for further use.
params is not a variable. Nor is it a struct or class. It is the name of an interface block. And the name of an interface block is not really part of GLSL itself; it's part of OpenGL. It's the name used by the OpenGL API to represent that particular block.
You never use an interface block's name in the shader text itself, outside of defining it.
Unless you give your interface block an instance name, the names of all variables within that block are essentially part of the global namespace. Indeed, scoping those names is the whole point of giving the block an instance name.
So the correct way to access the dims field in the interfae block is as "dims".

OpenGL - need a simple concept clarification

I understand how to create the vertex and fragments shaders and how to create vertex arrays and put them on the buffer, but how do i link the two?
Meaning - when i run my program, how does it know that the vertices array that is on the currently active buffer should be "fed" to the vertex shader?
Is that being done simply by using glVertexAttribPointer?
how does it know that the vertices array that is on the currently active buffer should be "fed" to the vertex shader
The "currently active buffer", i.e. GL_ARRAY_BUFFER, isn't used during the draw call. It's only purpose is to tell the glVertexAttribPointer functions which buffer to bind to the VAO. Once this connection is established GL_ARRAY_BUFFER can be unbound.
... but how do i link the two?
The link between your vertex arrays and the vertex shader is the currently active vertex array object (VAO). The pipeline will fetch the vertex attributes that the shader needs from the buffers that were bound to the VAO.
It may help to summarized VAO state as the following pseudo-C definitions:
struct VertexArrayObject
{
// VertexArrayElementBuffer
uint element_buffer;
struct Binding {
// VertexArrayVertexBuffers
uint buffer;
intptr offset;
sizei stride;
// VertexArrayBindingDivisor
uint divisor;
} bindings[];
struct Attrib {
// VertexArrayAttribBinding
uint binding; // This is an index into bindings[]
// EnableVertexArrayAttrib
bool enabled;
// VertexArrayAttrib*Format
int size;
enum type;
boolean normalized;
boolean integer;
boolean long;
uint relativeoffset;
} attribs[];
};
The comments mention the corresponding OpenGL 4.5 DSA function that can be used to set the respective state.
When you use glVertexAttribPointer, it essentially does the following on the currently bound VAO:
vao.attribs[index].binding = index;
vao.attribs[index].size = size;
vao.attribs[index].type = type;
vao.attribs[index].normalized = normalized;
vao.attribs[index].relativeoffset = 0;
vao.bindings[index].buffer = current ARRAY_BUFFER;
vao.bindings[index].offset = pointer;
vao.bindings[index].stride = stride; // if stride == 0 computes based on size and type
Notice that it's the glVertexAttribPointer call that binds the 'active' buffer to the VAO. If instead you set up your VAO using the direct state access API (DSA), you don't even need to ever 'activate' any buffer.

OpenGL glMultiDrawElementsIndirect with Interleaved Buffers

Originally using glDrawElementsInstancedBaseVertex to draw the scene meshes. All the meshes vertex attributes are being interleaved in a single buffer object. In total there are only 30 unique meshes. So I've been calling draw 30 times with instance counts, etc. but now I want to batch the draw calls into one using glMultiDrawElementsIndirect. Since I have no experience with this command function, I've been reading articles here and there to understand the implementation with little success. (For testing purposes all meshes are instanced only once).
The command structure from the OpenGL reference page.
struct DrawElementsIndirectCommand
{
GLuint vertexCount;
GLuint instanceCount;
GLuint firstVertex;
GLuint baseVertex;
GLuint baseInstance;
};
DrawElementsIndirectCommand commands[30];
// Populate commands.
for (size_t index { 0 }; index < 30; ++index)
{
const Mesh* mesh{ m_meshes[index] };
commands[index].vertexCount = mesh->elementCount;
commands[index].instanceCount = 1; // Just testing with 1 instance, ATM.
commands[index].firstVertex = mesh->elementOffset();
commands[index].baseVertex = mesh->verticeIndex();
commands[index].baseInstance = 0; // Shouldn't impact testing?
}
// Create and populate the GL_DRAW_INDIRECT_BUFFER buffer... bla bla
Then later down the line, after setup I do some drawing.
// Some prep before drawing like bind VAO, update buffers, etc.
// Draw?
if (RenderMode == MULTIDRAW)
{
// Bind, Draw, Unbind
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_indirectBuffer);
glMultiDrawElementsIndirect (GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 30, 0);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
}
else
{
for (size_t index { 0 }; index < 30; ++index)
{
const Mesh* mesh { m_meshes[index] };
glDrawElementsInstancedBaseVertex(
GL_TRIANGLES,
mesh->elementCount,
GL_UNSIGNED_INT,
reinterpret_cast<GLvoid*>(mesh->elementOffset()),
1,
mesh->verticeIndex());
}
}
Now the glDrawElements... still works fine like before when switched. But trying glMultiDraw... gives indistinguishable meshes but when I set the firstVertex to 0 for all commands, the meshes look almost correct (at least distinguishable) but still largely wrong in places?? I feel I'm missing something important about indirect multi-drawing?
//Indirect data
commands[index].firstVertex = mesh->elementOffset();
//Direct draw call
reinterpret_cast<GLvoid*>(mesh->elementOffset()),
That's not how it works for indirect rendering. The firstVertex is not a byte offset; it's the first vertex index. So you have to divide the byte offset by the size of the index to compute firstVertex:
commands[index].firstVertex = mesh->elementOffset() / sizeof(GLuint);
The result of that should be a whole number. If it wasn't, then you were doing unaligned reads, which probably hurt your performance. So fix that ;)

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;
}