Vulkan 学习(12)---- Vulkan pipeline 创建

news/2025/1/8 11:27:54 标签: 学习, spring, java

目录

      • Vulkan 渲染管线
        • 顶点输入阶段
        • 输入装配阶段
        • 顶点着色器阶段
        • 细分控制、评估着色器阶段(可选)
        • 几何着色器阶段(可选)
        • 图元装配阶段
        • 光栅化阶段
        • 片段着色器
        • 片段测试阶段
        • 混合阶段

Vulkan 渲染管线

渲染管线可以看作是一条生产流水线,定义了从输入顶点到输出图像的所有步骤,它包括一系列固定和可编程阶段,这些阶段按照顺序执行,以完成渲染任务
vulkan_pipeline

Vulkan 渲染管线的许多阶段是可选的,你可以禁用它们,或者 Vulkan 实现可能根本不支持这些功能

管线中唯一必须启用的阶段是顶点做着色器(vertex shader),其余阶段和功能可以根据需要选择启用或者禁用,比如集合着色器、片段着色器和光栅化阶段等

Vulkan 中提供了高度的灵活性,让开发者能够根据需求配置渲染管线

顶点输入阶段

顶点输入阶段主要是从应用程序传递的顶端缓存区中读取顶点数据,并传递给后续阶段,顶点数据通常包括顶点位置、法线、颜色和纹理坐标等

顶点输入阶段需要配置顶点绑定描述符(描述顶点缓存区的布局)和顶点属性描述符(描述顶点数据的格式和偏移量)。开发者在此阶段定义如何从顶点缓冲区中获取数据

顶点绑定描述符对应的结构是 VkVertexInputBindingDescription,顶点属性描述符对应的结构体 VkVertexInputAttributeDescription,通过下面的代码体现其含义

// 定义顶点输入绑定描述符,描述顶点的布局
VkVertexInputBindingDescription vertex_input_bindings{
    .binding = 0,                         // 绑定索引,指定顶点数据绑定的槽位(索引)
    .stride = 8 * sizeof(float),          // 每个顶点的数据跨度,即每个顶点数据的字节大小(8个float:3个float顶点坐标,2个float纹理坐标,3float个法向量)
    .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, // 指定输入率为每个顶点(每个顶点都有一组数据)
};

//定义顶点输入属性描述符数组,指定每个顶点属性的格式个偏移量
VkVertexInputAttributeDescription vertex_input_attributes[3]{
    {
        .location = 0,                         // 输入属性的位置,匹配顶点着色器中的输入变量
        .binding = 0,                          // 顶点绑定索引,指定此属性从哪个绑定中获取数据
        .format = VK_FORMAT_R32G32B32_SFLOAT,  // 属性的数据格式,这里是3个float(X, Y, Z坐标)
        .offset = 0,                           // 数据在顶点中的偏移量,这里从第0个字节开始
    },
    {
        .location = 1,                         // 第二个输入属性的位置,通常用于纹理坐标
        .binding = 0,                          // 绑定索引,仍然是从同一个绑定中获取数据
        .format = VK_FORMAT_R32G32_SFLOAT,     // 属性的数据格式,这里是2个float(纹理坐标U, V)
        .offset = sizeof(float) * 3,           // 数据在顶点中的偏移量,这里从第3个float开始(跳过XYZ坐标)
    },
    {
        .location = 2,                         // 第三个输入属性的位置
        .binding = 0,                          // 绑定索引
        .format = VK_FORMAT_R32G32B32_SFLOAT,  // 属性的数据格式,这里是3个float(X, Y, Z坐标)
        .offset = sizeof(float) * 5,           // 数据在顶点中的偏移量,这里从第5个float开始
    },
};

// 创建并初始化 VkPipelineVertexInputStateCreateInfo 结构体
VkPipelineVertexInputStateCreateInfo vertexInputInfo{
    .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // 指定结构体类型
    .pNext = nullptr,                           // 指定扩展指针(通常为nullptr)
    .vertexBindingDescriptionCount = 1,         // 顶点绑定描述符的数量
    .pVertexBindingDescriptions = &vertex_input_bindings, // 指向顶点绑定描述符的指针
    .vertexAttributeDescriptionCount = 3,       // 顶点属性描述符的数量
    .pVertexAttributeDescriptions = vertex_input_attributes, // 指向顶点属性描述符数组的指针
};

