Version: 2021.3
Branching, variants, and keywords
Branching in shaders

Conditionals in shaders

Sometimes, you want the same shader to do different things under different circumstances. For example, you might want to configure different settings for different materials, define functionality for different hardware, or dynamically change the behavior of shaders at runtime. You might also want to avoid executing computationally expensive code when it’s not needed, such as texture reads, vertex inputs, interpolators, or loops.

You can use conditionals to define behavior that the GPU only executes under certain conditions.

Different types of conditionals

To use conditionals in your shader, you can use the following approaches:

  • Static branching: the shader compiler evaluates conditional code at compile time.
  • Dynamic branching: the GPU evaluates conditional code at runtime.
  • Shader variants: Unity uses static branching to compile the shader source code into multiple shader programs. Unity then uses the shader program that matches the conditions at runtime.

When to use which type of conditional

There is no “one size fits all” approach to conditionals in shaders, and you should consider the advantages and disadvantages of each approach for a given shader, in a given project.

Bear in mind the following information:

  • If you know the conditions at compile time (for example, if you know that you are building for given hardware), then static branching is likely the best choice. Static branching code is simple to write and maintain, and it does not negatively impact build times, file sizes, or runtime performance. However, you cannot use it to execute code for different conditions at runtime.
  • If you need to execute code for different conditions at runtime, you should consider the following options:
    • Shader variants do not incur any GPU performance penalty. However, a large number of shader variants in a project can lead to significant problems: increased build times, file sizes, runtime memory usage, and loading times. Shader variants also introduce additional code complexity when manually preloading (“prewarming”) shaders.
    • Dynamic branching incurs a GPU performance penalty, which might be small or large depending on the shader code and the hardware. However, it allows you to use conditionals at runtime without increasing the number of shader variants in your project.
    • It’s possible to author your shader code so that it avoids branching or variants, and instead uses mathematical operations that return 0 or 1 to execute conditional code. This can lead to complex code that is difficult to maintain. Depending on the circumstances, it might result in only a very small performance improvement over dynamic branching, or no advantage at all.

In general, the best approach is to profile the performance of your application and carefully consider your decisions case-by-case. For example, if you can afford the slightly increased GPU cost, it might be best to use dynamic branching to achieve “good enough” GPU performance and reduce the risk of introducing more variants. However, if GPU performance is the primary concern for this shader and you have already accounted for the cost of additional variants, you might choose to use variants.

Branching, variants, and keywords
Branching in shaders
Copyright © 2023 Unity Technologies
优美缔软件(上海)有限公司 版权所有
"Unity"、Unity 徽标及其他 Unity 商标是 Unity Technologies 或其附属机构在美国及其他地区的商标或注册商标。其他名称或品牌是其各自所有者的商标。
公安部备案号:
31010902002961