着色器模块

和之前的一些图形API不同,Vulkan使用的着色器代码格式是一种叫做SPIR-V的字节码,这一字节码格式可以在Vulkan和OpenCL上使用。可以用它来编写图形和计算着色器,在本教程,我们将它用于编写图形管线的着色器。

GPU厂商的编译器将字节码转换为原生代码的工作复杂度远远低于直接编译较高级的类C代码。过去的经验告诉我们使用类C代码,比如GLSL作为着色器代码,会因为不同GPU厂商对代码的不同解释而造成大量问题,并且类C代码的编译器实现要比字节码编译器复杂的多,GPU厂商实现的编译器也极有可能存在错误,不同GPU厂商的实现也差异巨大。而使用字节码格式,上述的这些问题可以在极大程度上减少。

虽然,Vulkan使用字节码格式作为着色器代码,但这并不意味着我们要直接书写字节码来编写着色器。Khronos发布了一个独立于厂商的可以将GLSL代码转换为SPIR-V字节码的编译器。这个编译器可以验证我们的着色器代码是否完全符合标准,将GLSL代码转换为SPIR-V字节码。我们可以在应用程序运行时调用这个编译器,动态生成SPIR-V字节码,但在本教程,我们没有这样做。这一编译器已经被包含在了LunarG的Vulkan SDK中,编译器可执行文件名称为glslangValidator.exe,不需要读者另外下载。

GLSL是一个类C的着色器语言。使用GLSL编写的程序包含了一个main函数,这一函数完成具体的运算操作。GLSL使用全局变量进行输入输出,它包含了许多用于图形编程的特性,比如向量和矩阵支持,用于计算叉积的函数,用于矩阵与向量相乘的函数,用于计算反射向量的函数等等。GLSL中的向量类型叫做vec,后跟一个表示向量元素数的数字。比如,用于表示一个三维空间位置的向量的类型为vec3。GLSL允许我们访问向量的分量比如.x,也允许我们使用表达式来创建新的向量值,比如vec3(1.0, 2.0, 3.0).xy会返回一个vec2类型的值。向量构造器也可以被组合使用,比如可以使用vec3(vec2(1.0, 2.0), 3.0)生成一个vec3类型的值。

之前的章节提到,我们需要编写顶点着色器和片段着色器才能完成在屏幕上绘制三角形的工作。接下来的两节的内容就是使用GLSL编写顶点着色器和片段着色器代码,然后使用编译器将它们转换为SPIR-V字节码。