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.
Instanced rendering means that we can render multiple instances in a single draw call and provide each instance with some unique attributes. We are going to cover two methods for doing that. In the first method instance specific attributes (e.g. WVP matrix) go into a seperate vertex buffer.
We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, that among these are Life, Liberty and the pursuitof Happiness. Folks generally make the mistake of assuming that writing a game using the Vulkan rendering API will make your game more performant.
With Vulkan, you need to fill all of it out by hand. This includes things like the various shader stages you want to use (Vertex, Geometry, Fragment, etc), render passes you want to use, line widths, viewports sizes, blending, etc. Command Buffers– OpenGL and DirectX 11 both use a graphics context to allow you to issue commands to the GPU.
I currently know of only 2 ways of rendering a lot of (identical) objects: 2) Single DescriptorSet with Dynamic Uniforms / dynamic offsets;
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.
in your code:
vkCmdDrawIndexed(command_buffer, indices_size, instance_count, 0, 0, instance_first_index);
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With