Unity 셰이더 배리언트 최적화 및 문제 해결 팁

ATTILIO CAROTENUTO / UNITYTechnical Lead
May 28, 2024|15 분
Unity 셰이더 배리언트 최적화 및 문제 해결 팁
이 웹페이지는 이해를 돕기 위해 기계 번역으로 제공됩니다. 기계 번역으로 제공되는 콘텐츠에 대한 정확도나 신뢰도는 보장되지 않습니다. 번역된 콘텐츠의 정확도에 관해 의문이 있는 경우 웹페이지의 공식 영어 원문을 참고해 주시기 바랍니다.

Unity에서 셰이더를 작성할 때, 우리는 편리하게 여러 기능, 패스 및 분기 논리를 단일 소스 파일에 포함할 수 있는 능력을 가지고 있습니다. 빌드 시 셰이더 소스 파일은 하나 이상의 배리언트를 포함하는 셰이더 프로그램으로 컴파일됩니다. 배리언트는 단일 조건 집합을 따르는 해당 셰이더의 한 버전으로, 대부분의 경우 정적 분기형 조건부가 없는 선형적 실행 경로를 생성합니다.

모든 분기형 경로를 하나의 셰이더에 유지하는 대신 배리언트를 사용하는 이유는, 예측 가능하며 항상 동일한 경로를 따르는 코드를 GPU에서 병렬화하여 처리량을 늘릴 수 있기 때문입니다. 컴파일된 셰이더 프로그램에 조건부가 존재할 경우 GPU가 예측 작업을 수행하거나 다른 경로가 완료될 때까지 대기하는 등의 과정에서 리소스가 소비되므로 비효율적이라고 할 수 있습니다.

배리언트는 동적 브랜칭에 비해 GPU 성능을 크게 높여 주지만 몇 가지 단점도 있습니다. 배리언트의 수가 늘어날수록 빌드 시간도 길어지며, 때로는 빌드당 몇 시간씩 걸리기도 합니다. 또한 셰이더를 로드하고 프리워밍(Prewarming)하는 시간이 늘어나기 때문에 게임 부팅에도 더 오랜 시간이 걸립니다. 마지막으로, 배리언트를 적절히 관리하지 않으면 셰이더의 런타임 메모리 사용량이 크게 증가하여 1GB를 초과할 때도 있습니다.

생성되는 배리언트의 수는 정의된 키워드 및 프로퍼티, 품질 설정, 그래픽스 티어, 활성화된 그래픽스 API, 포스트 프로세싱 효과, 활성 렌더링 파이프라인, 조명 및 안개 모드, XR 활성화 여부와 같은 다양한 요인에 따라 증가합니다. 많은 수의 배리언트를 생성하는 셰이더를 흔히 ‘우버 셰이더’라고 합니다. 런타임에 Unity는 필요한 설정 및 키워드와 일치하는 배리언트를 로드하는데, 이 내용은 나중에 자세히 다루겠습니다.

특히 100개가 넘는 키워드를 갖는 셰이더로 인해 사실상 관리가 불가능한 수준의 배리언트가 생성되는 셰이더 배리언트 폭발이라 불리는 현상이 적잖이 발생한다는 점을 고려하면 이는 상당한 영향을 미칠 수 있습니다. 필터링을 적용하지 않은 초기 배리언트 공간이 수백만 개에 이르는 셰이더도 심심찮게 볼 수 있습니다.

Unity는 이를 완화하고자 몇 번의 필터링 패스를 통해 배리언트가 생성되는 양을 줄이고자 합니다. 예를 들어 XR이 활성화되지 않았다면 그에 필요한 배리언트는 일반적으로 스트리핑됩니다. 그런 다음 Unity는 조명 모드, 안개 등 씬에서 실제로 사용되는 기능들을 고려합니다. 개발자와 아티스트가 일견 문제가 없어 보이는 변경 사항을 적용하더라도 셰이더 배리언트의 숫자가 상당히 증가할 수 있기에, 배포 파이프라인에 별도의 안전 장치를 추가하지 않는 한 스트리핑할 수 있는 배리언트를 명확히 찾아내기는 쉽지 않습니다.

