本文档主要是对Unity官方手册的个人理解与总结(其实以翻译记录为主:>)
仅作为个人学习使用,不得作为商业用途,欢迎转载,并请注明出处。
文章中涉及到的操作都是基于Unity2018.2版本
参考链接:https://docs.unity3d.com/Manual/SL-MultipleProgramVariants.html
Often it is convenient to keep most of a piece of shader code fixed but also allow slightly different shader “variants” to be produced. This is commonly called “mega shaders” or “uber shaders”, and is achieved by compiling the shader code multiple times with different preprocessor directives for each case.
通常,保持着色器代码的大部分不变,但也允许生成稍微不同的着色器“变体”是很方便的。这通常被称为“mega shaders”或“uber shaders”,通过多次编译shader代码,并为每种情况使用不同的预处理器指令来实现。
In Unity this can be achieved by adding a #pragma multi_compile or #pragma shader_feature directive to a shader snippet. This works in surface shaders too.
在Unity中,这可以通过添加一个#pragma multi_compile或#pragma shader_feature指令到shader代码片段实现。这也适用于表面着色器。
At runtime, the appropriate shader variant is picked up from the Material keywords (Material.EnableKeyword and DisableKeyword) or global shader keywords (Shader.EnableKeyword and DisableKeyword).
在运行时,从材质关键字(材质)中选取适当的着色器变体(Material.EnableKeyword和DisableKeyword)或全局着色器关键字(shader.EnableKeyword和DisableKeyword)。
How multi_compile works
A directive like:
#pragma multi_compile FANCY_STUFF_OFF FANCY_STUFF_ON
Will produce two shader variants, one with FANCY_STUFF_OFF defined, and another with FANCY_STUFF_ON. At runtime, one of them will be activated based on the Material or global shader keywords. If neither of these two keywords are enabled then the first one (“off”) will be used.
将生成两个着色器变体,一个定义了FANCY_STUFF_OFF,另一个定义了FANCY_STUFF_ON。在运行时,其中一个将根据材质或全局着色器关键字被激活。如果这两个关键字都不启用,那么将使用第一个关键字(“off”)。
There can be more than two keywords on a multi_compile line, for example this will produce four shader variants:
在multi_compile行上可能有两个以上的关键字,例如,这将产生4个shader变体:
#pragma multi_compile SIMPLE_SHADING BETTER_SHADING GOOD_SHADING BEST_SHADING
When any of the names are all underscores, then a shader variant will be produced, with no preprocessor macro defined. This is commonly used for shaders features, to avoid using up two keywords (see notes on keywork limit below). For example, the directive below will produce two shader variants; first one with nothing defined, and second one with FOO_ON defined:
当名称只是下划线时,就会生成一个不定义预处理器宏的着色器变体。这通常用于着色器特性(features),以避免使用两个关键字(请参阅下面关于keywork限制的说明)。例如,下面的指令将产生两个着色器变体;第一个没有定义,第二个有FOO_ON定义:
#pragma multi_compile __ FOO_ON
Difference between shader_feature and multi_compile
#pragma shader_feature is very similar to #pragma multi_compile, the only difference is that unused variants of shader_feature shaders will not be included into game build. So shader_feature makes most sense for keywords that will be set on the materials, while multi_compile for keywords that will be set from code globally.
#pragma shader_feature与#pragma multi_compile非常相似,唯一的区别是shader_feature中shaders的未使用变体不会被包含在游戏构建中。所以shader_feature对于将设置在材质上的关键字最有意义,而multi_compile对于将从全局代码中设置的关键字。
Additionally, it has a shorthand notation with just one keyword:
此外,它有一个简写符号,只有一个关键字:
#pragma shader_feature FANCY_STUFF
Which is just a shortcut for #pragma shader_feature _ FANCY_STUFF, i.e. it expands into two shader variants (first one without the define; second one with it).
这只是#pragma shader_feature _fancy_stuff的一个快捷方式,即它扩展成两个着色器变体(第一个没有定义;第二个有)。
Combining several multi_compile lines
Several multi_compile lines can be provided, and the resulting shader will be compiled for all possible combinations of the lines:
可以提供几个multi_compile行,然后为所有可能的行组合编译生成shader:
#pragma multi_compile A B C
#pragma multi_compile D E
This would produce three variants for first line, and two for the second line, or in total six shader variants (A+D, B+D, C+D, A+E, B+E, C+E).
这将为第一行生成3个变体,为第二行生成2个变体,或者说总共生成6个着色器变体(A+D, B+D, C+D, A+E, B+E, C+E)。
It’s easiest to think of each multi_compile line as controlling a single shader “feature”. Keep in mind that the total number of shader variants grows really fast this way. For example, ten multi_compile “features” with two options each produces 1024 shader variants in total!
将每个multi_compile行看作是控制一个着色器“特性”是最简单的。请记住,通过这种方式,着色器变体的总数增长得非常快。例如,10个multi_compile“特性”,其中两个选项分别产生总共1024个着色器变量!
Keyword limit
When using Shader variants, remember that there is a limit of 256 keywords in Unity, and around 60 of them are used internally (therefore lowering the available limit). Also, the keywords are enabled globally throughout a particular Unity project, so be careful not to exceed the limit when multiple keywords are defined in several different Shaders.
当使用着色器变体时,请记住Unity中有256个关键字的限制,其中大约有60个是在内部使用的(因此降低了可用的限制)。此外,关键字在特定的Unity项目中是全局计数的,所以当多个关键字在几个不同的着色器中定义时,要小心不要超过限制。
Built-in multi_compile shortcuts
There are several “shortcut” notations for compiling multiple shader variants; they are mostly to deal with different light, shadow and lightmap types in Unity. See rendering pipeline for details.
有几个“快捷”符号编译多个着色器变体;它们主要用于处理不同的光、阴影和光照图类型。有关详细信息,请参阅渲染管线。
Most of the built-in shortcuts result in many shader variants. It is possible to skip compiling some of them if you know they are not needed, by using #pragma skip_variants. For example:
大多数内置快捷方式导致产生了许多着色器变体。通过使用#pragma skip_variation,如果您知道其中一些不需要编译,那么可以跳过编译。例如:
#pragma multi_compile_fwdadd
// will make all variants containing
// "POINT" or "POINT_COOKIE" be skipped
#pragma skip_variants POINT POINT_COOKIE
Shader Hardware Variants
One common reason for using shader variants is to create fallbacks or simplified shaders that can run efficiently on both high and low end hardware within a single target platform - such as OpenGL ES. To provide a specially optimised set of variants for different levels of hardware capability, you can use shader hardware variants.
使用着色器变体的一个常见原因是创建回退或简化的着色器,它们可以在单个目标平台(如OpenGL ES)的高端和低端硬件上高效运行。要为不同级别的硬件功能提供特别优化的变体集,您可以使用着色器硬件变体。
To enable the generation of shader hardware variants, add #pragma hardware_tier_variants renderer, where renderer is one of the available renderering platforms for shader program pragmas. With this #pragma 3 shader variants will be generated for each shader, regardless of any other keywords. Each variant will have one of the following defined:
为了支持生成着色器硬件变体,添加#pragma hardware_tier_variant渲染器,其中渲染器是着色器程序编译器可用的渲染平台之一。使用#pragma 将为每个着色器生成3个着色器变体,而不管其他的关键字是什么。每个变体都有以下定义之一:
UNITY_HARDWARE_TIER1
UNITY_HARDWARE_TIER2
UNITY_HARDWARE_TIER3
You can use these to write conditional fallbacks or extra features for lower or higher end. In the editor you can test any of the tiers by using the Graphics Emulation menu, which allows you to change between each of the tiers.
您可以使用它们来编写条件回退或为较低或较高端的额外功能。在编辑器中,您可以使用图形模拟(Graphics Emulation)菜单测试任何层,这允许您在每个层之间进行更改。
To help keep the impact of these variants as small as possible, only one set of shaders is ever loaded in the player. In addition, any shaders which end up identical - for example if you only write a specialised version for TIER1 and all others are the same - will not take up any extra space on disk.
为了使这些变体的影响尽可能的小,玩家只能加载一组着色器。此外,任何最终相同的着色器——例如,如果您只为TIER1编写一个专门的版本,并且所有其他的都是相同的——都不会占用磁盘上的任何额外空间。
At load time Unity will examine the GPU that it is using and auto-detect a tier value; it will default to the highest tier if the GPU is not auto-detected. You can override this tier value by setting Shader.globalShaderHardwareTier, but this must be done before any shaders you want to vary are loaded. Once the shaders are loaded they will have selected their set of variants and this value will have no effect. A good place to set this would be in a pre-load scene before you load your main scene.
在加载时,Unity会检查它正在使用的GPU,并自动检测一个层值;如果没有自动检测到GPU,它将默认设置为最高级别。你可以通过设置Shader.globalShaderHardwareTier来覆盖这个层值。但这必须在任何你想改变的着色器被加载之前完成。一旦着色器被加载,他们将会选择他们的变异体的集合并且这个值将没有影响。设置这个的好地方应该是在加载主场景之前的预加载场景中。
Note that these shader hardware tiers are not related to the quality settings of the player, they are purely detected from the relative capability of the GPU the player is running on.
注意,这些着色器硬件层与玩家的质量设置无关,它们纯粹是由玩家运行的GPU的相对性能检测出来的。
Platform Shader Settings
Apart from tweaking your shader code for different hardware tiers, you might want to tweak unity internal defines (e.g. you might want to force cascaded shadowmaps on mobiles). You can find details on this in the UnityEditor.Rendering.PlatformShaderSettings documentation, which provides a list of currently supported features for overriding per-tier. Use UnityEditor.Rendering.EditorGraphicsSettings.SetShaderSettingsForPlatform to tweak Platform Shader Settings per-platform per-tier.
除了为不同的硬件层调整着色器代码之外,您可能还需要调整unity内部定义(例如,您可能需要强制移动设备上的级联阴影映射)。您可以在UnityEditor.Rendering.PlatformShaderSettings文档 中找到有关这方面的详细信息。它提供了当前支持的覆盖每层的特性列表。使用UnityEditor.Rendering.EditorGraphicsSettings.SetShaderSettingsForPlatform来调整平台着色器的设置。
Please note that if PlatformShaderSettings set to different tiers are not identical, then tier variants will be generated for the shader even if #pragma hardware_tier_variants is missing.
请注意,如果设置到不同层的PlatformShaderSettings不相同,那么即使没有#pragma hardware_tier_variant,也会为着色器生成层变体。