Version: 2020.1
빌트인 셰이더 변수
GLSL 셰이더 프로그램

Shader variants and keywords

You can write shader snippets that share common code, but have different functionality when a given keyword is enabled or disabled. When Unity compiles these shader snippets, it creates separate shader programs for the different combinations of enabled and disabled keywords. These individual shader programs are called shader variants.

Shader variants can be useful for project workflow reasons; you can assign the same shader to different Materials, but configure the keywords differently for each. This means that you write and maintain your shader code in a single place, and have fewer shader assets in your project. You can also use shader variants to change shader behaviour at runtime, by enabling or disabling keywords.

Shaders with a large number of variants are called “mega shaders” or “uber shaders”. Unity’s Standard Shader is an example of such a shader.

Using shader variants and keywords

Creating shader variants

To create shader variants, you add one of the following directives to your shader snippet:

  • #pragma multi_compile
  • #pragma multi_compile_local
  • #pragma shader_feature
  • #pragma shader_feature_local

You can use these directives in regular shaders (including surface shaders).

Unity then compiles the same shader code multiple times with different preprocessor directives.

Enabling and disabling shader keywords

To enable and disable shader keywords, use the following APIs:

When you enable or disable a keyword, Unity uses the appropriate variant.

multi\_compile 작동 방식

예제 지시문:

#pragma multi_compile FANCY_STUFF_OFF FANCY_STUFF_ON

이 예제 지시문은 두 가지 셰이더 배리언트를 생성합니다. 하나는 FANCY_STUFF_OFF가 정의되고 다른 하나는 FANCY_STUFF_ON이 정의되어 있습니다. Unity는 머티리얼 또는 전역 셰이더 키워드에 따라 런타임 시점에 둘 중 하나를 활성화합니다. 두 키워드가 모두 활성화되지 않는 경우 Unity는 전자(이 예제에서는 FANCY_STUFF_OFF)를 사용합니다.

multi_compile 줄에 두 개 이상의 키워드를 추가할 수 있습니다. 예를 들면 다음과 같습니다.

#pragma multi_compile SIMPLE_SHADING BETTER_SHADING GOOD_SHADING BEST_SHADING

이 예제 지시문은 네 가지 셰이더 배리언트, 즉 SIMPLE_SHADING, BETTER_SHADING, GOOD_SHADING, 및 BEST_SHADING을 생성합니다.

아무 전처리기 매크로도 정의되지 않은 셰이더 배리언트를 생성하려면 밑줄(__)만 포함하는 이름을 추가하십시오. 프로젝트에서 사용할 수 있는 키워드 개수에는 제한이 있으며, 이렇게 하면 두 개의 키워드를 사용하는 것을 피할 수 있습니다(키워드 제한의 이후 섹션 참조). 예를 들면 다음과 같습니다.

#pragma multi_compile __ FOO_ON

이 지시문은 두 개의 셰이더 배리언트를 생성합니다. 하나는 아무것도 정의되어 있지 않고(__) 다른 하나는 FOO_ON이 정의되어 있습니다.

shader\feature와 multi\compile의 차이

shader_featuremulti_compile과 매우 유사합니다. 유일한 차이는 Unity가 shader_feature 셰이더의 미사용 배리언트를 최종 빌드에 포함하지 않는다는 점입니다. 이러한 이유로 머티리얼에서 설정된 키워드에는 shader_feature를 사용하고 코드에서 전역으로 설정된 키워드에는 multi_compile을 사용하는 것이 좋습니다.

또한 키워드가 하나뿐인 짧은 표기도 있습니다.

#pragma shader_feature FANCY_STUFF

이 표기는 #pragma shader_feature _ FANCY_STUFF의 단축키로, 두 셰이더 배리언트로 확장됩니다(첫 번째는 정의가 없고 두 번째는 정의가 있음).

여러 multi\_compile 줄 결합

multi_compile 줄을 제공하는 경우 Unity는 줄의 모든 가능한 조합에 대한 결과 셰이더를 컴파일합니다. 예를 들어 다음과 같습니다.

