1
votes

I am relatively familiar with instanced drawing and per instance data: I've implemented this in the past with success.

Now I am refactoring some old code, and I introduced a bug on how per instance data are supplied to shaders. The relevant bits are the following:

  1. I have a working render loop implemented using glMultiDrawElementsIndirect: if I ignore the per instance data everything draws as expected.
  2. I have a vbo storing the world transforms of my objects. I used AMD's CodeXL to debug this: the buffer is correctly populated with data, and is bind when drawing a frame.

    glBindBuffer(GL_ARRAY_BUFFER,batch.mTransformBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(glm::mat4) * OBJ_NUM, &xforms, GL_DYNAMIC_DRAW);

  3. The shader specifies the input location explicitly:

    #version 450
    layout(location = 0) in vec3 vertexPos;
    layout(location = 1) in vec4 vertexCol;
    //...
    layout(location = 6)uniform mat4 ViewProj;
    layout(location = 10)uniform mat4 Model;
    

The ViewProj matrix is equal for all instances and is set correctly using:

glUniformMatrix4fv(6, 1, GL_FALSE, &viewProjMat[0][0]);

Model is per instance world matrix it's wrong: contains all zeros.

After binding the buffer and before drawing each frame, I am trying to setup the attribute pointers and divisors in such a way that every drawn instance will receive a different transform:

for (size_t i = 0; i < 4; ++i)
{
  glEnableVertexAttribArray(10 + i);

  glVertexAttribPointer(10 + i, 4, GL_FLOAT, GL_FALSE,
                        sizeof(GLfloat) * 16,
                        (const GLvoid*) (sizeof(GLfloat) * 4 * i));

  glVertexAttribDivisor(10 + i, 1);
}

Now, I've looked and the code for a while and I really can't figure out what I am missing. CodeXL clearly show that Model (location 10) isn't correctly filled. No OpenGL error is generated.

My question is: does anyone know under which circumstances the setup of per instance data may fail silently? Or any suggestion on how to debug further this issue?

1
I don't quite understand the setup. Model isn't supposed to be a uniform, it's a regular attribute (... input of the vertex shader). You just set a non-zero divisor on it, and then it will be fed on a per-instance basis (all vertex shader invocations for instance number i will get the i / divisor attribute from that attribute array). Why do you use uniform on it?peppe

1 Answers

2
votes
layout(location = 6)uniform mat4 ViewProj;
layout(location = 10)uniform mat4 Model;

These are uniforms, not input values. They don't get fed by attributes; they get fed by glUniform* calls. If you want Model to be an input value, then qualify it with in, not uniform.

Equally importantly, inputs and uniforms do not get the same locations. What I mean is that uniform locations have a different space from input locations. An input can have the same location index as a uniform, and they won't refer to the same thing. Input locations only refer to attribute indices; uniform locations refer to uniform locations.

Lastly, uniform locations don't work like input locations. With attributes, each vec4-equivalent uses a separate attribute index. With uniform locations, every basic type (anything that isn't a struct or an array) uses a single uniform location. So if ViewProj is a uniform location, then it only takes up 1 location. But if Model is an input, then it takes up 4 attribute indices.