版本: 2022.3
语言: 英语
分支、变体和关键字
着色器中的分支

着色器中的条件语句

有时,您想在不同的环境下对同一着色器执行不同的操作。例如,您可能只想为不同的材质配置不同的设置,为不同的硬件定义功能,或在运行时动态地改变着色器的行为。您可能还希望避免在不需要时执行计算密集型代码,比如纹理读取、顶点输入、插值器或循环。

您可以使用条件语句定义GPU仅在满足特定条件时才执行的行为。

不同类型的条件语句

要使用着色器中的条件语句,您可以使用以下方法

  • 静态分支:着色器编译器在编译时评估条件代码。
  • 动态分支:GPU在运行时评估条件代码。
  • 着色器变体根据特定的着色器关键字及其状态的组合,Unity生成的着色器程序版本。一个着色器对象可以包含多个着色器变体。了解更多信息更多信息
    词汇表 中查看
    :Unity使用静态分支将着色器源代码编译成多个着色器程序。然后Unity在运行时使用满足条件的着色器程序。

何时使用哪种类型的条件语句

在着色器中使用条件语句没有“一刀切”的方法,您应考虑针对给定的着色器和项目,评估每种方法的优缺点。

使用哪种条件语句取决于何时需要着色器切换到不同的代码分支

在编辑时切换代码分支

如果您不需要着色器在运行时切换到不同的代码分支,您可以使用Unity在您编辑时才会评估的条件语句。

例如,您可以在材质的检查器一个Unity窗口,显示有关当前选中的GameObject、资产或项目设置的信息,允许您检查和编辑值。了解更多信息更多信息
词汇表 中查看
窗口中设置一个属性,使着色器执行以下操作

  • 为某些材质实例添加镜面反射,但不是其他实例。
  • 为某些对象添加不同的外观,例如在水下出现的对象。

使用这种方法,着色器代码更容易编写和维护,不太可能影响构建时间、文件大小和性能。

为此,您可以使用以下方法之一

  • 着色器变体:使用 shader_feature 声明关键字并在 if 语句中评估它们。
  • 静态分支:使用预处理器常量和宏。

如果您使用 shader_feature 关键字定义,Unity 会保留构建中 Materials 所使用的着色器变体,并移除(“剥离”)其他着色器变体。这有助于降低构建时间并减小文件大小。

请避免在运行时使用 C# 脚本来启用或禁用 shader_feature 关键字,因为如果 Material 使用了缺失的着色器变体,Unity 会选择其他可用的变体。如果您确实需要在运行时启用或禁用关键字,请使用以下方法之一确保您的构建包含所需的所有变体

  • 着色器变体系列 中包含您需要的着色器变体,并把它加入 预加载着色器 列表中。
  • 为想要使用的每个 shader_feature 关键字组合在您的构建中包含一个 Material。

在运行时切换代码分支

如果您需要使用 C# 脚本来在运行时使着色器切换到不同的代码分支,您可以使用 Unity 在编辑和运行时都会评估的条件。

例如,您可以使用 C# 脚本使着色器执行以下操作

  • 在特定时间动态改变 Material,使其具有雪景。
  • 当用户更改质量设置时改变 Material,例如,为用户提供雾是否出现的动态控制。

为此,您可以使用以下方法之一

如果您使用 multi_compile 关键字定义,Unity 会为每个可能的着色器代码分支组合构建着色器变体,包括构建中 Materials 没有使用的组合。这意味着您可以在运行时启用和禁用关键字,但这也可能大大增加构建时间、文件大小、加载时间和内存使用。有关更多信息,请参阅 着色器变体

动态分支不会创建着色器变体,但可能会导致您的着色器在 GPU 上的运行速度变慢,尤其是如果以下任何情况成立时

  • 您的着色器在性能较低的 GPU 上运行。
  • 您的条件代码有“不对称分支”,其中一条分支比另一条更长或更复杂。

您可以通过 检查您有多少个着色器变体 来确定您是否可以在不影响 GPU 性能的情况下使用动态分支。有关动态分支的优缺点,请参阅 着色器分支

分支、变体和关键字
着色器中的分支