Vulkan Tutorial 22 Index buffer
操作系统:Windows8.1
显卡:Nivida GTX965M
开发工具:Visual Studio 2017
Introduction
在实际产品的运行环境中3D模型的数据往往共享多个三角形之间的顶点数据。即使绘制一些简单的图形也是如此,比如矩形:
绘制矩形需要两个三角形,通常意味着我们需要6个顶点数据。问题是其中的两个顶点会重复,导致数据会有50%的冗余。如果更复杂的模型,该问题会更加严重,平均每三个三角形就会发生重复顶点使用的情况。解决问题的方法是使用index buffer,即索引缓冲区。
索引缓冲区纯粹是一个指向顶点缓冲区的指针数组。它允许我们重排列顶点数据,并复用多个已经存在的顶点数据。上图显示了有一个包含四个不重复顶点数据的顶点缓冲区,通过索引缓冲区将如何显示矩形的情况。前三个索引定义右上角的三角形,最后三个索引定义了左下角的三角形。
Index buffer creation
在本章节中,为了绘制如上图所示的矩形,我们需要修改顶点数据并添加索引数据。修改后的顶点数据分别代表矩形四个角:
const std::vector<Vertex> vertices = {
{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}},
{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
{{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}},
{{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}}
};
左上角是红色,右上角是绿色,右下角是蓝色,左下角是白色。我们添加一个新的索引数组indices代表索引缓冲区的数据内容。它应该匹配途中的索引来绘制右上角的三角形和左下角的三角形。
const std::vector<uint16_t> indices = {
, , , , ,
};
根据vertices中的条目个数,我们可以使用uint16_t或uint32_t作为索引缓冲区类型。现在我们可以使用uint16_t,因为我们使用的独立顶点数量小于65535。
如顶点数据,为了使GPU可以访问到它们,需要将索引数据上传到缓冲区VkBuffer。定义两个类成员保存索引缓冲区的资源:
VkBuffer vertexBuffer;
VkDeviceMemory vertexBufferMemory;
VkBuffer indexBuffer;
VkDeviceMemory indexBufferMemory;
createIndexBuffer函数与之前的createVertexBuffer函数非常类似:
void initVulkan() {
...
createVertexBuffer();
createIndexBuffer();
...
} void createIndexBuffer() {
VkDeviceSize bufferSize = sizeof(indices[]) * indices.size(); VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data;
vkMapMemory(device, stagingBufferMemory, , bufferSize, , &data);
memcpy(data, indices.data(), (size_t) bufferSize);
vkUnmapMemory(device, stagingBufferMemory); createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); copyBuffer(stagingBuffer, indexBuffer, bufferSize); vkDestroyBuffer(device, stagingBuffer, nullptr);
vkFreeMemory(device, stagingBufferMemory, nullptr);
}
仅有的两个差异。bufferSize现在等于索引数量乘以索引类型的大小,该类型或者是uint16_t,或者是uint32_t。indexBuffer的用法需改用VK_BUFFER_USAGE_INDEX_BUFFER_BIT代替VK_BUFFER_USAGE_VERTEX_BUFFER_BIT。其他的过程是一致的。我们创建暂存缓冲区拷贝顶点数据的内容,并最终拷贝到设备本地索引缓冲区。
索引缓冲区在程序退出的时候需要清理,与顶点缓冲区类似:
void cleanup() {
cleanupSwapChain(); vkDestroyBuffer(device, indexBuffer, nullptr);
vkFreeMemory(device, indexBufferMemory, nullptr); vkDestroyBuffer(device, vertexBuffer, nullptr);
vkFreeMemory(device, vertexBufferMemory, nullptr); ...
}
Using an index buffer
使用索引缓冲区绘制需要修改createCommandBuffers函数两个地方。首先需要绑定索引缓冲区,就像之前的顶点缓冲区一样。区别是现在仅使用一个索引缓冲区。不幸的是,不可能对每个顶点属性使用不同的索引,所以即使只有一个属性不同,我们仍然必须完全复制顶点数据。
vkCmdBindVertexBuffers(commandBuffers[i], , , vertexBuffers, offsets); vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer, , VK_INDEX_TYPE_UINT16);
索引缓冲区使用vkCmdBindIndexBuffer绑定,它持有索引缓冲区作为参数,还需要偏移量和索引数据的类型。如前所述,可能的类型是VK_INDEX_TYPE_UINT16和VK_INDEX_TYPE_UINT32。
仅仅绑定索引缓冲区不会发生任何改变,我们还需要告知Vulkan在使用索引缓冲区后,对应的绘制命令的变化。移除vkCmdDraw函数,并用vkCmdDrawIndexed替换:
vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), , , , );
该函数的调用与vkCmdDraw非常类似。前两个参数指定索引的数量和几何instance数量。我们没有使用instancing,所以指定1。索引数表示被传递到顶点缓冲区中的顶点数量。下一个参数指定索引缓冲区的偏移量,使用1将会导致图形卡在第二个索引处开始读取。倒数第二个参数指定索引缓冲区中添加的索引的偏移。最后一个参数指定instancing偏移量,我们没有使用该特性。
现在运行程序如下所示:
现在我们已经通过索引缓冲区复用了顶点数据。在未来的加载复杂的3D模型数据中,该技术会非常的重要。
在前一章提到,为了更优的分配使用资源,推荐在单个内存中分配多个资源,如缓冲区,但是实际上,我们应该更进一步细化。来自Nvidia的驱动程序开发者建议将多个缓冲区(顶点缓冲区、索引缓冲区)存储到单个VkBuffer中。并在诸如vkCmdBindVertexBuffers之类的命令中使用偏移量。优点在于,在这种情况下,数据会更加充分的利用缓存,因为它们排列在一块区域。甚至在同一个渲染操作中可以复用来自相同内存块的多个资源块,只要刷新数据即可。该技巧称为称为aliasing,一些Vulkan函数有明确的标志指定这样做的意图。
项目代码 GitHub 地址。
Vulkan Tutorial 22 Index buffer的更多相关文章
- Vulkan Tutorial 20 Vertex buffer creation
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Introduction 在Vulkan中,缓冲区是内存的一块区域,该区域用于向显卡 ...
- Vulkan Tutorial 21 Staging buffer
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Introduction 顶点缓冲区现在已经可以正常工作,但相比于显卡内部读取数据, ...
- [译]Vulkan教程(22)创建顶点buffer
[译]Vulkan教程(22)创建顶点buffer Vertex buffer creation 创建顶点buffer Introduction 入门 Buffers in Vulkan are re ...
- [译]Vulkan教程(24)索引buffer
[译]Vulkan教程(24)索引buffer Index buffer 索引buffer Introduction 入门 The 3D meshes you'll be rendering in a ...
- directx12中vetex buffer、index buffer和constant buffer绑定piple line的时机
类别 时机 函数 建Heap vetex buffer 在Draw函数中 ID3D12GraphicsCommandList::IASetVertexBuffer 否 index buffer 在Dr ...
- Vulkan Tutorial 23 Descriptor layout and buffer
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Introduction 我们现在可以将任意属性传递给每个顶点的顶点着色器使用.但是 ...
- Vulkan Tutorial 29 Loading models
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Introduction 应用程序现在已经可以渲染纹理3D模型,但是 vertice ...
- Vulkan Tutorial 11 Shader modules
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 与之前的图像API不同,Vulkan中的着色器代码必须以二进制字节码的格式使用,而不 ...
- Vulkan Tutorial 12 Fixed functions
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 早起的图形API在图形渲染管线的许多阶段提供了默认的状态.在Vulkan中,从vie ...
随机推荐
- Adaline网络识别印刷体数字0到9-java实现
本篇只给出实现的代码,下一篇将讲一讲实现的原理,及其Adline网络中的LMS算法原理. 包含两个类: package com.cgjr.com; import java.security.Diges ...
- Oracle树形结构查询之prior的理解
--1 建表 create table 宇宙( 行星等级 number ,行星名称 varchar2(50) ,上级行星等级 number); --2 数据准备 insert into 宇宙 (行星等 ...
- iis7 安装laravel5.4环境
laravel版本: Laravel5.4IIS版本:IIS7站点配置就不详细说啦,大家网上可以搜一坨很多的配置方法啦哈直接上图: 由于IIS没有像Apache.htaccess文件,创建一个Web. ...
- 使用Github Page鼓励自己每日编程
动机 三天不练手生,编程的基础训练本身是很枯燥的,需要很多的认真与坚持.无论是Debug的经验,语法规则的记忆,还是各类基础的算法运用,都需要持之以恒的认真.Github的"打卡" ...
- Android分享功能实现
通过系统分享组件实现分享功能 Intent.createChooser() 方法用来弹出系统分享列表. createChooser(Intent target, CharSequence title, ...
- Day3-函数及作用域
一.函数定义:一组代码片段用函数名封装起来,通过函数名的方式调用执行. 特性: 1.减少重复代码 2.使程序易扩展 3.使程序易维护 语法定义: def sayhi(): print("he ...
- Java Garbage Collectors
Generational Collectors (分代收集器) GC algos optimised based on two hypotheses / observations: Most obje ...
- netsh & winsock & 对前端的影响
netsh 与 winsock 一个是window的脚本工具,另一个则是window是网络编程中要用到的网络接口,而非要说跟我小小的前端有什么影响,那还真有...,当然这个影响是很不好的,比如node ...
- CefSharp使用入门
首先这是很重要的,环境搭建: 我用的是VS2017 步骤 方法 1. 打开VS的安装管理器 2. 进入修改界面,使用C++的桌面开发 ...
- Hibernate与Jpa的关系(1)
[转自:http://freewind.me/blog/20111129/588.html ] 我知道Jpa是一种规范,而Hibernate是它的一种实现.除了Hibernate,还有EclipseL ...