顶点着色器脚本中的 location 顶点和输入属性描述符的 location 属性一一对应

#version 400
 layout (location = 0) in vec4 pos;//顶点坐标
 layout (location = 1) in vec2 attr;//纹理坐标
 layout (location = 2) in vec3 normal;//顶点法向量
 
 layout (location = 0) out vec2 texcoord;
 
void main() {
   texcoord = attr;
   gl_Position = pos;
}
输入装配阶段

输入装配阶段将顶点数据组装成几何图元(比如点、线、三角形)。这是顶点着色器之前的最后一个阶段,定义了如何将顶点数据组合成图形基元
通过指定图元拓扑方式(如点列表、线条列表,三角形列表) 来控制如何将顶点组装成图元
VkPipelineInputAssemblyStateCreateInfo 是用于指定输入装配阶段(Input Assembly)配置的结构体,用于将顶点数据组装成图元(如点、线、三角形),这些图元会被后续的管线阶段处理

typedef struct VkPipelineInputAssemblyStateCreateInfo {
    VkStructureType                            sType;// 结构体类型
    const void*                                pNext; // 扩展属性, 属性通常为nullptr
    VkPipelineInputAssemblyStateCreateFlags    flags; //保留字段, 当前必须为 0
    VkPrimitiveTopology                        topology;// 图元拓扑类型(三角形,线,和点)
    VkBool32                                   primitiveRestartEnable;// 图元重启功能
} VkPipelineInputAssemblyStateCreateInfo;

其中的 VkPrimitiveTopology topology 定义了图元拓扑类型,比较常用,用于控制图元类型(如点、线、三角形)

  • VK_PRIMITIVE_TOPOLOGY_POINT_LIST
    每个输入的顶点位置表示一个点图元,对应触发的顶点索引为 i

  • VK_PRIMITIVE_TOPOLOGY_LINE_LIST
    每两个输入顶点构成一条直线,对应触发顶点索引为 2i

  • VK_PRIMITIVE_TOPOLOGY_LINE_STRIP
    每个顶点自身和前一个顶点之间构成一条直线,对应触发顶点索引为 i

  • VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
    每三个顶点构成一个填充三角形,对应触发顶点索引为 3i

  • VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
    每个顶点和之前的两个顶点一起构成一个填充三角形,对应触发索引顶点为 i
    primitives_topology

VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo{};
inputAssemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssemblyInfo.pNext = nullptr;
inputAssemblyInfo.flags = 0;
inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; // 设置为三角形列表拓扑
inputAssemblyInfo.primitiveRestartEnable = VK_FALSE; // 不启用图元重启
顶点着色器阶段

顶点着色器阶段处理每个顶点,通常用于应用几何变化(如模型视图转换,投影变换), 并计算顶点的输出属性。如颜色、纹理坐标和法线等

开发者编写顶点着色器程序来定义每个顶点的处理逻辑,该阶段是必须启用的,是管线中唯一一个必不可少的阶段

Vulkan 中通过结构体 VkPipelineShaderStageCreateInfo :

typedef struct VkPipelineShaderStageCreateInfo {
    VkStructureType                     sType;// 结构点类型,必须是 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO
    const void*                         pNext; // 指向扩展结构的指针,一般设置为 nullptr 
    VkPipelineShaderStageCreateFlags    flags;// 用于将来扩展的标志,当前必须为 0
    VkShaderStageFlagBits               stage; // 着色器阶段,是 VK_SHADER_STAGE_VERTEX_BIT 或 VK_SHADER_STAGE_FRAGMENT_BIT
    VkShaderModule                      module; // 指向包含着色器代码的 VkShaderModule 对象
    const char*                         pName; // 着色器入口函数的名称,通常 "main"
    const VkSpecializationInfo*         pSpecializationInfo;
    // 指向 VkSpecializationInfo 的指针,用于指定特化常量,可以是 nullptr
} VkPipelineShaderStageCreateInfo;

示例代码:

    VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
    vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
    vertShaderStageInfo.module = vertShaderModule;
    vertShaderStageInfo.pName = "main";
细分控制、评估着色器阶段(可选)

曲面细分是近代 GPU 的一项高级特性,可以在采用较少原始顶点数据的情况下绘制出如同采用海量数据描述的光滑曲面
曲面细分工作由细分控制着色器和细分求值着色器协同完成