이 프로세스는 도움이 되지만 무조건 완벽하다고 할 수는 없습니다. 게임의 시각적 품질에 영향을 주지 않으면서도 최대한 많은 배리언트를 스트리핑하는 방법은 이 외에도 다양하게 존재합니다.

여기에서는 배리언트를 처리하는 방법, 배리언트가 생성되는 출처를 파악하는 방법, 배리언트를 줄이는 효과적인 방법에 관하여 몇 가지 실용적인 팁을 공유하고자 합니다. 프로젝트 빌드 시간과 메모리 사용량을 크게 줄여 보세요.

셰이더 변형을 제거하는 방법에 대한 자세한 내용은 Unity 매뉴얼의 '셰이더 변형 줄이기'를 참조하십시오.

키워드가 배리언트에 미치는 영향 이해

셰이더 배리언트는 여러 요인에 의해 생성되지만, 셰이더에 사용된 shader_featuremulti_compile 키워드의 모든 가능한 조합을 기반으로 생성되기도 합니다. multi_compile로 표시된 키워드는 항상 빌드에 포함되며, shader_feature로 표시된 키워드는 프로젝트의 머티리얼에서 참조하는 경우 포함됩니다. 그렇기에 가급적이면 shader_feature를 사용해야 합니다.

셰이더에 어떤 키워드가 정의되어 있는지 확인하려면 셰이더를 선택해서 인스펙터(Inspector)를 살펴보면 됩니다.

셰이더 인스펙터 뷰에 표시된 각종 키워드

보시는 것처럼 키워드는 Overridable과 Not overridable로 분류됩니다. 글로벌 범위를 갖는 로컬 키워드(실제 셰이더 파일에 정의된 키워드)는 이름이 동일한 글로벌 셰이더 키워드로 오버라이드할 수 있습니다. 반면 로컬 범위에서 정의된 로컬 키워드(multi_compile_local 또는 shader_feature_local 사용)는 오버라이드할 수 없기 때문에 그 아래의 Not overridable 섹션에 표시됩니다. 글로벌 셰이더 키워드는 Unity 엔진에서 제공하며 오버라이드가 가능합니다. 빌드 프로세스의 어느 시점에서나 추가할 수 있으므로 일부 글로벌 키워드는 목록에 표시되지 않을 수도 있습니다.

키워드는 동일한 지시문 내에서 ‘세트’라고 하는 상호 배타적인 그룹으로 정의할 수 있습니다. 이렇게 하면 서로 다른 두 가지 유형의 조명 또는 안개처럼 동시에 활성화될 수 없는 키워드 조합에 대한 배리언트가 생성되는 것을 방지할 수 있습니다.

#pragma shader_feature LIGHT_LOW_Q LIGHT_HIGH_Q

플랫폼당 키워드 수를 줄이려면, 관련 플랫폼에 대해서만 정의하기 위해 전처리기 매크로를 사용할 수 있습니다. 예를 들어:

#ifdef SHADER_API_METAL
   #pragma shader_feature IOS_FOG_FEATURE
#else
   #pragma shader_feature BASE_FOG_FEATURE
#endif

매크로를 사용하는 이러한 표현식은 다른 빌드 타겟과도 관련이 있는 다른 키워드나 기능에 의존할 수 없습니다.

또한 키워드를 특정 패스로 제한하여 가능한 조합의 수를 줄일 수도 있습니다. 지시문에 다음 접미사 중 하나를 추가하면 됩니다.

  • _vertex
  • _fragment
  • _hull
  • _domain
  • _geometry
  • _raytracing

예를 들면 다음과 같습니다.

