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…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
企业大模型服务合规指南:深度解析备案与登记制度
伴随AI技术的爆炸式发展,尤其是大模型(LLM)在各行各业的深度应用和整合,企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者,还是积极拥抱AI转型的传统企业,在面向公众…...
快速排序算法改进:随机快排-荷兰国旗划分详解
随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...
初探用uniapp写微信小程序遇到的问题及解决(vue3+ts)
零、关于开发思路 (一)拿到工作任务,先理清楚需求 1.逻辑部分 不放过原型里说的每一句话,有疑惑的部分该问产品/测试/之前的开发就问 2.页面部分(含国际化) 整体看过需要开发页面的原型后,分类一下哪些组件/样式可以复用,直接提取出来使用 (时间充分的前提下,不…...
