Vulkan-着色器及编译SPIR-V
1.着色器模块介绍
Vulkan着色器代码一定要用字节码格式,而不是人类可读的语法如GLSL和HLSL。这个字节码就是SPIR-V,设计用于Vulkan和OpenCL。这是一个可以用于编写图形和计算着色器的格式,但是我们主要关注的是Vulkan的图形管线。使用字节码格式的优点之一是GPU厂商写的编译器将着色器代码转化为原生代码会非常简单。过去的经验表明,人类易读的语法如GLSL,某些GPU厂商是能很便捷地解读这些标准的。但是如果你碰巧写了不一般的着色器,那可能会导致厂家的着色器因为你的语法错误而拒绝执行,甚至更糟,就是能执行,却因为编译器bug得到的是错误的结果。直接用字节码格式就能避免这些问题。
Khronos已经发行了他们自己的厂商无关的编译器,能够将GLSL编译到SPIR-V格式。这个编译器就是用来验证你的着色器都是和标准兼容的,它会产生一个SPIR-V的二进制输出,可以和你的程序一同发行。该编译器包含在LunarG SDK中了,也就是glslangValidator.exe,所以不用额外下载任何内容。
GLSL是C语法风格的着色器语言,用它写的程序有一个main方法来让每个对象调用。没有用参数作为输入,返回一个值作为输出这种做法,GLSL使用了全局变量来处理输入和输出。该语言包含了许多特性以便于图形编程,比如内建的向量和矩阵原型。叉乘,矩阵-向量相乘,向量反射之类操作用的函数都包括在内。
向量类型叫做vec,后面跟着一个数字表示元素个数。比如一个3D位置应该存储为vec3。可以用类似.x的方式获取其单独的组件,但是也可能会创建一个新的变量,比如vec3(1.0, 2.0, 3.0).xy就会得到一个vec2。向量的构造器也可以接受向量对象的组合以及标量值,比如vec3可以用vec3(vec2(1.0, 2.0), 3.0)构造。
2.着色器例子
写一个顶点着色器和片段着色器,以便将三角形显示到屏幕上。下面两部分会介绍每一部分的GLSL代码,之后我会介绍如何产生两份SPIR-V二进制文件并加载到程序中。
2.1 定点着色器
顶点着色器处理每个到来的顶点,用其属性如世界坐标,颜色,法线和材质坐标等作为输入。输出是最终在裁剪坐标的位置和需要传递给片段着色器的属性,比如颜色和材质坐标。这些值会被片段着色器根据光栅器插值,产生平滑的梯度。
裁剪坐标是来自顶点着色器的四维向量,随后被通过最后一个元素除以整个向量转变成一个归一化设备坐标。这些归一化设备坐标是齐次坐标,将帧缓冲映射到纵横都是[-1, 1]的坐标系,如下:
我们第一个三角形不用任何变换,我们就直接明确三个点的位置作为归一化设备坐标,来创建如下的三角形:
直接输出归一化设备坐标,做法就是将他们作为裁剪坐标从顶点着色器输出,最后一个部分置为1。这样变换裁剪坐标到归一化设备坐标时候的除法操作就什么都保持不变。
通常这些坐标会存储在顶点缓冲中,但是创建顶点缓冲并填充数据在Vulkan中并非微不足道。因此我们决定先将其推迟,直到我们满足地看到三角形绘制到了屏幕上。同时我们还要做一些不太正统的东西:直接将坐标包含在顶点着色器中。代码如下
#version 450vec2 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);
}
main方法是每个顶点都涉及的,内置的gl_VertexIndex变量包含了当前顶点的索引。这通常是顶点缓冲的索引,但是我们这儿它就是硬编码数组的顶点数据的索引。每个顶点的位置通过着色器的连续数组获取,且和虚拟z和w部分一起组成一个裁剪坐标的位置。内置变量gl_Position作为输出。
2.2 片段着色器
由来自顶点着色器的位置形成的三角形用片段来填充屏幕上的区域。片段着色器就在这些片段上执行来为帧缓冲产生一个颜色和深度。一个简单的为整个三角形输出红色的片段着色器。
#version 450
#extension GL_ARB_separate_shader_objects : enablelayout(location = 0) out vec4 outColor;void main() {outColor = vec4(1.0, 0.0, 0.0, 1.0);
}
main方法被每个片段调用,就和顶点着色器的main方法被每个顶点调用一样。GLSL的颜色是由4部分组成的向量,就是RGB和alpha通道,范围都是[0, 1]。不像是顶点着色器的gl_Position,没有内置变量为当前片段输出一个颜色。你必须为每个帧缓冲明确自己的输出变量,布局(location = 0)修改器明确了帧缓冲的索引。这里outColor写成红色,和索引为0的第一个帧缓冲连接起来。
3.编译着色器
在项目根目录创建一个shaders目录,存储我们的着色器代码。两份着色器分别是shader.vert和shader.frag,GLSL没有官方扩展名,但是这两个通常用于区分它们。
shader.vert如下所示:
#version 450
#extension GL_ARB_separate_shader_objects : enablelayout(location = 0) out vec3 fragColor;vec2 positions[3] = vec2[](vec2(0.0, -0.5),vec2(0.5, 0.5),vec2(-0.5, 0.5)
);vec3 colors[3] = vec3[](vec3(1.0, 0.0, 0.0),vec3(0.0, 1.0, 0.0),vec3(0.0, 0.0, 1.0)
);void main(){gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);fragColor = colors[gl_VertexIndex];
}
shader.frag如下:
#version 450
#extension GL_ARB_separate_shader_objects : enablelayout(location = 0) in vec3 fragColor;layout(location = 0) out vec4 outColor;void main() {outColor = vec4(fragColor, 1.0);
}
现在我们准备用glslangValidator将其编译成SPIR-V字节码:
glslc shader.vert -o vert.spv
glslc shader.frag -o frag.spv
这两条命令用-V标志调用了编译器,表明要求编译器将GLSL源文件编译成SPIR-V字节码。当你运行编译脚本的时候,就会发现两个SPIR-V二进制文件产生了,即vert.spv和frag.spv。这些名字直接来自shader类型,但是你可以进行重命名。Vulkan SDK包含了libshaderc,也就是将你的GLSL代码编译成SPIR-V的东西。
4.加载着色器
当前我们可以产生SPIR-V着色器了,是时候将其加载到我们的程序中了,然后在某个时刻将其插入到图形管线中。我们先要写一个简单的助手方法来从文件加载二进制数据:
readFile方法会从指定文件读取所有字节,返回std::vector管理的byte数组。我们用两个标记打开该文件:
ate:开始读的时候在文件末尾,就是说打开文件的时候定位到文件尾;
binary:以二进制文件读取文件(避免text转换)。
现在我们从createGraphicsPipeline调用该方法:
void createGraphicsPipeline() {
auto vertShaderCode = readFile("shaders/vert.spv");
auto fragShaderCode = readFile("shaders/frag.spv");
}
准备创建着色器模块,在开始将代码传递到管线之前,我们需要将其包装到VkShaderModule对象中,创建一个createShaderModule方法
相关文章:
Vulkan-着色器及编译SPIR-V
1.着色器模块介绍 Vulkan着色器代码一定要用字节码格式,而不是人类可读的语法如GLSL和HLSL。这个字节码就是SPIR-V,设计用于Vulkan和OpenCL。这是一个可以用于编写图形和计算着色器的格式,但是我们主要关注的是Vulkan的图形管线。使用字节码格…...