#pragma shader_feature_fragment FRAG_FEATURE_1 FRAG_FEATURE_2

이는 사용 중인 렌더러에 따라 다르게 동작할 수 있습니다. 예를 들어, OpenGL, OpenGL ES 및 Vulkan에서는 접미사가 무시됩니다.

지시문 #pragma skip_variants를 사용하면 특정 셰이더의 배리언트를 생성할 때 제외할 키워드를 정의할 수 있습니다. 그러면 플레이어 빌드를 만들 때 해당 키워드가 포함된 셰이더의 모든 셰이더 배리언트가 배제됩니다.

#pragma dynamic_branch 지시문을 사용하여 키워드를 정의할 수도 있는데, 이 경우 Unity는 동적 브랜칭에 의존하며 해당 키워드에 대한 배리언트를 생성하지 않게 됩니다. 이렇게 하면 생성되는 배리언트의 양이 줄어들지만, 셰이더와 게임 콘텐츠에 따라 GPU 성능도 저하될 수 있으니 적절한 프로파일링을 통해 확인하는 것이 좋습니다.

셰이더 키워드에 대한 자세한 내용은 Unity 매뉴얼의 '키워드를 사용하여 셰이더 작동 방식 변경'을 참조하십시오.

생성된 셰이더 코드 확인

일반적으로 셰이더 배리언트는 게임을 실제로 빌드하기 전까지 컴파일되지 않습니다. 이 옵션을 사용하면 특정 빌드 플랫폼 또는 그래픽스 API에 대하여 생성된 셰이더 배리언트를 확인할 수 있습니다. 그 결과 오류를 미리 확인할 수 있게 됩니다. 또한 생성된 코드를 PVRShaderEditor와 같은 GPU 셰이더 성능 분석 툴에 붙여넣어 추가적인 최적화를 수행할 수 있습니다.

셰이더 인스펙터 뷰에 표시된 각종 키워드

하단에는 스크립터블 스트리핑이 적용되지 않은 상태에서 현재 열린 씬에 존재하는 머티리얼을 기준으로 몇 개의 배리언트가 존재하는지를 나타내는 항목이 있습니다. Show 버튼을 누르면 버텍스 스테이지 배리언트의 수를 포함하여 다양한 플랫폼에서 사용되거나 스트리핑된 키워드에 대한 추가 디버그 정보를 담고 있는 임시 파일이 열립니다.

Preprocess only 체크박스를 선택하면 컴파일된 셰이더 코드와 전처리된 셰이더 소스를 전환하면서 신속하고 편리하게 디버깅할 수 있습니다.

빌트인 렌더 파이프라인을 사용하고 표면 셰이더로 작업하는 경우, 빌드 과정에서 Unity가 단순화된 셰이더 소스를 대체하는 데 사용할 생성 코드를 확인할 수 있는 옵션이 있습니다. 이후 결과물을 수정하고 싶다면 셰이더 소스를 생성된 코드로 대체할 수 있습니다.

자세한 내용은 Unity 매뉴얼의 '셰이더 변형 수 확인'을 참조하십시오.

Surface shader의 Show generated code 옵션 대체 텍스트: Surface shader의 Show generated code 옵션 활성화
빌드 시 생성되는 배리언트 파악

게임을 빌드할 때 Unity는 셰이더의 기능, 엔진 설정 및 기타 요소의 가능한 모든 조합을 기반으로 각 셰이더의 배리언트 공간을 결정합니다. 이후 해당 조합들은 프리 프로세서로 전달되어 여러 번의 스트리핑 패스를 거칩니다. 이 과정은 아래와 같이 IPreprocessShaders 콜백을 사용해 커스텀 로직을 생성하여 빌드에서 더 많은 배리언트를 스트리핑하는 방식으로 확장할 수 있습니다.

