Version: 2021.2
Targeting graphics APIs and platforms in HLSL
Shader semantics

Declaring and using shader keywords in HLSL

This page contains information on working with shaderA program that runs on the GPU. More info
See in Glossary
keywords in HLSL code. For a general introduction to shader keywords, see Shader keywords. For information on declaring and using shader keywords in Shader Graph, see Keywords.

In your HLSL code, use #pragma directives to declare shader keywords, and #if directives to indicate that a section of shader code depends on the state of a shader keyword. You can use shader keywords in regular graphics shaders (including Surface ShadersA streamlined way of writing shaders for the Built-in Render Pipeline. More info
See in Glossary
) and compute shaders.

Declaring shader keywords

To declare shader keywords, use one of the following #pragma directives in the HLSL code:

Directive Description
#pragma multi_compile Declares a set of keywords.

By default, these keywords have global scope and affect all shader stages.

The build process includes all keywords from this set.
#pragma shader_feature Declares a set of keywords, and also instructs the compiler to compile variants where none of these keywords are enabled.

By default, these keywords have global scope and affect all shader stages.

The build process includes keywords from this set that are in use at build time.

For information on the difference between #pragma multi_compile and #pragma shader_feature, and guidance on when to use which one, see Shader keywords.

Note: If you add a shader to the list of Always Included Shaders in the Graphics settings window, Unity includes all keywords from all sets in the build, even if they were declared with #pragma shader_feature.

You can also add suffixes to these directives to modify their behavior:

  • Add _local to indicate that a set of keywords has local scope and cannot be overridden by global keywords; otherwise, the keywords have global scope and can be overridden by global keywords. For more information, see Shader keywords: global and local scope.

    You can add this suffix to #pragma multi_compile, or #pragma shader_feature directives; for example, #pragma multi_compile_local, and #pragma shader_feature_local are valid.
  • Add _vertex, _fragment, _hull, _domain, _geometry, or _raytracing to indicate that a set of keywords only affects a given shader stage, which can reduce the number of unneeded shader variants. For more information, see Shader keywords: Stage-specific keywords.

    You can add these suffixes to #pragma multi_compile or #pragma shader_feature directives, either standalone or after a _local modifier; for example, #pragma multi_compile_vertex and #pragma shader_feature_local_fragment are valid.

Additionally, there are some “shortcut” variations of #pragma multi_compile that add predefined sets of keywords. For more information on these, see multi_compile shortcuts.

Declaring a set of keywords

You declare keywords in sets. A set contains mutually exclusive keywords.

To declare a set of keywords, use a #pragma multi_compile or #pragma_shader_feature directive, followed by a space-delimited list of keywords.

This example demonstrates how to declare a set of four keywords:

#pragma multi_compile QUALITY_LOW QUALITY_MEDIUM QUALITY_HIGH QUALITY_ULTRA

Internally, this works by using #define directives. When Unity compiles the shader, it generates four variants: one where QUALITY_LOW is defined, one where QUALITY_MEDIUM is defined, one where QUALITY_HIGH is defined, and one where QUALITY_ULTRA is defined. At runtime, Unity uses the appropriate variant, based on which of those keywords is enabled.

When you use #pragma shader_feature to declare a set of keywords, Unity also compiles a variant where none of the keywords in that set are defined. This allows you to define behavior without using an additional keyword. Reducing the number of keywords is beneficial in a few ways: it can reduce the total number of variants that Unity compiles, which improves both build times and runtime performance; it reduces the total number of keywords that a shader uses, which prevents it from hitting shader keyword limits; and it makes it simpler to manage keyword state from C# scripts, because there are fewer keywords to enable and disable.

This example demonstrates how to declare a set that contains only a single keyword:

#pragma shader_feature EXAMPLE_ON

You can also instruct Unity to do this when you use #pragma multi_compile. To do so, add a “blank” keyword to the set, with a name that is one or more underscores (_), like this:

#pragma multi_compile __ EXAMPLE_ON

Declaring multiple sets of keywords

You can declare multiple sets of keywords to represent different features. To do this, use multiple #pragma multi_compile or #pragma_shader_feature directives.

This example demonstrates how to declare one set of four keywords, and another set of three keywords:

#pragma multi_compile QUALITY_LOW QUALITY_MEDIUM QUALITY_HIGH QUALITY_ULTRA
#pragma multi_compile COLOR_RED COLOR_GREEN COLOR_BLUE

Limitations

There are some limitations to how you declare sets of keywords:

  • You cannot include the same keyword more than once in the same set; however, you can declare the same keyword in different sets.
  • You cannot declare the same set of keywords more than once in a shader program.
  • There is a limit to the number of keywords that a shader can use. Every keyword declared in the shader source file and its dependenciesIn the context of the Package Manager, a dependency is a specific package version (expressed in the form package_name@package_version) that a project or another package requires in order to work. Projects and packages use the dependencies attribute in their manifests to define the set of packages they require. For projects, these are considered direct dependencies; for packages, these are indirect, or transitive, dependencies. More info
    See in Glossary
    count towards this limit. For more information, see Shader keyword limits.

Using shader keywords

