Confused about having to bind VBO before editing VAO - c++

I'm trying to draw a textured cube in OpengL.
At first, I initialize VBO and VAO in the class constructor as follows.
Block::Block(...)
{
glGenBuffers(1, &VBO);
glGenVertexArrays(1, &VAO);
//glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindVertexArray(VAO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(3 *
sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(6 *
sizeof(float)));
glEnableVertexAttribArray(2);
}
and in the method called renderBlock(), I render the cube like this
void Block::renderBlock()
{
setMatrix();
shader.use();
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindVertexArray(VAO);
glActiveTexture(GL_TEXTURE0);
shader.setInt("tex", 0);
shader.use();
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
and if I call the block.renderBlock(), the program will crash at glDrawArrays(GL_TRIANGLES, 0, 6);. The error message says that 0xC0000005: Access conflict occurred at read position 0x0000000000000000.. But if I uncomment the //glBindBuffer(GL_ARRAY_BUFFER, VBO); in constructer, the program will run successfully. It's very confusing to me. Why should I bind the VBO before I edit the VAO. Is there any connection between them?Any advice would be greatly appreciated.

You must bind the VBO before calling glVertexAttribPointer. When glVertexAttribPointer is called, the buffer currently bound to the GL_ARRAY_BUFFER target is associated with the specified attribute index and the ID of the buffer object is stored in the state vector of the currently bound VAO. Therefore, the VAO and the VBO must be bound before calling glVertexAttribPointer.

Related

Can a VAO name be re-used after calling glDeleteVertexArrays by calling glGenVertexArrays later?

It is my understanding from the OpenGL documentation that a VAO can be deleted (glDeleteVertexArrays), and then later regenerated (glGenVertexArrays). However, I have an issue when I am getting an OpenGL error when trying to re-use an existing VAO variable in a Chunk class (for a Minecraft clone). This only happens for some chunks and I cannot understand why. I output the VAO value (unsigned int type) and it doesn't seem to change after deleting with glDeleteVertexArrays. It was my understanding from the documentation that this value would be reset to zero after running this function. See Chunk class code below.
void Chunk::load()
{
// Update chunk state
loaded = true;
// Set up OpenGL buffers
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &vertexVBO);
glGenBuffers(1, &textureVBO);
glGenBuffers(1, &EBO);
// VAO bound before setting up buffer data
glBindVertexArray(VAO);
// Indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
indices.size() * sizeof(unsigned int),
&indices[0],
GL_DYNAMIC_DRAW);
// Vertices
glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
glBufferData(GL_ARRAY_BUFFER,
vertices.size() * sizeof(float),
&vertices[0],
GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(unsigned int), (void*)0);
glEnableVertexAttribArray(0);
// Texture Coordinates
glBindBuffer(GL_ARRAY_BUFFER, textureVBO);
glBufferData(GL_ARRAY_BUFFER,
texCoords.size() * sizeof(float),
&texCoords[0],
GL_DYNAMIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
// Unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void Chunk::unload()
{
// Update chunk state
loaded = false;
// Delete arrays/buffers.
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &vertexVBO);
glDeleteBuffers(1, &textureVBO);
glDeleteBuffers(1, &EBO);
}
Just as delete ptr; in C++ or free(ptr); in C does not actually change the pointer value of ptr variable, calling glDelete* on an OpenGL object does not change the value of the variables you give it. It is up to you to not use the variable again or to assign it to a neutral value.
That having been said, if your intent is to immediately create a new VAO... why bother? Just clear out the old one by disabling all of the attribute arrays and buffer bindings, and its ready to be used anew:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
GLint maxAttrib;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttrib);
for(int attribIx = 0; attribIx < maxAttrib; ++attribIx)
{
glDisableVertexAttribArray(attribIx);
glVertexAttribPointer(attribIx, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
glVertexAttribDivisor(attribIx, 0);
}

glDrawElements not drawing

I create my buffers with the following code:
//generate buffers
glGenVertexArrays(1, &VAO);
//glGenBuffers(1, &EBO);
glGenBuffers(1, &VBO_vertices);
glGenBuffers(1, &VBO_colors);
glGenBuffers(1, &VBO_normals);
// Bind the Vertex Array Object first, then bind and set vertex buffer(s) and attribute pointer(s).
glBindVertexArray(VAO);
// Copy our vertices array in a buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, VBO_vertices);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*vertices.size(), &vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, vTable.size() * sizeof(int), &vTable[0], GL_STATIC_DRAW);
// Position attribute
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); //size = 3 (X,Y,Z)
glEnableVertexAttribArray(0);
//Buffer for color
glBindBuffer(GL_ARRAY_BUFFER, VBO_colors);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*vertices.size(), &v_color[0], GL_STATIC_DRAW);
// Color attribute
glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); //size = 3 (R,G,B)
glEnableVertexAttribArray(1);
//Buffer for normals
glBindBuffer(GL_ARRAY_BUFFER, VBO_normals);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*vertices.size(), &v_normals[0], GL_STATIC_DRAW);
//normal attribute
glVertexAttribPointer((GLuint)2, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); //size = 3 (R,G,B)
glEnableVertexAttribArray(2);
// Unbind the VAO
glBindVertexArray(0);
My data are :
vector<vec3> vertices, v_normals,v_color;
vector<int> vTable;
I have vertices, normals and colors per vertex and an index table with the index vertices of each triangle.
When I try to render this, nothing appears on the window.
glBindVertexArray(VAO); //Bind VAO
glDrawElements(GL_TRIANGLES, vTable.size(), GL_UNSIGNED_INT, &vTable[0]);
glBindVertexArray(0); //Unbind VAO
If I used this:
glDrawArrays(GL_TRIANGLES,0,vTable.size());
It draws something but an incomplete object, like in the link image.
image
Anybody knows what happens? Thanks in advance
Your glDrawElements call is wrong, the last parameter should be a byte offset into your GL_ELEMENT_ARRAY_BUFFER that holds the indices, not pointer to system memory.
glDrawElements(GL_TRIANGLES, vTable.size(), GL_UNSIGNED_INT, 0);