Always-included shaders 목록(Project Settings > Graphics)에 포함된 셰이더의 모든 배리언트는 빌드에 포함됩니다. 따라서 이러한 셰이더는 많은 수의 배리언트를 생성할 수 있으므로 꼭 필요한 경우에만 사용하는 것이 좋습니다.

마지막으로 빌드 파이프라인은 중복 제거라는 프로세스를 거쳐 동일한 패스 내에서 동일한 배리언트를 식별한 다음 이들이 동일한 바이트코드를 가리키도록 합니다. 이렇게 하면 셰이더 파일이 디스크에서 차지하는 용량을 줄일 수 있습니다. 하지만 동일한 배리언트는 여전히 빌드 타임, 로딩 시간, 런타임 메모리 사용량에 부정적인 영향을 미치므로 이는 적절한 배리언트 스트리핑의 대안이 될 수 없습니다.

빌드를 완료한 후에는 Editor.log 파일을 보면서 빌드에 포함된 셰이더 배리언트에 관하여 몇 가지 유용한 정보를 수집할 수 있습니다. ‘Compiling shader’와 셰이더 이름으로 로그 파일을 검색하면 다음과 같은 내용을 확인할 수 있습니다.

Compiling shader "GameShaders/MyShader" pass "Pass 1" (vp)
	Full variant space:     	608
	After settings filtering:   608
	After built-in stripping:   528
	After scriptable stripping: 528
	Processed in 0.00 seconds
	starting compilation...
	finished in 0.02 seconds. Local cache hits 528 (0.16s CPU time), remote cache hits 0 (0.00s CPU time), compiled 0 variants (0.00s CPU time), skipped 0 variants

XR이 활성화된 프로젝트와 같은 경우에는 설정 필터링 단계 이후에 배리언트의 수가 늘어나는 것을 볼 수 있습니다.

게임이 여러 그래픽스 API를 지원할 경우, 지원되는 각 렌더러에 대한 정보도 다음과 같이 확인할 수 있습니다.

Serialized binary data for shader GameShaders/MyShader in 0.00s
	gles3 (total internal programs: 290, unique: 193)
	vulkan (total internal programs: 290, unique: 193)

마지막으로 특정 그래픽스 API에 대한 셰이더가 디스크에서 차지하는 최종적인 크기를 표시하는 압축 로그를 다음과 같이 확인할 수 있습니다.

Compressed shader 'GameShaders/MyShader' on vulkan from 1.35MB to 0.19MB

URP(유니버설 렌더 파이프라인)를 사용하는 경우 로그를 SRP 셰이더에서만 생성할지, 모든 셰이더에서 생성할지, 아니면 로그를 비활성화할지 선택할 수 있습니다. Project Settings > Graphics > URP Global Settings에서 로그 레벨을 선택하면 됩니다.

URP Global Settings에서 로그 레벨 설정

또한 그 아래의 Export Shader Variants 옵션을 선택하면 셰이더 배리언트 컴파일 보고서가 포함된 JSON 파일이 빌드 이후에 생성됩니다. 이 기능은 Unity 2022.2 이상에서 사용할 수 있습니다.

런타임에 사용되는 배리언트 파악

런타임에 실제로 어떤 셰이더가 GPU에 컴파일되는지 파악하려면 Project Settings > Graphics에서 Log Shader Compilation 옵션을 활성화하면 됩니다.

Graphics 프로젝트 설정에서 Log Shader Compilation 옵션 활성화

이렇게 하면 플레이 도중 셰이더가 컴파일될 때마다 플레이어 로그에 해당 내용이 출력됩니다. 이는 툴팁에 설명된 것처럼 개발 빌드 및 디버그 모드에서만 작동합니다.

형식은 다음과 같습니다.

Compiled Shader: Folder/ShaderName, pass: PASS_NAME, stage: STAGE_NAME, keywords ACTIVE_KEYWORD_1 ACTIVE_KEYWORD_2

