From what I understand VAOs should store the states needed for rendering like the buffers and the attribute pointers.
But the problem I am having is, I need to set-up the VAO and load the data to the buffers every time before rendering or else the things being drawn is wrong.
I am using a class called mesh that hold the VAO and VBO handles as protected GLuint variables to initialize and load the vertex data into the GPU.
I searched for hours but it seams no one else is having the same problem.
So if I initialize like this and render like this :
mesh coneMesh, sphereMesh, boxMesh;
coneMesh.setup(coneVertex, GL_STATIC_DRAW, 1, ShaderA);
sphereMesh.setup(*sphereVertex, GL_STATIC_DRAW,1, ShaderA);
boxMesh.setup(boxVertex, GL_STATIC_DRAW, 1, ShaderA);
and in the rendering loop:
//sphereMesh.setup(*sphereVertex, GL_STATIC_DRAW,1, ShaderA);
sphereMesh.render(GL_TRIANGLE_STRIP,0,sphereVertex->size(),0);
sphereMesh.render(GL_TRIANGLE_STRIP,0,sphereVertex->size(),1);
//coneMesh.setup(coneVertex, GL_STATIC_DRAW, 1, ShaderA);
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE);
coneMesh.render(GL_TRIANGLE_STRIP,0,coneVertex.size(),2);
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL);
//boxMesh.setup(boxVertex, GL_STATIC_DRAW, 1, ShaderA);
boxMesh.render(GL_LINE_LOOP, 0, boxVertex.size());
glfwSwapBuffers(window);
If I take out he comments and reinitialize the VAO and reload the data every thing works perfectly, can someone please tell me what I am doing wrong and how to fix it? Thank You
int mesh::setup(std::vector<vertex> &vert, GLenum BufferDataUsage, GLuint nuberOfAttribute, shader &shad)
{
this->nuberOfAttribute = nuberOfAttribute;
this->shad = &shad;
std::vector<glm::vec3> position;
std::vector<glm::vec2> textureCoord;
position.reserve(vert.size());
textureCoord.reserve(vert.size());
for(unsigned int i; i<vert.size(); i++)
{
position.push_back(vert[i].pos());
textureCoord.push_back((vert[i].textureCoordinate));
}
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1,&vbo[0]);
glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
glBufferData(GL_ARRAY_BUFFER,(GLsizeiptr)vert.size() * sizeof (position[0]), &position[0], BufferDataUsage);
glEnableVertexAttribArray(0);
glVertexAttribPointer ( ( GLuint ) 0, 3, GL_FLOAT, GL_FALSE,0,0);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(0);
std::cout <<vbo[0]<<std::endl;
return 0;
}
And the rendering function:
void mesh::render(GLenum DrawHint, GLint first,GLsizei count)
{
shad->bind();//glUseProgram(id)
//set up transform matrix and set up uniform
glBindVertexArray(vao);
glDrawArrays(DrawHint, first, count);
glBindVertexArray(0);
Edit
1.)I have ran the code in another machine and the problem didn't go away. So it's probably not a driver bug.
2.)I can confirm that the different VAO and VBO are not overwriting each other since the handles on each of them is unique.
3.) Now I have no idea what could possibly course this problem.
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(0);
Unbinding the VBO has to go after unbinding the VAO, as otherwise VAO will remember your VBO not being bound.
EDIT
As pointed out in comments, it's OK to unbind GL_ARRAY_BUFFER before unbinding the VAO. It wouldn't be OK for GL_ELEMENT_ARRAY_BUFFER, which is not used in this example though.
Therefore, the problem must lie elsewhere.
Related
I am trying to draw a simple triangle and set the buffers as follows;
triangle t;
point3f vertices[] = { t.p1(), t.p2(), t.p3() };
GLushort indices[] = { 0, 1, 2 };
gl_vertex_array vao{ 3 };
vao.bind_vertex_array();
gl_vertex_buffer position_vbo{ buffer_type::array_buf };
position_vbo.bind_vertex_buffer();
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0],
GL_STATIC_DRAW);
position_vbo.unbind_vertex_buffer();
gl_vertex_buffer index_vbo{ buffer_type::element_array_buf };
index_vbo.bind_vertex_buffer();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices[0],
GL_STATIC_DRAW);
index_vbo.unbind_vertex_buffer();
vao.unbind_vertex_array();
Setting up of buffers and VAOs are fine I think, I checked with glGetError at each stage and everything seems to be working. On my render function, I do the following:
glClearColor(0.4f, 0.3f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
o.vao.bind_vertex_array();
o.sp.use_program();
GLenum error = glGetError();
assert(error == GL_NO_ERROR);
//glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
error = glGetError();
assert(error == GL_NO_ERROR);
o.sp.unuse_program();
o.vao.unbind_vertex_array();
This rendering call with glDrawArrays works just fine but when I try to render with glDrawElements, I get an exception thrown. Moreover, this is hard exception. I can't go to the next line to see the error code. I didn't know that OpenGl calls could throw. I am stuck here. What might be the problem?
Here is a similar discussion
nvoglv32.dll throws the exception
The problem lies in the VAO setup code. The index buffer gets unbound before the VAO is unbound:
index_vbo.unbind_vertex_buffer();
vao.unbind_vertex_array();
Since the VAO always stores the last state of the bound GL_ELEMENT_ARRAY_BUFFER, this is effectively unbinding the index buffer. The exception happens then because you try to read from a not bound index buffer. The solution should be to exchange these two lines and unbind the VAO first:
vao.unbind_vertex_array();
index_vbo.unbind_vertex_buffer();
As Nicol Bolas mentioned in the comments: You can actually leave away the unbinding of the element buffer completely. When the VAO gets unbound, there is no element buffer bound anymore.
I'm trying to implement a batch-rendering system using OpenGL, but the triangle I'm trying to render doesn't show up.
In the constructor of my Renderer-class, I'm initializing the VBO and VAO and also load my shader program (this does work, so the error can't be found here). The VBO is supposed to be capable of holding the maximum amount of vertices I'll permit which is defined in the header to be 30000. The VAO contains the information about how the data that I'll store in that buffer is laid out - in this case I use a struct called VertexData which only contains a 3D-vector ('vertex'), but will also contain stuff like colors etc. later on. So I create the buffer with the size I already stated, don't fill in any content yet and provide the layout using 'glVertexAttribPointer'. The '_vertexCount', as the name implies, counts the amount of vertices currently stored inside that buffer for drawing purposes.
The constructor of my Renderer-class (note that every private member variable defined in the header file starts with an _ ):
Renderer::Renderer(std::string vertexShaderPath, std::string fragmentShaderPath) {
_shaderProgram = ShaderLoader::createProgram(vertexShaderPath, fragmentShaderPath);
glGenBuffers(1, &_vbo);
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glEnableVertexAttribArray(0);
glBufferData(GL_ARRAY_BUFFER, RENDERER_MAX_VERTICES * sizeof(VertexData), NULL, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) 0);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
_vertexCount = 0;
}
Once the initization is done, to render anything, the 'begin' procedure has to be called during the main-loop. This gets the current buffer with write permissions to fill in the vertices that should be rendered in the current frame:
void Renderer::begin() {
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
_buffer = (VertexData*) glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
}
After beginning, the 'submit' procedure can be called to add vertices and their corrosponding data to the buffer. I add the data to the location in memory the buffer currently points to, then advance the buffer and increase the vertexcount:
void Renderer::submit(VertexData* data) {
_buffer = data;
_buffer++;
_vertexCount++;
}
Finally, once all vertices are pushed to the buffer, the 'end' procedure will unmap the buffer to enable the actual rendering of the vertices, bind the VAO, use the shader program, render the provided vertices as triangles, unbind the VAO and reset the vertex count:
void Renderer::end() {
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(_vao);
glUseProgram(_shaderProgram);
glDrawArrays(GL_TRIANGLES, 0, _vertexCount);
glBindVertexArray(0);
_vertexCount = 0;
}
In the main loop I'm beginning the rendering, submitting three vertices to render a simple triangle and ending the rendering process. This is the most important part of that file:
Renderer renderer("../sdr/basicVertex.glsl", "../sdr/basicFragment.glsl");
Renderer::VertexData one;
one.vertex = glm::vec3(-1.0f, 1.0f, 0.0f);
Renderer::VertexData two;
two.vertex = glm::vec3( 1.0f, 1.0f, 0.0f);
Renderer::VertexData three;
three.vertex = glm::vec3( 0.0f,-1.0f, 0.0f);
...
while (running) {
...
renderer.begin();
renderer.submit(&one);
renderer.submit(&two);
renderer.submit(&three);
renderer.end();
SDL_GL_SwapWindow(mainWindow);
}
This may not be the most efficient way of doing this and I'm open for criticism, but my biggest problem is that nothing appears at all. The problem has to lie within those code snippets, but I can't find it - I'm a newbie when it comes to OpenGL, so help is greatly appreciated. If full source code is required, I'll post it using pastebin, but I'm about 99% sure that I did something wrong in those code snippets.
Thank you very much!
You have the vertex attribute disabled when you make the draw call. This part of the setup code looks fine:
glBindVertexArray(_vao);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glEnableVertexAttribArray(0);
glBufferData(GL_ARRAY_BUFFER, RENDERER_MAX_VERTICES * sizeof(VertexData), NULL, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) 0);
At this point, the attribute is set up and enabled. But this is followed by:
glDisableVertexAttribArray(0);
Now the attribute is disabled, and there's nothing else in the posted code that enables it again. So when you make the draw call, you don't have a vertex attribute that is actually enabled.
You can simply remove the glDisableVertexAttribArray() call to fix this.
Another problem in your code is the submit() method:
void Renderer::submit(VertexData* data) {
_buffer = data;
_buffer++;
_vertexCount++;
}
Both _buffer and data are pointers to a VertexData structure. So the assignment:
_buffer = data;
is a pointer assignment. Instead of copying the data into the buffer, it modifies the buffer pointer. This should be:
*_buffer = *data;
This will copy the vertex data into the buffer, and leave the buffer pointer unchanged until you explicitly increment it in the next statement.
I have been working to get OpenGL to render multiple different entities on the scene.
According to http://www.opengl.org/wiki/Vertex_Specification,
Vertex Array Object should remember what Vertex Buffer Object was bound to GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER. (Or at least that is how I understood what it was saying)
Yet, even though I call draw after binding any vao, the application will use only the last one bound to GL_ARRAY_BUFFER.
Question - Am I understanding it right? Considering the code below, is all sequence of calling to gl functions is correct?
void OglLayer::InitBuffer()
{
std::vector<float> out;
std::vector<unsigned> ibOut;
glGenVertexArrays(V_COUNT, vaos);
glGenBuffers(B_COUNT, buffers);
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
glBindVertexArray(vaos[V_PLANE]);
PlaneBuffer(out, ibOut, 0.5f, 0.5f, divCount, divCount);
OGL_CALL(glBindBuffer(GL_ARRAY_BUFFER, buffers[B_PLANE_VERTEX]));
OGL_CALL(glBufferData(GL_ARRAY_BUFFER, out.size()*sizeof(float), out.data(), GL_DYNAMIC_DRAW));
//GLuint vPosition = glGetAttribLocation( programs[P_PLANE], "vPosition" );
OGL_CALL(glEnableVertexAttribArray(0));
//OGL_CALL(glVertexAttribPointer( vPosition, 3, GL_FLOAT, GL_FALSE, sizeof(float)*3, BUFFER_OFFSET(0) ));
OGL_CALL(glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, sizeof(float)*3, BUFFER_OFFSET(0) ));
bufferData[B_PLANE_VERTEX].cbSize = sizeof(float) * out.size();
bufferData[B_PLANE_VERTEX].elementCount = out.size()/3;
OGL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[B_PLANE_INDEX]));
OGL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, ibOut.size()*sizeof(unsigned), ibOut.data(), GL_STATIC_DRAW));
bufferData[B_PLANE_INDEX].cbSize = sizeof(float) * ibOut.size();
bufferData[B_PLANE_INDEX].elementCount = ibOut.size();
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
glBindVertexArray(vaos[V_CUBE]);
out.clear();
ibOut.clear();
GenCubeMesh(out, ibOut);
glBindBuffer(GL_ARRAY_BUFFER, buffers[B_CUBE_VERTEX]);
glBufferData(GL_ARRAY_BUFFER, out.size()*sizeof(float), out.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), BUFFER_OFFSET(0));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[B_CUBE_INDEX]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned), ibOut.data(), GL_STATIC_DRAW);
}
void RenderPlane::Render( float dt )
{
// Putting any vao here always results in using the lastly buffer bound.
OGL_CALL(glBindVertexArray(g_ogl.vaos[m_pRender->vao]));
{
OGL_CALL(glUseProgram(g_ogl.programs[m_pRender->program]));
// uniform location
GLint loc = 0;
// Send Transform Matrix ( Rotate Cube over time )
loc = glGetUniformLocation(g_ogl.programs[m_pRender->program], "transfMat");
auto transf = m_pRender->pParent->m_transform->CreateTransformMatrix();
glUniformMatrix4fv(loc, 1, GL_TRUE, &transf.matrix()(0,0));
// Send View Matrix
loc = glGetUniformLocation(g_ogl.programs[m_pRender->program], "viewMat");
mat4 view = g_ogl.camera.transf().inverse();
glUniformMatrix4fv(loc, 1, GL_TRUE, &view(0,0));
// Send Projection Matrix
loc = glGetUniformLocation(g_ogl.programs[m_pRender->program], "projMat");
mat4 proj = g_ogl.camera.proj();
glUniformMatrix4fv(loc, 1, GL_TRUE, &proj(0,0));
}
OGL_CALL(glDrawElements(GL_TRIANGLES, g_ogl.bufferData[m_pRender->ib].elementCount, GL_UNSIGNED_INT, 0));
}
The GL_ARRAY_BUFFER binding is not part of the VAO state. The wiki page you link explains that correctly:
Note: The GL_ARRAY_BUFFER​ binding is NOT part of the VAO's state! I know that's confusing, but that's the way it is.
The GL_ELEMENT_ARRAY_BUFFER binding on the other hand is part of the VAO state.
While I don't completely disagree with calling this confusing, it actually does make sense if you start thinking about it. The goal of a VAO is to capture all vertex state that you would typically set up before making a draw call. When using indexed rendering, this includes binding the proper index buffer used for the draw call. Therefore, including the GL_ELEMENT_ARRAY_BUFFER binding in the VAO state makes complete sense.
On the other hand, the current GL_ARRAY_BUFFER binding does not influence a draw call at all. It only matters that the correct binding is established before calling glVertexAttribPointer(). And all the state set by glVertexAttribPointer() is part of the VAO state. So the VAO state contains the vertex buffer reference used for each attribute, which is established by the glVertexAttribPointer() call. The current GL_ARRAY_BUFFER on the other hand is not part of the VAO state because the current binding at the time of the draw call does not have any effect on the draw call.
Another way of looking at this: Since attributes used for a draw call can be pulled from different vertex buffers, having a single vertex buffer binding tracked in the VAO state would not be useful. On the other hand, since OpenGL only ever uses a single index buffer for a draw call, and uses the current index buffer binding for the draw call, tracking the index buffer binding in the VAO makes sense.
I've been trying to convert some of my code to modern OpenGL. I've gotten it to the point where I don't get any OpenGL errors, but nothing shows up when I try to draw an object. Here's my code (minus context creation, and error checking):
//Compile shaders and create/link program
//I very highly doubt the problem's here (all my tests say it worked fine),
//so I'm leaving this out for now, but I'll dig it out of my classes if
//there's no obvious problem with the VBO code.
//Create VAO, VBO
unsigned vaoId, vboId;
int positionAttributeLocation;
float vertices[] = {...vertex data here...};
unsigned indices[] = {...index data here...};
positionAttributeLocation = glGetAttribLocation(programId, "position");
glGenVertexArrays(1, &vaoId);
glGenBuffers(1, &vboId);
glBindVertexArray(vaoId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(positionAttributeLocation, 3, GL_FLOAT, GL_FALSE, 0, null);
glEnableVertexAttribArray(positionAttributeLocation);
//Create index buffer
unsigned indexId;
glGenBuffers(1, &indexId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glUseProgram(programId);
glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(unsigned int), GL_UNSIGNED_INT, null);
Not quite SSCCE, but I think that's all the code that could possibly be causing an issue and it's pretty much self-contained.
Try glUseProgram() before your glGetAttribLocation()/glEnableVertexAttribArray() calls.
I figured it out. With some of my refactoring, I forgot to set my width and height variables properly, creating a 0 by 0 viewport. Oops...
Your problem more than likely lies with your cg program and modelview space.
Add cgGLSetStateMatrixParameter(modelViewMatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); to your program just before gldrawarrays, and in your cg file add OUT.HPos = mul(ModelViewProj, IN.position);.
Also add modelViewMatrix as a cgparameter in you initcg section.
I worked this out from the basic opengl samples in the cgtoolkit, and my render function is very similar to yours and now works after having the same problem.
I am transferring over my vertex arrays functions to VBOs to increase the speed of my application.
Here was my original working vertex array rendering function:
void BSP::render()
{
glFrontFace(GL_CCW);
// Set up rendering states
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &vertices[0].x);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &vertices[0].u);
// Draw
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, indices);
// End of rendering - disable states
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
Worked great!
Now I am moving them into VBOs and my program actually caused my graphics card to stop responding. The setup on my vertices and indices are exactly the same.
New setup:
vboId is setup in the bsp.h like so: GLuint vboId[2];
I get no error when I just run the createVBO() function!
void BSP::createVBO()
{
// Generate buffers
glGenBuffers(2, vboId);
// Bind the first buffer (vertices)
glBindBuffer(GL_ARRAY_BUFFER, vboId[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Now save indices data in buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
}
And the rendering code for the VBOS. I am pretty sure it's in here. Just want to render whats in the VBO like I did in the vertex array.
Render:
void BSP::renderVBO()
{
glBindBuffer(GL_ARRAY_BUFFER, vboId[0]); // for vertex coordinates
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId[1]); // for indices
// do same as vertex array except pointer
glEnableClientState(GL_VERTEX_ARRAY); // activate vertex coords array
glVertexPointer(3, GL_FLOAT, 0, 0); // last param is offset, not ptr
// draw the bsp area
glDrawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
glDisableClientState(GL_VERTEX_ARRAY); // deactivate vertex array
// bind with 0, so, switch back to normal pointer operation
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
Not sure what the error is but I am pretty sure I have my rendering function wrong. Wish there was a more unified tutorial on this as there are a bunch online but they are often contradicting eachother.
In addition what Miro said (the GL_UNSIGNED_BYTE should be GL_UNSIGNED_SHORT), I don't think you want to use numVertices but numIndices, like in your non-VBO call.
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0);
Otherwise your code looks quite valid and if this doesn't fix your problem, maybe the error is somewhere else.
And by the way the BUFFER_OFFSET(i) thing is usuaully just a define for ((char*)0+(i)), so you can also just pass in the byte offset directly, especially when it's 0.
EDIT: Just spotted another one. If you use the exact data structures you use for the non-VBO version (which I assumed above), then you of course need to use sizeof(Vertex) as stride parameter in glVertexPointer.
If you are passing same data to glDrawElements when you aren't using VBO and same data to VBO buffer. Then parameters little differs, without FBO you've used GL_UNSIGNED_SHORT and with FBO you've used GL_UNSIGNED_BYTE. So i think VBO call should look like that:
glDrawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_SHORT, 0);
Also look at this tutorial, there are VBO buffers explained very well.
How do you declare vertices and indices?
The size parameter to glBufferData should be the size of the buffer in bytes and if you pass sizeof(vertices) it will return the total size of the declared array (not just what is allocated).
Try something like sizeof(Vertex)*numVertices and sizeof(indices[0])*numIndices instead.