几何着色器阶段(可选)

几何着色器(Geometry Shader)是图形渲染的一个可选阶段,在顶点着色器和光栅化阶段之间运行
几何着色器的主要作用是处理图元(比如点、线或三角形),可以生成、修改或者删除图元
通过几何着色器,输入为一个图元,输出可以为一个或多个图元,图元的类型可以不同
比如输入三角形,输出三角形的三条边和法线共四根线。开发者能够对几何形状执行复杂的几何变换和操作,从而创建丰富的视觉效果

图元装配阶段

将来自顶点着色器、细分求值着色器或几何着色器的顶点按照指定的绘制模式(如点,线,三角形)
进行分组,以形成基本图元(如点、线段、三角形等),这些图元将被传递到光栅化阶段

在图元组装完成后,对其进行裁剪,若图元完全位于视景体或裁剪平面内部,则将完整的图元传递到下一个阶段

若完全位于视景体会自定义裁剪平面外部,则丢弃该图元,如果图元部分位于内部,部分位于外部,则需要对
对图元进行裁剪,以确保仅保留视景体内部的部分

光栅化阶段

光栅化是将图元(如三角形)转换为片段的过程,这些片段最终会被着色并显示到屏幕上
Vulkan 的光栅化阶段包括设置光栅化模式(如填充模式、线框模式、点模式),面剔除模式(如剔除背面或者正面)
以及深度偏移等,光栅化是将三维几何体转换为二维像素的关键步骤

VkPipelineRasterizationStateCreateInfoVulkan 渲染管线中用于配置光栅化阶段的结构体

typedef struct VkPipelineRasterizationStateCreateInfo {
    VkStructureType                            sType;
    const void*                                pNext;
    VkPipelineRasterizationStateCreateFlags    flags;
    VkBool32                                   depthClampEnable;
    VkBool32                                   rasterizerDiscardEnable;
    VkPolygonMode                              polygonMode;
    VkCullModeFlags                            cullMode;
    VkFrontFace                                frontFace;
    VkBool32                                   depthBiasEnable;
    float                                      depthBiasConstantFactor;
    float                                      depthBiasClamp;
    float                                      depthBiasSlopeFactor;
    float                                      lineWidth;
} VkPipelineRasterizationStateCreateInfo;

示例代码如下:

    VkPipelineRasterizationStateCreateInfo rasterizer{};
    rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
    rasterizer.pNext = nullptr;  // 指向扩展结构的指针,通常为 nullptr
    rasterizer.depthClampEnable = VK_FALSE; // 禁用深度钳制,深度值不会被限制在 [minDepth, maxDepth] 范围内
    rasterizer.rasterizerDiscardEnable = VK_FALSE; // 禁用光栅化丢弃,光栅化阶段正常进行
    rasterizer.polygonMode = VK_POLYGON_MODE_FILL; // 使用填充模式绘制多边形
    rasterizer.lineWidth = 1.0f; // 线宽设置为 1.0. 单位为像素,注意这里应该使用浮点数
    rasterizer.cullMode = VK_CULL_MODE_NONE;// 不进行面剔除,渲染正面和背面
    rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; // 指定顺时针方向为正面
    rasterizer.depthBiasEnable = VK_FALSE; // 禁用深度偏移,深度值不会被调整
片段着色器

片段着色器阶段对每个片段进行处理,决定最终的像素值,这一阶段通常用于纹理映射,光照计算和颜色处理

    VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
    fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
    fragShaderStageInfo.module = fragShaderModule;
    fragShaderStageInfo.pName = "main";
片段测试阶段

在片段着色器执行后对片段进行深度和模板测试

深度测试中,它可以根据片段的深度值决定是否更新帧缓冲区中的深度和颜色值,而模板测试是将绘制区域
限定在任意形状的指定范围内

结构体 VkPipelineDepthStencilStateCreateInfo 用于设置深度和模板测试

VkPipelineDepthStencilStateCreateInfo depthStencil = {};
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencil.depthTestEnable = VK_TRUE; // 启用深度测试
depthStencil.depthWriteEnable = VK_TRUE; // 启用深度写入
depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; // 深度比较操作
depthStencil.depthBoundsTestEnable = VK_FALSE; // 禁用深度边界测试
depthStencil.stencilTestEnable = VK_FALSE; // 禁用模板测试
混合阶段

