Version: 2020.3
셰이더 에셋
비동기 셰이더 컴파일

셰이더 컴파일

개요

프로젝트를 빌드할 때마다 Unity 에디터는 빌드가 필요로 하는 모든 셰이더, 즉 필요한 모든 그래픽스 API에 대해 필요한 모든 셰이더 배리언트를 컴파일합니다.

Unity 에디터에서 작업할 때 에디터는 모든 요소를 미리 컴파일하지 않습니다. 모든 그래픽스 API에 대해 모든 배리언트를 컴파일하는 데에는 매우 오랜 시간이 소요될 수 있기 때문입니다.

대신 Unity 에디터는 다음을 수행합니다.

  • 셰이더 에셋을 임포트할 때는 최소한의 프로세싱(예: 표면 셰이더 생성)을 수행합니다.
  • 셰이더 배리언트를 표시해야 하는 경우, Library/ShaderCache 폴더를 확인합니다.
  • 동일한 소스 코드를 사용하는, 이전에 컴파일된 셰이더 배리언트를 찾으면 해당 배리언트를 사용합니다.
  • 일치하는 항목을 찾을 수 없으면 필요한 셰이더 배리언트를 컴파일하여 캐시에 결과를 저장합니다.
    • 참고: 비동기 셰이더 컴파일을 활성화하면 이를 배경에서 수행하고 그동안 플레이스홀더 셰이더를 표시합니다.

셰이더 컴파일은 UnityShaderCompiler라는 프로세스를 사용합니다. 다수의 UnityShaderCompiler 프로세스가 시작될 수 있어 (보통 컴퓨터의 CPU 코어당 하나) 플레이어 빌드 시에 셰이더 컴파일이 동시에 진행될 수 있습니다. 에디터는 셰이더를 컴파일하지 않고 컴파일러 프로세스는 아무 일도 하지 않으며 컴퓨터 리소스를 소비하지 않습니다.

자주 변경되는 셰이더가 많으면 셰이더 캐시 폴더가 꽤 커질 수 있습니다. 이 폴더는 Unity가 셰이더 배리언트를 다시 컴파일하게 만들 뿐이므로 삭제하는 것이 안전합니다.

플레이어 빌드 시에는 “아직 컴파일되지 않은” 모든 셰이더 배리언트가 컴파일되므로 이러한 배리언트들이 에디터가 사용하지 않았어도 게임 데이터에 포함됩니다.

서로 다른 셰이더 컴파일러

다음과 같이 플랫폼마다 서로 다른 셰이더 컴파일러를 셰이더 프로그램 컴파일에 사용합니다.

  • DirectX를 사용하는 플랫폼은 Microsoft의 FXC HLSL 컴파일러를 사용합니다.
  • OpenGL(Core 및 ES)을 사용하는 플랫폼은 Microsoft의 FXC HLSL 컴파일러를 사용하며, 이후 HLSLcc를 사용하여 GLSL로 바이트코드 변환을 수행합니다.
  • Metal을 사용하는 플랫폼은 Microsoft의 FXC HLSL 컴파일러를 사용하며, 이후 HLSLcc를 사용하여 Metal로 바이트코드 변환을 수행합니다.
  • Vulkan을 사용하는 플랫폼은 Microsoft의 FXC HLSL 컴파일러를 사용하며, 이후 HLSLcc를 사용하여 SPIR-V로 바이트코드 변환을 수행합니다.
  • 콘솔 플랫폼과 같은 여타 플랫폼은 각각 해당하는 컴파일러를 사용합니다.
  • 표면 셰이더는 코드 생성 분석 단계에 HLSL 및 MojoShader를 사용합니다.

pragma 지시문을 사용하여 여러 셰이더 컴파일러 설정을 설정할 수 있습니다.

캐시 셰이더 프리 프로세서

셰이더 컴파일에는 여러 단계가 소요됩니다. 첫 단계는 프리 프로세싱입니다. 이 단계에는 프리 프로세서라는 프로그램이 컴파일러의 셰이더 소스 코드를 준비합니다.

이전 Unity 버전에서는 셰이더 컴파일러가 현재 플랫폼에 제공하는 프리 프로세서를 에디터가 사용했습니다. 이제는 Unity의 캐시 셰이더 프리 프로세서를 사용하는 것과 이전 동작으로 되돌아가는 것 중에서 선택할 수 있습니다. 문제가 없는 한 캐시 셰이더 프리 프로세서를 사용하십시오.

캐시 셰이더 프리 프로세서는 더 빠른 셰이더 임포트와 컴파일에 최적화되어 있습니다(최대 25% 더 빠름). 이 프리 프로세서는 중간 프리 프로세싱 데이터를 캐시하여 작동하므로, 에디터는 include 파일의 콘텐츠가 변경되는 경우에만 해당 파일을 파싱하면 됩니다. 따라서 같은 셰이더의 여러 배리언트를 더 효율적으로 컴파일할 수 있습니다. 캐시 셰이더 프리 프로세서 활성화는 프로젝트 내 셰이더가 대규모 세트의 일반적인 include 파일을 사용하는 경우 가장 효과적입니다.

캐시 셰이더 프리 프로세서는 성능 개선 외에도 다음의 기능을 추가로 제공합니다.

  • 조건부 내 #pragma 지시문을 제한적으로 지원합니다.
  • #pragma warning 지시문을 지원합니다.
  • #include_with_pragmas 지시문을 지원하여 include 파일에 #pragma 지시문을 넣을 수 있습니다.
  • 셰이더 인스펙터Preprocess Only 체크박스. 이 체크박스에서 해당 셰이더 에셋의 프리 프로세스된 소스를 확인할 수 있습니다.

캐시 셰이더 프리 프로세서와 이전 동작의 차이를 자세히 알아보려면 Unity 포럼의 글 새로운 셰이더 프리 프로세서를 참조하십시오.

Editor settings 창의 Shader Compilation 섹션에 있는 Caching Shader Preprocessor 체크박스 또는 EditorSettings.cachingShaderPreprocessor API를 사용하여 캐시 셰이더 프리 프로세서를 활성화하거나 비활성화할 수 있습니다.

빌드 타임 스트리핑

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

  • #pragma shader_feature를 사용하는 셰이더의 경우 Unity는 배리언트가 사용되는지 여부를 자동으로 확인합니다. 빌드의 아무 머티리얼도 배리언트를 사용하지 않는 경우 해당 배리언트는 빌드에 포함되지 않습니다. 내부 셰이더 배리언트 문서를 참조하십시오. 이는 스탠다드 셰이더에서 사용됩니다.
  • Fog 및 Lightmapping 모드를 취급하는 셰이더 배리언트. 어떠한 씬에서도 사용되지 않는 배리언트는 게임 데이터에 포함하지 않습니다. 이 동작을 오버라이드하려면 Graphics 창을 참조하십시오.
  • 또한 수동으로 배리언트를 식별한 후 OnProcessShader API를 사용하여 해당 배리언트를 빌드에서 제외하도록 Unity에 지시할 수 있습니다.

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

셰이더 에셋
비동기 셰이더 컴파일