To compile code that is used only when a given shader keyword is enabled, you use an #if directive, like this:

// Declare a set of keywords
#pragma multi_compile QUALITY_LOW QUALITY_MEDIUM QUALITY_HIGH QUALITY_ULTRA


#if QUALITY_ULTRA
// Code here is compiled for variants that are used when the keyword QUALITY_ULTRA is enabled
#endif

In Unity, #if directives work the same as in standard HLSL. For more information on #if directives, see the HLSL documentation: if, elif, else, and endif Directives.

Additionally, the #pragma require and #pragma target directives can take keywords as parameters, so that they only apply to variants where given keywords are enabled. For more information, see Targeting shader models and GPU features in HLSL.

multi_compile shortcuts

Unity provides several “shortcut” notations for declaring shader keywords.

The following shortcuts relate to light, shadow and lightmapping in the Built-in Render PipelineA series of operations that take the contents of a Scene, and displays them on a screen. Unity lets you choose from pre-built render pipelines, or write your own. More info
See in Glossary
:

  • multi_compile_fwdbase adds this set of keywords: DIRECTIONAL LIGHTMAP_ON DIRLIGHTMAP_COMBINED DYNAMICLIGHTMAP_ON SHADOWS_SCREEN SHADOWS_SHADOWMASK LIGHTMAP_SHADOW_MIXING LIGHTPROBE_SH. These variants are needed by PassType.ForwardBase.
  • multi_compile_fwdbasealpha adds this set of keywords: DIRECTIONAL LIGHTMAP_ON DIRLIGHTMAP_COMBINED DYNAMICLIGHTMAP_ON LIGHTMAP_SHADOW_MIXING VERTEXLIGHT_ON LIGHTPROBE_SH. These variants are needed by PassType.ForwardBase.
  • multi_compile_fwdadd adds this set of keywords: POINT DIRECTIONAL SPOT POINT_COOKIE DIRECTIONAL_COOKIE. These variants are needed by PassType.ForwardAdd.
  • multi_compile_fwdadd_fullshadows adds this set of keywords: POINT DIRECTIONAL SPOT POINT_COOKIE DIRECTIONAL_COOKIE SHADOWS_DEPTH SHADOWS_SCREEN SHADOWS_CUBE SHADOWS_SOFT SHADOWS_SHADOWMASK LIGHTMAP_SHADOW_MIXING. This is the same as multi_compile_fwdadd, but this adds the ability for the lights to have real-time shadows.
  • multi_compile_lightpass adds this set of keywords: POINT DIRECTIONAL SPOT POINT_COOKIE DIRECTIONAL_COOKIE SHADOWS_DEPTH SHADOWS_SCREEN SHADOWS_CUBE SHADOWS_SOFT SHADOWS_SHADOWMASK LIGHTMAP_SHADOW_MIXING. This is effectively a catch-all shortcut for all functionality related to real-time light and shadows, other than Light ProbesLight probes store information about how light passes through space in your scene. A collection of light probes arranged within a given space can improve lighting on moving objects and static LOD scenery within that space. More info
    See in Glossary
    .
  • multi_compile_shadowcaster adds this set of keywords: SHADOWS_DEPTH SHADOWS_CUBE. These variants are needed by PassType.ShadowCaster.
  • multi_compile_shadowcollector adds this set of keywords: SHADOWS_SPLIT_SPHERES SHADOWS_SINGLE_CASCADE. It also compiles variants without any of these keywords. These variants are needed for screen-space shadows.
  • multi_compile_prepassfinal adds this set of keywords: LIGHTMAP_ON DIRLIGHTMAP_COMBINED DYNAMICLIGHTMAP_ON UNITY_HDR_ON SHADOWS_SHADOWMASK LIGHTPROBE_SH. It also compiles variants without any of these keywords. These variants are needed by PassType.LightPrePassFinal and PassType.Deferred.

The following shortcuts relate to other settings:

  • multi_compile_particles adds this keyword relating to the Built-in particle systemA component that simulates fluid entities such as liquids, clouds and flames by generating and animating large numbers of small 2D images in the scene. More info
    See in Glossary
    : SOFTPARTICLES_ON. It also compiles variants without this keyword. For more information, see Built-in Particle System.
  • multi_compile_fog adds this set of keywords relating to fog: FOG_LINEAR, FOG_EXP, FOG_EXP2. It also compiles variants without any of these keywords. You can control this behavior in the Graphics settings window.
  • multi_compile_instancing adds keywords relating to instancing. If the shader uses procedural instancing, it adds this set of keywords: INSTANCING_ON PROCEDURAL_ON. Otherwise, it adds this keyword: INSTANCING_ON. It also compiles variants without any of these keywords. You can control this behavior in the Graphics settings window.

Most of these shortcuts contain multiple keywords. if you know the project doesn’t need them, you can use #pragma skip_variants to remove some of them. For example:

#pragma multi_compile_fwdadd
#pragma skip_variants POINT POINT_COOKIE

This tells the compiler to remove the keywords POINT or POINT_COOKIE from other directives.

Targeting graphics APIs and platforms in HLSL
Shader semantics