混合阶段是将片段着色器输出的颜色和帧缓冲区中现有的颜色进行混合,该阶段处理透明度和混合效果
开发者可以设置混合操作、混合因子和颜色掩码,以实现诸如半透明,叠加等效果, 混合阶段直接影响最终输出的图像

管线混合阶段设置:

    VkPipelineColorBlendAttachmentState colorBlendAttachment{};
    // 颜色写掩码
    colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
    // 启用颜色混合
    colorBlendAttachment.blendEnable = VK_TRUE;
    // src 的alphablend 系数为 src_alpha
    colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
    // 目标混合因子为 1 - src_alpha
    colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
    
    // 颜色混合方程为 加法
    colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
    colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; 
    colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; 
    // alpha 混合方程为加法
    colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; 

    VkPipelineColorBlendStateCreateInfo colorBlending{};
    colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
    colorBlending.logicOpEnable = VK_FALSE; // 禁用逻辑操作
    colorBlending.logicOp = VK_LOGIC_OP_COPY; // 设置逻辑操作为复制
    colorBlending.attachmentCount = 1; // 颜色缓和附件的数量
    colorBlending.pAttachments = &colorBlendAttachment;
    //colorBlending.blendConstants[0] = 0.0f;
    //colorBlending.blendConstants[1] = 0.0f;
    //colorBlending.blendConstants[2] = 0.0f;
    //colorBlending.blendConstants[3] = 0.0f;

http://www.niftyadmin.cn/n/5816258.html

相关文章

常见的开源网络操作系统

常见的开源网络操作系统有很多,它们通常用于路由器、交换机、网络设备和服务器等场景,具有灵活、可定制、易于扩展的特点。以下是一些常见的开源网络操作系统: OpenWRT 用途:主要用于路由器、无线接入点和网络设备。提供了广泛的定制选项和高级功能,如防火墙配置、VPN 支持…

Android Studio创建新项目并引入第三方jar、aar库驱动NFC读写器读写IC卡

本示例使用设备:https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.52de2c1bbW3AUC&ftt&id615391857885 一、打开Android Studio,点击 File> New>New project 菜单,选择 要创建的项目模版,点击 Next 二、输入项目名称…

Elasticsearch:聚合操作

这里写目录标题 一、聚合的概述二、聚合的分类1、指标聚合(Metric Aggregation)2、桶聚合(Bucket Aggregation)3、管道聚合(Pipeline Aggregation) 三、ES聚合分析不精准原因分析四、聚合性能优化1、ES聚合…

Taro地图组件和小程序定位

在 Taro 中使用腾讯地图 1.首先在项目配置文件 project.config.json 中添加权限: {"permission": {"scope.userLocation": {"desc": "你的位置信息将用于小程序位置接口的效果展示"}} }2.在 app.config.ts 中配置&#x…

信创、湖仓一体化、AI+DB,2024年数据库湖仓发展总结与展望

作者:吴炳锡 时光荏苒,转眼间 2025 年已然来临,这又是我从传统 OLTP 数据库领域转向云原生湖仓 Databend 的第三个年头,这段转变恰如一场快速的旅程,让我深感这一年如飞箭般迅速。展望未来,我意识到&#x…

后端开发入门超完整速成路线(算法篇)

引言 后端开发是软件开发中不可或缺的一部分,它涉及到服务器、数据库、API等核心组件的构建和维护。对于初学者来说,掌握算法和数据结构是进入后端开发领域的基础。本文将为你提供一个超完整的算法学习路线,帮助你快速入门,并在文…

解决“KEIL5软件模拟仿真无法打印浮点数”之问题

在没有外部硬件支持时,我们会使用KEIL5软件模拟仿真,这是是仿真必须要掌握的技巧。 1、点击“Project”,然后点击“Options for target 项目名字”,点击“Device”,选择CPU型号。 2、点击“OK” 3、点击“Target”,勾选“Use Mi…

教育咨询系统架构与功能分析

一、系统架构 服务端 服务端:Java(最低JDK1.8,支持JDK11以及JDK17)数据库:MySQL数据库(标配5.7版本,支持MySQL8)ORM框架:Mybatis(集成通用tk-mapper&#x…