Vulkan编程指南翻译 第八章 图形管线 第3节 索引化绘制

8.3 索引化绘制

简单的吧连续的顶点给入管线并不总是你所想要的。在大多数几何网格中,很多顶点不止被使用一次。一个完全连接的网格也许会让多个三角形共用一个顶点。甚至一个立方体中三个相邻的三角形共享一个顶点。在你的顶点缓冲区中为每一个顶点指定三次是非常浪费的。除了这个,一些Vulkan实现也许很聪明,如果看到相同的一个顶点出现多次,在后面的过程中会跳过对相同的顶点的处理,并使用之前顶点着色器调用的结果。

要想这样做,Vulkan允许索引化绘制。vkCmdDraw()使用索引化和vkCmdDrawIndexed()是等价的,vkCmdDrawIndexed()的原型是:

         voidvkCmdDrawIndexed (

VkCommandBuffer          commandBuffer,

uint32_t                             indexCount,

uint32_t                             instanceCount,

uint32_t                             firstIndex,

int32_t                                vertexOffset,

uint32_t                             firstInstance);

vkCmdDrawIndexed()的第一个参数是将被执行的命令所在的命令缓冲区的handle。然而,相比于简单从零开始,vkCmdDrawIndexed()从一个索引缓冲区中取出索引。索引缓冲区是一个通常的缓冲区对象,通过vkCmdBindIndexBuffer()绑定到命令缓冲区,命令原型为:

         voidvkCmdBindIndexBuffer (

VkCommandBuffer          commandBuffer,

VkBuffer                             buffer,

VkDeviceSize                     offset,

VkIndexType                      indexType);

索引缓冲区所绑定的命令缓冲区通过commandBuffer指定,包含索引数据的缓冲区通过buffer指定。从offset开始的缓冲区的一部分可以绑定到命令缓冲区。绑定的部分总是拓展到缓冲区对象的结尾。在索引缓冲区上没有绑定检查,Vulkan将读取你告诉它的索引数量。然而,读取数据时将不会突破缓冲区对象的尾部。

缓冲区内的索引的类型通过indexType指定。这是VkIndexType枚举的一个成员,所有成员如下:

         •VK_INDEX_TYPE_UINT16: Unsigned 16-bit integers

•VK_INDEX_TYPE_UINT32: Unsigned 32-bit integers

 

当你调用vkCmdDrawIndexed()时,Vulkan将从当前绑定的索引缓冲区中offset位置开始读取数据

         offset+ firstIndex * sizeof(index)

其中,sizeof(index)对于VK_INDEX_TYPE_UINT16来说是2,对VK_INDEX_TYPE_UINT32来说是4。代码将会从索引缓冲区中读取indexCount个连续的整形,然后把它们加上vertexOffset。加法操作总是以32位执行的,不管当前绑定的索引缓冲区的索引类型。如果加法操作在无符号32整形上溢出了,结果是未知的,所以要避免这种状况。

Figure 8.1语义化的展示了数据流

Figure8.1: Index Data Flow

 

注意,当索引类型是VK_INDEX_TYPE_UINT32时,索引数值的最大范围也许并不受支持。可查看调用vkGetPhysicalDeviceProperties(). 获取的VkPhysicalDeviceLimits结构的maxDrawIndexedIndexValue域来做检查。这个数值被保证至少是224-1,也可以高达232-1。

为了演示如何高效率的使用索引数据,Listing 8.2展示了用索引和非索引方式绘制一个立方体所需数据的不同。

         Listing8.2: Indexed Cube Data

         //Raw, non-indexed data

static const float vertex_positions[] =

{

-0.25f, 0.25f, -0.25f,

-0.25f, -0.25f, -0.25f,

0.25f, -0.25f, -0.25f,

0.25f, -0.25f, -0.25f,

0.25f, 0.25f, -0.25f,

-0.25f, 0.25f, -0.25f,

0.25f, -0.25f, -0.25f,

0.25f, -0.25f, 0.25f,

0.25f, 0.25f, -0.25f,

0.25f, -0.25f, 0.25f,

0.25f, 0.25f, 0.25f,

0.25f, 0.25f, -0.25f,

0.25f, -0.25f, 0.25f,

-0.25f, -0.25f, 0.25f,

0.25f, 0.25f, 0.25f,

-0.25f, -0.25f, 0.25f,

-0.25f, 0.25f, 0.25f,

0.25f, 0.25f, 0.25f,

-0.25f, -0.25f, 0.25f,

-0.25f, -0.25f, -0.25f,

-0.25f, 0.25f, 0.25f,

-0.25f, -0.25f, -0.25f,

-0.25f, 0.25f, -0.25f,

-0.25f, 0.25f, 0.25f,

-0.25f, -0.25f, 0.25f,

0.25f, -0.25f, 0.25f,

0.25f, -0.25f, -0.25f,

0.25f, -0.25f, -0.25f,

-0.25f, -0.25f, -0.25f,

-0.25f, -0.25f, 0.25f,

-0.25f, 0.25f, -0.25f,

0.25f, 0.25f, -0.25f,

0.25f, 0.25f, 0.25f,

0.25f, 0.25f, 0.25f,

-0.25f, 0.25f, 0.25f,

-0.25f, 0.25f, -0.25f

};

static const uint32_t vertex_count = sizeof(vertex_positions) /

(3 * sizeof(float));

// Indexed vertex data

static const float indexed_vertex_positions[] =

{

-0.25f, -0.25f, -0.25f,

-0.25f, 0.25f, -0.25f,

0.25f, -0.25f, -0.25f,

0.25f, 0.25f, -0.25f,

0.25f, -0.25f, 0.25f,

0.25f, 0.25f, 0.25f,

-0.25f, -0.25f, 0.25f,

-0.25f, 0.25f, 0.25f,

};

 // Index buffer

static const uint16_t vertex_indices[] =

{

0, 1, 2,

2, 1, 3,

2, 3, 4,

4, 3, 5,

4, 5, 6,

6, 5, 7,

6, 7, 0,

0, 7, 1,

6, 0, 2,

2, 4, 6,

7, 5, 3,

7, 3, 1

};

 static const uint32_tindex_count = vkcore::utils::arraysize(vertex_indices);

 

如你在Listing 8.2中所见,绘制一个立方体的所需数据很小。只有存储八个不同顶点的数据,和36个用来引用它们的索引数据。随着场景的复杂几何尺寸在增长,存储量也可能相当大。在这个简单的例子中,非索引化的顶点数据有36个顶点,每一个都包含三个4字节元素,总共是432字节的数据。同时,索引化数据有12个顶点,每一个都包含三个4字节元素,加上36个索引,每一个消耗2字节。索引化的立方体产生了168字节的数据。

除了使用索引化数据来节省空间,很多Vulkan实现包含了顶点缓存,可以重复利用顶点着色器之前计算的结果。如果顶点数据是非索引化的,那么管线必须假设他们都是不同的。然而,当顶点被索引化,两个具有相同索引的顶点是相同的。在任何一个闭合的网格中,同一个顶点将会出现多次,因为有多个图元会共享它。重用可以节省不少的计算量。

 

8.3.1  只索引绘制

在你的顶点着色器中可以直接访问到当前顶点的原生索引。这个索引在SPIR-V中是以VertexIndex修饰的变量,通过GLSL中内置的变量gl_VertexIndex生成的。这包含了索引缓冲区()的内容加上传递给vkCmdDrawIndexed()的vertexOffset的值。

你可以使用

 

 

8.3.2 重置索引

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值