shader变体功能是引擎常见需求,可以通过自定义选项来从同一个shader源码中编译出不同的shader,而一个最常接触到的变体编译就是在代码中编写API_VULKAN、API_OPENGLES、PLATFORM_MOBILE宏来针对不同平台以及Api的差异进行处理。但这类平台和Api的变体相对于用户shader变体来说,最大区别就是程序在运行时仅会加载一种,如果要切换API则需要重新启动应用程序来加载另一种,不用担心这类的变体过多而导致内存问题;但用户shader变体一般是用来控制不同的效果开关的,是有全部都载入内存的可能,所以要尤其注意用户shader变体内存问题。为了避免shader变体的自动膨胀等一系列问题,这里将完全的手动管理变体的生成,并且做到打包时对所有变体的情况可知。

 

当前引擎的shader是使用hlsl编写的,这些hlsl放在Engine/Shaders文件夹内而不是Engine/Assets文件夹内,也就是说这些hlsl的源代码并不会被引擎当做资产来处理,如有以下shader:

  • Common.inc.hlsl
  • Lit.inc.hlsl
  • Lit.vs.hlsl
  • Lit.ps.hlsl
  • Lit.sh.json

按照shader的编译规则,其中.vs.hlsl、.ps.hlsl与.sh.json将会被编译,如果你用过unity的shaderLab,那么可以将这三个文件理解为将shaderlab的着色器部分和状态配置部分拆开。

而存在Engine/Assets内的shader资产,则是对这些hlsl的组合引用,一个vs.hlsl一个ps.hlsl一个sh.json这三个文件将会被视为一个Pass,引擎下的一个Shader资产可以拥有多个Pass。用户可以在这个Shader资产上添加预编译宏。

https://www.imxqy.com/imagegx/engine/ShaderEd.png

添加PreDefines定义即是变体,如果想新增改shader的变体,那就复制一份shader资产,修改PreDefines预定义。这些shader资产都指向着相同的hlsl,SPIRV编译器使用预编译等编译设置去编译这些hlsl并储存于shader资产中,这样每个shader资产用同一份代码编译出不同的变体。

pulsar引擎的Shader仅仅只是编译数据没有渲染相关逻辑,无法直接使用,渲染相关逻辑以及参数集都在材质资产中,需要使用材质来对Shader引用,这样可以根据不同的逻辑在材质中切换对不同shader变体的引用。