Contents
Shader源码
对于一个游戏引擎需要有一个灵活的着色材质系统,较旧的做法一般是直接提供glsl源码,在程序运行时读取并编译。但这种做法难以纳入到资产管理系统中来,也无法更加灵活的变更。
在引擎内分为shader源码、shader资产、材质。三种着色相关内容。
shader源码被视为和C++同一级别的源码,这里定义ShaderPass的概念为API层中的ShaderProgram以及相关管线状态的集合,每一个逻辑级别的ShaderPass都拥有多个HLSL和json的配置文件,例如:
- Lit.vs.hlsl
- Lit.ps.hlsl
- Lit.sh.json
这三个文件将会被视为一个ShaderPass,vs.hlsl后缀的文件为顶点着色器,ps.hlsl后缀的文件为像素(片元)着色器 ,sh.json后缀的文件为该Pass的管线设置,如正反面剔除,是否是透明材质等等。引擎内的Shader资产可以配置多个ShaderPass,通过组织多个ShaderPass的顺序来对一个物体进行渲染。
一个.sh.json的样例:
{ "PassName": "Engine/Missing", "CullMode": "None", "DepthTestEnable": true, "DepthWriteEnable": true, "DepthCompareOp": "Less", "StencilTestEnable": false }
除了这三种后缀可能还会有cs.hlsl(Compute Shader)和ms.hlsl(Mesh Shader)等可编程的代码。但有一种是不会被编译的,那就是文件后缀为.inc.hlsl的类型,这种文件不应被扫描和编译,该类型的定义作用类似与C语言中的.h头文件,用于编写前置类型,函数库以及宏定义等等。
Shader资产
Shader资产是引擎内的一种普通资产,可以设置多个ShaderPass,主要作为shader源码与引擎资产系统之间的桥梁。Shader资产的概念和Unity中的Shader资产还有和UE中的母材质概念比较像,都是一个不太可修改的原型。
材质
材质可以说是Shader+参数的集合,类似于Unity的材质以及UE中的材质实例概念。场景中无法使用Shader直接渲染,而是要使用材质。
编译器
在早期的版本里,引擎使用OpenGLAPI和glsl语言,采用直接读取源代码拿给驱动进行编译的做法,而现代引擎有着需要支持多个平台以及多种图形API的需求。
编译SPIR-V的编译器主要为两个,一个是微软出品的DirectXShaderCompiler(dxc),另一个是KhronosGroup的glslang,DXC可以将HLSL编译为DXIL以及SPIRV,glslang可以将HLSL和GLSL编译为SPIRV,这两个工具都可以将HLSL编译为SPIR-V字节码。
有一些图形api仅拥有字节码或中间语言接口,无法使用源码提供给api进行编译,但几乎都支持字节码,所以在做统一的时候使用字节码是个很好的选择,例如vulkan使用的SPIRV,D3d使用DXIL,Opengl450开始也可以读取SPIRV。
虽然vulkan和opengl都支持着SPIRV中间语言,但各个图形平台有着许多不同的实现细节导致无法进行图形api差异无感编程,例如opengl内的NDC与vulkan的NDC不一致,部分平台会使用反向的深度等等,这些全部都要靠用户去通过平台差异来编写宏,而字节码是相当经过了一次预编译,会将原本源码内的宏预处理处理完毕,当没有宏后的文件就只能在对应的平台上执行了,为了跨平台跨图形API,则需要将一份shader源码处理出多个目标结果,例如引擎打包支持的版本为DX12,Vulkan以及OpenGL450,那么就要先用预处理分别定义PLATFORM_D3D、PLATFORM_VULKAN、PLATFORM_OPENGL并且编译三次。因为源码采用了HLSL所以可以使用DXC直接编译为D3D可用的DXIL中间语言,而Opengl450也有了SPIRV字节码的读取支持,可以通过glslang等工具进行编译,或者采用SPIRV-CROSS工具将SPIRV转换为glsl给opengl使用。
在编写编译流程时,可以将一个ShaderPass编译为一个文件,例如将.vs.hlsl和.ps.hlsl编译后的字节与.sh.json文件内容合并为一个文件,这样在Shader资产读取时会更加方便管理,而且也可以在这个文件中附加编译的其他信息,比如有没有ComputeShader等等。我将这个合并的文件后缀其名为.shader,作为编译流程的编译结果。
在打包的包体里要有各个不同图形API的Shader,Shader包体数据格式大概为:
- 文本配置、渲染设置等
- 平台Shaders[]
- Vulkan
- 顶点着色器SPIRV
- 片元着色器SPIRV
- 计算着色器SPIRV
- D3D
- 顶点着色器DXIL
- 像素着色器DXIL
- 计算着色器DXIL
- OpenGL
- 顶点着色器GLSL/SPIRV
- 片元着色器GLSL/SPIRV
- 计算着色器GLSL/SPIRV
- Vulkan
文章评论