Unity 和 Unreal 作为流行的商业引擎,引擎这个东西,最主要的特点就是抽象。其中关于Shader部分,他们都做了比较好的抽象,使用者不需关注每个平台的shader不同,写一次,build各个平台。
这是当今游戏引擎的一个重要标配,Unity 和 Unreal 都自己做了大量的工作,网上也有人分析过Unity和Unreal各自的方案。
替代方案
现如今,开源世界也有一些方案来处理这个问题了
主要是两条线
1.DirectXShaderCompiler + spirvcross
2.glsllang +spirvcross
方案一,DirectXShaderCompiler 是微软开源的hlsl编译器,最新的版本增加了一个编译开关,重编译后可获取将hlsl 编译为 spirv 的能力,然后通过spirvcross项目编译成各种各样的东西
方案二,glsllang 是 Khronos 官方的 for vulkan 的 glsl编译器,他负责将glsl编译为spirv,然后通过spirvcross项目编译成各种各样的东西
这两个方案使用的编写语言分别是hlsl 和 glsl(方案二其实也支持hlsl,但是资料比较少,我还没有实验出来),都是用sprivcross来跨平台
这里就要解释一下什么是spirv
爷爷Khronos: 是图形标准化组织,OPENGL就是他们制定的,然后在微软搞dx12,苹果搞metal的时候,他们也推出了新一代图形API标准,就是Vulkan。
爹Vulkan:大伯OPENGL,二伯OPENGL ES
儿子spirv:而vulkan使用的shader二进制格式就是spirv
因为opengl 和opengles 的时代,都没有发展二进制格式,爷爷制定标准的时候就想把他打造成一个通用的格式,所以spirv实际上是个很通用的执行格式(想象一下c#背后的IL)
而spirvcross也是爷爷开发的一个反编译项目,专门把spirv反编译成各种shader源文件
https://github.com/KhronosGroup/SPIRV-Cross
官网上说他的功能是,(反编译spirv)生成可读的GLSL,苹果MSL,HLSL,c++,json好了,天下大同了
- Convert SPIR-V to readable, usable and efficient GLSL
- Convert SPIR-V to readable, usable and efficient Metal Shading Language (MSL)
- Convert SPIR-V to readable, usable and efficient HLSL
- Convert SPIR-V to debuggable C++ [DEPRECATED]
- Convert SPIR-V to a JSON reflection format [EXPERIMENTAL]
废话不多说,咱们试试
实践方案一
DirectXShaderCompiler 还要自己重编译,麻烦(其实是我没编译通过…build.py写的太烂了,辣鸡微软)
好在微软直接给了个整合好的方案一
ShaderConductor
https://github.com/microsoft/ShaderConductor
根据文档指导,直接下个最新的预发行版本就好
下份windowsx64的回来,其它平台的我没测试,都是命令行工具,大差不差。
写一个test.hlsl
然后执行命令行来编译成glsl
ShaderConductorCmd –I test.hlsl –E vs_main –S vs –T glsl –V 200
一长串的参数
-I test.hlsl 输入文件
-E vs_main 要编译的函数
-S vs 编译那种shader
-T glsl 输出为glsl格式
-V 110 glsl版本号 ,glsl版本号
副GLSL版本号表
2.0 110
2.1 120
3.0 130
3.1 140
3.2 150
3.3 330
4.0 400
4.1 410
4.2 420
4.3 430
4.5 450
产生的ios_matal文件
产生的glsl文件
问题,因为这个方案里的DXshadercompiler 是dx11的,所以这有个问题
我单独写的uniform matView也被放进了cbuffer里,观看glsl就会发现有了语义变化,这就像卡了一根刺。
实验方案二
下载glsllang
https://github.com/KhronosGroup/glslang
有release下载
https://github.com/KhronosGroup/glslang/releases
也下载个x64的
下载spirvcross
https://github.com/KhronosGroup/SPIRV-Cross
也有release下载
https://github.com/KhronosGroup/SPIRV-Cross/releases
也下载个x64的
解压出来就能用
这次写glsl
glsllang 默认使用文件扩展名识别功能
vertexshader就要.vert结尾
调用上述命令编译test.vert 和 test.frag 分别是 vertexshader 和 fragmentshader
分别得到frag.spv 和 vert.spv文件
这就是spirv的二进制格式shader
然后调用spirvcross 可以反编译他们到不同的shader
没有参数就反编译为glsl
加--hlsl就反编译为hlsl
加--msl就反编译为苹果metal
还有一堆参数就得你自己研究了
生成的hlsl比较啰嗦
生成的glsl就比较干爽了
最后说两句
目前我想要做的备胎,第一服务对象是Android(gl +vulkan)
第二才考虑 IOS PC web 这些
方案二明显更加合适,使用glsl作为基准,对gl和vulkan环境支持良好,在第二考虑时才需要spirvcross上马,可以支持dx 和 metal。
原理通了,接下去就是整合了。