셰이더 코드 조각 대부분을 고정시키되 약간 다른 셰이더 “배리언트”가 생성될 수 있게 하면 편리합니다. 일반적으로 “메가 셰이더” 또는 “우버 셰이더”라고 하며, 각 경우마다 다른 프리프로세서 명령으로 셰이더 코드를 여러 번 컴파일할 수 있습니다.
Unity에서는 #pragma multi_compile
또는 #pragma shader_feature
명령을 셰이더 스니핏에 추가하여 이렇게 할 수 있습니다. 표면 셰이더에서도 가능합니다.
런타임 시 적절한 셰이더 배리언트는 머티리얼 키워드(Material.EnableKeyword 및 DisableKeyword) 또는 전역 셰이더 키워드(Shader.EnableKeyword 및 DisableKeyword)에서 선택됩니다.
명령은 다음과 같습니다.
#pragma multi_compile FANCY_STUFF_OFF FANCY_STUFF_ON
하나는 FANCY_STUFF_OFF
가 정의되고 다른 하나는 FANCY_STUFF_ON
이 정의된 두 가지 셰이더 배리언트를 생성합니다. 머티리얼 및 전역 셰이더 키워드에 따라 런타임 시점에 둘 중 하나가 활성화됩니다. 두 키워드가 모두 활성화되지 않는 경우 전자(“off”)가 사용됩니다.
multi\_compile 줄에 키워드가 두 개보다 많을 수 있습니다. 예를 들어, 다음은 네 가지 셰이더 배리언트를 생성합니다.
#pragma multi_compile SIMPLE_SHADING BETTER_SHADING GOOD_SHADING BEST_SHADING
모두 밑줄 처리된 이름이 있으면 프리프로세서 매크로가 정의되지 않은 셰이더 배리언트가 생성됩니다. 이 배리언트는 일반적으로 셰이더 기능에 사용하여 키워드 2개를 모두 소진하는 것을 방지합니다(키워드 제한에 대한 아래 참고 사항 참조). 예를 들어, 다음은 셰이더 배리언트를 아무 것도 정의되지 않은 것과 FOO_ON
이 정의된 것을 하나씩 포함해 총 2개 생성하는 명령입니다.
#pragma multi_compile __ FOO_ON
#pragma shader_feature
는 #pragma multi_compile
과 매우 유사하고 shader\feature 셰이더의 사용되지 않는 배리언트가 게임 빌드에 포함되지 않는다는 유일한 차이점이 있습니다. 따라서 shader\feature는 머티리얼에 설정되는 키워드에 가장 적합하고 multi\_compile은 코드에서 전역으로 설정되는 키워드에 적합합니다.
또한 키워드가 하나뿐인 짧은 표기도 있습니다.
#pragma shader_feature FANCY_STUFF
이 표기는 #pragma shader_feature _ FANCY_STUFF
의 단축키로, 두 셰이더 배리언트로 확장됩니다(첫 번째는 정의가 없고 두 번째는 정의가 있음).
여러 multi_compile 줄이 제공될 수 있고, 결과 셰이더가 가능한 모든 줄 조합에 대해 컴파일됩니다.
#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 프로젝트 전반에 걸쳐 전역으로 활성화되므로 여러 셰이더에 여러 키워드가 정의된 경우 제한을 초과하지 않도록 주의해야 합니다.
여러 셰이더 배리언트를 컴파일하는 데 사용되는 “단축키” 표기가 몇 개 있으며, 주로 Unity의 다양한 광원, 섀도우, 라이트맵을 처리하는 데 사용됩니다. 자세한 내용은 렌더링 파이프라인을 참조하십시오.
multi_compile_fwdbase
은 ForwardBase
(포워드 렌더링 베이스) 패스 타입에 필요한 모든 배리언트를 컴파일합니다. 각 배리언트는 다양한 라이트맵 타입과 섀도우가 켜지거나 꺼진 주 방향 광원을 처리합니다.multi_compile_fwdadd
는 ForwardAdd
(포워드 렌더링 추가) 패스 타입의 배리언트를 컴파일합니다. 방형광, 스폿 광원 또는 점 광원 타입과 쿠키 텍스처가 있는 각각의 배리언트를 처리하도록 배리언트를 컴파일합니다.multi_compile_fwdadd_fullshadows
- 위와 동일하지만, 광원이 실시간 섀도우를 표시하는 기능도 포함합니다.multi_compile_fog
는 다양한 안개 타입(off/linear/exp/exp2)을 처리하는 여러 배리언트로 확장됩니다.대부분의 빌트인 단축키를 사용하면 여러 셰이더 배리언트가 생깁니다. #pragma skip_variants
를 사용하여 일부 불필요한 배리언트를 컴파일하지 않아도 됩니다. 예제:
#pragma multi_compile_fwdadd
// will make all variants containing
// "POINT" or "POINT_COOKIE" be skipped
#pragma skip_variants POINT POINT_COOKIE
셰이더 배리언트를 사용하는 일반적인 이유 중 하나는 OpenGL ES 같은 단일 타겟 플랫폼에서 하이엔드 및 로우엔드 하드웨어로 모두 효율적으로 실행할 수 있는 폴백이나 간단한 셰이더를 만들기 위해서입니다. 셰이더 하드웨어 배리언트를 사용하여 각기 다른 레벨의 하드웨어 기능에 특별히 최적화된 여러 베리언트를 제공할 수 있습니다.
셰이더 하드웨어 배리언트 생성을 활성화하려면 #pragma hardware_tier_variants renderer
를 추가합니다. 여기서 renderer
는 셰이더 프로그램 pragma에 사용 가능한 렌더링 플랫폼 중 하나입니다. 이#pragma
로 다른 키워드에 관계없이 셰이더 배리언트가 각 셰이더마다 3개씩 생성됩니다. 각 배리언트에는 다음 중 하나가 정의됩니다.
UNITY_HARDWARE_TIER1
UNITY_HARDWARE_TIER2
UNITY_HARDWARE_TIER3
위 정의를 사용하여 조건부 폴백이나 로우엔드 또는 하이엔드용 추가 기능을 작성할 수 있습니다. 에디터에서 각 티어 간에 전환할 수 있는 그래픽스 에뮬레이션 메뉴를 사용하여 티어를 테스트할 수 있습니다.
플레이어에 셰이더 집합이 하나만 로드되므로 배리언트의 영향을 가능한 한 작게 유지하는 데 도움이 됩니다. 또한, 예를 들어 TIER1에 대해서만 특수 버전을 작성하고 나머지는 모두 동일하게 한 경우처럼 결과적으로 동일한 셰이더는 디스크 공간을 추가로 사용하지 않습니다.
로드 시에 Unity는 사용 중인 GPU를 검사하고 티어 값을 자동으로 인식합니다. GPU가 자동으로 인식되지 않는 경우 디폴트는 가장 높은 티어입니다. Shader.globalShaderHardwareTier
를 설정하여 이 티어 값을 오버라이드할 수 있지만, 배리언트를 생성할 셰이더가 로드되기 전에 이 작업을 수행해야 합니다. 셰이더가 로드된 후에는 이미 배리언트 집합이 선택된 상태이므로 이 값은 영향을 받지 않습니다. 메인 씬을 로드하기 전에 프리로드 씬에서 설정하는 것이 좋습니다.
이런 셰이더 하드웨어 티어는 플레이어의 Quality 설정과 관련이 없고, 전적으로 플레이어를 실행하는 GPU의 상대적인 성능을 통해 인식됩니다.
다양한 하드웨어 티어에 따라 셰이더를 미세 조정하는 작업과 별도로 Unity 내부 정의를 미세 조정해야 할 수 있습니다(예를 들어 모바일에서 캐스캐이드된 섀도우 맵을 적용해야 할 수 있습니다). 이에 대한 자세한 내용은 UnityEditor.Rendering.PlatformShaderSettings 문서에서 확인할 수 있습니다. 이 문서에는 현재 지원되는 피어당 오버라이드 기능의 리스트가 있습니다. UnityEditor.Rendering.EditorGraphicsSettings.SetShaderSettingsForPlatform을 사용하여 플랫폼 셰이더 설정을 플랫폼과 티어별로 미세 조정할 수 있습니다.
다른 티어로 설정된 PlatformShaderSetting
이 동일하지 않으면 #pragma hardware_tier_variants
가 없어도 티어 배리언트가 셰이더에 대해 생성됩니다.