从MVC到DDD,该如何下手重构?
作者:付政委 博客:bugstack.cn 沉淀、分享、成长,让自己和他人都能有所收获!😄 大家好,我是技术UP主小傅哥。多年的 DDD 应用,使我开了技术的眼界! MVC 旧工程腐化严重,…...
论文阅读:基于隐马尔可夫模型的蛋白质多序列比对方法研究
本文来自chatpaper Basic Information: • Title: Research on Protein Multiple Sequence Alignment Method Based on Hidden Markov Model (基于隐马尔可夫模型的蛋白质多序列比对方法研究) • Authors: Zhan Qing • Affiliation: Harbin Institute of Technology (哈尔滨工…...
Vim同时打开多个文件
分屏模式 在 Vim 中,可以同时打开多个文件并使用分屏模式来查看它们。以下是一些常见的方法和命令: 在启动 Vim 时打开多个文件 使用 -o 选项打开文件并水平分屏: vim -o file1.txt file2.txt使用 -O 选项打开文件并垂直分屏: v…...
SpringCloudStreamkafka接收jsonarray字符串失败
文章目录 场景现象问题处理 场景现象 kafka作为消息队列,作为前端设备数据到后端消费的渠道,也被多个不同微服务消费一个服务与前端边缘计算设备建立socket消息,接收实时交通事件推送,再将事件发送到kafka里面。此处使用的是Spri…...

面向对象特性分析大全集
面向对象特性分析 先进行专栏介绍 面向对象总析前提小知识分类浅析封装浅析继承浅析多态面向对象编程优点abc 核心思想实际应用总结 封装概念详解关键主要目的核心思想优点12 缺点12 Java代码实现封装特性 继承概念详解语法示例关键主要目的核心思想优点12 缺点12 Java代码实现…...

【数据结构】队列和栈
大家中秋节快乐,玩了好几天没有学习,今天分享的是栈以及队列的相关知识,以及栈和队列相关的面试题 1.栈 1.1栈的概念及结构 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作…...
WordPress主题开发( 十)之—— 条件标签函数(上)
这里写目录标题 什么是条件标签函数?条件标签函数的使用场景使用条件标签函数的注意事项常用的条件标签函数主页示例:is_front_page() 示例:管理后台is_admin() 示例:单个文章页面is_single() 示例:is_single(17) 示例:is_single(Hello World) 示例:is_single(hello…...
vue学习-10vue整合SpringBoot跨域请求
在Vue.js应用整合Spring Boot后端时,需要处理跨域请求。跨域请求通常发生在前端应用运行在不同的域名或端口上时,而后端服务运行在不同的域名或端口上。以下是一种处理跨域请求的常见方式: 后端(Spring Boot)配置 在…...

ElasticSearch - 基于 JavaRestClient 查询文档(match、精确、复合查询,以及排序、分页、高亮)
目录 一、基于 JavaRestClient 查询文档 1.1、查询 API 演示 1.1.1、查询基本框架 DSL 请求的对应格式 响应的解析 1.1.2、全文检索查询 1.1.3、精确查询 1.1.4、复合查询 1.1.5、排序和分页 1.1.6、高亮 一、基于 JavaRestClient 查询文档 1.1、查询 API 演示 1.1.…...
简易实现通讯录(2.0)
这篇文章是在上期实现的通讯录基础上,增加了自动增容的功能,也解决了一开始通讯录自动开辟一个空间,可能会浪费空间,或者是信息过多无法增容的痛点,由于我们使用的是malloc这类函数来开辟空间,我们也需要来…...
Jasypt 实现自定义加解密
如下文章已经讲解了, Jasypt 是什么,怎么集成 Jasypt,怎么使用 Jasypt。 Jasypt 开源加密库使用教程_jasyptstringencryptor-CSDN博客Jasypt 加密框架概述1、Jasypt Spring Boot 为 spring boot 应用程序中的属性源提供加密支持,…...

Leetcode 554. 砖墙
文章目录 题目代码(9.25 首刷自解) 题目 Leetcode 554. 砖墙 代码(9.25 首刷自解) class Solution { public:int leastBricks(vector<vector<int>>& wall) {unordered_map<int, int> mp;int count 0;for…...

Python 内置函数详解 (3) 进制转换
近期在外旅游,本篇是出发前定时发布的,不完整,旅游回来后再补充。 Python 内置函数 Python3.11共有75个内置函数,其来历和分类请参考:Python 新版本有75个内置函数,你不会不知道吧_Hann Yang的博客-CSDN博客 函数列表 abs aiter all …...

SPSS列联表分析
前言: 本专栏参考教材为《SPSS22.0从入门到精通》,由于软件版本原因,部分内容有所改变,为适应软件版本的变化,特此创作此专栏便于大家学习。本专栏使用软件为:SPSS25.0 本专栏所有的数据文件可在个人主页—…...

聊聊并发编程——并发容器和阻塞队列
目录 一.ConcurrentHashMap 1.为什么要使用ConcurrentHashMap? 2.ConcurrentHashMap的类图 3.ConcurrentHashMap的结构图 二.阻塞队列 Java中的7个阻塞队列 ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。 LinkedBlockingQueue…...
我庄严承诺终生不去承德旅游
虽然人微言轻,但也要尽一份力。 在此,我庄严承诺: 如果承德相关机构不返还那名"灵活就业人员"105.82万元的财产,并进行公开道歉。 我将终生不去承德旅游, 我将终生不买承德出产的任何产品。 我还将劝诫我…...

【python】python实现杨辉三角的三种方法
文章目录 1.杨辉三角介绍:2.方法一:迭代3.方法二:生成器4.方法三:递归 1.杨辉三角介绍: 杨辉三角是一种数学图形,由数字排列成类似三角形的形状。它的每个数值等于它上方两个数值之和。这个三角形的形状可以…...

GitHub 基本操作
最近要发展一下自己的 github 账号了,把以前的项目代码规整规整上传上去,这里总结了一些经验,经过数次实践之后,已解决几乎所有基本操作中的bug,根据下面的操作步骤来,绝对没错了。(若有其他问题…...

Docker和Docker compose的安装使用指南
一,环境准备 Docker运行需要依赖jdk,所以需要先安装一下jdk yum install -y java-1.8.0-openjdk.x86_64 二,Docker安装和验证 1,安装依赖工具 yum install -y yum-utils 2,设置远程仓库 yum-config-manager --add-r…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...

【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...

搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...