Drawing multiple objects in OpenGL with different buffers

With OpenGL shaders, I want to render two objects. Each is defined by a set of vertex positions and vertex indices for the triangles. When I make my buffers, I use the following code:
// Object 1 vertex positions
glBindBuffer(GL_ARRAY_BUFFER, object1_vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, object1_vertices_size, object1_vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Object 1 vertex indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object1_index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, object1_indices_size, object1_indices, GL_STATIC_DRAW);
// Object 2 vertex positions
glBindBuffer(GL_ARRAY_BUFFER, object2_vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, object2_vertices_size, object2_vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Object 2 vertex indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object2_index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, object2_indices_size, object2_indices, GL_STATIC_DRAW);
And then when I render my scene, I use the following code:
// Object 1
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object1_index_buffer);
glDrawElements(GL_TRIANGLES, object1_num_indices, GL_UNSIGNED_INT, (void*)0);
// Object 2
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object2_index_buffer);
glDrawElements(GL_TRIANGLES, object2_num_indices, GL_UNSIGNED_INT, (void*)0);
However, this results in only object 2 being drawn. What am I doing wrong?
If you have openGL 3.3+ you should use a VAO:
glBindVertexArray(vao1);
// Object 1 vertex positions
glBindBuffer(GL_ARRAY_BUFFER, object1_vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, object1_vertices_size, object1_vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Object 1 vertex indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object1_index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, object1_indices_size, object1_indices, GL_STATIC_DRAW);
glBindVertexArray(vao2);
// Object 2 vertex positions
glBindBuffer(GL_ARRAY_BUFFER, object2_vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, object2_vertices_size, object2_vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Object 2 vertex indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object2_index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, object2_indices_size, object2_indices, GL_STATIC_DRAW);
and then you only need to bind the right vao when drawing:
// Object 1
glBindVertexArray(vao1);
glDrawElements(GL_TRIANGLES, object1_num_indices, GL_UNSIGNED_INT, (void*)0);
// Object 2
glBindVertexArray(vao2);
glDrawElements(GL_TRIANGLES, object2_num_indices, GL_UNSIGNED_INT, (void*)0);
otherwise you will need to repeat the bind and glVertexAttribPointer calls between draws:
// Object 1
glBindBuffer(GL_ARRAY_BUFFER, object1_vertex_buffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object1_index_buffer);
glDrawElements(GL_TRIANGLES, object1_num_indices, GL_UNSIGNED_INT, (void*)0);
// Object 2
glBindBuffer(GL_ARRAY_BUFFER, object2_vertex_buffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object2_index_buffer);
glDrawElements(GL_TRIANGLES, object2_num_indices, GL_UNSIGNED_INT, (void*)0);
If this is all the code present, then there are several problems:
One has to enable vertex attributes by calling glEnableVertexAttribArray.
In the drawing code you are only rebinding the index buffer, but not the vertex buffer. Both, glBindBuffer(GL_ARRAY_BUFFER,... and glVertexAttribPointer change the current state, so you are overriding the first objects setting with the second ones. If you really want to work without VAOs, you'll have to bind the correct buffer before each draw call and update the glVertexAttribPointer
There is no VAO in use (VAOs are mandatory when working in Core profile but I would recommend using them also in compatibility mode)

glDrawElements not drawing anything to screen

Whenever I try to draw a mesh using glDrawElements, my program gets no errors, but it doesn't draw anything. I'm pretty sure that the issue is with glDrawElements since if I comment glDrawElements out and replace it with glDrawArrays, it works perfectly. So, my question is, can anyone help me figure out why this is happening?
Also glGetError returns no errors
#include "Mesh.h"
Mesh::Mesh(glm::vec2* vertices, glm::vec2* texCoords, GLushort* elements, int size)
{
m_size = size;
m_vertices = vertices;
m_elements = elements;
movementVector = glm::vec2(0.0f, 0.0f);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, size * sizeof(float), vertices, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glGenBuffers(1, &tex_vbo);
glBindBuffer(GL_ARRAY_BUFFER, tex_vbo);
glBufferData(GL_ARRAY_BUFFER, size * sizeof(float), texCoords, GL_STATIC_DRAW);
// note: I assume that vertex positions are location 0
int dimensions = 2; // 2d data for texture coords
glVertexAttribPointer(1, dimensions, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray (1); // don't forget this!
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
}
Mesh::~Mesh()
{
glDeleteVertexArrays(1, &vbo);
}
void Mesh::Draw()
{
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
//glDrawArrays(GL_TRIANGLES, 0, 8);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
glDisableVertexAttribArray(0);
}
Here's a link to the code handling drawing objects to the screen, also, I have tested my shaders, they are fully functional and unless drawing via glDrawElements requires changes to the shaders as well, then there is nothing that is causing this with them.

OPEN GL: is this the right way of using VBO IBO and VAO

I'm familiar with IBO, VBO and VAO, while passing vertices, uvs and normals in one buffer. Though there are cases, when it's a little bit difficult to combine them in one buffer.
Therefore I came up with this piece of code:
glGenBuffers(2, &iboID[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, vertInd.size() * sizeof(unsigned int), &vertInd[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, uvInd.size() * sizeof(unsigned int), &uvInd[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glGenBuffers(2, &vboID[0]);
glBindBuffer(GL_ARRAY_BUFFER, vboID[0]);
glBufferData(GL_ARRAY_BUFFER, tempV.size() * sizeof(glm::vec3), &tempV[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vboID[1]);
glBufferData(GL_ARRAY_BUFFER, tempUV.size() * sizeof(glm::vec2), &tempUV[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenVertexArrays(1, &vaoID[0]);
glBindVertexArray(vaoID[0]);
glBindBuffer(GL_ARRAY_BUFFER, vboID[0]);
glVertexAttribPointer(_shader->attrib("vert"), 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(_shader->attrib("vert"));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID[0]);
outputError();
glBindBuffer(GL_ARRAY_BUFFER, vboID[1]);
glVertexAttribPointer(_shader->attrib("vertTexCoord"), 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(_shader->attrib("vertTexCoord"));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID[1]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
So my question is : Is this the right way of doing this? (because at the moment I see nothing drawn to the screen)
You are trying to specify different element arrays (in separate IBOs), each for a vertex attribute. This is not going to work. Defining separate VBOs for each attribute is fine, but the GL can only have one element array, indexing all the currently enabled attribute arrays at the same time.