Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How attribute divisor works with indexed drawing

Tags:

opengl

From khronos:

glDrawElementsInstanced behaves identically to glDrawElements except that primcount instances of the set of elements are executed. Those attributes that have divisor N where N is other than zero (as specified by glVertexAttribDivisor) advance once every N instances.

The two ideas of indexed rendering and attribute divisors seem incompatible to me. How do you have an index choose which location to fetch data, and at the same time have a (instance count)/(divisor) BE the index to fetch the data.

like image 500
Thomas Avatar asked Jan 08 '23 23:01

Thomas


1 Answers

It does make sense. When using instanced rendering, you often do not want to draw exactly the same thing multiple times. In fact, you mostly do not, because drawing exactly the same thing multiple times is kind of pointless.

Instanced rendering is intended to draw multiple instances of an object that are very similar, but there is still a difference between each instance. For example, you may want to draw a lot of objects that are basically the same, but that are positioned differently. Or in other words, each instance has its own translation vector.

You have two main options to actually draw each instance differently:

  • You can use gl_InstanceID in the vertex shader. Since it has a different value for each instance, you can use it to look up or calculate different values per instance.
  • You can use the attribute divisor.

The divisor allows you to have vertex attributes that have a value per instance. For the example I mentioned above, this is perfect. You can have a vertex attribute that contains the translation vector. In the buffer that you source the attribute from, you store a translation vector value per instance. You then set the divisor for this attribute to 1.

This allows you to draw multiple instances of the object with a single draw call, with different translation vectors. And you don't have to replicate any vertex data.

For all your existing vertex attributes, like your vertex positions, normals, and texture coordinates, you keep the divisor at its default value of 0. This means that they behave just as they did before, with the value for each vertex being fetched based on the index in the index buffer.

I have personally never used divisor values larger than 1, but it's perfectly valid. Instead of using a value for each instance, you can use the same value for n instances. But IMHO, by far the most useful values are 0 and 1:

  • 0, the default, specifies that the attribute behaves as usual, meaning that the value is fetched based on the vertex index.
  • 1 specifies that you have one attribute value per instance, and the value is fetched based on the instance id (gl_InstanceID).
like image 96
Reto Koradi Avatar answered Jan 18 '23 23:01

Reto Koradi