Vulkan教程翻译之十四 创建 Vertex Buffer

本文详细介绍了在Vulkan图形API中创建和使用顶点缓冲区的过程,包括顶点数据的组织方式、缓冲区的创建与内存分配、数据的初始化以及如何将顶点缓冲区绑定到渲染通道。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文链接:https://vulkan.lunarg.com/doc/sdk/1.2.131.2/windows/tutorial/html/13-init_vertex_buffer.html

创建 Vertex Buffer

本章节代码文件是 13-init_vertex_buffer.cpp

vertex buffer 是 CPU 和 GPU 都可见的缓冲区,它包含描述你想要渲染的物体网格的顶点数据。一般来说,顶点数据包含位置数据(x,y,z)和可选颜色,法线,或其他信息。像其他 3D API一样,这里的方法是用顶点数据填充缓冲区,然后在绘制操作中传递给 GPU。

创建 Vertex Buffer 对象

创建 vertex buffer 和创建 uniform buffer 几乎是一样的,就像你在 uniform 示例中做过的那样,从创建一个缓冲区对象开始。

VkBufferCreateInfo buf_info = {};
buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
buf_info.pNext = NULL;
buf_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
buf_info.size = sizeof(g_vb_solid_face_colors_Data);
buf_info.queueFamilyIndexCount = 0;
buf_info.pQueueFamilyIndices = NULL;
buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
buf_info.flags = 0;
res = vkCreateBuffer(info.device, &buf_info, NULL, &info.vertex_buffer.buf);

创建一个 uniform buffer 对象和一个 vertex buffer 对象唯一真正的不同就是 usage 字段的设置。

立方体的数据(g_vb_solid_face_colors_Data)包含了36个顶点,定义了12个三角形,6个立方体面上每个面2个。每个三角形还有关联着表面颜色。你可以检查 cube_data.h 文件来看看实际的数据。

分配 Vertex Buffer 内存

这里也是,步骤和分配 uniform buffer 的步骤很相似。首先查询内存需求,包括考虑到机器限制比如内存对齐。查看示例中的代码就能看到这个过程和 uniform 示例中执行的步骤是很相似的。

把顶点数据存入缓冲区

分配完后,内存就被映射,用顶点数据初始化,再取消映射:

uint8_t *pData;
res = vkMapMemory(info.device, info.vertex_buffer.mem, 0,
                  mem_reqs.size, 0, (void **)&pData);

memcpy(pData, g_vb_solid_face_colors_Data,
       sizeof(g_vb_solid_face_colors_Data));

vkUnmapMemory(info.device, info.vertex_buffer.mem);

作为最后一步,内存被绑定到缓冲区对象上:

res = vkBindBufferMemory(info.device, info.vertex_buffer.buf,
                         info.vertex_buffer.mem, 0);

输入顶点数据的描述

示例按以下顺序排列顶点数据:

struct Vertex {
    float posX, posY, posZ, posW; // Position data
    float r, g, b, a;             // Color
};

你需要创建顶点输入绑定来向GPU描述数据排列顺序。以下的 vi_binding 和 vi_attribs 成员在这里被设置,但是稍后在 subsequent 示例中才被使用作为创建图形管道的一部分。因为你正在看顶点数据格式,最好在这里就了解一下这些代码:

info.vi_binding.binding = 0;
info.vi_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
info.vi_binding.stride = sizeof(g_vb_solid_face_colors_Data[0]);

info.vi_attribs[0].binding = 0;
info.vi_attribs[0].location = 0;
info.vi_attribs[0].format = VK_FORMAT_R32G32B32A32_SFLOAT;
info.vi_attribs[0].offset = 0;
info.vi_attribs[1].binding = 0;
info.vi_attribs[1].location = 1;
info.vi_attribs[1].format = VK_FORMAT_R32G32B32A32_SFLOAT;
info.vi_attribs[1].offset = 16;

stride 是一个顶点的大小,或者说为获取下一个顶点需要给指针增加的数量。

