When I first add some vertices to the buffer, these are the relevant functions I'm calling
// Create and bind the object's Vertex Array Object:
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
// Create and load vertex data into a Vertex Buffer Object:
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), &vertices[0], GL_STATIC_DRAW);
// Tells OpenGL that there is vertex data in this buffer object and what form that vertex data takes:
// Obtain attribute handles:
_posAttrib = glGetAttribLocation(program, "position");
glEnableVertexAttribArray(_posAttrib);
glVertexAttribPointer(_posAttrib, // attribute handle
4, // number of scalars per vertex
GL_FLOAT, // scalar type
GL_FALSE,
0,
0);
// Unbind vertex array:
glBindVertexArray(0);
But later on in my program, I want to add some more vertices.
I do this by the following (within a separate function:
add_vertices(x,y); //adds the necessary vertices to the vector.
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, (TRIANGLE_AMOUNT+1)*4*_number_of_circles * sizeof(float), &vertices[0], GL_STATIC_DRAW);
Assuming the funky size in the 2nd argument of glBufferData is fine, am I missing anything? Are there any other OpenGL functions that need calling?
I'm not getting any errors, but when I'm trying to draw the extra shapes with the new vertices by looping over glDrawArrays with different subsets of the vertices, nothing happens. Only the first shape gets drawn.
I hope that this is semi-coherent...let me know if there's any info I haven't provided.
Cheers.
In OpenGL, changing the buffers and exchanging the buffers data are two different things which require different actions to be taken afterwards:
Exchanging the data
In this case a previously generated vbo is required. To upload new data, it is only required to bind the buffer and to buffer new data:
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, (TRIANGLE_AMOUNT+1)*4*_number_of_circles * sizeof(float),
&vertices[0], GL_STATIC_DRAW);
Creating a new buffer
In this case a new buffer is generated by glGenerateBuffers and (in addition to uploading the data) all VAO bindings have to be updated.
Sidenote: In the code shown above, you create a new buffer without deleting the previous buffer.
Related
I am trying to render multiple models sharing the same VAO and vertex format (following top answer on this post Render one VAO containing two VBOs), however I cannot get it to work with GL_ELEMENT_ARRAY_BUFFER nor can I find any resource/example to help me. Is it even possible to do that or does the element array buffer work in a way that is incompatible with glVertexAttribFormat/glBindVertexBuffer and sharing VAOs? or am I missing the ELEMENT_ARRAY_BUFFER equivalent of glBindVertexBuffer?
My VAO is first created this way:
glCreateVertexArrays(1, &sharedVao);
glBindVertexArray(sharedVao);
glEnableVertexAttribArray(0);
glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(0, 0);
// (just 1 for the example but there is more)
glBindVertexArray(0);
Then my model buffers are created as follow:
glBindVertexArray(sharedVao); // tried with and without binding vao first, no success
glCreateBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertex), vertices.data(), GL_STATIC_DRAW);
// (just 1 for the example but there is more)
glCreateBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangles.size() * sizeof(triangle), triangles.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
And finally I render as follow:
glBindVertexArray(sharedVao);
for (auto const& model : models)
{
glBindVertexBuffer(0, model.vbo, sizeof(vertex));
// (just 1 for the example but there is more)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model.ebo);
// also tried glVertexArrayElementBuffer(sharedVao, model.ebo);
glDrawElements(GL_TRIANGLES, model.triangleCount * 3, GL_UNSIGNED_INT, nullptr);
}
Note that it does work if I start rendering the same VAO with glDrawArray (so without element array buffer).
This C++ GLSL Multiple IBO in VAO may be of valuable use, but still not sure what it means for sharing VAO formats for multiple models... (also realized that calling it IBO gives me more results than EBO...).
EDIT: this question was originally closed as supposedly a duplicate of Rendering meshes with multiple indices but it is not. Unlike this other question I am not talking about having different indices for different data (ex: indices for positions, indices for normals, indices for texture coords, etc.) but to have different indices per draw calls, while still using the same VAO format (the same way it is done with VBO and glBindVertexBuffer in Render one VAO containing two VBOs).
Multiple draw calls with shared Vertex Array Object
The purpose of this method is to avoid the cost of changing VAO format (see glVertexAttribPointer and glVertexAttribFormat: What's the difference? or https://www.youtube.com/watch?v=-bCeNzgiJ8I&t=1860) by sharing VAO and only rebinding buffers for every draw.
A clear example that doesn't make use of Element Buffer Array can be seen here: Render one VAO containing two VBOs
Create shared VAO (could be only once per program):
GLuint sharedVao = 0;
glCreateVertexArray(1, &sharedVao);
glBindVertexArray(sharedVao);
glEnableVertexAttribArray(0);
glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
// binding each attribute from its own buffer so attrib_index == buffer_index
glVertexAttribBinding(0, 0);
glEnableVertexAttribArray(1);
glVertexAttribFormat(1, 2, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(1, 1);
Create mesh buffers (would be only once per mesh):
struct Mesh
{
GLuint m_ebo = 0;
std::array<GLuint, 2> m_vbos = 0;
GLuint m_triangleCount = 0;
};
// Binding shared VAO here is mandatory as operations accessing or modifying EBO's
// state are not guaranteed to succeed if it wasn't bound to a VAO.
// However, for every new model, binding the EBO will unbind the previous, and we
// will need to rebind EBO to shared VAO for every draw call.
glBindVertexArray(sharedVao);
glCreateBuffer(1, &mesh.m_ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.m_ebo);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
triangles.size() * sizeof(Triangle),
triangles.data(),
GL_STATIC_DRAW);
glBindVertexArray(0);
mesh.m_triangleCount = triangles.size();
glCreateBuffers(2, mesh.m_vbos.data());
glBindBuffer(GL_ARRAY_BUFFER, mesh.m_vbos[0]);
glBufferData(
GL_ARRAY_BUFFER,
positions.size() * sizeof(glm::vec3),
positions.data(),
GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, mesh.m_vbos[1]);
glBufferData(
GL_ARRAY_BUFFER,
textureCoords.size() * sizeof(glm::vec2),
textureCoords.data(),
GL_STATIC_DRAW);
Render loop:
// Bind shared VAO only once
// If drawing with different set of vertex data bound, use glEnableVertexAttribArray
// or glDisableVertexAttribArray before draw calls
glBindVertexArray(sharedVao);
for (auto const& mesh : meshes)
{
glBindVertexBuffer(0, mesh.m_vbos[0], 0, sizeof(glm::vec3));
glBindVertexBuffer(1, mesh.m_vbos[1], 0, sizeof(glm::vec2));
// This is the key difference with existing example on sharing VAO:
// EBO must be rebound for every draw (unless 2 draws share the same primitive indices)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.m_ebo);
glDrawElements(GL_TRIANGLES, mesh.m_triangleCount * 3, GL_UNSIGNED_INT, nullptr);
}
Here is a sample code :-
unsigned int instanceVBO;
glGenBuffers(1, &instanceVBO);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glBindVertexArray(VAO);
...
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * 100,
&translations[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
... ... ...
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribDivisor(2, 1); //<--- who own this setting?
//^ mostly copied from https://learnopengl.com/Advanced-OpenGL/Instancing
Who own the glVertexAttribDivisor setting? (VAO / instanceVBO / global state)
A comment in https://gamedev.stackexchange.com/questions/99236/what-state-is-stored-in-an-opengl-vertex-array-object-vao-and-how-do-i-use-the#comment174555_99238 suggests that it is stored in VBO.
However, the comment contradicts (?) to the above code which calls glVertexAttribDivisor(2, 1) after unbinds glBindBuffer(GL_ARRAY_BUFFER, 0); .
I would be appreciate if you are also kind to provide reference that I can read more about :
which settings/states owned by which one of Opengl's thingy (VAO/VBO/etc).
The vertex array divisor (VERTEX BINDING DIVISOR) is stored in the Vertex Array Objects state vector, separately for each vertex attribute (like enable state, offset, stride etc.).
The states which are stored in the VAO are listed in the specification in Table 23.3: Vertex Array Object State.
VAOs are specified in OpenGL 4.6 API Core Profile Specification - 10.3.1 Vertex Array Objects.
See also Vertex Specification - Instanced arrays
I'm confused on the concept of buffers. I understand the very basics with glBufferData and glBufferSubData. Using glBufferSubData before a render function in your main loop you can use a offset and size parameter to store multiple model objects in a vertex buffer and a index buffer. Then at render you bind the single vertex buffer and call glDrawElements with the correct offsets and sizes to render multiple objects.
Is this the case with glMapBuffer? Or am I suppose to call glMapBuffer to link vertex and index data at render, then draw?
GLuint vertexArrayId;
GLuint verticesBufferId;
GLuint indicesBufferId;
void setupBuffers() {
glGenVertexArrays(1, &vertexArrayId);
glBindVertexArray(vertexArrayId);
glGenBuffers(1, &verticesBufferId);
glGenBuffers(1, &indicesBufferId);
glBindBuffer(GL_ARRAY_BUFFER, verticesBufferId);
glBufferData(GL_ARRAY_BUFFER, VERTICES_SIZE, NULL, GL_STATIC_DRAW);
// glMapBuffer stuff here
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBufferId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, INDICES_SIZE, NULL, GL_STATIC_DRAW);
// glMapBuffer stuff here
}
void render() {
glBindBuffer(GL_ARRAY_BUFFER, verticesBufferId);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)((sizeof(GLfloat) * 0)));
glEnableVertexAttribArray(0);
// glDrawElements stuff here
glDisableVertexAttribArray(0);
// Model, View, Projection transformations here
// glUniformMatrix4fv
}
You can use glMapBuffer to upload data from ram to the GPU:
glBindBuffer(GL_ARRAY_BUFFER, verticesBufferId);
void *data = glMapBuffer( GL_ARRAY_BUFFER, ... );
// copy vertex data from instance
::memcpy( data, vertices, vertexSize );
...
glUnmapBuffer( ... );
For instance when you want to upload vertex- and index-data from a model. You can use the pointer returned from glMapBuffer like a raw-c-pointer ( just for convenience )
Keep in mind: glMapBuffer is not fast, so try to avoid using it during your render loop. After calling the glUnMap the data will be transfered to the GPU.
There are much better ways when you have to upload data from the CPU to the GPU periodically like using using Uniform-Blocks.
I found this blog-post, where the mapping is explained really well ( with all its drawbacks ): Mapping in OpenGL
I'm currently learning OpenGL in my free time and lately I have been facing an "error" I don't understand.
The thing is, I have no errors, only nothing appear on my screen. I'm using OpenGL with SFML.
Here is my code. Here is my method:
void CreateObjet(GLuint& vao, GLuint& vbo, GLuint& ebo, GLuint& textureLocation)
//I create my arrays here.. Don't worry they are fine.
CreateTexture(textureLocation);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
glGenVertexArrays (1, &vao);
glBindVertexArray (vao); //On travaille dans le VAO
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData (GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), NULL);
glEnableVertexAttribArray(0);
glBufferData (GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glVertexAttribPointer (1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3* sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBufferData (GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_STATIC_DRAW);
glVertexAttribPointer (2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6* sizeof(GLfloat)));
glEnableVertexAttribArray(2);
//EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indiceFinal), indiceFinal, GL_STATIC_DRAW);
glBindVertexArray(0);
I know my problem is not with my shaders because I receive no errors in my console with GlshaderRiv().
I would like to know if I'm doing the order properly.
I Create a VBO and a EBO
I Create a VAO
I bind the current VAO to modify it
I bind the current VBO inside the VAO
I bind my first array (Vertex Position vector3f) in my VBO and put them in the first pointer with the correct offset and stride.
I bind my second array (Color Position vector3f) in my VBO and put them in the first pointer with the correct offset and stride.
I bind my third array (Texture Position vector2f) in my VBO and put them in the first pointer with the correct offset and stride.
I bind a EBO within the VAO
I bind the EBO with my element position (Vector 3u).
I unbind the VAO from the memory because my drawing loop is quite later in the code and so, I don't want to use memory space for nothing. Don't worry, Before I draw I put glBindVertexArray(&vao);
That definitely does not look right. You're writing the values for all attributes to the same buffer, with each one overwriting the previous one:
glBufferData (GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), NULL);
glEnableVertexAttribArray(0);
glBufferData (GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
...
When you make the second glBufferData() call, it will overwrite the points data that you previously stored in the buffer with the colors data.
The misunderstanding is probably about what glVertexAttribPointer() does. It specifies which buffer the given attribute is sourced from, as well as the data layout (component count, type, etc). But it does not create a copy of the buffer data, or anything like that. The attribute data you want to use must still be stored in the buffer at the time of the draw call.
To fix this, you either have to use a different buffer for each attribute, or arrange the attribute data so that the values for all 3 attributes can be stored in the same buffer. The arguments of your glVertexAttribPointer() calls actually suggest that you were intending to store all attribute values interleaved in the same buffer. To get this working, you have to arrange the attribute values accordingly, and then store them in the buffer with a single glBufferData() call.
The memory arrangement you will need for this will have all the attribute values for the first vertex in sequence, followed by the values for the second vertex, etc. With pi the position of vertex i, ci the color, and ti the texture coordinates, the correct memory layout is:
p0x p0y p0z c0r c0g c0b t0s t0t
p1x p1y p1z c1r c1g c1b t1s t1t
p2x p2y p2z c2r c2g c2b t2s t2t
...
I have been implementing a small opengl application that I based off of this tutorial:
http://openglbook.com/the-book/chapter-4-entering-the-third-dimension/
I understand most of the code but I am really confused about this line:
glGenBuffers(2, &BufferIds[1]);
Which is then followed by
glBindBuffer(GL_ARRAY_BUFFER, BufferIds[1]);
glBufferData(GL_ARRAY_BUFFER, size, &theModel->theMesh.pos[0], GL_STATIC_DRAW);
I assume I only need one free name/id to bind my buffer data to, but if I change
glGenBuffers(2,
to
glGenBuffers(1,
The buffer fails to bind and nothing works.
BufferIds is 3 in size (GLuint BufferIds[3]). I would like to make it BufferIds[2] using the first slot for the VAO & the second for the VBO.
glGenVertexArrays(1, &BufferIds[0]);
ExitOnGLError("ERROR: Could not generate the VAO");
glBindVertexArray(BufferIds[0]);
ExitOnGLError("ERROR: Could not bind the VAO");
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
ExitOnGLError("ERROR: Could not enable vertex attributes");
glGenBuffers(2, &BufferIds[1]); //if this gets from changed 2 to 1 ...
ExitOnGLError("ERROR: Could not generate the buffer objects");
int size = theModel->theMesh.pos.size() * sizeof(theModel->theMesh.pos[0]) ;
glBindBuffer(GL_ARRAY_BUFFER, BufferIds[1]);
ExitOnGLError("ERROR: Could not bind the VBO to the VAO"); // ...this error triggers
glBufferData(GL_ARRAY_BUFFER, size, &theModel->theMesh.pos[0], GL_STATIC_DRAW);
That is because you pass BufferIds[1] to glBindBuffer. Index 1 is actually the second element, so your code crashes when you only create one buffer.
Try that:
glGenBuffers(1, &BufferIds[0]);
glBindBuffer(GL_ARRAY_BUFFER, BufferIds[0]);