在接下来的几章中,我们将设置一个图形管线,该管线配置为绘制我们的第一个三角形。图形管线是将网格的顶点和纹理一直传递到渲染目标像素的操作序列。下面显示了一个简化的概述

输入汇编器 从您指定的缓冲区中收集原始顶点数据,并且还可以使用索引缓冲区来重复某些元素,而无需复制顶点数据本身。

顶点着色器 为每个顶点运行,通常应用变换将顶点位置从模型空间转换为屏幕空间。它还将每个顶点的数据传递到管线下方。

细分着色器 允许您根据某些规则细分几何体,以提高网格质量。这通常用于使砖墙和楼梯等表面在靠近时看起来不那么平坦。

几何着色器 在每个图元(三角形、线、点)上运行,并且可以丢弃它或输出比输入更多的图元。这与细分着色器类似,但更加灵活。但是,它在当今的应用程序中使用不多,因为在大多数显卡上性能不是很好,除了英特尔的集成 GPU。

光栅化 阶段将图元离散化为片段。这些是它们在帧缓冲上填充的像素元素。任何落在屏幕外的片段都将被丢弃,并且顶点着色器输出的属性将在片段之间进行插值,如图所示。通常,由于深度测试,位于其他图元片段后面的片段也会在此处被丢弃。

片段着色器 对每个幸存的片段调用,并确定片段写入哪个帧缓冲,以及使用哪个颜色和深度值。它可以利用来自顶点着色器的插值数据来做到这一点,这些数据可以包括纹理坐标和用于光照的法线等。

颜色混合 阶段应用操作来混合映射到帧缓冲中同一像素的不同片段。片段可以简单地相互覆盖、累加或基于透明度进行混合。

带有绿色的阶段被称为固定功能 阶段。这些阶段允许您使用参数调整其操作,但它们的工作方式是预定义的。

另一方面,带有橙色的阶段是 programmable,这意味着您可以将自己的代码上传到显卡,以精确地应用您想要的操作。这使您可以使用片段着色器,例如,实现从纹理和光照到光线追踪器的任何功能。这些程序在许多 GPU 核心上同时运行,以并行处理许多对象,例如顶点和片段。

如果您以前使用过像 OpenGL 和 Direct3D 这样的旧 API,那么您会习惯于使用像 glBlendFuncOMSetBlendState 这样的调用随意更改任何管线设置。Vulkan 中的图形管线几乎是完全不可变的,因此如果您想更改着色器、绑定不同的帧缓冲或更改混合功能,则必须从头开始重新创建管线。缺点是您必须创建许多管线来表示您想在渲染操作中使用的所有不同状态组合。但是,由于您将在管线中执行的所有操作都是预先知道的,因此驱动程序可以对其进行更好的优化。

一些可编程阶段是可选的,具体取决于您打算做什么。例如,如果您只是绘制简单的几何体,则可以禁用细分和几何阶段。如果您只对深度值感兴趣,则可以禁用片段着色器阶段,这对于 阴影贴图 生成很有用。

在下一章中,我们将首先创建将三角形放到屏幕上所需的两个可编程阶段:顶点着色器和片段着色器。混合模式、视口、光栅化等固定功能配置将在之后的章节中设置。在 Vulkan 中设置图形管线的最后一部分涉及输入和输出帧缓冲的规范。

创建一个 createGraphicsPipeline 函数,该函数在 initVulkan 中的 createImageViews 之后立即调用。我们将在接下来的章节中处理此函数。

void initVulkan() {
    createInstance();
    setupDebugMessenger();
    createSurface();
    pickPhysicalDevice();
    createLogicalDevice();
    createSwapChain();
    createImageViews();
    createGraphicsPipeline();
}

...

void createGraphicsPipeline() {

}

C++ 代码