셰이더는 GPU에서 실행되는 소형 프로그램으로 로딩하는 데에는 다소 시간이 소요됩니다. 각각의 GPU 프로그램은 빠르게 로딩되지만, 셰이더는 내부적으로 많은 “배리언트”를 포함하고 있습니다.
예를 들어 스탠다드 셰이더는 완전히 컴파일된 경우 서로 조금씩 다른 수천 개의 GPU 프로그램으로 구성됩니다. 이러한 이유로 다음과 같이 두 개의 잠재적인 문제가 발생합니다.
Unity는 게임 빌드 중에 게임에서 사용되지 않는 몇몇 내부 셰이더 배리언트를 찾아 빌드 데이터에서 제외(“스트리핑”)할 수 있습니다. 빌드 타임 스트리핑은 다음을 제거하기 위해 수행됩니다.
#pragma shader_feature
를 사용하는 셰이더의 경우 Unity는 배리언트가 사용되는지 여부를 자동으로 확인합니다. 빌드의 아무 머티리얼도 배리언트를 사용하지 않는 경우 해당 배리언트는 빌드에 포함되지 않습니다. 내부 셰이더 배리언트 문서를 참조하십시오. 이는 스탠다드 셰이더에서 사용됩니다.위의 조합을 사용하면 셰이더의 데이터 크기가 상당히 줄어듭니다. 예를 들어 완전히 컴파일된 스탠다드 셰이더는 수백 메가바이트를 차지하지만 일반적인 프로젝트에서는 몇 메가바이트만 차지합니다. 또한 애플리케이션 패키징 과정에서 이 용량은 더욱 압축됩니다.
모든 기본 설정에서 Unity는 런타임 시점에 shaderlab 셰이더 오브젝트를 메모리에 로드하지만 실제로 필요하기 전까지는 내부 셰이더 배리언트를 생성하지 않습니다.
즉, 게임 빌드에 포함되는 모든 셰이더 배리언트가 사용될 수도 있지만 필요한 시점 전까지는 메모리나 로드 타임을 요구하지 않습니다. 예를 들어, 셰이더는 항상 배리언트를 포함하여 섀도우가 있는 점 광원을 처리하지만 섀도우가 있는 점 광원을 한 번도 사용하지 않는 경우 이 특정 배리언트가 로드되지 않습니다.
이 기본 동작의 단점은 셰이더 배리언트가 처음으로 필요한 경우 일시적으로 끊김 현상이 발생할 수 있다는 점입니다. 새로운 GPU 프로그램 코드가 그래픽스 드라이버에 로드되어야 하기 때문입니다. 게임플레이 중에는 이런 현상이 발생하지 않아야 하므로 Unity는 이를 해결하기 위해 ShaderVariantCollection 에셋을 지원합니다.
ShaderVariantCollection은 셰이더의 리스트에 해당하는 에셋이며, 각각은 필요할 때까지 기다리는 것이 아니라, 미리 로드할 패스 타입과 셰이더 키워드 조합의 리스트를 포함합니다.
실제로 사용되는 셰이더와 배리언트에 기반하여 이러한 에셋을 생성하는 것을 돕기 위해 에디터는 실제로 사용되는 셰이더와 배리언트를 추적할 수 있습니다. Graphics 창에는 현재 추적되는 셰이더에서 새로운 ShaderVariantCollection을 생성하거나 현재 추적되는 셰이더의 리스트를 지울 수 있는 버튼이 있습니다.
ShaderVariantCollection 에셋을 생성한 다음 이러한 배리언트가 애플리케이션을 로드하는 동안 자동으로 미리 로드하도록 할 수 있습니다. Graphics 창의 Preloaded Shaders 리스트를 사용하면 됩니다. 또는 스크립트에서 개별 셰이더 배리언트 컬렉션을 미리 로드할 수 있습니다.
미리 로드된 셰이더 리스트에는 자주 사용되는 셰이더가 나열됩니다. 이 리스트에 나열된 셰이더 배리언트는 애플리케이션의 전체 사용 기간 동안 메모리에 로드되어 있습니다. 따라서 ShaderVariantCollections 에셋에 다수의 배리언트가 포함된 경우 메모리가 매우 많이 사용될 수 있습니다. 이 문제를 방지하려면 ShaderVariantCollection 에셋을 더 작게 세분화하여 생성하고 스크립트에서 로드해야 합니다. 각 씬마다 사용된 셰이더 배리언트를 기록하고 별도의 ShaderVariantCollections 에셋에 저장하고 씬이 시작될 때 로드하는 등의 방법으로 이를 수행할 수 있습니다.
ShaderVariantCollection 스크립팅 클래스를 참조하십시오.