2

I am trying to render multiple text labels in a single draw call. To that end I pass the matrices of each label in a uniform array. For each vertex of the text meshes a "labelIndex" attribute is passed to select the correct matrix from the array.

But when I check the VS Input in RenderDoc the labelIndex is 0 for every vertex as if it is uninitialized. What am I missing when setting up the labelIndex vertex attribute?

uint labelIdx = 0;
std::vector<uint> labelIndices;
for (auto& label : Labels)
{
  ... 
  for (unsigned int i = 0; i < wcslen(label.Text); i++)
  {
    ...
    labelIndices.push_back(labelIdx);
    labelIndices.push_back(labelIdx);
    labelIndices.push_back(labelIdx);
    labelIndices.push_back(labelIdx);
  }      
  labelIdx++;
}
glGenBuffers(1, &LabelIndexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, LabelIndexBufferID);
glBufferData(GL_ARRAY_BUFFER, labelIndices.size() * sizeof(uint), &labelIndices[0], GL_STATIC_DRAW);

glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);

...

// 2nd attribute buffer : Label indices
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, LabelIndexBufferID);
glVertexAttribIPointer(1, 1, GL_UNSIGNED_INT, 0, (void*)0);

// element buffer
glGenBuffers(1, &ElementBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ElementBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint), &indices[0], GL_DYNAMIC_DRAW);

glBindVertexArray(0);

Rendering:

glUseProgram(ShaderID);
...
glUniformMatrix4fv(ParentMatrixLocation, 1, GL_FALSE, glm::value_ptr(Renderer::VP));
glUniformMatrix4fv(LabelMatricesLocation, Labels.size(), GL_FALSE, glm::value_ptr(LabelMatrices.get()[0]));

glBindVertexArray(VertexArrayID);

glDrawElements(
    GL_TRIANGLES,
    CharacterCount * 6,
    GL_UNSIGNED_INT,
    (void*)0
);

glBindVertexArray(0);

Vertex Shader:

#version 430 core

layout(location = 0) in vec4 PositionUV;
layout(location = 1) in uint LabelIndex;

uniform mat4 ParentMatrix;
uniform mat4 LabelMatrices[200];
out vec2 UV;

void main()
{
    gl_Position = ParentMatrix * LabelMatrices[LabelIndex] * vec4(PositionUV.xy, 0, 1);
    UV = PositionUV.zw;
}

Edit:

I dont know what is going on here. When I get the buffer after filling it:

uint* data = NULL;
data = new uint[labelIndices.size()];
for (int i = 0; i < labelIndices.size(); i++)
{
    data[i] = 0;
}
glGetBufferSubData(GL_ARRAY_BUFFER, 0, labelIndices.size() * sizeof(TextVertex), data);

I look at data and the LabelIndex is set to the appropriate label. But when grabbing the frame in RenderDoc the LabelIndex is still 0. When I initialize LabelIndex with, say, 7 and do not increment it in the loop, LabelIndex will correctly have the value 7 in the VS Input. It's bizarre.

Christian
  • 317
  • 1
  • 14
  • 1
    Have you considered making the matrix an [instance attribute](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glVertexAttribDivisor.xhtml) and using instanced rendering? – Nico Schertler Apr 23 '20 at 09:22
  • 1
    As far as I know instancing is useful for drawing the same set of vertex data multiple times. I rejected it because in my case the vertex data differs from label to label as it is created from the variable label text. – Christian Apr 23 '20 at 09:55
  • 1
    In principle, you are right and it might well be that instanced rendering is not a good fit for your scenario. You can, however, also try to make your labels structurally similar if possible (maybe they are all rectangular with a position and size - those would be instance attributes) and the vertex shader just moves the vertices to the correct location. – Nico Schertler Apr 23 '20 at 10:06
  • 1
    Where's your elements buffer? Did you try to calculate the `LabelIndex` in the shader by `gl_VertexID/4`? – Yakov Galka Apr 23 '20 at 19:45
  • The element buffer is working fine so I left it out to declutter the code. It's four vertices per character of the label's string. I edited my code to make it clearer. – Christian Apr 24 '20 at 06:30

0 Answers0