#pragma multi_compile A B C
#pragma multi_compile D E

첫 번째 줄에서 세 가지 배리언트가 생성되고 두 번째 줄에서 두 가지 배리언트가 생성되어 총 여섯 가지의 셰이더 배리언트(A+D, B+D, C+D, A+E, B+E, C+E)가 생성됩니다.

multi_compile 줄이 셰이더 “기능” 하나를 제어한다고 생각하십시오. 이 방법을 사용하면 전체 셰이더 배리언트 수가 매우 빠르게 증가합니다. 예를 들어 옵션이 각각 두 개인 multi_compile 기능이 열 개가 있으면 셰이더 배리언트가 총 1,024개 생성됩니다.

키워드 제한

셰이더 배리언트를 사용할 때는 Unity에서 키워드가 256개로 제한되고 이 중 약 60개가 내부적으로 사용되므로 실제로 사용 가능한 키워드는 더 적습니다. 또한 키워드는 Unity 프로젝트 전반에 걸쳐 전역으로 활성화되므로 여러 셰이더에 여러 키워드를 정의하는 경우에는 제한을 초과하지 않도록 주의해야 합니다.

로컬 키워드

shader_featuremulti_compile 의 주요 단점으로는 이 둘에서 정의된 모든 키워드가 Unity의 전역 키워드 개수 제한(256개 전역 키워드 + 64개 로컬)에 포함된다는 것을 들 수 있습니다. 이 문제를 피하려면 다른 셰이더 배리언트 지시문, 즉 shader_feature_localmulti_compile_local 을 사용할 수 있습니다.

  • shader_feature_local: shader_feature 와 유사하지만 열거된 키워드가 로컬입니다.
  • multi_compile_local: multi_compile 과 유사하지만 열거된 키워드가 로컬입니다.

로컬 지시문은 해당 지시문 아래에 정의된 키워드를 전체 프로젝트에 적용하는 대신, 해당 셰이더에 보관합니다. 이러한 이유로 전역 키워드가 아니라 로컬 키워드를 사용해야 합니다. 단, 전역 API를 통해 특정 키워드를 활성화하려는 경우는 예외입니다.

로컬 키워드 사용을 시작하면 성능상의 변화를 볼 수 있지만, 성능 차이는 프로젝트의 설정 방식에 따라 다릅니다. 셰이더당 로컬 및 전역 키워드의 총 개수는 성능에 영향을 미칩니다. 로컬 키워드는 많이 사용하고 전역 키워드는 적게 사용하여 셰이더당 총 키워드 개수를 줄이는 것이 이상적인 설정입니다.

동일한 이름의 전역 키워드와 로컬 키워드가 있는 경우 Unity는 로컬 키워드에 더 우선 순위를 둡니다.

한계

  • 전역 키워드를 변경하는 API가 포함된 로컬 키워드(예: Shader.EnableKeyword 또는 CommandBuffer.EnableShaderKeyword)는 사용할 수 없습니다.

  • 셰이더당 최대 64개의 고유 로컬 키워드를 사용할 수 있습니다.

  • 머티리얼에 활성화된 로컬 키워드가 있고 해당 셰이더가 더 이상 선언되지 않는 셰이더로 변경되면 Unity는 새로운 전역 키워드를 생성합니다.

예제

# pragma multi_compile_local __ FOO_ON

이 지시문은 두 개의 셰이더 배리언트를 생성합니다. 하나는 아무것도 정의되어 있지 않고(__) 다른 하나는 FOO_ON이 로컬 키워드로 정의되어 있습니다.

로컬 키워드를 활성화하기 위한 프로세스는 전역 키워드와 동일합니다.

public Material mat;
Private void Start()
{
    mat.EnableKeyword("FOO_ON");
}

빌트인 multi\_compile 단축키

