着色器变体,有时也称为着色器在 GPU 上运行的程序。 更多信息
参见 术语表排列,是一种在着色器代码中引入条件行为的方法。
Unity 将着色器源文件编译成着色器程序。每个编译后的着色器程序都有一个或多个变体:针对不同条件的着色器程序的不同版本。在运行时,Unity 使用与当前要求匹配的变体。您可以使用着色器关键字配置变体。
有关着色器代码中条件语句的概述以及何时使用哪种技术的常规信息,请参阅着色器代码中的条件语句。有关 Unity 如何加载着色器变体的更多信息,请参阅着色器加载。
具有大量变体的着色器称为“超级着色器”或“统一着色器”。Unity 的标准着色器就是这种着色器的示例。
着色器变体的主要优点是,它们允许您在着色器程序中使用运行时条件语句,而不会受到动态分支对 GPU 性能的影响。着色器变体的主要缺点是,大量的变体会导致构建时间和运行时性能问题。
当 Unity 创建着色器变体时,它使用静态分支创建多个小型专用着色器程序。在运行时,Unity 使用与条件匹配的着色器程序。这意味着您可以将着色器变体用于可能导致动态分支中 GPU 性能降低的代码,而不会造成 GPU 性能损失。
但是,大量变体会导致构建时间、文件大小、运行时内存使用量和加载时间增加。它还会在手动预加载(“预热”)着色器时导致更大的复杂性。当项目包含大量着色器变体时,这些问题会导致性能和工作流程出现重大问题。
警告:很容易无意中创建过多的着色器变体,这会导致严重的性能问题。因此,了解Unity 如何确定着色器变体的数量、如何排除(剥离)编译中不需要的变体以及何时在着色器中使用其他类型的条件语句非常重要。
在构建时,Unity 会为当前构建目标的每个图形 API 编译一组着色器变体。每个图形 API 和构建目标组合的变体数量取决于您的着色器源文件以及您对着色器关键字的使用情况。
您可以检查您有多少个着色器变体。
Unity 会为当前构建目标的列表中的每个图形 API 编译一组着色器变体。每个构建目标和图形 API 组合的着色器都不同;例如,Unity 为 iOS 上的 Metal 编译的着色器与为 macOS 上的 Metal 编译的着色器不同。
某些着色器程序或关键字可能仅针对给定的图形 API 或给定的构建目标,因此每个图形 API 和构建目标组合的变体总数可能不同;但是,编译这些变体的过程相同。
要查看和编辑当前构建目标的图形 API 列表,请使用播放器设置允许您为 Unity 生成的最终游戏设置各种特定于播放器的选项的设置。 更多信息
参见 术语表窗口或PlayerSettings API。
Unity 必须确定为当前构建目标和图形 API 组合编译多少个着色器程序。
对于构建中包含的每个着色器源文件,Unity 都会确定它定义了多少个唯一的着色器程序
注意:如果着色器源文件在该构建的场景场景包含游戏环境和菜单。将每个唯一的场景文件视为唯一的关卡。在每个场景中,您放置环境、障碍物和装饰,从本质上讲是分段设计和构建您的游戏。 更多信息
参见 术语表中被引用、资源文件夹中的某些内容引用或包含在图形设置窗口的始终包含的着色器部分中,则该文件将包含在构建中。
当 Unity 确定必须为当前构建目标和图形 API 编译多少个着色器程序后,它将确定必须为每个着色器程序编译多少个着色器变体。
对于每个着色器程序,Unity 都会确定导致不同变体的着色器关键字组合。这包括
Unity 为着色器程序编译的着色器变体的数量是关键字集的乘积;也就是说,Unity 会为每个包含每个集合中一个元素的组合编译一个变体。
例如,此集合包含三个着色器变体关键字
此集合包含四个着色器变体关键字
受这些着色器变体关键字影响的着色器程序将导致以下 12 个变体
随着您添加更多着色器变体关键字集,Unity 编译的变体数量会迅速增长。这种非常快速的增长称为组合爆炸。
例如,考虑一个相当典型的用例,其中着色器具有一系列包含两个关键字的着色器变体关键字集(<feature name>_ON
和 <feature name>_OFF
)。如果着色器有两个这样的关键字集,则会产生四个变体。如果着色器有十个这样的关键字集,则会产生 1024 个变体。
编译后,Unity 会自动识别同一通道内相同的变体,并确保这些相同的变体指向相同的字节码。这称为重复数据删除。
重复数据删除可防止同一通道内的相同变体增加文件大小;但是,相同的变体仍会导致编译期间浪费工作,并在运行时增加内存使用量和着色器加载时间。考虑到这一点,始终最好剥离不需要的变体。