Vulkan vertex buffer绑定过程

代码实战

我们用indirect draw绘制6个不同位置的三角形,效果如下:

重点:具备layout(location = xx) in 格式描述的资源就是 vertex buffer。

vs shader如下, inPos,inColor,instancePos则是vertext buffer数据:

//vs
#version 450 
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inColor;
layout (location = 2) in vec3 instancePos;

layout(location = 0) out vec3 fragColor;
 
void main() {
    gl_Position = vec4(inPos, 1.0) + vec4(instancePos, 1.0);
    gl_Position.y = -gl_Position.y;
    fragColor = inColor;
}

 

vertex buffer的布局分布如下:

  • location 0的inPos、location 1的inColor使用binding 0
  • location 2的instancePos使用binding 1

代码侧调用vkCmdBindVertexBuffers告诉gpu从哪个binding位置读取顶点数据(即vkCmdBindVertexBuffers的firstBinding参数,与shader中layout的binding完全没关系,这点在后面的descriptor章节再讲)。

gpu知道了从哪里读数据,但是怎么读?这就用到了VkVertexInputBindingDescription和 VkVertexInputAttributeDescription两个结构体,它们在创建pipeline时被使用。

结构体详细说明:

typedef struct VkVertexInputBindingDescription {
    uint32_t             binding;   //数据绑定位置
    uint32_t             stride;    //连续两个数据之间的间隔
    VkVertexInputRate    inputRate; //两种方式, per-vertex:对每个顶点输入, per-instance:对每个实例输入
} VkVertexInputBindingDescription; 

typedef struct VkVertexInputAttributeDescription {
    uint32_t    location;    //在shader中location一致
    uint32_t    binding;     //数据绑定位置
    VkFormat    format;      //数据格式
    uint32_t    offset;      //属性相对于顶点开始位置的偏移
} VkVertexInputAttributeDescription;

这里需要注意的是VkVertexInputBindingDescription::inputRate, 它代表两种数据输入:

  • VK_VERTEX_INPUT_RATE_VERTEX:per-vertex,按图元的定点数分配
  • VK_VERTEX_INPUT_RATE_INSTANCE:per-instance,按图元数分配

本例画6个三角形,对于编号i的三角形,会读取顶点数据vertices[0],vertices[1],vertices[2]以及中心点位置instancePosData[i]。

本例完整代码说明:

/* {inPosition, inColor}*/
struct Vertex {
    vec3 pos;
    vec3 color;
}
// vertex data of triangle
std::vector<Vertex> vertices = {
    { {  0.0f,  0.2f, 0.0f }, { 1.0f, 0.0f, 0.0f } },
    { { -0.2f, -0.2f, 0.0f }, { 0.0f, 1.0f, 0.0f } },
    { { 0.2f,  -0.2f, 0.0f }, { 0.0f, 0.0f, 1.0f } },
};
// 6 triangle instance center point postion
std::vector<Vec3> instancePosData = {
    {-0.45, 0.45, 0},{-0.45, -0.45, 0},{0, -0.8, 0},
    {0.45, -0.45, 0},{0.45, 0.45, 0},{0, 0.8, 0},
};
 
//create vertex buffer
VkDeviceSize vertexBufferSize = vertices.size() * sizeof(Vertex);
VkDeviceSize instancePosBufferSize = instancePosData.size() * sizeof(Vec3);
 
createBuffer(
        VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
        &vertexBuffer, &vertexMemory,
        vertexBufferSize, vertices.data());
                    
createBuffer(
    VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
    &instancePosBuffer, &instancePosMemory,
    instancePosBufferSize,instancePosData.data());

VkDeviceSize offsets[] = {0};
//三角形顶点位置、颜色数据从binding 0读取
vkCmdBindVertexBuffers(
    commandBuffer, 
    0,    // firstBinding
    1,    // bindingCount
    &vertexBuffer, 
    offsets);

//三角形的中心点位置从binding 1读取
vkCmdBindVertexBuffers(
    commandBuffer, 
    1,    // firstBinding
    1,    // bindingCount
    &instancePosBuffer, 
    offsets);

