Version: Unity 6.0 (6000.0)
语言 : 中文
减少着色器变体
检查您有多少着色器变体

着色器变体简介

着色器变体(有时也称为着色器排列)是将条件行为引入着色器代码的一种方式。

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 列表,请使用播放器设置 (Player Settings) 窗口或 PlayerSettings API。

着色器程序的数量

Unity 必须确定针对当前构建目标和图形 API 的组合要编译多少着色器程序。

对于构建中包含的每个着色器源文件,Unity 会确定其定义的唯一着色器程序的数量:

  • 计算着色器资源定义了单个着色器程序。
  • 在手动编码着色器中,着色器程序的数量取决于代码。总数包括:
    • 源文件中所有通道的所有着色器阶段。例如,每个顶点阶段定义一个着色器程序;每个片元阶段定义一个着色器程序;依此类推。
    • 源文件依赖关系中所有通道的所有着色器阶段。这包括所有回退着色器以及通过 UsePass 命令纳入的所有通道。
  • 在 Shader Graph 着色器中,着色器程序的数量取决于 Unity 从图形中生成的代码。要查看 Unity 生成的着色器代码,请右键单击 Shader Graph 资源并选择查看生成的代码 (See generated code)。然后,您可以像确定手动编码着色器一样确定着色器程序的总数。

注意:如果着色器源文件在构建的场景中被引用,或被 Resources 文件夹中的内容引用,或被纳入 图形设置 (Graphics Settings) 窗口的始终包含的着色器 (Always-included shaders) 部分中,则其会包含在构建中。

影响着色器程序的关键字

在确定了必须为当前构建目标和图形 API 编译多少个着色器程序后,Unity 会确定必须为每个着色器程序编译多少个着色器变体。

对于每个着色器程序,Unity 会确定导致不同变体的着色器关键字组合。这包括:

Unity 为着色器程序编译的着色器变体的数量是关键字集的乘积;也就是说,Unity 会为每个组合编译一个变体,每个组合包含一个来自各个集合的元素。

例如,此集合包含三个着色器变体关键字:

  • COLOR_RED
  • COLOR_GREEN
  • COLOR_BLUE

此集合包含四个着色器变体关键字:

  • QUALITY_LOW
  • QUALITY_MEDIUM
  • QUALITY_HIGH
  • QUALITY_ULTRA

受这些着色器变体关键字影响的着色器程序将产生以下十二个变体:

  • 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 编译的变体数量可能会迅速增加。这种非常迅速的增长被称为组合爆炸。

例如,考虑一个相当典型的用例:一个着色器包含多组着色器变体关键字,每组关键字包含两个关键字(<feature name>_ON<feature name>_OFF)。如果着色器有两组这样的关键字,则会产生四种变体。如果着色器有十组这样的关键字,则会产生 1024 个变体。

着色器变体的重复数据删除

编译后,Unity 会自动识别同一通道中的相同变体,并确保这些相同的变体指向相同的字节码。这称为重复数据删除

重复数据删除可防止同一通道中的相同变体增加文件大小;但是,相同的变体仍然会导致编译期间的冗余工作,并增加运行时的内存使用量和着色器加载时间。考虑到这一点,最好始终剥离不需要的变体

减少着色器变体
检查您有多少着色器变体