当前位置: 首页 > news >正文

Vulkan 学习(17)---- 使用 IndexBuffer

目录

      • Index Buffer 简介
      • 创建 IndexBuffer
      • 使用 IndexBuffer 绘制

Index Buffer 简介

绘制一个矩形可以通过绘制两个三角形来实现,如果不共享顶点,就需要 6 个顶点,共享顶点的话,只需要 4 个顶点就可以
可以想象对于更加复杂的三维网格,通过共享顶点可以节约大量内存资源

indexBuffer

索引缓冲(IndexBuffer)是一个包含了指向顶点缓冲中顶点数据的索引数组的缓冲,使用索引缓冲,我们可以对顶点数据进行复用

创建 IndexBuffer

  1. 首先定义矩形的四个顶点
const std::vector<Vertex> vertices = {{{-0.5f, 0.5f}, {1.0f, 0.0f, 0.0f}}, // color R{{-0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}}, // color G{{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}, // color B{{0.5f, -0.5f }, {1.0f, 0.0f, 0.0f} } // color R
};

四个顶点定义两个三角形,这个两个三角形的绘制顺序如下,

// 这里按照顺时针的方式绘制
const std::vector<uint16_t> indices = {0, 1, 3, 0, 3, 2
};

index

可以使用 uint16_tuint32_t 变量类型作为索引的类型,这里是根据顶点的最大数量作为定义依据
方法还是将索引数据加载到一个VkBuffer来让 GPU 可以访问它,我们定义了两个类成员变量来存储索引缓冲对象

VkBuffer vertexBuffer;
VkDeviceMemory vertexBufferMemory;
VkBuffer indexBuffer;
VkDeviceMemory indexBufferMemory;
std::vector<uint16_t> drawIndices;

添加 createIndexBuffer 函数用于索引缓冲创建,它和内容和 createVertexBuffer 函数的内容几乎一样

void basicTriangleIndexBuffer::createIndexBuffer() {VkDeviceSize bufferSize = sizeof(drawIndices[0]) * drawIndices.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, 0, bufferSize, 0, &data);memcpy(data, drawIndices.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 的大小是根据顶点的数量计算出来的
  • indexBuffer 的用法标记为 VK_BUFFER_USAGE_INDEX_BUFFER_BIT

除此之外的处理和顶点缓冲的创建是相同的, 我们也需要创建一个暂存缓冲来存储 indices 数组中的索引数据,然后复制暂存缓冲中的索引数据到 GPU 能够快速访问的缓冲中

使用 IndexBuffer 绘制

首先我们需要将顶点缓冲区绑定到指令缓存对象上,和绑定顶点缓冲基本类似,不同之处是我们只能绑定一个索引缓冲对象

vkCmdBindIndexBuffer(commandBuffer, indexBuffer, 0, VK_INDEX_TYPE_UINT16);

索引缓冲通过调用 vkCmdBindIndexBuffer函数来进行绑定,vkCmdBindIndexBuffer 函数以索引缓冲对象,索引数据在索引缓冲中的偏移,以及索引数据的类型作为参数

仅仅绑定索引缓冲是不会起任何作用的,我们需要使用 vkCmdDrawIndexed 指令替换之前使用 vkCmdDraw 指令进行绘制操作

vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(drawIndices.size()), 1, 0, 0, 0);
//替代
//vkCmdDraw(commandBuffer, static_cast<uint32_t>(vertices.size()), 1, 0, 0);

vkCmdDrawIndexed 函数使用和 vkCmdDraw 函数类似,前两个参数分别为指令缓冲区对象(commandbuffer)和指定索引的个数,第三个参数表示实例的个数,在这里我们没有使用实例渲染,所以将实例个数设置为 1
第四个参数偏移值用于指定 GPU 开始读取索引的位置,偏移值为 1 对应索引数据中的第二个索引
倒数第二个参数是检索顶点数据前加到顶点索引上的数值
最后一个参数用于第一个被渲染的实例的ID,在这里我们没有使用

最后显示效果如下:
index_draw
这里我们分别创建了 vertexBuffer indexBuffer,实际上可以更进一步,使用一个缓冲对象通过偏移值来存储多个不同的顶点缓冲和索引缓冲数据
也就是只创建一个 vkBuffer 类型,这样做之后,由于数据之间非常紧凑,可以更好地被缓存,对于没有同时进行的操作使用的内存块可以供多个对象复用

This is known as aliasing and some Vulkan functions have explicit flags to specify that you want to do this

相关文章:

  • c#,vb.net LockObject ,多线程锁,多线程安全字典ConcurrentDictionary
  • C/C++数据结构之静态数组
  • Matplotlib入门指南:从安装到绘制基本图形
  • 3D制作角色模型的教程-1
  • Java的锁机制问题
  • 【论文阅读笔记】TransparentGS:当高斯溅射学会“看穿”玻璃,如何攻克透明物体重建难题?
  • Protobuf 与 JSON 的兼容性:技术选型的权衡与实践
  • 风险矩阵与灰色综合评价
  • [OS_26] 计算机系统安全 | CIA原则 | 侧信道攻击
  • 【工具】CrossAttOmics:基于交叉注意力的多组学数据整合技术
  • React纯函数和hooks原理
  • 一次性理解Java垃圾回收--简单直接方便面试时使用
  • 华为云Flexus+DeepSeek征文|在Dify-LLM平台中开发童话故事精灵工作流AI Agent
  • java中关于异步转同步的一些解决方案的对比与思考。【spring mvc堵塞式】
  • springboot企业级项目开发之项目测试——集成测试!
  • 【Java】HQL批量增删改
  • 从零理解鱼眼相机的标定与矫正(含 OpenCV 代码与原理讲解)
  • 性能测试之接口关联和函数使用
  • Android14 app被冻结导致进程间通信失败
  • NumPy 数组排序
  • 建设局官方网站/百度seo代理
  • 蚌埠本地网站/seo文章外包
  • 手把手教你搭建自己的网站/上海公关公司
  • 柳市网站制作/seo优化方案报价
  • 一诺建站/手机优化软件
  • 广州网站建设培训学校/广州网站关键词排名