여러 셰이더 배리언트를 컴파일하는 데 사용되는 “단축키” 표기가 몇 개 있으며, 주로 Unity의 다양한 광원, 그림자, 라이트맵 타입을 처리하는 데 사용됩니다. 자세한 내용은 렌더링 파이프라인 문서를 참조하십시오.

  • multi_compile_fwdbasePassType.ForwardBase에 필요한 모든 배리언트를 컴파일합니다. 배리언트는 다양한 라이트맵 타입을 처리하며, 주요 방향 광원의 섀도우를 활성화하거나 비활성화합니다.
  • multi_compile_fwdaddPassType.ForwardAdd에 대한 배리언트를 컴파일합니다. 방향 광원, 스폿 광원 또는 점 광원 타입과 쿠키 텍스처가 있는 각각의 배리언트를 처리하도록 배리언트를 컴파일합니다.
  • multi_compile_fwdadd_fullshadows - multi_compile_fwdadd와 동일하지만, 광원에 실시간 섀도우가 적용되는 기능도 포함합니다.
  • multi_compile_fog는 다양한 안개 타입(off/linear/exp/exp2)을 처리하는 여러 배리언트로 확장됩니다.

대부분의 빌트인 단축키는 많은 셰이더 배리언트를 생성합니다. 프로젝트에 필요하지 않은 경우에는 #pragma skip_variants를 사용하여 그중 일부에 대한 컴파일을 건너뛸 수 있습니다. 예를 들면 다음과 같습니다.

# pragma multi_compile_fwdadd
# pragma skip_variants POINT POINT_COOKIE

이 지시문은 POINT 또는 POINT_COOKIE가 포함된 모든 배리언트를 건너뜁니다.

Graphics tiers and shader variants

At runtime, Unity examines the capabilities of the GPU and determines which graphics tier it corresponds to. In the Built-in Render Pipeline, you can automatically create a set of shader variants for each graphics tier; to do this, usethe #pragma hardware_tier_variants directive.

This feature is compatible with the Built-in Render Pipeline only. It is not compatible with the Universal Render Pipeline (URP), the High Definition Render Pipeline (HDRP), or custom Scriptable Render Pipelines.

To enable this feature, add #pragma hardware_tier_variants renderer, where renderer is a valid rendering platform, like this:

#pragma hardware_tier_variants gles3

Unity generates three shader variants for each shader, in addition to any other keywords. Each generated variant has one of the following defines, which correspond to the same numbered values of the GraphicsTier enum:

UNITY_HARDWARE_TIER1
UNITY_HARDWARE_TIER2
UNITY_HARDWARE_TIER3

You can use these to write conditional fallbacks or extra features for lower or higher-end hardware.

When Unity first loads your application, it detects the GraphicsTier and stores the result in Graphics.activeTier. To override the value of Graphics.activeTier, set it directly. Note that you must do this before Unity loads any shaders that you want to vary. A good place to set this value is in a pre-load Scene before you load your main Scene.

To help keep the impact of these variants as small as possible, Unity only loads one set of shaders in the player. Shaders that are identical (for example, if you only write a specialised version for TIER1, but all others are the same) do not take up any extra space on disk.

To test the tiers in the Unity Editor, navigate to to Edit > Graphics tier and choose the tier that you want the Unity Editor to use.

Note that graphics tiers are not related to Quality settings. They are in addition to this setting.

Per-platform shader define settings and graphics tier variants

In the Built-in Render Pipeline, you can use the EditorGraphicsSettings.SetShaderSettingsForPlatform API to override Unity’s internal #defines for a given BuildTarget and GraphicsTier.

This feature is compatible with the Built-in Render Pipeline only. It is not compatible with the Universal Render Pipeline (URP), the High Definition Render Pipeline (HDRP), or custom Scriptable Render Pipelines.

Note that if you provide different TierSettings values for the different GraphicsTier of a given BuildTarget, Unity generates tier variants for the shader even if you do not add #pragma hardware_tier_variants to your shader code.

참고 항목

빌트인 셰이더 변수
GLSL 셰이더 프로그램