0
votes

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!

1
I can not show you my current solution that handles batches and shaders in OpenGL for two reasons; one it is too large of a project and two it is also copyright code. What I can do is suggest that you check out this website that I have been a member of for almost 8 years. MarkeKnows.com and this is covered under the ShaderEngine series of his video tutorials. If you are new to OpenGL especially modern OpenGL this is one of the best websites I have found! It doesn't only teach about the Graphics API--Library but also 3D Game Engine Design and Batches are covered in the Shader Series. - Francis Cugler

1 Answers

4
votes

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.