aTom
aTom

Reputation: 546

glDrawElementsInstanced getting only one vertex position and texture coordinate

I am trying to use instanced rendering to render a simple mesh (a textured quad made of 2 triangles) multiple times in a single draw call. When rendering, I don't see my instanced meshes, and when analyzing a frame with renderdoc, all vertices positions are set to the position of the first vertex of the mesh, same for texture coordinates, so I tend to think I have an issue with vertex data uploading, but I can't figure out what.

My main source of inspiration for instanced rendering has been this tutorial, and the OpenGL documentation.

Here are the relevant parts of my code:

  // This is part of the instanced mesh object initialization code.
  // VAO, VBO, and EBO are unsigned int private members of the object.

  glGenVertexArrays(1, &VAO);
  glGenBuffers(1, &VBO);
  glGenBuffers(1, &EBO);

  glBindVertexArray(VAO);
  glBindBuffer(GL_ARRAY_BUFFER, VBO);

  // I could confirm in a debug session that vertices contains the data I expect it to contain
  glBufferData(GL_ARRAY_BUFFER,
               static_cast<GLsizeiptr>(sizeof(float) * vertices.size()),
               vertices.data(),
               GL_STATIC_DRAW);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

  // Same as vertices, I could confirm indices contains the data I expect.
  glBufferData(GL_ELEMENT_ARRAY_BUFFER,
               static_cast<GLsizeiptr>(sizeof(unsigned int) * indices.size()),
               indices.data(),
               GL_STATIC_DRAW);

  GLsizei vertexStride = static_cast<GLsizei>(7 * sizeof(float));

  // vertex coordinates (only x and y, so the size of 2 is ok here)
  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, vertexStride, 0);
  glVertexAttribDivisor(0, 1);
  glEnableVertexAttribArray(0);

  // color
  glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertexStride, 2);
  glVertexAttribDivisor(1, 1);
  glEnableVertexAttribArray(1);

  // texture coordinates
  glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertexStride, 5);
  glVertexAttribDivisor(2, 1);
  glEnableVertexAttribArray(2);

  glBindVertexArray(0);
  // This is the rendering code.

  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, texture.id);
  glActiveTexture(GL_TEXTURE1);
  glBindTexture(GL_TEXTURE_1D, palette.id);

  glBindVertexArray(VAO);

  // As advised by learnopengl.com, 4th argument is set to 0 since I'm using an element buffer
  glDrawElementsInstanced(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0, instances.size());
  glBindVertexArray(0);

  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, 0);
  glActiveTexture(GL_TEXTURE1);
  glBindTexture(GL_TEXTURE_1D, 0);
// vertex shader
#version 330 core
layout (location = 0) in vec2 vertex_pos;
layout (location = 1) in vec3 vertex_color;
layout (location = 2) in vec2 vertex_tex_coord;

out vec2 tex_coord;
out vec3 color;

uniform mat4 viewproj;

void main()
{
  gl_Position = viewproj * vec4(vertex_pos, 0.0, 1.0);
  tex_coord = vertex_tex_coord;
  color = vertex_color;
}

// fragment shader
#version 330 core
out vec4 fragment_color;

in vec2 tex_coord;
in vec3 color;

uniform sampler2D tex;
uniform sampler1D palette;

void main()
{
  float base_index = texture(tex, tex_coord).r;
  fragment_color = texture(palette, base_index) * vec4(color, 1);
}

Here is what I get : enter image description here I have the correct number of vertices, the indices are ok too and the color seems ok (color is set to glm:vec3(1.0f, 1.0f, 1.0f) earlier in the code. However, vertex_pos and vertex_tex_coord values are all the same. The values are coherent, but all the same.

I would have expected something like that: enter image description here

Considering I get the correct values for the indices, I think the EBO is ok, but there may be a problem with my VBO, and since data is correct in my vertices vector just before uploading it, and incorrect just before rendering it, I'm lost ^^' and I don't know where to go from here.

Upvotes: 2

Views: 614

Answers (1)

Rabbid76
Rabbid76

Reputation: 210908

You have misunderstood what glVertexAttribDivisor does. glVertexAttribDivisor is used for instance attributes. Instance attributes are attributes that change for instances, not the vertices of an instance. The vertex coordinate, color and texture coordinate are not instance attributes, but vertex attributes. Hence you must remove the calls to glVertexAttribDivisor (or set the divisor argument to 0):

glVertexAttribDivisor(0, 1);


If a named buffer object is bound to the GL_ARRAY_BUFFER target, the last argument of glVertexAttribPointer is treated as a byte offset into the buffer objects data store. Therefore, the offset of the color and texture coordinates attribute must be 2*sizeof(float) and 5*sizeof(float) instead of 2 and 5:

glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertexStride, 2);

glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertexStride, (void*)(2*sizeof(float)));

glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertexStride, 5);

glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertexStride, (void*)(5*sizeof(float)));

Upvotes: 2

Related Questions