初识Vulkun(9):图形流水线/管道
08/09/2020
文章目录
- 图形流水线
- 输入装配
- 顶点着色器
- 曲面细分着色器
- 几何着色器
- 光栅化阶段
- 片元着色器
- 输出混合阶段
- 固定函数阶段
- 可编程阶段
- 着色器模块(Shader Modules)
- 坐标系
- 顶点着色器
- 内置变量
- 片元着色器
- layout(location = 0)
- 加载编译器文件
- 创建着色器模块(Shader Module)
- 创建着色器/阶段
- 顶点着色器/片元着色器
- 输入顶点描述
- 输入顶点装配
- 视图和裁剪
- 光栅化
- 多重采样
- 颜色输出混合
- 管道布局
- 创建管线/流水线
- 知识补充
- SPIR-V
- 顶点输入
- 输入组件
- 视图和裁剪
- 光栅化
- 多重采样
- 动态修改
- 总结
图形流水线
输入装配
从顶点/索引缓冲区提取元数据,比如顶点位置,索引和顶点属性,组装方式,比如三角形,点
顶点着色器
用于每一个顶点数据进行空间变换,从模型空间输出为裁剪空间,具体如下
输出的顶点坐标会进行透视除法变为标准化设备坐标(NDC),将上述ClipSpace坐标的全部分量同时除以其w的分量,形成近大远小的特点,透视除法之后,所有将会显示到屏幕上的坐标都会归一化一个[-1,1],[-1,1],[0,1]范围内的坐标值,超出范围的顶点将会被裁减掉,左上为-1,右下为1
曲面细分着色器
进一步基于某些规则细分几何图形来提高网格质量,这通常用于使诸如砖墙和楼梯之类的表面在附近时看起来不太平坦
几何着色器
用于每一个原始图形(点,线,三角)可以进行丢弃或者增多,类型于曲面细分着色器,但是更加灵活,但现在如今的应用程序并不使用,因为大多数显卡性能表现不是很好,仅仅在集成显卡上有优势
光栅化阶段
把顶点坐标转换为屏幕上的像素,并算出这些像素对应的重心坐标和深度,再根据这些值对变换后的顶点属性进行深度矫正差值,生成一系列和像素对应的片元(fragment),同时像素元素填充了framebuffer,任何片段不在屏幕上的和没有经过深度测试的将会被丢弃
片元着色器
调用每一个没被丢弃的片元来决定那些framebuffers的片元将会有颜色和深度值,可以引进顶点着色器的数据来模拟光照和贴图等等
输出混合阶段
在framebuffer中,在相同像素位置混合不同片元。
固定函数阶段
上图中绿色方框为固定函数阶段,这个阶段可以调整它们的操作,因为它们必须存在而且还提前定义好了
可编程阶段
上图中黄色方框为可编程的,意思就是可以自己写代码提交给显卡来执行自己想要的操作。曲面细分阶段和几何阶段是可选的,在编写简单的图形可以禁用。如果只感兴趣深度值,也可以取消片元着色器。
着色器模块(Shader Modules)
坐标系
这里有两个坐标系,通常来说顶点着色器输入的是关于framebuffer的坐标点,但经过变换后,输出是右边的标准设备的坐标点,所以我们可以直接使用右边的标准坐标系传递给顶点着色器作为输入和输出。
顶点着色器
#version 450
#extension GL_ARB_separate_shader_objects:enablelayout(location = 0) out vec3 fragColor;vec2 positions[3] = vec2[](vec2(0.0,-0.5f),vec2(0.5,0.5),vec2(-0.5,0.5)
);vec3 colors[3] = vec3[](vec3(1.0,0.0,0.0),vec3(0.0,1.0,0.0),vec3(0.0,0.0,1.0)
);void main(){gl_Position = vec4(positions[gl_VertexIndex],0.0,1.0);fragColor = colors[gl_VertexIndex];
}
简单的顶点着色器,直接把顶点数据写在顶点着色器中,而不是从外部传进来,通常输出为裁剪坐标,需要有4个分量,所以我们返回一个4个分量的坐标。顶点着色器自定义输入颜色给片元着色器
内置变量
- gl_VertexIndex:当前顶点数据下标
- gl_Position: 裁剪坐标
片元着色器
#version 450
#extension GL_ARB_separate_shader_objects:enablelayout(location = 0) in vec3 fragColor;
layout(location = 0) out vec4 outColor;
void main()
{outColor = vec4(fragColor,1.0);}
没有内置变量,需要自己手写输出颜色变量fragcolor,颜色变量也是4个分量的,分别表示Red,Green,Blue,Alpha,取值范围0到1。
layout(location = 0)
您必须为每个帧缓冲区指定自己的输出变量,其中layout(location = 0)修饰符指定帧缓冲区的索引。将红色写入此outColor变量,该变量链接到索引为0的第一个(也是唯一一个)帧缓冲区。
加载编译器文件
static std::vector<char> readFile(const std::string& filename) {std::ifstream file(filename, std::ios::ate | std::ios::binary); //从最后开始读二进制,因为最后显示本文件的字节数量if (!file.is_open()) {throw std::runtime_error("failed to open file!");}size_t fileSize = (size_t)file.tellg(); //文本大小std::vector<char> buffer(fileSize); //文本容器file.seekg(0); //回归到头部,开始读内容file.read(buffer.data(), fileSize); //读取内容到容器中file.close(); //关闭文本return buffer;
}
创建着色器模块(Shader Module)
一旦有了一个SPIR-V模块,就需要把它传递给Vulkan,以便可以使用它创建一个着色器模块对象。
VkShaderModule createShaderModule(const std::vector<char>& code)
{VkShaderModuleCreateInfo createInfo{};createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;createInfo.codeSize = code.size(); //包含SPIR-V模块的大小,以字节为单位createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data()); //代码传入VkShaderModule shaderModule; //着色器模块对象if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS){throw std::runtime_error("failed to create shader module"); //检测是否读取有效}return shaderModule;
}
返回的着色器模块来创建管线,这是用来在设备上工作的着色器的最终形态。一旦使用完着色器模块,就应该销毁它并释放资源,在管道用完就可以销毁了。
创建着色器/阶段
顶点着色器/片元着色器
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";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";VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo};
输入顶点描述
顶点数据写在C++文件中,需要描写顶点属性和类型,而不是现在直接在着色器中定义顶点数据。
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;vertexInputInfo.vertexBindingDescriptionCount = 0;vertexInputInfo.vertexAttributeDescriptionCount = 0;
输入顶点装配
图元拓扑,点,线,三角
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
inputAssembly.primitiveRestartEnable = VK_FALSE;
视图和裁剪
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = (float) swapChainExtent.width;
viewport.height = (float) swapChainExtent.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = swapChainExtent;VkPipelineViewportStateCreateInfo viewportState{};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.pViewports = &viewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &scissor;
光栅化
VkPipelineRasterizationStateCreateInfo rasterizer{};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
rasterizer.depthBiasEnable = VK_FALSE;
多重采样
VkPipelineMultisampleStateCreateInfo multisampling{};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable = VK_FALSE;
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
颜色输出混合
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_FALSE;
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;
管道布局
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 0;
pipelineLayoutInfo.pushConstantRangeCount = 0;if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {throw std::runtime_error("failed to create pipeline layout!");
}
创建管线/流水线
着色器及其执行方式是Vulkan的核心。通常使用图形管线来将像素渲染进图像,以供进一步处理或者直接显示给哟用户。
VkGraphicsPipelineCreateInfo pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = shaderStages;
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &inputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.layout = pipelineLayout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.subpass = 0;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {throw std::runtime_error("failed to create graphics pipeline!");
}
知识补充
SPIR-V
SPIR-V着色器嵌入在模块里。每一个着色器都有一个拥有名字的入口点和着色器类型,着色器类型用来定义着色器在哪个着色阶段使用。入口点是着色器开始运行时的初始位置。着色文件的后缀名表示着色器类型,以.comp表示以计算着色器编译它。
SPIR-V是Vulkan官方唯一支持的着色语言。
顶点输入
输入组件
图形拓扑
视图和裁剪
Viewport用于描述framebuffer作为渲染输出结果目标区域,交换链图像将会在帧缓冲区使用。
**viewport定义了image图像到framebuffer帧缓冲区的转换关系。**裁剪矩阵定义了那些区域的像素被存储。任何在裁剪矩形外的像素都会在光栅化阶段丢弃。
光栅化
- 深度测试
- 面裁切
- 裁剪测试
- 线框渲染或者整体渲染
多重采样
多重采样时抗锯齿的一种实现。
动态修改
创建的一些结构体的状态可以在运行时动态修改,而不必重新创建。
总结
主要了解管道上的不同阶段做什么,如果加载着色器模块,和配置不同阶段的情况,最后创建管道。
初识Vulkun(9):图形流水线/管道相关推荐
- GPU工作原理,可编程渲染管线,图形流水线和GPU架构
由于计算机图形的性质,最图形管线已构造为计算状态与数据流动作为它们之间的数据流.每个阶段工作在一组元素,如顶点,三角形或像素.下图1 [ Shr99 ]给出了典型的OpenGL固定管道. 图1: 在 ...
- 【转】图形流水线中坐标变换详解:模型矩阵、视角矩阵、投影矩阵
转自:图形流水线中坐标变换详解:模型矩阵.视角矩阵.投影矩阵_sherlockreal的博客-CSDN博客_视角矩阵 图形流水线中坐标变换详解:模型矩阵.视角矩阵.投影矩阵 图形流水线中坐标变换过程 ...
- 图形流水线中光栅化原理与实现
图形流水线中光栅化原理与实现 光栅化主要解决的问题 光栅化原理 判断像素在三角形内部or外部 顶点属性插值 重心坐标系 插值深度 直接插值Z值的问题 正确的深度插值公式推导 透视校正 代码实现 光栅化 ...
- 图形流水线中坐标变换详解:模型矩阵、视角矩阵、投影矩阵
图形流水线中坐标变换详解:模型矩阵.视角矩阵.投影矩阵 图形流水线中坐标变换过程 模型矩阵:模型局部坐标系和世界坐标系之间的桥梁 1.模型局部坐标系存在的意义 2.根据模型局部坐标系中点求其在世界坐标 ...
- 《图形编程技术学习》(一)计算机图形学与图形流水线
这个系列是学习北京林业大学杨刚教授的课程时的学习笔记,课程简洁易懂又含以重要知识,谨以此分享出来.欢迎勘误~ 一.计算机图形学的概念及主要研究内容 计算机图形学是作什么的 计算机图形学(Comput ...
- GPU大百科全书 前传 看图形与装修的关系
又是一年装修季 前言:大部分人都会觉得,把我们面前这些晶体管铺成的电路跟现实生活联系起来是非常荒谬的.比如说显卡吧,只要显卡没有坏掉的话,把它插在完整的主板系统上再通上电,接在上面的屏幕就会很自然的亮 ...
- Android 图形系统概述
Android framework 为2D 和 3D 提供了各种各样的图形渲染 APIs 来与设备制造商的图形驱动实现交互,因此对于那些 API 在上层如何工作有一个好的理解非常重要.这一页介绍驱动基 ...
- 图形加速卡技术(大众扫盲篇)
图形加速卡技术论坛:1.入门篇--图形加速之 图形 (发表于GZeasy.com: Jul 20 2003, 04:14 PM) 来了这么久,也对这里的朋友有了一个大概的了解. 恕我罗索一两句,这里的 ...
- [资料] [转载] 图形加速卡技术 [专业的基础技术文章]
图形加速卡技术论坛:1.入门篇--图形加速之 图形 (发表于GZeasy.com: Jul 20 2003, 04:14 PM) 来了这么久,也对这里的朋友有了一个大概的了解. 恕我罗索一两句,这里的 ...
最新文章
- Spring 报It is indirectly referenced。。
- 100G 免费技术学习资料大全分享 (2020 年最新)
- C++ 复数类加减法运算重载为成员函数形式
- HDU 1506 Largest Rectangle in a Histogram
- Oracle 11g安装步骤
- [转]TortoiseSVN客户端重新设置用户名和密码
- padding 后尺寸变化 设置_padding margin border 和元素大小
- 分布式系统开发工具包 —— 基于Kryo的Java对象序列化
- latex导数_Latex:导数【高中常用公式】
- mac配置环境变量不生效
- Windows下常用的100个CMD指令以及常见的操作
- OSPFv3中LSA详解(一)——概述
- esp8266教程:编译sdk常用命令
- JSP登录中Session的用法
- 寒江独钓:键盘的过滤 学习笔记
- 如何将notepad++设置为默认打开方式
- 第一学期-期中考试-考试总结
- 解决Office 2010打开文件提示“文件已损坏,无法打开。”的问题
- MT4_应用于外汇交易的量化模型
- 华南理工大学广州学院计算机二级,华南理工大学广州学院学子在“中国高校计算机大赛...
热门文章
- openwrt桥接上海电信宽带+高清4KIptv适用
- 武汉计算机985211大学有哪些,湖北公认“最好”的7所大学,2所985,5所211,全部在武汉...
- 十大护眼灯品牌什么牌子好?盘点护眼灯品牌排行前十名
- python:爬取租房100页数据
- Codeforces911题解
- Aspose.PDF for Java系列4-基本操作
- MongoDB的安全认证
- 服务器个人买能干什么_动态vps是干什么用的?拨号VPS的作用功能是什么?
- Matlab基础编程知识处理(2)(数学建模中模型的模拟与数据提取,本篇全干货)
- Linux服务器报错:xx.sh: line 4: $‘\r‘: command not found 解决方法(记录在自己的容器中解决过程)