一、图形管线概述
-
输入汇编器(Input assembler)从您指定的缓冲区收集原始顶点数据,并且还可以使用索引缓冲区来重复某些元素,而无需复制顶点数据本身。
-
顶点着色器(Vertex shader)为每个顶点运行,通常应用变换将顶点位置从模型空间转换为屏幕空间。它还将每个顶点的数据传递到管线中。
-
细分着色器(Tessellation)允许您根据某些规则细分几何图形以提高网格质量。这通常用于使附近的砖墙和楼梯等表面看起来不那么平坦。
-
几何着色器(Geometry shader)在每个图元(三角形、直线、点)上运行,可以丢弃它或输出比输入更多的图元。这与细分着色器类似,但更加灵活。但是,它在当今的应用程序中使用不多,因为除了英特尔的集成 GPU 外,大多数图形卡的性能都不是很好。
-
光栅化阶段(Rasterization)将图元离散化为片段。这些是它们在帧缓冲上填充的像素元素。落在屏幕外的任何片段都会被丢弃,并且顶点着色器输出的属性会在片段之间进行插值,如图所示。通常,由于深度测试,此处也会丢弃其他图元片段后面的片段。
-
片段着色器(Fragment shader)为每个幸存的片段调用,并确定将片段写入哪个(哪些)帧缓冲区,以及使用哪个颜色和深度值。它可以使用来自顶点着色器的插值数据来做到这一点,其中可以包括纹理坐标和用于照明的法线等内容。
-
颜色混合阶段(Color blending)应用操作来混合映射到帧缓冲区中同一像素的不同片段。片段可以简单地相互覆盖、相加或基于透明度进行混合。
-
颜色为绿色的阶段称为固定功能阶段。这些阶段允许您使用参数调整其操作,但它们的工作方式是预定义的。
-
橙色的阶段是可编程的,这意味着您可以将自己的代码上传到图形卡以精确应用您想要的操作。这使您可以使用片段着色器,例如,实现从纹理和照明到光线追踪器的任何功能。这些程序在许多 GPU 内核上同时运行,以并行处理许多对象,如顶点和片段。
-
Vulkan 中的图形管线几乎完全不可变,因此如果您想更改着色器、绑定不同的帧缓冲区或更改混合功能,则必须从头开始重新创建管线。优点:管线中执行的所有操作都是预先知道的,因此驱动程序可以更好地对其进行优化;缺点:必须创建许多代表您希望在渲染操作中使用的所有不同状态组合的管线。
二、着色器模块
Vulkan 着色器代码使用 SPIR-V 字节码格式,可以通过 D:\VulkanSDK\1.4.313.2\Bin\glslc.exe 把 GLSL编写的着色器编译为字节码。
确保VulkanSDK环境变量配置正确,编写脚本compile.bat,放到着色器目录。
glslc triangle.vert -o triangle_vert.spv
glslc triangle.frag -o triangle_frag.spv
每次修改完 traingle glsl 着色器,运行 compile.bat。
Vulkan NDC(标准化设备坐标)和 OpenGL有差异,Y轴坐标符号翻转了。
着色器模块只参与创建管线过程,管线创建完成后直接销毁。
三、图形管线初步配置
void HelloTriangle::createGraphicsPipeline() {
// 1. 读取着色器SPIR-V二进制代码
auto vertShaderCode = utils::readFile("assets/shaders/triangle_vert.spv");
auto fragShaderCode = utils::readFile("assets/shaders/triangle_frag.spv");
// 2. 创建着色器模块(封装SPIR-V代码,供管线使用)
VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);
VkShaderModule fragShaderModule = c