Rendering an indexed geometry

In this section, you will learn to use the vkCmdDrawIndexed() draw command. This command is used for drawing the index geometry.The vkCmdDrawIndexed() API is an index buffer's draw command. In an index buffer, each vertex is represented using an index number. This fashion of representing mesh data requires less memory and storage space to represent connected meshes when the mesh has shared vertices (such as enclosed shapes).

For example, a square geometry rendered using two triangles shares two common vertices as shown in the following example; as you can see, the first and third vertices are repeated:

static const VertexWithColor squareData[] = 
{ 
  { -0.5f,  0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0 }, 
  {  0.5f,  0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0 }, 
  {  0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0 }, 
  { -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0 }, 
}; 
 
uint16_t squareIndices[] = { 0,3,1, 3,2,1 }; // 6 indices 

In this section, we will use the geometry data and indices to demonstrate the use of the vkCmdDrawIndexed() API. The following is the syntax:

void vkCmdDrawIndexed( 
    VkCommandBuffer commandBuffer, 
    uint32_t        indexCount, 
    uint32_t        instanceCount, 
    uint32_t        firstIndex, 
    int32_t         vertexOffset, 
    uint32_t        firstInstance); 

Let's take a look at the different fields used in this API and their respective descriptions:

Parameter

Description

commandBuffer

This field specifies the command buffer object (VkCommandBuffer) into which the recording is performed.

indexCount

This is the total count of the index elements in the index list of the buffer resources that are intended to be drawn.

instanceCount

This field indicates the total number of instances to be drawn using this command.

firstIndex

This field specifies the first index (into the indices) from where the indices are read.

vertexOffset

This field specifies an offset value that will be added into the vertex index to produce a resultant index. This computed index then is used to read the vertex from the vertex buffer.

firstInstance

This field specifies the very first instance ID into the instances to draw.

The following are the steps to render an indexed draw:

  1. Using squareData and squareIndices, create a buffer resource (VkBuffer). Store VkBuffer's handles in VertexBuffer::buf and VertexIndex::idx. For more information, please refer to the Indexed Draw example provided in this chapter.
  2. Bind the vertex buffer using vkCmdBindVertexBuffers() and pass VertexBuffer.buf into it.
  3. Similarly, the index buffer (VertexIndex.idx) is bound using the vkCmdBindIndexBuffer() API command.
  4. Draw the object using vkCmdDrawIndexed().

vkCmdDrawIndexed() is used in conjunction with the vkCmdBindIndexBuffer() API. Similar to vkCmdBindVertexBuffers(), which binds the vertex buffer, this command binds the index buffer. The following is the syntax of this API; for more information on the vkCmdBindVertexBuffers() API, please refer to the Specifying the drawing object geometry information section.

void vkCmdBindIndexBuffer( 
    VkCommandBuffer             commandBuffer, 
    VkBuffer                    buffer, 
    VkDeviceSize                offset, 
    VkIndexType                 indexType); 

Let's take a look at the different fields used in this API and their respective descriptions:

Parameter

Description

commandBuffer

This specifies the command buffer object into which this command—vkCmdBindIndexBuffer()—will be recorded.

buffer

This indicates the handle of the index buffer (VkBuffer) that will be bound to this API.

offset

This is the starting offset specified in bytes in the index buffer that will be used for index buffer address calculation.

indexType

This field indicates whether the indices are 16-bits or 32-bits wide.

This must be one of the VkIndexType types:

typedef enum VkIndexType {
VK_INDEX_TYPE_UINT16 = 0,
VK_INDEX_TYPE_UINT32 = 1,
} VkIndexType;

Similar to the createVertexBuffer() function, we have created a new function called createIndexBuffer(); it creates the index buffer and stores the index buffer handle in VertexIndex.idx. For a detailed implementation of this function, please refer to the accompanying source code. The implementation of createIndexBuffer() is very similar to createVertexBuffer(); for a detailed understanding on the implementation of this function, please refer to Implementing the buffer resource—creating the vertex buffer for the geometry in Chapter 7, Buffer Resource, Render Pass, Framebuffer, and Shaders with SPIR-V.

The following code demonstrates the rendering of the indexed geometry object:

// Local data structure in VulkanDrawable class

// for storing vertex buffer and index buffer metadata 
struct { 
   VkBuffer buf; 
   VkDeviceMemory mem; 
   VkDescriptorBufferInfo bufferInfo; 
} VertexBuffer; 
 
struct { 
   VkBuffer idx; 
   VkDeviceMemory mem; 
   VkDescriptorBufferInfo bufferInfo; 
} VertexIndex; 
 
// Create the VkBuffer and store the handle in

// VertexBuffer.buf and VertexIndex.idx 
.  .  .  . 
// Bind the vertex buffer 
const VkDeviceSize offsets[1] = { 0 }; 
vkCmdBindVertexBuffers(*cmdDraw, 0, 1,&VertexBuffer.buf, 
                                               offsets); 
 
// Bind the Index buffer 
vkCmdBindIndexBuffer(*cmdDraw, VertexIndex.idx, 
                      0, VK_INDEX_TYPE_UINT16); 
 
// Draw the object 
vkCmdDrawIndexed(*cmdDraw, 6, 1, 0, 0, 0); 

The output of the preceding geometry data will be displayed as follows; for detailed code, please refer to the Indexed Draw example in this chapter:

Rendering an indexed geometry

The vkCmdDrawIndirect and vkCmdDrawIndexedIndirect draw commands are very similar to vkCmdDraw and vkCmdDrawIndexed, except that the parameters here are read from the buffer memory. For more information on these APIs, please refer to the official Vulkan specification.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.221.133