在接下来的几章中,我们将设置一个图形管线,用于绘制我们的第一个三角形。图形管线是将网格的顶点和纹理一路处理到渲染目标中的像素的一系列操作。下面是一个简化的概述:
输入汇编器(Input Assembler) 从你指定的缓冲中收集原始顶点数据,并且也可以使用索引缓冲来重复某些元素,而无需复制顶点数据本身。
顶点着色器(Vertex Shader) 对每个顶点执行,通常应用变换将顶点位置从模型空间转换到屏幕空间。它还将每个顶点的数据沿管线向下传递。
细分着色器(Tessellation Shaders) 允许你根据某些规则细分几何体,以提高网格质量。这通常用于使砖墙和楼梯等表面在靠近时看起来不那么平坦。
几何着色器(Geometry Shader) 对每个图元(三角形、线段、点)执行,可以丢弃它或输出比输入更多的图元。这与细分着色器类似,但更加灵活。然而,它在当今的应用程序中很少使用,因为在大多数显卡(除了 Intel 的集成 GPU)上性能并不好。此外,几乎所有几何着色器的用例都可以用更现代的 Mesh 着色器管线来解决,它和光线追踪一样,是一个全新的管线解决方案,因此它存在于标准图形管线设置之外。我们将在未来的教程部分讨论该管线。
光栅化(Rasterization) 阶段将图元分解为 片段(fragments)。这些是它们填充到帧缓冲中的像素元素。任何落在屏幕外的片段都会被丢弃,并且顶点着色器输出的属性会在片段之间进行插值,如图所示。通常,在其他图元片段后面的片段也会因为深度测试而在此时被丢弃。
片段着色器(Fragment Shader) 对每个存活的片段调用,并决定片段写入哪个(些)帧缓冲以及使用什么颜色和深度值。它可以使用来自顶点着色器的插值数据来完成此操作,这些数据可以包括纹理坐标和用于光照的法线等信息。
颜色混合(Color Blending) 阶段应用操作来混合映射到帧缓冲中同一像素的不同片段。片段可以简单地相互覆盖、相加或基于透明度进行混合。
带有绿色的阶段被称为 固定功能(fixed-function) 阶段。这些阶段允许你使用参数调整其操作,但它们的工作方式是预定义的。
另一方面,带有橙色的阶段是 可编程(programmable) 的,这意味着你可以将自己的代码上传到显卡,以精确应用你想要的任何操作。例如,这允许你使用片段着色器来实现从纹理和光照到光线追踪器的任何功能。这些程序同时在许多 GPU 核心上运行,以并行处理许多对象,如顶点和片段。
如果你以前使用过 OpenGL 和 Direct3D 等较旧的 API,那么你可能习惯于能够通过 glBlendFunc 和 OMSetBlendState 等调用随意更改任何管线设置。Vulkan 中的图形管线几乎是完全不可变的,因此如果你想更改着色器、绑定不同的帧缓冲或更改混合函数,则必须从头开始重新创建管线。缺点是你必须创建许多管线来表示你希望在渲染操作中使用的所有不同状态组合。然而,由于管线中将要执行的所有操作都是预先知道的,驱动程序可以更好地对其进行优化。
一些可编程阶段是可选的,具体取决于你的意图。例如,如果你只是绘制简单的几何体,则可以禁用细分和几何阶段。如果你只对深度值感兴趣,那么你可以禁用片段着色器阶段,这对于 阴影贴图 生成非常有用。
在下一章中,我们将首先创建将三角形显示到屏幕上所需的两个可编程阶段:顶点着色器和片段着色器。像混合模式、视口、光栅化这样的固定功能配置将在之后的章节中设置。在 Vulkan 中设置图形管线的最后一部分涉及指定输入和输出帧缓冲。
创建一个 createGraphicsPipeline 函数,在 initVulkan 中 createImageViews 之后立即调用它。我们将在接下来的几章中完善这个函数。
void initVulkan() {
createInstance();
setupDebugMessenger();
createSurface();
pickPhysicalDevice();
createLogicalDevice();
createSwapChain();
createImageViews();
createGraphicsPipeline();
}
...
void createGraphicsPipeline() {
}
下一章将讨论实际在屏幕上显示某些内容所需的着色器模块。
Vulkan 是 Khronos Group Inc. 的注册商标
教程内容版权归原作者,遵循 CC BY-SA 4.0;本站独立代码及设计除外。