版本:Unity 6 (6000.0)
语言:English
减少着色器变体
检查您有多少个着色器变体

着色器变体简介

着色器变体,有时也称为着色器在 GPU 上运行的程序。 更多信息
参见 术语表
排列,是一种在着色器代码中引入条件行为的方法。

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 列表,请使用播放器设置允许您为 Unity 生成的最终游戏设置各种特定于播放器的选项的设置。 更多信息
参见 术语表
窗口或PlayerSettings API。

着色器程序的数量

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

对于构建中包含的每个着色器源文件,Unity 都会确定它定义了多少个唯一的着色器程序

  • 计算着色器资源定义单个着色器程序。
  • 在手动编写的着色器中,着色器程序的数量取决于您的代码。总数包括
    • 源文件本身中所有通道中的所有着色器阶段。例如,每个顶点阶段定义一个着色器程序;每个片段阶段定义一个着色器程序;等等。
    • 源文件依赖项中所有通道中的所有着色器阶段。这包括所有后备着色器以及使用UsePass 命令包含的所有通道。
  • 在着色器图着色器中,着色器程序的数量取决于 Unity 从您的图生成的代码。要查看 Unity 生成的着色器代码,请右键单击着色器图资源并选择查看生成的代码。然后,您可以按照与手动编写的着色器相同的方式确定着色器程序的总数。

注意:如果着色器源文件在该构建的场景场景包含游戏环境和菜单。将每个唯一的场景文件视为唯一的关卡。在每个场景中,您放置环境、障碍物和装饰,从本质上讲是分段设计和构建您的游戏。 更多信息
参见 术语表
中被引用、资源文件夹中的某些内容引用或包含在图形设置窗口的始终包含的着色器部分中,则该文件将包含在构建中。

影响着色器程序的关键字

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

对于每个着色器程序,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 编译的变体数量会迅速增长。这种非常快速的增长称为组合爆炸。

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

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

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

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

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