PDA

View Full Version : Instancing with instance index buffer



nostalgic
04-06-2016, 06:49 AM
Hello everybody,

I am using instancing to draw a lot of geometry that in some cases is valid for only one frame. This is why for view frustum culling, I use a compute shader that writes the indices of all visible instances into a shader storage buffer. Let's call that buffer visibleInstanceIndices. Right now, I then call glDrawElementsInstanced and fetch attributes such as the transformation in the vertex shader like this:


int instance = visibleInstanceIndices[gl_InstanceID];
mat4 trafo = transformations[instance];

transformations is only updated once at loading time, only the visible instance indices change at runtime. The indirection this introduces is annoying and - so I suspect - unnecessary. Is it possible (any OpenGL version, any extension supported on Nvidia Maxwell cards) to render all of my instances with a single draw call such that gl_InstanceID is not incremented internally for each instance, but the value is taken from a bound buffer (visibleInstanceIndices in my case)?

Edit: I might also add a follow-up question right away. I am not only culling single instances, but also groups of instances. In this case, the instances are arranged such that the instances of one group have consecutive indices. For example, if group 0 is visible, then I want to draw 1000 instances with transformations[0] to transformations[999]. I believe that I can do that with glMultiDrawElementsIndirect, but only for the first group. If I add another DrawElementsIndirectCommand struct for each group, gl_InstanceID will start from 0 for each group/draw command. So I would need to specify an offset for gl_InstanceID for each command, which I think is not possible. But maybe I'm heading in the right direction?


Regards,
nostalgic

malexander
04-06-2016, 07:57 AM
Why is the indirection annoying? It's pretty straightforward, IMO:


in int instanceIndex; // instanced attribute w/step 1 (GL3.3)
...
void main()
{
mat4 trafo = transformations[ instanceIndex ];
}

No gl_InstanceID required. instanceIndex contains the list of visible object indices, and you draw with #instances set to its length.

nostalgic
04-07-2016, 03:36 AM
Thank you for your reply! Using glVertexAttribDivisor to declare the instance indices as a per-instance vertex attribute indeed solves the problem. I don't know how I missed that.

The second question that I have added to the original post remains: What if I don't have individual indices, but ranges of indices? If the visible instances are grouped in blocks of 1000, I might have a million instances in total, but only instances [0, 1000), [3000, 4000) and [21000, 22000) are visible. Is there a way I can do this in a single (indirect/multi) draw call? The alternative would be a round trip to the CPU to loop over all visible ranges and call glDrawElementsInstanced for each of them. As I have already written, glMultiDrawElementsIndirect might do what I need where the compute shader fills the buffer with the draw command structs, but I have not fully understood its parameters yet.