Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Instanced rendering using vertex attribute buffer or uniform buffer for the instance data

I have seen instanced rendering using a vertex attribute buffer. So in addition to your usual data such as 'position' and 'normal' you have an extra 'attribute' for the instanced data:

in vec3 position;
in vec3 normal;
in instanceData
{
    mat4 worldMatrix;
};

For each vertex the pointer for 'position' and 'normal' is advanced the stride of one vertex, but the pointer for 'in instanceData' is advanced one stride length for each instance drawn. In OpenGL this is set with the glVertexAttribDivisor function, and in Direct3D I think with IndexCountPerInstance.

I was wondering however whether instanced rendering could be done with the 'instanceData' buffer read from a uniform or constant buffer. In OpenGL this would like this:

in vec3 position;
in vec3 normal;
uniform instanceData
{
    mat4 worldMatrix[4000]; // Drawing 4000 objects
};

int main()
{
     worldMatrix[glInstanceID]; // If we're drawing for example the 4th instance then the instance data
// is read from the uniform buffer using the instance ID at index 4
}

This way your instance data could be fed to a uniform buffer instead having it as a vertex attribute, which would require changing the vertex input layout when you wanted to instanced render. I know in OpenGL uniform buffers are of a limited size and so would you would be restricted to fewer instances than using the vertex attribute method. But in the case you needed to draw that many instances you can always use a Shader Storage Buffer Object, which allow for much bigger buffers (maybe unlimited), so SSBOs can sort of act like uniforms anyway.

I'm just wondering:

  1. Whether using the uniform buffer method is doable/a good idea, and what are the tradeoffs between the two methods? For example, is the uniform buffer method slower? You'd be indexing into it at each shader call, for each vertex.

  2. Is using this method still instanced rendering? I've only seen examples of instanced rendering using the vertex attribute method.

like image 359
Zebrafish Avatar asked Mar 15 '26 08:03

Zebrafish


1 Answers

Attribute-based instancing relies on vertex attributes. And therefore, it is subject to the limitations of vertex attributes.

Taking your example:

in instanceData
{
    mat4 worldMatrix;
};

First, this is incorrect; you cannot aggregate vertex shader inputs into interface blocks. So really this should be in mat4 worldMatrix;.

More importantly, the correct version burns four vertex attribute locations. A mat4, as a vertex attribute, is comprised of 4 attribute locations.

Many implementations don't allow more than 16 attribute locations. So there are non-trivial limitations on attribute-based per-instance data.

By using gl_InstanceID and an explicit memory fetch, you are not limited on the amount of per-instance data that you can have.

The primary limitation of using explicit memory fetches is not UBO limits (you shouldn't be using UBOs for per-instance data) or even SSBO limits (because SSBOs in all practical implementations are of unlimited size). The primary limitation is that gl_InstanceID does not respect the base instance parameter of instance calls. So if you need to use this functionalty, you must either use vertex attributes or rely on GL 4.6/ARB_shader_draw_parameter's gl_BaseInstance value.

Note that Vulkan doesn't have this problem; gl_InstanceIndex always respects the base instance.

like image 101
Nicol Bolas Avatar answered Mar 17 '26 02:03

Nicol Bolas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!