Unity3D:着色器变体
推荐:将NSDT场景编辑器加入你的3D工具链
3D工具集:NSDT简石数字孪生
着色器变体
着色器变体(有时也称为着色器排列)是将条件行为引入着色器代码的一种方法。
Unity 将着色器源文件编译为着色器程序。每个编译的着色器程序都有一个或多个变体:针对不同条件的不同版本的着色器程序。在运行时,Unity 使用符合当前要求的变体。您可以使用着色器关键字配置变体。
有关着色器代码中的条件以及何时使用哪种技术的一般概述,请参阅着色器代码中的条件。有关 Unity 如何加载着色器变体的更多信息,请参阅着色器加载。
具有大量变体的着色器被称为“大型着色器”或“超级着色器”。 Unity 的标准着色器就是此类着色器的一个示例。
着色器变体的优缺点
着色器变体的主要优点是它们允许您在着色器程序中使用运行时条件,而不会受到动态分支的 GPU 性能影响。着色器变体的主要缺点是,其中大量着色器变体可能会导致构建时和运行时性能问题。
当 Unity 创建着色器变体时,它会使用静态分支来创建多个小型专用着色器程序。在运行时,Unity 使用与条件匹配的着色器程序。这意味着您可以将着色器变体用于可能导致动态分支中 GPU 性能降低的代码,而不会受到 GPU 性能损失。
但是,大量变体可能会导致构建时间、文件大小、运行时内存使用量和加载时间增加。这也会导致手动预加载(“预热”)着色器时的复杂性增加。当项目包含大量着色器变体时,这些问题可能会导致性能和工作流程出现重大问题。
警告:很容易无意中创建过多的着色器变体,这可能会导致严重的性能问题。因此,了解 Unity 如何确定着色器变体的数量、如何从编译中排除(“剥离”)不需要的变体以及何时在着色器中使用其他类型的条件非常重要。
着色器变体的数量
在构建时,Unity 会为当前构建目标的每个图形 API 编译一组着色器变体。图形 API 和生成目标的每个组合的变体数取决于着色器源文件以及着色器关键字的使用。
图形 API
Unity 为当前构建目标列表中的每个图形 API 编译一组着色器变体。着色器因构建目标和图形 API 的每个组合而异;例如,Unity 在 iOS 上为 Metal 编译的着色器与在 macOS 上为 Metal 编译的着色器不同。
某些着色器程序或关键字可能仅针对给定的图形 API 或给定的构建目标,因此图形 API 和构建目标的每个组合的变体总数可能不同;但是,编译这些变体的过程是相同的。
若要查看和编辑当前生成目标的图形 API 列表,请使用“播放器设置”窗口或“播放器设置 API”。
着色器程序数量
Unity 必须确定要为当前构建目标和图形 API 组合编译多少着色器程序。
对于构建中包含的每个着色器源文件,Unity 确定它定义的唯一着色器程序的数量:
- 计算着色器资源定义单个着色器程序。
- 在手动编码的着色器中,着色器程序的数量取决于您的代码。总数包括:
- 源文件本身中所有刀路中的所有着色器阶段。例如,每个顶点阶段定义一个着色器程序;每个片段阶段定义一个着色器程序;等等。
- 源文件依赖项中所有通道中的所有着色器阶段。这包括所有回退着色器,以及使用 UsePass 命令包含的所有通道。
- 在着色器图着色器中,着色器程序的数量取决于 Unity 从图形生成的代码。要查看 Unity 生成的着色器代码,请在上下文中单击着色器图资源,然后选择查看生成的代码。然后,您可以像确定手动编码着色器一样确定着色器程序的总数。
注意:如果着色器源文件在该构建的场景中被引用、被“资源”文件夹中的某些内容引用,或者包含在“图形设置”窗口的“始终包含的着色器”部分中,则该着色器源文件将包含在构建中。
影响着色器程序的关键字
当 Unity 确定必须为当前构建目标和图形 API 编译多少个着色器程序时,它会确定必须为每个着色器程序编译多少个着色器变体。
对于每个着色器程序,Unity 确定导致不同变体的着色器关键字的组合。这包括:
- 在该着色器的源文件中声明的着色器变体关键字集。有关详细信息,请参阅声明着色器关键字。
- Unity 自动添加的着色器关键字集。有关更多信息,请参阅 Unity 的预定义着色器关键字。
Unity 为着色器程序编译的着色器变体数量是关键字集的乘积;也就是说,Unity 为每个组合编译一个变体,其中包含每个集合中的一个元素。
例如,此集包含三个着色器变体关键字:
- COLOR_RED
- COLOR_GREEN
- COLOR_BLUE
此集合包含四个着色器变体关键字:
- QUALITY_LOW
- QUALITY_MEDIUM
- QUALITY_HIGH
- QUALITY_ULTRA
受这些着色器变体关键字影响的着色器程序将产生以下 12 个变体:
- COLOR_RED和QUALITY_LOW
- COLOR_RED和QUALITY_MEDIUM
- COLOR_RED和QUALITY_HIGH
- COLOR_RED和QUALITY_ULTRA
- COLOR_GREEN和QUALITY_LOW
- COLOR_GREEN和QUALITY_MEDIUM
- COLOR_GREEN和QUALITY_HIGH
- COLOR_GREEN和QUALITY_ULTRA
- COLOR_BLUE和QUALITY_LOW
- COLOR_BLUE和QUALITY_MEDIUM
- COLOR_BLUE和QUALITY_HIGH
- COLOR_BLUE和QUALITY_ULTRA
随着您添加更多着色器变体关键字集,Unity 编译的变体数量可能会迅速增长。这种非常快速的增长的术语是组合爆炸。
例如,考虑一个相当典型的用例,其中着色器具有许多着色器变体关键字集,每个关键字包含两个关键字(和)。如果着色器有两组这样的关键字,则会产生四个变体。如果着色器有十个这样的关键字集,则会产生 1024 个变体。<feature name>_ON<feature name>_OFF
着色器变体的重复数据删除
编译后,Unity 会自动识别同一 Pass 中的相同变体,并确保这些相同的变体指向相同的字节码。这称为重复数据删除。
重复数据删除可防止同一 Pass 中的相同变体增加文件大小;但是,相同的变体仍然会导致编译期间浪费工作,并增加运行时的内存使用量和着色器加载时间。考虑到这一点,最好去掉不需要的变体。
由3D建模学习工作室整理翻译,转载请注明出处!