binding 和 location 成员指向在 GLSL shader 源码里它们各自的值。你可以回顾 shader 示例中的着色器源码来了解对应关系。

即使第一个 attribute 是位置数据,也在attribute 0 的 format 成员中用一个4字节的 float 数据格式来描述它。attribute 1 的 format 更明显是一个颜色格式,因为 atttibute 1 就是颜色。

offset 成员就简单的表明在顶点数据中每个 attribute 在哪里被找到。

绑定 Vertex Buffer 到 Render Pass

你可以先跳过设置 render pass 的大部分代码,因为你会在之后的示例中看到。但是现在,找到绑定 vertex buffer 和 render pass 的代码:

vkCmdBeginRenderPass(info.cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);

vkCmdBindVertexBuffers(info.cmd, 0,             /* Start Binding */
                       1,                       /* Binding Count */
                       &info.vertex_buffer.buf, /* pBuffers */
                       offsets);                /* pOffsets */

vkCmdEndRenderPass(info.cmd);

注意你只能在 render pass 内部将 vertex buffer 和 render pass进行连接;也就是说,在 vkCmdBeginRenderPass 和 vkCmdEndRenderPass 之间录入 command buffer 的时候。这实际上告诉GPU在绘制时使用什么 vertex buffer。

### Vulkan 中的顶点缓冲区使用与实现 在 Vulkan API 中,顶点缓冲区 (Vertex Buffer) 是存储几何数据的数据结构,这些数据用于渲染图形。为了高效地管理和更新顶点数据,在实际应用中经常采用暂存缓冲区 (Staging Buffer),这有助于优化性能并简化复杂操作。 #### 创建 Vertex Buffer 和 Staging Buffer 创建顶点缓冲区的过程涉及几个关键步骤: 1. **准备顶点数据**:定义要上传到 GPU 的顶点数组。 2. **分配内存给 Staging Buffer**:由于直接映射设备本地内存可能效率低下甚至不可行,因此先在一个 CPU 可访问的临时缓冲区内写入数据。 3. **复制数据至 Device Local Memory**:通过命令缓冲区将数据从 staging 缓冲区传输到最终目标——device local memory 上的目标 vertex buffer。 4. **清理资源**:完成数据转移后释放不再需要的 staging 资源[^1]。 下面是一个简单的 Python 伪代码示例展示如何设置一个顶点缓冲区及其对应的暂存缓冲区: ```python import vulkan as vk def create_vertex_buffer(device, command_pool, queue, vertices): # 定义顶点属性描述符和其他必要的参数... # Step 1 & 2: Prepare data on host side and allocate staging buffer. staging_buffer = ... staging_memory = ... # 将顶点数据拷贝进staging buffer... # Step 3: Create device-local vertex buffer. vertex_buffer = ... vertex_memory = ... # Bind buffer memory. # Begin one-time-use command buffer for copying operation. copy_command_buffer = begin_single_time_commands(command_pool) # Record commands to transition image layout if necessary, # then add a buffer copy command from staging to destination. buffer_copy_region = vk.VkBufferCopy( srcOffset=0, dstOffset=0, size=len(vertices) * sizeof(Vertex) ) vkCmdCopyBuffer(copy_command_buffer, staging_buffer, vertex_buffer, [buffer_copy_region]) end_and_submit_single_time_commands(copy_command_buffer, queue) # Clean up after ourselves by freeing the temporary resources used during transfer. destroy_staging_resources(staging_buffer, staging_memory) ``` 此过程展示了如何利用暂存机制有效地初始化或动态更改顶点缓冲中的内容,从而提高应用程序的整体表现[^2]。 对于更复杂的场景,比如每帧都需要频繁修改大量顶点的情况,则可以考虑保持 mapping 映射状态不变,并直接操纵指针指向的位置来快速刷新数据,但这可能会带来同步方面的问题以及潜在的安全隐患,所以在实践中需谨慎评估利弊后再做决定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值