이어지는 섹션에서는 에셋 번들을 사용하는 프로젝트에서 흔히 발생하는 몇 가지 문제에 대해 설명합니다.
Unity 5의 에셋 번들 시스템은 오브젝트가 에셋 번들에 내장된 경우 오브젝트의 모든 종속성을 인식합니다. 이 작업은 에셋 데이터베이스를 사용하여 수행됩니다. 이 종속성 정보는 에셋 번들에 포함된 오브젝트 집합을 결정하는 데 사용됩니다.
에셋 번들에 명시적으로 할당되는 오브젝트는 해당 에셋 번들에만 내장됩니다. 오브젝트의 AssetImporter에 해당 오브젝트의 assetBundleName 프로퍼티가 비어 있지 않은 문자열로 설정되어 있으면 오브젝트가 “명시적으로 할당” 되었다고 합니다.
에셋 번들에 명시적으로 할당되지 않은 오브젝트는 태그되지 않은 오브젝트를 참조하는 오브젝트가 한 개 이상 들어있는 모든 에셋 번들에 포함됩니다.
두 개의 서로 다른 오브젝트가 두 개의 서로 다른 에셋 번들에 할당되어 있지만 두 에셋 번들에 모두 공통 종속성 오브젝트에 대한 레퍼런스가 포함되어 있는 경우, 해당 종속성 오브젝트가 두 에셋 번들에 모두 복사됩니다. 또한 중복되는 종속성은 인스턴스화하므로 종속성 오브젝트의 복사본 두 개는 식별자가 서로 다른 별개의 오브젝트로 간주됩니다. 따라서 애플리케이션의 총 에셋 번들 크기가 커집니다. 이로 인해 애플리케이션에서 상위 오브젝트 두 개를 모두 로드할 경우 오브젝트의 서로 다른 복사본 두 개가 메모리에 로드됩니다.
이 문제는 아래의 몇 가지 방법으로 해결할 수 있습니다.
서로 다른 에셋 번들에 내장된 오브젝트가 종속성을 공유하지 않도록 합니다. 종속성을 공유하는 오브젝트는 종속성 중복 없이 동일한 에셋 번들에 포함시킬 수 있습니다.
종속성을 공유하는 두 에셋 번들이 동시에 로드되지 않도록 에셋 번들을 분할합니다.
모든 종속성 에셋이 자체적인 에셋 번들에 내장되도록 합니다. 그러면 에셋이 중복될 위험이 완전히 배제되지만, 애플리케이션이 에셋 번들 간 종속성을 추적해야 하고 AssetBundle.LoadAsset API를 호출하기 전에 올바른 에셋 번들이 로드되는지 확인해야 하는 복잡성이 발생합니다.
Unity 5에서 오브젝트 종속성은 UnityEditor 네임스페이스에 있는 AssetDatabase API를 통해 추적됩니다. 네임스페이스가 시사하듯, 이 API는 Unity 에디터에서만 사용 가능하고 런타임 시점에 사용할 수 없습니다. AssetDatabase.GetDependencies를 사용해 특정 오브젝트 또는 에셋의 직접적인 종속성을 모두 찾을 수 있습니다. 이런 종속성에는 자체적인 종속성이 있을 수 있다는 점에 유의하십시오. 또한 AssetImporter API는 쿼리를 사용하여 특정 오브젝트가 할당된 에셋 번들을 찾아낼 수도 있습니다.
AssetDatabase 또는 AssetImporter API를 결합하여 에셋 번들의 직접적이거나 간접적인 종속성이 에셋 번들에 할당되거나 두 에셋 번들이 에셋 번들에 할당되지 않은 종속성을 공유하지 않도록 보장하는 에디터 스크립트를 작성할 수 있습니다. 중복 에셋의 메모리 사용량으로 인해, 모든 프로젝트에 이런 스크립트가 포함되도록 하는 것이 좋습니다.
이어지는 섹션에서는 Unity 5의 에셋 종속성 계산 코드를 자동 생성된 스프라이트 아틀라스와 함께 사용할 경우에 발생할 수 있는 문제점에 대해 설명합니다.
자동 생성 스프라이트 아틀라스는 스프라이트 아틀라스가 생성된 스프라이트 오브젝트가 포함된 에셋 번들에 할당됩니다. 스프라이트 오브젝트가 여러 에셋 번들에 할당된 경우, 스프라이트 아틀라스가 에셋 번들에 할당되지 않고 중복됩니다. 스프라이트 오브젝트가 에셋 번들에 할당되지 않은 경우, 스트라이트 아틀라스도 에셋 번들에 할당되지 않습니다.
스프라이트 아틀라스가 중복되지 않도록 하려면 모든 동일한 스프라이트 아틀라이스 안에 태그된 스프라이트가 동일한 에셋 번들에 할당되는지 확인합니다.
Unity 5.2.2p3 또는 이전 버전
자동 생성된 스프라이트 아틀라스는 에셋 번들에 할당되지 않기 때문에 아틀라스에 포함되는 스프라이트가 들어있는 에셋 번들에 포함되고 그 스프라이트를 참조하는 에셋 번들에도 포함됩니다.
이 문제로 인해 Unity의 스프라이트 패커를 사용하는 모든 Unity 5 프로젝트는 Unity 5.2.2p4, 5.3이나 더 새로운 버전의 Unity로 업그레이드할 것을 적극 권장합니다.
업그레이드할 수 없는 프로젝트의 경우, 이 문제를 해결하는 두 가지 방법이 있습니다.
쉬운 방법: Unity에 빌트인 스프라이트 패커를 사용하지 않습니다. 외부 툴에서 생성된 스프라이트 아틀라스는 일반 에셋일 것이므로 에셋 번들에 올바르게 할당될 수 있습니다.
어려운 방법: 자동으로 아틀라스된 스프라이트를 사용하는 모든 오브젝트를 스프라이트와 동일한 에셋 번들에 할당합니다.
이렇게 하면 생성된 스프라이트 아틀라스가 다른 에셋 번들의 간접적인 종속성으로 인식되지 않으며 중복되지 않습니다.
이 해결 방법을 사용하면 Unity의 스프라이트 패커를 사용하는 워크플로가 보존되지만, 에셋을 서로 다른 에셋 번들로 분리하기 위한 작업으로 개발자의 능력이 저하되고 아틀라스를 참조하는 컴포넌트의 데이터가 변경되면 아틀라스 자체가 변경되지 않아도 전체 스프라이트 아틀라스를 다시 다운로드해야 합니다.
Android 에코시스템에는 매우 다양한 디바이스가 있기 때문에 종종 텍스처를 몇 가지 다른 포맷으로 압축해야 할 필요가 있습니다. 모든 Android 디바이스는 ETC1을 지원하지만, ETC1은 알파 채널이 있는 텍스처를 지원하지 않습니다. 애플리케이션에서 OpenGL ES 2 지원이 필요하지 않은 경우, 모든 OpenGL ES 3 디바이스에서 지원되는 ETC2를 사용하면 문제를 가장 간단하게 해결할 수 있습니다.
대부분의 애플리케이션은 ETC2 지원이 제공되지 않는 구형 디바이스를 지원해야할 필요가 있습니다. 이 문제를 해결하는 한 가지 방법으로 Unity 5의 에셋 번들 배리언트를 사용할 수 있습니다. 그 외의 방법에 대한 자세한 내용은 Unity의 Android 최적화 가이드를 참조하십시오.
에셋 번들 배리언트를 사용하려면 ETC1을 사용하여 완전히 압축할 수 없는 모든 텍스처를 텍스처 전용 에셋 번들에 분리해야 합니다. 그런 다음 DXT5, PVRTC 및 ATITC 같은 제조사별 텍스처 압축 포맷을 사용해 Android 에코시스템의 ETC2 사용 불가 부분을 지원하는 해당 에셋 번들의 배리언트를 충분히 만드십시오. 각 에셋 번들 배리언트에 대해, 포함된 텍스처의 TextureImporter 설정을 배리언트에 해당되는 압축 포맷으로 변경합니다.
런타임 시 다양한 텍스처 압축 포맷 지원 여부를 SystemInfo.SupportsTextureFormat API를 사용하여 인식할 수 있습니다. 이 정보를 사용해 지원되는 포맷으로 압축된 텍스터가 포함되어 있는 에셋 번들 배리언트를 선택하고 로드해야 합니다.
Android 텍스처 압축 포맷에 대한 자세한 내용은 여기에서 확인할 수 있습니다.
이어지는 섹션에서 설명하는 문제점은 Unity 5.3.2p2에서 수정되었으므로 최신 버전의 Unity에 영향을 미치지 않습니다.
Unity 5.3.2p2보다 오래된 버전의 Unity에서는 에셋 번들에 열려 있는 파일 핸들을 에셋 번들이 로드되는 시간 내내 유지합니다. 대부분의 플랫폼에서는 문제가 되지 않지만, iOS에서는 한 프로세스에서 동시에 열어둘 수 있는 파일 핸들 수가 255개로 제한됩니다. 에셋 번들을 로드함으로 인해 이 한도가 초과되면 로딩에 실패하고 “파일 핸들이 너무 많이 열려 있음” 오류가 발생합니다.
이 문제는 콘텐츠를 수백 내지는 수천 개의 에셋 번들로 나누려고 하는 프로젝트에서 많이 발생합니다.
패치된 Unity 버전으로 업그레이드할 수 없는 프로젝트의 경우, 다음과 같은 일시적인 해결 방법을 사용할 수 있습니다.
When you build an AssetBundle, Unity uses information in that bundle to select which shader variants to compile. This includes information about the scenes, materials, Graphics Settings, and ShaderVariantCollections in the AssetBundle.
별도의 빌드 파이프라인은 다른 파이프라인과 독립적으로 자체 셰이더를 컴파일합니다.플레이어 빌드와 어드레서블 빌드가 모두 셰이더를 참조하는 경우 Unity는 각 파이프라인에 대해 하나씩 두 개의 셰이더 사본을 컴파일합니다.
이 프로세스에서는 키워드, 텍스처 또는 코드 실행으로 인한 변경 사항과 같은 런타임 정보는 고려하지 않습니다.빌드에 특정 셰이더를 포함하려면 원하는 셰이더가 포함된 ShaderVariantCollection을 포함하거나 그래픽 설정의 항상 포함된 셰이더 목록에 셰이더를 추가하여 수동으로 빌드에 셰이더를 포함하십시오.