Android와 같은 일부 플랫폼은 컴파일된 셰이더를 캐시에 저장한다는 점에 유의하세요. 따라서 컴파일된 셰이더를 모두 파악하려면 테스트 패스를 수행하기 전에 게임을 삭제했다가 재설치해야 할 수 있습니다.

마지막으로 Memory Profiler 패키지를 사용하면 실행 중인 게임의 상태를 파악하여 현재 메모리에 로드된 셰이더와 그 크기를 확인할 수 있습니다. 보통 크기순으로 목록을 정렬하면 어떤 셰이더가 가장 많은 배리언트를 발생시키며 최적화할 필요가 있는지 알 수 있습니다.

Memory Profiler에 표시된 셰이더 정보
그래픽 설정에 따른 스트리핑

스트리핑 패스의 일환으로, Unity는 게임에서 사용되지 않는 그래픽스 기능과 관련된 셰이더 배리언트를 제거합니다. 빌트인 렌더 파이프라인 또는 URP를 사용하는 경우 해당 프로세스는 약간 변경됩니다.

이를 정의하려면 Project Settings > Graphics로 이동합니다. 여기에서 빌트인 렌더 파이프라인을 사용하는 동안 게임이 지원하는 Lightmap Modes 및 Fog Modes를 선택할 수 있습니다.

그래픽스 셰이더 스트리핑 설정

이를 Automatic으로 설정하면 Unity가 빌드에 포함된 씬에 따라 스트리핑할 배리언트를 결정합니다.

어떤 기능을 사용하고 있는지 확실히 알기 어려우면 Import From Current Scene 버튼을 클릭하여 Unity가 필요한 기능을 파악하도록 할 수도 있습니다. 물론 이 옵션은 모든 씬이 동일한 설정을 사용하는 경우에만 유용하므로 이 옵션을 사용할 때는 대표 씬을 선택해야 합니다.

URP를 사용하는 경우 상기 옵션의 일부는 숨겨집니다. 대신 Pipeline Settings 에셋에서 게임에 필요한 기능을 직접 정의할 수 있습니다.

예를 들어 터레인 구멍을 비활성화하면 모든 터레인 구멍 셰이더 배리언트가 스트리핑되며 빌드 시간도 단축됩니다.

URP를 사용하면 게임에 포함할 기능을 더욱 세밀하게 제어할 수 있으므로, 사용하지 않는 배리언트를 줄여 빌드를 더욱 최적화할 수 있습니다.

그래픽스 티어에 따른 스트리핑

참고: 이는 빌트인 렌더 파이프라인을 사용할 때만 해당됩니다. URP와 같은 스크립터블 렌더 파이프라인을 사용할 때는 이러한 설정이 무시됩니다.

그래픽스 티어는 게임을 실행하는 하드웨어에 따라 다른 그래픽스 설정을 적용하는 데 사용됩니다(품질 설정과는 다름). 게임이 시작되면 Unity는 하드웨어 성능, 그래픽스 API 및 기타 요인에 따라 기기 그래픽 티어를 결정합니다.

이는 Project Settings > Graphics > Tier Settings에서 설정할 수 있습니다.

그래픽스 티어 설정

Unity는 그래픽스 티어를 바탕으로 모든 셰이더에 아래의 세 가지 키워드를 추가합니다.

UNITY_HARDWARE_TIER1

UNITY_HARDWARE_TIER2

UNITY_HARDWARE_TIER3

이후 정의된 각 그래픽스 티어에 대한 셰이더 배리언트를 생성합니다. 그래픽스 티어를 사용하지 않으며 그와 관련된 배리언트를 배제하고 싶다면 Unity가 해당 배리언트를 무시할 수 있도록 모든 그래픽스 티어를 정확히 동일한 설정으로 구성해야 합니다.

