[Gemin/요약]Unity 셰이더 배리언트 최적화 및 문제 해결 팁
셰이더 배리언트 최적화 핵심 방법
1. shader_feature
적극 사용하기
#pragma multi_compile
은 머티리얼에서 사용되지 않아도 모든 조합을 빌드에 포함시키는 경향이 있습니다. 반면, #pragma shader_feature
는 프로젝트 내 머티리얼에서 단 한 번이라도 사용된 조합만 빌드에 포함시킵니다. 따라서 특별한 이유가 없다면 항상 shader_feature
를 우선적으로 사용하는 것이 좋습니다. 이것이 가장 기본적이고 강력한 최적화입니다.
2. 불필요한 조합 명시적으로 제외하기
셰이더 코드 내에서 특정 키워드 조합이 논리적으로 말이 안 되거나 절대 사용되지 않을 경우, #pragma skip_variants
지시어를 사용해 해당 조합은 만들지 말라고 명시할 수 있습니다. 예를 들어, WET_EFFECT
(젖음 효과)와 ON_FIRE
(불타는 효과) 키워드가 동시에 켜지는 경우는 없다고 선언하는 것입니다.
3. 동적 분기(Dynamic Branching) 활용하기
성능이 허락하는 최신 GPU에서는 여러 배리언트를 만드는 대신, 셰이더 코드 안에 if
문을 사용하여 동적으로 코드를 분기하는 것이 더 효율적일 수 있습니다. 이렇게 하면 **하나의 배리언트(하나의 도장)**가 여러 상황을 데이터(잉크)에 따라 다르게 처리할 수 있습니다. 다만, 분기문은 성능 비용이 발생할 수 있어 신중하게 사용해야 합니다.
4. ShaderVariantCollection으로 필요한 배리언트 관리하기
이것은 "우리 게임에서 필요한 배리언트는 이것들이니, 이것들만 확실히 빌드에 포함해 주세요"라고 명시하는 '필수 배리언트 목록' 에셋입니다. 동적으로 생성되는 머티리얼처럼 빌드 시점에서는 파악하기 어려운 배리언트가 누락되지 않도록 보장하면서, 동시에 목록에 없는 것은 빌드에서 제외하도록 유도할 수 있습니다.
5. 스크립터블 스트리핑(Scriptable Stripping)으로 최종 제어하기
가장 강력하고 확실한 방법입니다. IPreprocessShaders
인터페이스를 사용한 C# 스크립트를 작성하여, Unity가 빌드하려는 모든 배리언트 목록을 직접 확인하고 필요한 것만 남기고 나머지는 전부 제거할 수 있습니다. 게임의 로직을 기반으로 "우리 게임에서는 A맵에서 B옵션을 절대 쓰지 않으니 관련 배리언트는 모두 삭제해" 와 같은 정교한 규칙을 프로그래밍적으로 구현할 수 있습니다.
댓글
댓글 쓰기