一般网站建设多少钱,秦皇岛酒店网站设计,龙岩论坛,wordpress 无法写新文章一、定义
在unity中我们可以通过使用#pragma multi_compile或#pragma shader_feature指令来为shader创建多个稍微有点区别的shader变体。这个Shader被称为宏着色器#xff08;mega shader#xff09;或者超着色器#xff08;uber shader#xff09;。实现原理#xff1a;…一、定义
在unity中我们可以通过使用#pragma multi_compile或#pragma shader_feature指令来为shader创建多个稍微有点区别的shader变体。这个Shader被称为宏着色器mega shader或者超着色器uber shader。实现原理根据不同的情况使用不同的预处理器指令来多次编译Shader代码。 在运行时Unity从Material宏Material.EnableKeyword和Shader.DisableKeyword或全局着色器宏Shader.EnableKeyword和Shader.DisableKeyword中选择适当的着色器变体。如果这两个宏都未启用则Unity使用第一个宏。
二、使用
//定义两个TEST_1,TEST_2两个宏
#pragma multi_compile TEST_1 TEST_2
//在shader中使用
#ifdef TEST_1//Todo
#endif
#ifdef TEST_2//Todo
#endif上面这个命令会产生2种着色器变种TEST_1TEST_2。 要生成未定义预处理器宏的着色器变体请添加一个仅为下划线__的名称。这是避免使用两个宏的常用技术因为对项目中可以使用的宏数量有限制例如
#pragma multi_compile __ TEST_1在脚本中控制使用
//使用TEST_1变种
Shader.EnableKeyword (TEST_1);
Shader.DisableKeyword (TEST_2);三、组合
#pragma multi_compile TEST_1 TEST_2
#pragma multi_compile TEST_3 TEST_4 TEST_5它产生总共六个着色器变体TEST_1_TEST_3TEST_1_TEST_4TEST_1_TEST_5TEST_2_TEST_3TEST_2_TEST_4TEST_2_TEST_5。 所以如果有10行multi_compile每行2个选项那么将一共产生1024个着色器变体。 请记住着色器变体数量将以这种方式疯狂增长。
四、pragma shader_feature
shader_feature非常相似multi_compile。唯一的区别是Unity shader_feature在最终版本中不包含未使用的着色器变体。所以shader_feature适用于在我们在编辑器中选中材质设置它使用的shader的宏如果在程序中动态的去设置可能无效原因下面说明。而对于multi_compile会把所有的变体都编译进程序里所以适合需要在程序运行中动态改变状态的宏适合全局设置 。 材质中设置位置截图
五、宏限制
在unity中限制了全局的宏个数为265个而unity内部使用了大约60个所以在多个不同的着色器中定义全局宏时需要注意宏数量不要超过限制。 使用本地宏替代一部分全局宏使用shader_feature_local和multi_compile_local。 shader_feature_local类似于shader_feature但枚举宏是本地的。 multi_compile_local类似于multi_compile但枚举宏是本地的。 在项目中除非是希望通过全局API启用的那些特定宏否则应尽量使用本地宏 使用更多本地宏和更少的全局宏以减少每个着色器的宏总计数。如果存在具有相同名称的全局和本地宏则Unity会优先使用local宏。 注意 1不能将本地宏与进行全局宏更改的API一起使用例如Shader.EnableKeyword或CommandBuffer.EnableShaderKeyword。 2每个着色器最多有64个唯一的本地宏。 3如果Material启用了本地宏并且其着色器更改为不再声明的宏则Unity会创建一个新的全局宏。
六、内置multi_compile快捷方式
unity中提供一些内置的宏用于编译多个着色器变体。这些主要用于处理Unity中不同的光照阴影和光照贴图类型。 multi_compile_fwdbase编译PassType.ForwardBase所需的所有变体。变体处理不同的光照贴图类型并启用或禁用主方向光的阴影。 multi_compile_fwdadd为PassType.ForwardAdd编译变体。这将编译变体以处理DirectionalSpot或Point Light类型及其变体与Cookie纹理。 multi_compile_fwdadd_fullshadows同样multi_compile_fwdadd但也包括灯具有实时阴影的能力。 multi_compile_fog扩展为多个变体以处理不同的雾类型off / linear / exp / exp2。
大多数内置快捷方式都会产生许多着色器变体。如果您知道项目不需要它们您可以使用#pragma skip_variants跳过编译它们中的一些。例如
#pragma multi_compile_fwdadd
#pragma skip_variants POINT POINT_COOKIE该指令跳过包含POINT或POINT_COOKIE的所有变体。
七、查看shader变种数量
#pragma multi_compile TEST_1 TEST_2 TEST_3
#pragma multi_compile TEST_4 TEST_5
#pragma multi_compile TEST_6 TEST_7查看变体数量.png 上面的组合会产生3x2x212种变体我们可以点击show查看具体的变体组合名称。
// Total snippets: 1
// -----------------------------------------
// Snippet #0 platforms ffffffff:
Keywords always included into build: TEST_1 TEST_2 TEST_3 TEST_4 TEST_5 TEST_6 TEST_712 keyword variants used in scene:TEST_1 TEST_4 TEST_6
TEST_1 TEST_4 TEST_7
TEST_1 TEST_5 TEST_6
TEST_1 TEST_5 TEST_7
TEST_2 TEST_4 TEST_6
TEST_2 TEST_4 TEST_7
TEST_2 TEST_5 TEST_6
TEST_2 TEST_5 TEST_7
TEST_3 TEST_4 TEST_6
TEST_3 TEST_4 TEST_7
TEST_3 TEST_5 TEST_6
TEST_3 TEST_5 TEST_7这里查看的是所有会被编译的变体的数量也就是#pragma multi_compile声明的宏的全部组合。
#pragma multi_compile TEST_1 TEST_2 TEST_3
#pragma multi_compile TEST_4 TEST_5
#pragma shader_feature TEST_6 TEST_7查看变种数量.png
// Total snippets: 1
// -----------------------------------------
// Snippet #0 platforms ffffffff:
Keywords stripped away when not used: TEST_6 TEST_7
Keywords always included into build: TEST_1 TEST_2 TEST_3 TEST_4 TEST_56 keyword variants used in scene:TEST_1 TEST_4 TEST_6
TEST_1 TEST_5 TEST_6
TEST_2 TEST_4 TEST_6
TEST_2 TEST_5 TEST_6
TEST_3 TEST_4 TEST_6
TEST_3 TEST_5 TEST_6上面的组合会产生3x2x16种变体,#pragma shader_feature没有特别处理的话只有会默认包括第一个宏。
八、编译
1material的ShaderKeywords
Material所包含的Shader Keywords表示启用shader中对应的宏Unity会调用当前宏组合所对应的变体来为Material进行渲染。在Editor下可以通过将material的inspector调成Debug模式来查看当前material定义的Keywords也可在此模式下直接定义Keywords用空格分隔Keyword。 设置ShaderKeywords.png 优点根据material中的ShaderKeywords自动生成变体。无需额外设置 缺点多个不同的material包中可能存在相同的shader变体造成资源冗余。若在程序运行时动态改变material的keyword其变体可能并没有被生成 如上图设置如果ShaderKeywords中没有设置TEST_6这是如果我们想在程序中通过代码动态使用TEST_6这个宏Shader.EnableKeyword(TEST_6))。可能不能得到想要的效果因为TEST_6这个变种没有生成。
2把Shader加入到Always Include Shaders列表里
找到ProjectSetting-Graphics-Always Include Shaders列表将我们需要的shader添加到里面这样unity将会把这个shader的所有的变种都生成出来。 AlwaysIncludeShaders.png
优点我们不用担心项目发布出去以后有些变种没有生成不能在程序中动态的去控制我们的宏。 缺点生成的变体数量庞大导致发布时间变长游戏包体过大。比如你把standardShader放进去,由于它有大量的keyword全部变种都生成的话大概有几百兆。
3使用ShaderVariantCollection是生成指定变体
ShaderVariantCollection是unity5.x以后用来记录shader的哪些变体需要被生成。这样做的好处就是在shader_feature与multi_compile结合使用时能够设置生成何种变体从而避免生成不必要的变体shader不必和material打在一个包中避免了多个包中存在相同的变体资源明确直观的显示了哪些变体是需要生成的。
生成方式
1通过Create-Shader- Shader Variant Collection就可以新建一个shader variant collection文件手动添加需要编译的变种 ShaderVariantCollection.png 选择需要生成的变种.png 2通过Edit-Project Settings-Graphics中的save to asst...按钮生成unity帮我们自动收集的使用到的变种信息。 自动生成.png
这时候只需要先Clear一下然后依次打开我们的所有场景把需要的物体都显示一遍Unity就会自动记录下来哪些着色器的哪些着色器变体已经被使用到。统计完后只需点击下面的保存按钮就可以生成我们所需要的ShaderVariantCollection资源。当然你也可以为你的每一个场景或者按需生成足够多的ShaderVariantCollection资源。自动收集的功能不一定百分百可靠最好事后多检查。
ShaderVariantCollection加载
启动时预加载 最简单最粗暴的使用方式就是在游戏启动的瞬间就直接加载ShaderVariantCollection资源并编译里面的着色器变体Unity已经为我们做好这一步了依然还是在图形设置面板里只需把需要启动是就编译的ShaderVariantCollection添加在Preloaded Shaders里面 预加载.png 代码加载
由于ShaderVariantCollection也是一种资源可以跟纹理、模型等等资源一起打包和加载等只需在加载之后调用一句WarmUp。
ShaderVariantCollection shaderVariantCollection Resources.Load ShaderVariantCollection( MainShaderVariant);
if (shaderVariantCollection )shaderVariantCollection.WarmUp ();也可以把ShaderVariantCollection放在Resources目录下好像会被自动加载。