VBO Instancing - Attribute per Vertex per Instance

As I understand it, glDrawArraysInstanced() will draw a VBO n times.
glVertexAttribDivisor() using 1, so that each instance has a unique attribute in the shader. So far I can pass a different color for each instance, with vec4*instances, and each vertex in that instance will share that attribute, hence each instance of a triangle has a different color.

However, what I’m looking for is a type of divisor that will advance the attribute per vertex for each instance, and the best example would be a different color for each vertex in a triangle, for each instance. I would fill a VBO with 3vec4instances.

Eg. I want to draw 2 triangles using instancing, I would assume to give the 3 colors per vertex for as many instances I am drawing:

color_vbo_data [] = {
    vec4, vec4, vec4, // first triangle's vertex colors
    vec4, vec4, vec4 // second triangle's vertex colors
};

glDrawArraysInstanced(GL_TRIANGLES, 0, 3(vertexes), 2(instances));

If I set the attribute divisor to 0, it will use the first 3 colors of the color_vbo_data everywhere (so each triangle will have the first 3 colors in the VBO only), rather than advancing.
Effectively each vertex should get the attribute from the VBO as if it were:

color_attribute = color_vbo[(vertex_count * current_instance) + current_vertex];

You cannot do this using vertex attributes and the features provided by ARB_instanced_arrays.
However, you can do it (and way more) using ARB_draw_instanced and ARB_texture_buffer_object.

Before going forward, though, I’d like to clarify a few things:
There is no such thing like “drawing a VBO”. Draws are just draws that issue a certain number of primitives. Also, VBO is just a term that refers to using a buffer object as the source of vertex attribute information. But the same buffer can be used for other purposes too, like texture buffer access, etc.

So the solution:
Put your color data into a separate buffer object. Bind it as e.g. an RGBA8 texture buffer (if you store your color as 8-bit normalized RGBA values).
Then, in your vertex shader, just fetch the appropriate color value as follows:


...
uniform samplerBuffer myTextureBuffer;
...
void main() {
  ...
  color_attribute = texelFetch(myTextureBuffer, (gl_InstanceID * vertex_count) + gl_VertexID);
  ...
}

Please note a few things here:
gl_InstanceID always gives you the currently processed instance’s number, and gl_VertexID always gives you the currently processed vertex’s number. These are built-in GLSL variables.
Now for vertex_count, there is no built-in variable, thus you’ll have to pass it e.g. as a uniform to the vertex shader.

I guess that will have to do for now. I believe what I am trying to achieve is reasonable, I am quite disappointed that this has not been provided. That texture buffer solution is rather hackish and was hoping for an elegant solution, but as it seems, OpenGL is lacking some basic support for their instancing method.

Thank you :slight_smile:

One small addition: The texture solution is far from being a “hackish” solution. The uniform arrays have, depending on the graphics card, a very limited size over that the shader simply does not compile. I found the border being between 250 on better cards down to 170 on some, with each element being a vec4. With texturing, you can easily store millions of elements without experiencing any issues.

On the other hand, it depends how you look at it: What is a texture more than a huge array of floating point values that you can display? :wink:

That’s the thing. The instanced arrays are the “hacky”, old-style solution. Why have a set of fixed function features instead of one that is fully programmable?
Using texture buffers, uniform buffers, or shader storage buffers and fetch from them arbitrarily using gl_VertexID and gl_InstanceID is a flexible, fully customizable solution. Using the vertex attrib divisor is just some old-style fixed function thing.

Hmm, I wasn’t aware of that. I am fairly new to this modern OpenGL, seems like they should just make it even lower level and enable basic C style ideas. The name “Texture buffer” should instead be maybe called an array or something.

Both are useful, but instance arrays can perform better than gl_InstanceID-style instancing, so I wouldn’t write it off. Makes some sense as the GPU is pushing the right attributes into the shaders rather than waiting on the shaders to pull the correct attributes randomly from memory.