8

I'm currently trying to render multiple cubes efficiently, so I'd like to know how to use this "Instanced Rendering" in Vulkan.

I currently know of only 2 ways of rendering a lot of (identical) objects:

1) Multiple DescriptorSets;

2) Single DescriptorSet with Dynamic Uniforms / dynamic offsets;

In the first case, a lot of memory is wasted because the cubes only need a different model matrix each, but still using an entire DescriptorSet each: also, because I'm registering a new command buffer each frame, every cube cost me 2 'Cmd' calls:

vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, descriptorSet, 0, nullptr);
vkCmdDraw(commandBuffer, numberOfVertices, 1, 0, 0);

But, for a lot of cubes, this results in a not insignificant CPU load, and a waste of memory.

In the second case, I only need a single DescriptorSet, registering the model matrix as a Dynamic Uniform and filling it with all the model matrices; However, I still need (with little modifications) the same 2 'Cmd' calls for each cube:

vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, descriptorSet, 1, index);
vkCmdDraw(commandBuffer, numberOfVertices, 1, 0, 0);

As before, for a lot of cubes, despite the huge memory save for using a unique DescriptorSet, the CPU load still bothers me.

So I heard about this "Instanced rendering", that should somehow tell with a single command to draw all the cubes, providing it a collection of model matrices (Probably still a Buffer).

How to do this, preventing my program to register thousands of 'Cmd' in a single command buffer, using a single call? Thanks.

ShockCoding
  • 216
  • 2
  • 12

2 Answers2

8

You set one of the vertex attributes to have VkVertexInputBindingDescription::inputRate == VK_VERTEX_INPUT_RATE_INSTANCE. Then you put the necessary data to offset and rotate into the attibute.

Another option is to use the vertex shader built in variable which indicates which instance that is being processed. You can use that to index into a SSBO or UBO to get the data you need.

ratchet freak
  • 47,288
  • 5
  • 68
  • 106
  • "Another option is to use the vertex shader built in variable which indicates which instance that is being processed" Can you elaborate on said variable, or link to a code snippet? – Jeffrey Sep 02 '19 at 14:37
  • 4
    In glsl I think it's gl_InstanceID – Nicolás Abram May 26 '20 at 15:42
  • The [learnopengl.com](https://learnopengl.com/Advanced-OpenGL/Instancing) tutorial shows an example of a shader program. This would be the case of using `VK_VERTEX_INPUT_RATE_VERTEX` for the binding description, before the section that says "Instanced arrays". Since the site uses OpenGL 3.3, shader storage buffers are not an option.. – alexpanter May 10 '23 at 12:43
6

in your code:

vkCmdDrawIndexed(command_buffer, indices_size, instance_count, 0, 0, instance_first_index);

  • instance_count: number of instances to draw
  • instance_first_index: first instance will have this id

in your vertex shader you can then use variable gl_InstanceIndex which contains the instance id starting with instance_first_index

[1] https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCmdDrawIndexed.html

AdamM
  • 81
  • 1
  • 5