앞서 설명했던 것처럼 Unity는 동일한 배리언트로 인한 중복을 제거하려 합니다. 따라서 예를 들어 세 개의 티어 중 두 개 티어의 설정이 동일하다면 모든 배리언트가 여전히 생성되지만 디스크에서 차지하는 용량은 줄어들게 됩니다. 필요하다면 아래와 같이 hardware_tier_variants를 사용해서 Unity가 주어진 셰이더와 그래픽스 렌더러 API에 대한 티어 배리언트를 생성하게 할 수 있습니다.

// Direct3D 11/12
#pragma hardware_tier_variants d3d11 

자세한 내용은 Unity 매뉴얼의 '내장 렌더 파이프라인의 그래픽 계층'을 참조하십시오.

그래픽스 API 기반 스트리핑

Unity는 빌드에 포함된 각 그래픽스 API에 대해 하나의 셰이더 배리언트 세트를 컴파일합니다. 그러므로 때에 따라서는 API를 직접 선택하여 필요 없는 API를 배제하는 것이 좋습니다.

이렇게 하려면 Project Settings > Player로 이동합니다. 기본적으로는 Auto Graphics API가 선택되어 있는데, 이 경우 Unity는 빌트인 그래픽스 API 세트를 포함한 다음 기기의 성능에 따라서 그 중 하나를 런타임에 선택합니다. 예를 들어 Android의 경우 Unity는 먼저 Vulkan을 사용하려고 시도하며, 기기가 이를 지원하지 않으면 GLES3.2, GLES3.1, GLES3.0 중 하나로 폴백합니다(다만 서로 다른 GLES 버전에서도 배리언트는 동일하게 유지됨).

대신 해당하는 플랫폼에 대해 Auto Graphics API를 비활성화하고 포함할 API를 직접 선택하세요. 그러면 Unity가 목록의 첫 번째 항목에 우선순위를 부여합니다.

Auto Graphics API를 비활성화하고 원하는 API 선택

다만 이렇게 설정할 경우 게임을 지원하는 기기의 수가 제한될 수 있으니, 주의하여 설정하고 다양한 기기에서 테스트해 볼 필요가 있습니다.

엄격한 셰이더 배리언트 매칭

일반적으로 런타임 시 Unity는 요청된 키워드 세트와 정확히 일치하는 배리언트가 사용 불가하거나 플레이어 빌드에서 스트리핑된 경우 가장 가까운 배리언트를 로드하려고 시도합니다. 이는 편리하지만 셰이더 키워드 설정에 존재하는 잠재적인 문제를 숨기기도 합니다.

Unity 2022.3부터는 Project Settings > Player에서 Strict shader variant matching을 선택하여 Unity가 필요한 로컬 및 글로벌 키워드 조합과 정확히 일치하는 배리언트만 로드하게 만들 수 있습니다.

Project Settings에서 Strict shader variant matching 활성화

정확히 일치하는 배리언트를 찾지 못할 경우 Unity는 오류 셰이더를 사용하며, 콘솔에 해당 셰이더, 서브셰이더 인덱스, 실제 패스, 요청된 키워드가 포함된 오류가 출력됩니다. 이는 실제로 필요하지만 누락된 배리언트를 추적해야 할 때 매우 유용합니다. 스트리핑과 마찬가지로 이는 플레이어에서만 작동하며 에디터에는 영향을 미치지 않습니다.

사용한 배리언트를 Shader Variants Collection으로 익스포트

에디터에서 게임을 플레이하는 동안 Unity는 씬에서 현재 사용 중인 셰이더와 배리언트를 추적하여 이를 컬렉션으로 익스포트할 수 있게 합니다. 이렇게 하려면 Project Settings > Graphics로 이동합니다. 그러면 하단의 Shader Loading 섹션에서 현재 활성 상태로 추적되는 셰이더의 수를 확인할 수 있습니다.

먼저 Clear 버튼을 눌러 샘플의 정확도를 높인 다음 플레이 모드로 들어가 씬을 둘러보면서 특정 셰이더를 사용하는 모든 게임 요소를 확인하세요. 그러면 추적 카운터 값이 증가합니다. 이후 ‘Save to asset...’ 버튼을 눌러 컬렉션 에셋에 모두 저장합니다.

