I'm trying to draw multiple objects with a (the same) basic shader program. The objects have vertex buffers that I intend to draw using associated index buffers by calling glDrawElements. I've set up a VAO for each object and thought I'd associated the index buffer and vertex buffer with the VAO, but when I draw the second (and any additional objects) they are drawn using the wrong vertices.
Here's my (pseudoish) code for setting up the VBO's and EBO's:
glGenBuffers(1, &vboCube);
glBindBuffer(GL_ARRAY_BUFFER, vboCube);
glBufferData(GL_ARRAY_BUFFER, getNumSphereVertices() * sizeof(Vertex), &data[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &iboCube);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboCube);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, getNumCubeIndices() * sizeof(uint32), &data[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glGenBuffers(1, &vboSphere);
glBindBuffer(GL_ARRAY_BUFFER, vboSphere);
glBufferData(GL_ARRAY_BUFFER, getNumSphereVertices() * sizeof(Vertex), &data[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &iboSphere);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboSphere);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, getNumSphereIndices() * sizeof(uint32), &data[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
Edit:
These have been updated to use DSA equivalents and the problem persists. DSA code as per:
glCreateBuffers(1, &vboCube);
glBindBuffer(GL_ARRAY_BUFFER, vboCube);
glNamedBufferData(vboCube, getNumCubeVertices() * sizeof(Vertex), &data[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
Next linking my program attributes:
glUseProgram(programID);
uint32 vaoCube;
glCreateVertexArrays(1, &vaoCube);
glBindVertexArray(vaoCube);
i = 0
for each attribute:
uint32 attribIndex = glGetAttribLocation(program, name.c_str());
glVertexArrayVertexBuffer(vaoCube, i, vboCube, 0, stride);
glEnableVertexArrayAttrib(vaoCube, attribIndex);
glVertexArrayAttribFormat(vaoCube, attribIndex, numCells, dataType, normalise, offset);
glVertexArrayAttribBinding(vaoCube, attribIndex, i);
glVertexArrayBindingDivisor(vaoCube, i, divisor);
i++
glBindVertexArray(0);
glBindVertexArray(vaoCube);
glVertexArrayElementBuffer(vaoCube, iboCube);
glBindVertexArray(0);
uint32 vaoSphere;
glCreateVertexArrays(1, &vaoSphere);
glBindVertexArray(vaoSphere);
i = 0
for each attribute:
uint32 attribIndex = glGetAttribLocation(program, name.c_str());
glVertexArrayVertexBuffer(vaoSphere, i, vboSphere, 0, stride);
glEnableVertexArrayAttrib(vaoSphere, attribIndex);
glVertexArrayAttribFormat(vaoSphere, attribIndex, numCells, dataType, normalise, offset);
glVertexArrayAttribBinding(vaoSphere, attribIndex, i);
glVertexArrayBindingDivisor(vaoSphere, i, divisor);
i++
glBindVertexArray(0);
glBindVertexArray(vaoSphere);
glVertexArrayElementBuffer(vaoSphere, iboSphere);
glBindVertexArray(0);
And finally drawing the objects:
glBindVertexArray(vaoCube);
glDrawElements(GL_TRIANGLES, getNumCubeIndices(), GL_UNSIGNED_INT, (GLvoid*)0);
glBindVertexArray(0);
glBindVertexArray(vaoSphere);
glDrawElements(GL_TRIANGLES, getNumSphereIndices(), GL_UNSIGNED_INT, (GLvoid*)0);
glBindVertexArray(0);
Finally the result:
Is the VAO setup incorrect?
If you are using ARB_direct_state_access/OpenGL 4.5, you should do so consistently and entirely. So all of that stuff in "my (pseudoish) code for setting up the VBO's and EBO's:" is wrong. You should be using glCreateBuffer, glNamedBufferData and the like.
This is important because while GL_ARRAY_BUFFER is part of context state, GL_ELEMENT_ARRAY_BUFFER is part of VAO state. And if you're using core OpenGL and don't have a VAO bound... that means there is no element array buffer state. So your glBindBuffer call should have errored out, and your subsequent attempts to use them would similarly fail.
The problem was external to the code shown above. The above code actually works.
Related
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);
}
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);
So I have some code that creates a buffer and puts some vertices in it:
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(0);
I also bind it to a shader attribute:
glBindAttribLocation(programID, 0, "pos");
And, finally, draw it:
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glDrawArrays(GL_TRIANGLES, 0, 3);
Of course, there is other code, but all of this stuff runs fine (displays a red triangle on the screen)
However, the instant I try to factor this stuff out in a struct, nothing will display (here is one of the methods):
void loadVerts(GLfloat verts[], int indices)
{
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
glVertexAttribPointer(indice, indices, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(indice);
indice++;
buffers.push_back(vertexbuffer);
}
I've quadruple checked this code, and I've also traced it to make sure it would match the code above whenever its called. My draw call is almost the same as my original:
void draw()
{
glBindBuffer(GL_ARRAY_BUFFER, buffers.at(0));
glDrawArrays(GL_TRIANGLES, 0, 3);
}
I've also tried making this a class, and adding/changing many parts of the code. buffers and indice are just some vars to keep track of buffers and attribute indexes. buffers is an std::vector<GLuint> FWIW.
The main problem is here:
void loadVerts(GLfloat verts[], int indices)
{
...
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
The type of the verts argument is a pointer to GLfloat. Your function signature is equivalent to:
void loadVerts(GLfloat* verts, int indices)
So sizeof(verts), which is used as the second argument to glBufferData(), is 4 on a 32-bit architecture, 8 on a 64-bit architecture.
You will need to pass the size as an additional argument to this function, and use that value as the second argument to glBufferData().
These statements also look somewhat confusing:
glVertexAttribPointer(indice, indices, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(indice);
I can't tell if there's a real problem, but you have two variables with very similar names that are used very differently. indice needs to be the location of the attribute in your vertex shader, while indices needs to be the number of components in the attribute.
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.
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.