vulakn教程--Drawing a Triangle--Pipeline--Shader Module
原文地址 : vulkan-tutorial 着色器模块 Shader modulesVulkan 和之前的图形API有所不同,为了避免不同厂商移植代码的复杂性,Vulkan的着色器代码(shader code)采用字节码格式(bytecode) SPIR-V,而非人类可以阅读的文本格式,如GLSL(opengl 的一套体系)等。但这并不意味着我们要亲自手写字节码, 幸运的是LunarG SDK 已经提供了 Vertex shader它以vertex position 、mormal(法线)、texture Coordination 、color等作为输入,输出color、position、和texture Coordination等。最终作为输入传递给Fragment Sahder 的position 是以clip Coordination表示的。 如同Drect3D ,齐次坐标的z轴取值为0到1。 通常坐标值都是被放在Vertex Buffer中的,但是Vertex Buffer 也是个比较大的概念,我们之后再讨论。这里我们将采用一种看起来不太规范的做法:直接把坐标硬编码到着色器代码里。 #version 450
#extension GL_ARB_separate_shader_objects : enable
out gl_PerVertex {
vec4 gl_Position;
};
vec2 positions[3] = vec2[](
vec2(0.0,-0.5),vec2(0.5,0.5),vec2(-0.5,0.5)
);
void main() {
gl_Position = vec4(positions[gl_VertexIndex],0.0,1.0);
}
着色器需要 Fragment shaderVertex Shader的坐标点组成三角形,然后再用片原在屏幕上填充一块三角新区域。我们的Fragment Shader 被片原调用后为 #version 450
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(1.0,1.0); //r,g,b,a 取值[0.0,1.0]
}
Fragment shader不同于Vertex Shader有类似 Per-vertex colors整个三角形都是红色是不是太没意思了,下面这个三角形是不是更有趣一点? 如图: 现在为Vertex Shader 里为每一个顶点添加颜色值: vec3 colors[3] = vec3[](
vec3(1.0,0.0),//r,b
vec3(0.0,1.0,vec3(0.0,1.0)
);
然后添加输出到 Fragment Shader 里的颜色变量 layout(location = 0) out vec3 fragColor;
void main() {
gl_Position = vec4(positions[gl_VertexIndex],1.0);
fragColor = colors[gl_VertexIndex];
}
修改对应的Fragment Shader : layout(location = 0) in vec3 fragColor;
void main() {
outColor = vec4(fragColor,1.0);
}
Compiling the shaders在应用的根目录下建立文件夹shaders,然后建立两个文件:shader.vert和shader.frag,GLSL并没有限定文件的扩展名,我们这样定义只是为了见名知意。 Shader.vert 内容: #version 450
#extension GL_ARB_separate_shader_objects : enable
out gl_PerVertex { vec4 gl_Position; };
layout(location = 0) out vec3 fragColor;
vec2 positions[3] = vec2[](
vec2(0.0,0.5)
);
vec3 colors[3] = vec3[](
vec3(1.0,1.0)
);
void main() {
gl_Position = vec4(positions[gl_VertexIndex],1.0);
fragColor = colors[gl_VertexIndex];
}
Shader.frag内容: #version 450
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) in vec3 fragColor;
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(fragColor,1.0);
}
Windows 上编译 : C:/VulkanSDK/1.0.17.0/Bin32/glslangValidator.exe -V shader.vert C:/VulkanSDK/1.0.17.0/Bin32/glslangValidator.exe -V shader.frag pause
编译过后GLSL 文件就变为SPIR-V文件了,我们将看到两个结果文件: vert.spv 和 frag.spv。 Loading a shader现在我们要把这两个着色器程序加载到应用中,然后在适当的时机插入到Pipeline。所以我们需要一个从文件加载到当前应用的工具函数: 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;
}
然后我们会在接下来的适当时机进行读取: auto vertShaderCode = readFile("shaders/vert.spv");
auto fragShaderCode = readFile("shaders/frag.spv");
Creating shader modules要把着色器程序传递到Pipeline之前,我们需要把它们包裹成: void createShaderModule(const std::vector<char>& code,VDeleter<VkShaderModule>& shaderModule) {
}
老规矩,先填充一个结构体: kShaderModuleCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size();
createInfo.pCode = (uint32_t*) code.data();
然后创建 Modeule: if (vkCreateShaderModule(device,&createInfo,nullptr,&shaderModule) != VK_SUCCESS) {
throw std::runtime_error("failed to create shader module!");
}
我们声明两个Module变量: VDeleter<VkShaderModule> vertShaderModule {device,vkDestroyShaderModule};
VDeleter<VkShaderModule> fragShaderModule {device,vkDestroyShaderModule};
//调用我们的创建函数
createShaderModule(vertShaderCode,vertShaderModule);
createShaderModule(fragShaderCode,fragShaderModule);
Shader stage creation看起来所有的工作都做完了,但我们还没有告诉Pipeline什么时候使用着色器程序,究竟Pipeline是在什么阶段使用哪一个着色器呢? 让我们先填充一个结构,这结构也是我们将要创建的Pipeline工作的一部分: 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";
Fragment Shader Module 类似: 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";
最后我们定义一个包裹这两个结构的数组,我们在创建Pipeline的时候要用到: VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo,fragShaderStageInfo };
原文源码: source code (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |