Version: 2020.1
Asynchronous shader compilation in the Unity Editor
셰이더 작성 시 성능 팁

Optimizing shader variants

셰이더는 GPU에서 실행되는 소형 프로그램으로 로딩하는 데에는 다소 시간이 소요됩니다. 각각의 GPU 프로그램은 빠르게 로딩되지만, 셰이더는 내부적으로 많은 “배리언트”를 포함하고 있습니다.

예를 들어 스탠다드 셰이더는 완전히 컴파일된 경우 서로 조금씩 다른 수천 개의 GPU 프로그램으로 구성됩니다. 이러한 이유로 다음과 같이 두 개의 잠재적인 문제가 발생합니다.

  • 셰이더 배리언트가 다수 생성되는 경우 게임 빌드 시간과 게임 데이터 크기가 증가합니다.
  • Loading large numbers of shader variants at runtime is slow and takes up memory.

Build time stripping

While building the game, Unity can detect that some of the internal shader variants are not used by the game, and exclude (“strip”) them from build data. Build-time stripping is done for:

  • For shaders that use #pragma shader_feature, Unity automatically checks whether variants are used. If none of the Materials in a build use a variant, that variant it is not included into the build. See internal shader variants documentation. The Standard shader uses this.
  • Fog 및 Lightmapping 모드를 취급하는 셰이더 배리언트. 어떠한 씬에서도 사용되지 않는 배리언트는 게임 데이터에 포함하지 않습니다. 이 동작을 오버라이드하려면 Graphics 창을 참조하십시오.
  • You can also manually identify variants and tell Unity to exclude them from a build using using the OnProcessShader API.

위의 조합을 사용하면 셰이더의 데이터 크기가 상당히 줄어듭니다. 예를 들어 완전히 컴파일된 스탠다드 셰이더는 수백 메가바이트를 차지하지만 일반적인 프로젝트에서는 몇 메가바이트만 차지합니다. 또한 애플리케이션 패키징 과정에서 이 용량은 더욱 압축됩니다.

디폴트 Unity 셰이더 로딩 동작

Under all default settings, Unity loads the shaderlab Shader object into memory at runtime, but does not create the internal shader variants until they are actually needed.

This means that all shader variants that are included in the build can still potentially be used, but there’s no memory or load time cost paid until they are needed. For example, a shader might always include a variant to handle point lights with shadows, but if you never end up using a point light with shadows in your game, then there’s no point in loading this particular variant.

One downside of this default behavior, however, is a possible hiccup for when a shader variant is needed for the first time - since a new GPU program code has to be loaded into the graphics driver. This is often undesirable during gameplay, so Unity has ShaderVariantCollection assets to help solve that.

셰이더 배리언트 컬렉션

ShaderVariantCollection is an asset that is basically a list of Shaders, and for each of them, a list of Pass types and shader keyword combinations to load in advance, rather than wait until they are needed.

셰이더 배리언트 컬렉션 인스펙터
셰이더 배리언트 컬렉션 인스펙터

실제로 사용되는 셰이더와 배리언트에 기반하여 이러한 에셋을 생성하는 것을 돕기 위해 에디터는 실제로 사용되는 셰이더와 배리언트를 추적할 수 있습니다. Graphics 창에는 현재 추적되는 셰이더에서 새로운 ShaderVariantCollection을 생성하거나 현재 추적되는 셰이더의 리스트를 지울 수 있는 버튼이 있습니다.

에디터가 사용하는 셰이더에서 ShaderVariantCollection 생성
에디터가 사용하는 셰이더에서 ShaderVariantCollection 생성

ShaderVariantCollection 에셋을 생성한 다음 이러한 배리언트가 애플리케이션을 로드하는 동안 자동으로 미리 로드하도록 할 수 있습니다. Graphics 창의 Preloaded Shaders 리스트를 사용하면 됩니다. 또는 스크립트에서 개별 셰이더 배리언트 컬렉션을 미리 로드할 수 있습니다.

미리 로드된 셰이더 리스트에는 자주 사용되는 셰이더가 나열됩니다. 이 리스트에 나열된 셰이더 배리언트는 애플리케이션의 전체 사용 기간 동안 메모리에 로드되어 있습니다. 따라서 ShaderVariantCollections 에셋에 다수의 배리언트가 포함된 경우 메모리가 매우 많이 사용될 수 있습니다. 이 문제를 방지하려면 ShaderVariantCollection 에셋을 더 작게 세분화하여 생성하고 스크립트에서 로드해야 합니다. 각 씬마다 사용된 셰이더 배리언트를 기록하고 별도의 ShaderVariantCollections 에셋에 저장하고 씬이 시작될 때 로드하는 등의 방법으로 이를 수행할 수 있습니다.

ShaderVariantCollection 스크립팅 클래스를 참조하십시오.

참고 항목

Asynchronous shader compilation in the Unity Editor
셰이더 작성 시 성능 팁