자세한 내용은 Unity 매뉴얼의 '셰이더 변형 컬렉션 만들기'를 참조하십시오.

Save to asset 버튼

Shader Variants Collection은 셰이더와 관련 배리언트의 목록이 포함된 에셋입니다. 일반적으로 빌드에 포함할 배리언트를 미리 정의하고 셰이더를 프리워밍하는 데 사용됩니다.

Shader Variants Collection에 셰이더 추가

일부 프로젝트에서는 게임의 모든 레벨에서 이 과정을 실행하여 레벨별로 하나의 컬렉션을 저장한 다음, IPreprocessShaders 스크립트를 사용하여 어떤 컬렉션에도 존재하지 않는 배리언트를 모두 스트리핑하기도 합니다(다음 섹션에서 설명). 편리한 방법이기는 하지만 경험상 오류를 일으키는 경우가 잦았습니다. 한 번의 플레이에서 필요한 배리언트를 모두 접하기는 어려우며, 일부 기능은 특정한 경우에만 기기에 로드되는 경우도 있어 컬렉션의 정확도가 떨어지기 때문입니다. 게임이 변경되어 각 레벨에 새로운 요소가 추가되거나 머티리얼이 바뀌면 컬렉션을 업데이트해야 합니다. 따라서 이 방법은 빌드 파이프라인에 직접 통합하기보다는 주로 디버깅 및 조사 목적으로 사용하는 것이 좋습니다.

자세한 내용은 Unity 매뉴얼의 '셰이더 변형 컬렉션 만들기'를 참조하십시오.


스크립터블 셰이더 배리언트 스트리핑

셰이더가 게임 빌드에 컴파일될 때마다 Unity는 콜백을 디스패치합니다. 이는 플레이어와 에셋 번들 빌드 모두에서 발생합니다. IPreprocessShaders.OnProcessShader 및 IPreprocessComputeShaders.OnProcessComputeShader(컴퓨트 셰이더의 경우)를 사용하여 이를 편리하게 감지한 다음, 커스텀 로직을 추가하여 불필요한 배리언트를 스트리핑할 수 있습니다. 이렇게 하면 빌드 시간, 빌드 크기, 빌드에 포함되는 배리언트의 총 수를 크게 줄일 수 있습니다.

이를 위해서는 IPreprocessShaders 인터페이스를 구현하는 스크립트를 만든 다음 OnProcessShader 내에서 스트리핑 로직을 작성해야 합니다. 예를 들어 다음은 릴리스 빌드에서 DEBUG 셰이더 키워드가 포함된 모든 배리언트를 스트리핑하는 스크립트입니다.

public class StripDebugVariantsPreprocessor : IPreprocessShaders
{
   public int callbackOrder => 0;

   ShaderKeyword keywordToStrip;

   public StripDebugVariantsPreprocessor()
   {
      keywordToStrip = new ShaderKeyword("DEBUG");
   }


   public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> data)
   {
      if (EditorUserBuildSettings.development)
      {
         return;
      }

      for (int i = data.Count - 1; i >= 0; i--)
      {
         if (data[i].shaderKeywordSet.IsEnabled(keywordToStrip))
         {
            data.RemoveAt(i);
         }
      }
   }
}

콜백 순서를 설정하면 먼저 실행할 전처리 스크립트를 정의해 다단계의 스트리핑 패스를 만들 수 있습니다. 이때 우선순위가 낮은 스크립트가 먼저 실행됩니다.

자세한 내용은 Graphics-Shaders 포럼을 참조하세요.

추가 리소스

자세한 내용은 Unity 매뉴얼의 다음 섹션을 참조하십시오:

  • 사용자 정의 셰이더 작성하기
  • 셰이더 변형 줄이기
  • URP에서 셰이더 변형 줄이기