Version: 2017.2
프레임 디버거
레이어

셰이더 로드 시간 최적화

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

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

  • 셰이더 배리언트가 다수 생성되는 경우 게임 빌드 시간과 게임 데이터 크기가 증가합니다.
  • 게임 도중 다수의 셰이더 배리언트를 로드하면 시간이 오래 걸리며, 메모리를 많이 차지합니다.

셰이더 빌드 타임 스트리핑

Unity는 게임 빌드 중에 게임에서 사용되지 않는 몇몇 내부 셰이더 배리언트를 찾아 빌드 데이터에 포함되지 않도록 할 수 있습니다. 빌드 타임 스트리핑은 다음을 제거하기 위해 수행됩니다.

  • #pragma shader_feature를 사용하는 셰이더의 개별 셰이더 기능. 사용되는 머티리얼 중 아무 것도 특정 배리언트를 사용하지 않는 경우 빌드에 포함하지 않습니다. 내부 셰이더 배리언트 문서를 참조하십시오. 빌트인 셰이더 이외에 스탠다드 셰이더가 이 기능을 사용합니다.
  • 안개 및 라이트매핑 모드를 취급하는 셰이더 배리언트. 어떠한 씬에서도 사용되지 않는 배리언트는 게임 데이터에 포함하지 않습니다. 이 동작을 오버라이드하려면 그래픽스 설정을 참조하십시오.

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

디폴트 Unity 셰이더 로딩 동작

모든 디폴트 설정에서 Unity는 shaderlab 셰이더 오브젝트를 메모리에 로드하지만 실제로 필요하기 전까지는 내부 셰이더 배리언트를 생성하지 않습니다.

즉, 게임 빌드에 포함되는 셰이더 배리언트가 사용될 수도 있지만 필요한 시점 전까지는 메모리나 로드 타임을 요구하지 않습니다. 예를 들어, 셰이더는 항상 배리언트를 포함하여 섀도우가 있는 점 광원을 처리하지만 섀도우가 있는 점 광원을 한 번도 사용하지 않는 경우 이 특정 배리언트가 로드되지 않습니다.

이 디폴트 동작의 단점은 특정 셰이더 배리언트가 처음으로 필요한 경우 일시적으로 성능 저하가 발생할 수 있다는 점입니다. 새로운 GPU 프로그램 코드가 그래픽스 드라이버에 로드되어야 하기 때문입니다. 게임플레이 중에는 이런 현상이 발생하지 않아야 하므로 Unity는 이를 해결하기 위해 ShaderVariantCollection 에셋을 지원합니다.

셰이더 배리언트 컬렉션

ShaderVariantCollection은 셰이더의 리스트에 해당하는 에셋이며, 각각은 로드할 패스 타입과 셰이더 키워드 조합의 리스트를 포함합니다.

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

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

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

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

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

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

참고 항목

프레임 디버거
레이어