// 读取顶点的方式、以及顶点数据布局传入graphicsPipelineCreateInfo
std::vector<VkVertexInputBindingDescription> bindingDescription = {
    {.binding=0, .stride=sizeof(Vertex), .inputRate = VK_VERTEX_INPUT_RATE_VERTEX},   //逐顶点方式获取三角形顶点数据
    {.binding=1, .stride=sizeof(Vec3), .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE}    //逐实例方式获取三角形位置数据
};
std::vector<VkVertexInputAttributeDescription> attributeDescriptions = 
{
    {.binding = 0, .location = 0, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(Vertex, pos)},   // inPos: binding 0, location 0
    {.binding = 0, .location = 1, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(Vertex, color)}, // inColor: binding 0, location 1
    {.binding = 1, .location = 2, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = 0}    // instancePos: binding 1, location 2
}
...
vkPipelineVertexInputStateCreateInfo.pVertexBindingDescriptions = bindingDescription.data();
vkPipelineVertexInputStateCreateInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
...
vkGraphicsPipelineCreateInfo.pVertexInputState = &vkPipelineVertexInputStateCreateInfo;

上面从代码到shader的vertex buffer数据绑定过程可以归纳成这张图:

这篇文章对vertext buffer的处理逻辑讲的很详细,可以扩展阅读一下:

https://github.com/KhronosGroup/Vulkan-Guide/blob/main/chapters/vertex_input_data_processing.adoc

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
探索全栈前端技术的魅力:HTML+CSS+JS+JQ+Bootstrap网站源码深度解析 在这个数字化时代,构建一个既美观又功能强大的网站成为了许多开发者和企业追逐的目标。本份资源精心汇集了一套完整网站源码,融合了HTML的骨架搭建、CSS的视觉美化、JavaScript的交互逻辑、jQuery的高效操作以及Bootstrap的响应式设计,全方位揭秘了现代网页开发的精髓。 HTML,作为网页的基础,它构建了信息的框架;CSS则赋予网页生动的外观,让设计创意跃然屏上;JavaScript的加入,使网站拥有了灵动的交互体验;jQuery,作为JavaScript的强力辅助,简化了DOM操作与事件处理,让编码更为高效;而Bootstrap的融入,则确保了网站在不同设备上的完美呈现,响应式设计让访问无界限。 通过这份源码,你将: 学习如何高效组织HTML结构,提升页面加载速度与SEO友好度; 掌握CSS高级技巧,如Flexbox与Grid布局,打造适应各种屏幕的视觉盛宴; 理解JavaScript核心概念,动手实现动画、表单验证等动态效果; 利用jQuery插件快速增强用户体验,实现滑动效果、Ajax请求等; 深入Bootstrap框架,掌握移动优先的开发策略,响应式设计信手拈来。 无论是前端开发新手渴望系统学习,还是资深开发者寻求灵感与实用技巧,这份资源都是不可多得的宝藏。立即深入了解,开启你的全栈前端探索之旅,让每一个网页都成为技术与艺术的完美融合!
探索全栈前端技术的魅力:HTML+CSS+JS+JQ+Bootstrap网站源码深度解析 在这个数字化时代,构建一个既美观又功能强大的网站成为了许多开发者和企业追逐的目标。本份资源精心汇集了一套完整网站源码,融合了HTML的骨架搭建、CSS的视觉美化、JavaScript的交互逻辑、jQuery的高效操作以及Bootstrap的响应式设计,全方位揭秘了现代网页开发的精髓。 HTML,作为网页的基础,它构建了信息的框架;CSS则赋予网页生动的外观,让设计创意跃然屏上;JavaScript的加入,使网站拥有了灵动的交互体验;jQuery,作为JavaScript的强力辅助,简化了DOM操作与事件处理,让编码更为高效;而Bootstrap的融入,则确保了网站在不同设备上的完美呈现,响应式设计让访问无界限。 通过这份源码,你将: 学习如何高效组织HTML结构,提升页面加载速度与SEO友好度; 掌握CSS高级技巧,如Flexbox与Grid布局,打造适应各种屏幕的视觉盛宴; 理解JavaScript核心概念,动手实现动画、表单验证等动态效果; 利用jQuery插件快速增强用户体验,实现滑动效果、Ajax请求等; 深入Bootstrap框架,掌握移动优先的开发策略,响应式设计信手拈来。 无论是前端开发新手渴望系统学习,还是资深开发者寻求灵感与实用技巧,这份资源都是不可多得的宝藏。立即深入了解,开启你的全栈前端探索之旅,让每一个网页都成为技术与艺术的完美融合!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值