원문 : AssetBundle Fundamentals

주의 : 번역이 개판이므로 이상하면 원문을 참조하세요.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.



AssetBundle Fundamentals


확인 완료한 버전: 5.3 - 난이도: 고급


이것은 유니티 5 의 애샛, 리소스, 그리고 리소스 관리를 다루는 기사 시리즈의 네 번째 챕터입니다.


이 챕터에서는 애셋번들에 대해서 이야기합니다. 여기에서는 애셋번들이 빌드될 때까지의 기본적인 이스템과 함께 애셋번들과 상호작용하기 위해서 사용하는 핵심 API 들에 대해서 소개합니다. 특히, 애셋번들 자체를 로드하거나 언로드하는 것과 애셋번들로부터 특정 애셋과 오브젝트를 언로드하는 것에 대해서도 논의합니다.


애셋번들을 사용함에 있어서, 더 많은 패턴 및 best practices 를 원한다면 이 시리즈의 다음 챕터를 참조하십시오.


3.1. Overview


애셋번들 시스템은 하나 이상의 파일들을 유니티가 인덱싱할 수 있는 압축( archival ) 포맷으로 저장하는 기법을 제공합니다. 이 시스템의 목적은 유니티의 직렬화 시스템과 호환되는 데이터 전송 기법을 제공하는데 있습니다. 애셋번들은 설치 후에 non-code content 를 전송하고 갱신하기 위한 유니티의 주요 도구입니다. 이는 개발자들로 하여금 shipped asset size 를 줄이고, 런타임 메모리 압력을 최소화하고, 엔드 유저의 디바이스를 위해서 최적화된 칸텐트를 선택적으로 로드할 수 있도록 해 줍니다.


애셋번들이 동작하는 방식에 대해서 이해하는 것은 모바일 디바이스를 위해 성공적인 유니티 프로젝트를 빌드하기 위한 기초입니다.


3.2. What's in an AssetBundle?


애셋번들은 두 개의 부분으로 구성됩니다: 헤더와 데이터 세그먼트.


헤더는 애셋번들이 빌드될 때 유니티에 의해서 생성됩니다. 그것은 애셋 번들에 대한 정보를 포함하는데요, 그 정보로는 애셋번들의 식별자, 압축 여부, 매니페이스( manifest ) 등이 있습니다.


매니페스트는 오브젝트의 이름을 키로 사용하는 검색 테이블입니다. 각 엔트리는 주어진 오브젝트를 애셋번들의 데이터 세그먼트의 어느 부분에서 찾을 수 있는지를 가르쳐 주는 바이트 인덱스를 제공합니다. 대부분의 플랫폼에서, 이 검색 테이블은 STL std::multimap 으로 구현됩니다. 주어진 플랫폼에서 STL 구현에 의해 사용되는 특정 알고리즘은 다양하지만, 대부분은 균형잡힌 검색 트리( balanced search tree )를 사용합니다. Windows 와 OSX 에서 파생된 ( iOS 를 포함한 ) 플랫폼들은 red-black tree 를 사용합니다. 그러므로 매니페스트를 생성하기 위해 필요한 시간은 애셋번들 내부의 애셋들이 많아질 수록 비선형적으로 증가합니다.


데이터 세그먼트는 애셋번들 내의 애셋들을 직렬화함으로써 생성된 raw data 를 포함합니다. 만약 데이터 세그먼트가 압축되어 있다면, LZMA 알고리즘이 collective sequence of serialized bytes 에 적용된 것입니다 - 즉, 모든 애셋들은 직렬화되어 있으며, 전체 바이트 배열이 압축된 것입니다.


유니티 5.3 전에는 오브젝트들이 애셋번들 내부에 개별적으로 압축될 수 없었습니다. 결과적으로 5.3 전 버전에서는 압축된 애셋번들로부터 하나 이상의 오브젝트를 읽을 때, 유니티는 전체 애셋번들을 압축해제해야 했습니다. 일반적으로 유니티는 같은 애셋번들에서 발생하는 연속적인 로딩 요청을 최적화하기 위해서 애셋번들에 대한 압축해제된 복사본을 캐싱합니다.


유니티 5.3 은 LZ4 압축 옵션을 추가했습니다. LZ4 압축 옵션으로 빌드된 애셋번들은 애셋번들 내의 오브젝트를 개별적으로 압축하며, 이는 유니티가 압축된 애셋번들을 디스크에 저장할 수 있도록 허용합니다. 이는 유니티가 전체 애셋번들을 압축해제하지 않고도 개별 오브젝트를 압축해제할 수 있도록 해 줍니다.


3.3. The AssetBundle Manager


유니티는 Bitbucket 에 애셋번들 관리자의 구현에 대한 레퍼런스를 개발하고 유지합니다. 이 관리자는 이 챕터에서 세부적으로 설명하는 많은 개념들과 API 들을 사용하며, 애셋번들을 리소스 관리 워크플로우에 통합해야 하는 프로젝트들을 위한 유용한 시작점을 제공합니다.


주목할 만한 특징은 "simulation mode" 를 포함합니다. 유니티 에디터가 활성화되면, 이 모드는 애셋번들로 표시된( tagged ) 애셋들에 대한 요청을 프로젝트의 /Assets/ 폴더 내에 있는 원래 애셋으로 리디렉트( redirect )합니다. 이는 개발자로 하여금 애셋번들을 리빌드하지 않고도 프로젝트에서 작업할 수 있도록 해 줍니다.


애셋번들 관리자는 오픈소스 프로젝트이며, 여기에서 찾아볼 수 있습니다.


3.4. Loading AssetBundles


유니티 5 에서, 애셋번들은 네 개의 API 를 통해서 로드될 수 있습니다. 이 네 개의 API 들의 동작은 두 개의 조건에 의존해 달라집니다:


    1. 애셋번들이 LZMA 압축인가, LZ4 압축인가.
    2. 애셋번들이 로드되고 있는 플랫폼이 어디인가.


다음과 같은 API 들이 있습니다:




3.4.1. AssetBundle.LoadFromMemroyAsync


유니티는 이 API 를 사용하는 것을 추천하지 않습니다.


유니티 5.3.3 업데이트: 이 API 는 유니티 5.3.3 에서 이름이 변경되었습니다. 유니티 5.3.2( 및 이전 )에는, 이 API 가 AssetBundle.CreateFromMemory 로 알려져 있었습니다. 그것의 기능이 변경되지는 않았습니다.


AssetBundle.LoadFromMemoryAsync 는 관리되는 코드의 바이트 배열( byte[] in C# )에서 애셋번들을 로드합니다. 그것은 항상 소스 데이터를 관리되는 코드 바이트 배열에서 새롭게 할당된 연속된 네이티브 메모리 블록의 배열로 복사합니다. 만약 애셋번들이 LZMA 로 압축되었다면, 그것은 복사하는 동안 애셋번들을 압축해제합니다. 압축이 안 되어 있거나 LZ4 로 압축된 애셋번들은 말 그대로 복사됩니다.


이 API 에 의해 소비되는 메모리의 최대량은 적어도 애셋번들의 크기의 두 배입니다: 한 복사본은 API 에 의해 생성된 네이티브 메모리에 있고, 한 복사본은 API 에 넘겨진 관리되는 바이트 배열에 있습니다. 그러므로 이 API 를 통해 애셋번들로부터 로드된 애셋들은 메모리에 세 번 복사됩니다: 하나는 관리되는 코드 바이트 배열, 하나는 네이티브 메모리 복사본, 하나는 애셋 자체를 위해서 GPU 나 시스템 메모리에.


3.4.2. AssetBundle.LoadFromFile


유니티 5.3 업데이트: 이 API 는 유니티 5.3 에서 이름이 변경되었습니다. 유니티 5.2( 및 이전 )에서는 AssetBundle.CreateFromFile 로 알려져 있었습니다. 그것의 기능은 변경되지 않았습니다.


AssetBundle.LoadFromFile 은 매우 효율적인 API 이며, SD 카드나 하드 디스크와 같은 로컬 저장소에서 압축되지 않은 애셋번들을 로드하기 위한 의도로 만들어졌습니다. 만약 애셋번들이 압축되지 않았거나 LZ4 로 압축되었다면, 이 API 의 동작은 다음과 같습니다:


모바일 디바이스: 이 API 는 애셋번들의 헤더만을 로드하며, 데이터는 디스크에 남겨 둡니다. 애셋번들의 오브젝트는 로딩 메서드들이 호출되거나 그것들의 InstanceID 가 역참조될 때 요청에 의해( on-demand ) 로드될 것입니다. 이 시나리오에서는 과도하게 사용되는 메모리가 없습니다.


유니티 에디터: 이 API 는 마치 AssetBundle.LoadFromMemoryAsync 가 사용되거나 바이트들이 디스크에서 일어들여 지는 것처럼 전체 애셋번들을 메모리로 로드할 것입니다. 이 API 는 프로젝트가 유니티 에디터에서 프로우파일링되고 있는 동안에는 메모리 스파이크를 발생시킬 수 있습니다. 이는 디바이스 상에서의 성능에 영향을 미치지 않으며, 개선책을 취하기 전에 이 스파이크를 디바이스에서 다시 테스트해 보아야 합니다.


노트: 유니티 5.3 이전의 안드로이드 디바이스에서, 이 API 는 Streaming Assets 경로에서 애셋번들을 로드하려고 시도할 때 실패할 것입니다. 이는 그 경로의 내용이 압축된 .jar 파일 내부에 존재하기 때문입니다. 더 많은 세부사항에 대해서 알고자 한다면, AssetBundle usage patterns 챕터의 Distribution - shipped with project 섹션을 참고하십시오. 이 이슈는 유니티 5.4 에서 해결되었습니다. 유니티 5.4 이상에서 빌드된 게임에서는 이제 이 API 를 사용해 Streaming Asset 으로부터 애셋번들을 로드할 수 있습니다.


노트: AssetBundle.LoadFromFile 에 대한 호출은 LZMA 압축 애셋번들에 대해서는 항상 실패합니다.


3.4.3. WWW.LoadFromCacheOrDownload


WWW.LoadFromCacheOrDownload 는 원격 서버와 로컬 저장소에서 오브젝트를 로딩하기 위해서 유용한 API 입니다. 파일들은 file:// URL 을 사용해서 로컬 저장소로부터 로드될 수 있습니다. 만약 애셋번들이 유니티 캐시에 제출되었다면, 이 API 는 AssetBundle.LoadFromFile 과 정확히 같은 동작을 수행하게 됩니다.


만약 애셋번들이 아직 캐싱되지 않았다면, WWW.LoadFromCacheOrDownload 는 애셋번들을 소스로부터 읽어들일 것입니다. 만약 애셋번들이 압축되어 있다면, 그것은 워커 스레드( worker thread )를 사용하여 압축을 해제하고 그것을 캐시에 쓰게 됩니다. 그렇지 않다면, 그것은 워커 스레드를 통해 캐시로 바로 쓰여집니다.


일단 애셋번들이 캐싱되면, WWW.LoadFromCacheOrDownload 는 헤더 정보를 캐싱되고 압축해제된 애셋번들에서 로드합니다. 그리고 나서 이 API 는 AssetBundle.LoadFromFile 을 사용해 애셋번들을 로드하는 것과 동일한 동작을 수행합니다.


노트: 고정크기 버퍼를 통해 데이터가 압축해제되고 캐시에 쓰이는 동안, WWW 오브젝트는 애셋번들의 바이트의 전체 복사본을 네이티브 메모리에 유지합니다. 이 부가적인 복사본은 WWW.bytes 속성에 의해서 지속적으로 지원됩니다.


WWW 오브젝트 내에 애셋번들의 바이트를 캐싱하기 위한 메모리 오우버헤드 때문에, WWW.LoadFromCacheOrDownload 를 사용하는 개발자들은 자신들의 애셋번들을 작게 유지할 필요가 있습니다 - 거의 몇 메가 바이트 정도로. 또한 모바일 디바이스와 같은 제한된 메모리를 가진 플랫폼에서 작업하는 개발자들은 메모리 스파이크를 피하기 위해서 자신들의 코드가 한 번에 하나의 애셋번들만을 다운로드하도록 해야 합니다. 애셋번들 크기와 관련한 더 많은 논의를 원한다면, AssetBundle usage Patterns 챕터의 Asset assignment strategies 섹션을 참고하십시오.


노트: 이 API 에 대한 각각의 호출은 새로운 워커 스레드를 생성할 것입니다. 이 API 를 여러 번 호출할 때는 스레드가 너무 많이 생성되지 않도록 주의해야만 합니다. 만약 5 ~ 10 개 이상의 애셋번들이 다운로드되어야 한다면, 적은 개수의 애셋번들이 동시에 다운로드되도록 코드를 작성하는 것을 권장합니다.


3.4.4. AssetBundleDownloadHandler


유니티 5.3 에서 모바일 플랫폼을 위해 소개된 UnityWebRequest API 는 WWW API 를 대체할 더욱 유연한 대안을 제공합니다. UnityWebRequest 는 개발자로 하여금 유니티가 다운로드된 데이터를 어떻게 다룰지 정확하게 지정할 수 있게 합니다. 또한 개발자로 하여금 불필요한 메모리 사용량을 줄일 수 있도록 해 줍니다. UnityWebRequest 를 통해 애셋번들을 다운로드하는 가장 단순한 방법은 UnityWebRequest.GetAssetBundle API 를 호출하는 것입니다.


이 가이드의 목적을 볼 때 흥미로운 클래스는 DownloadHandlerAssetBundle 입니다. 다운로드 핸들러는 WWW.LoadFromCacheOrDownload 와 유사한 동작을 수행합니다. 그것은 워커 스레드를 사용해서 다운로드된 데이터를 고정 크기 버퍼에 스트리밍하고, 다운로드 핸들러의 구성에 따라 버퍼링된 데이터를 임시 저장소나 애셋번들 캐시에 스풀링합니다. LZMA 압축된 애셋번들은 다운로드 동안 압축해제되고 압축되지 않은 캐시로 저장됩니다.


이러한 모든 연산들은 네이티브 코드 상에서 수행되며, 관리되는 힙이 확장될 위험성을 제거해 줍니다. 더우기 이 다운로드 핸들러는 다운로드된 모드 바이트들에 대한 네이티브 코드 복사본을 유지하지 않습니다. 게다가 애셋번들을 다운로드하는 데 필요한 메모리 오우버헤드를 줄여줍니다.


다운로드가 완료되면, 다운로드 핸들러의 assetBundle 프라퍼티는 다운로드된 애셋번들에 대한 접근을 제공합니다. 마치 AssetBundle.LoadFromFile 이 다운로드된 애셋번들상에서 호출되는 것처럼 말이죠.


UnityWebRequest API 는 WWW.LoadFromCacheOrDownload 와 동일한 방식으로 캐싱을 지원하기도 합니다. 만약 캐싱 정보가 UnityWebRequest 오브젝트에 제공되고 요청된 애셋번들이 이미 유니티 캐시에 존재한다면, 애셋번들은 즉시 이용가능해지며 이 API 는 AssetBundle.LoadFromFile 과 동일하게 동작합니다.


노트: 유니티 애셋번들 캐시는 WWW.LoadFromCacheOrDownload 와 UnityWebRequest 사이에서 공유됩니다. 한 API 에 의해서 다운로드된 모든 애셋번들은 다른 API 를 통해서 사용할 수 있습니다.


노트: WWW 와는 다르게, UnityWebRequest 시스템은 내부 워커 스레드 풀과 내부 잡( job ) 시스템을 가지고 있으며, 이는 개발자가 동시에 너무 많은 번들을 다운로드할 수 없게 해 줍니다. 스레드 풀의 크기는 현재 사용자가 설정할 수 없습니다.


3.4.5. Recommendations


일반적으로, 가능하다면 AssetBundle.LoadFromFile 을 사용하십시오. 이 API 는 속도, 디스크 사용량, 런타임 메모리 사용량의 관점에서 가장 효율적입니다.


애셋번들을 다운로드하고 패치해야 하는 프로젝트를 위해서는, 유니티 5.3 이상의 버전을 사용하고 있다면 UnityWebRequest 를 사용하고 5.2 이하의 버전을 사용하고 있다면 WWW.LoadFromCacheOrDownload 를 사용하는 것을 강력히 권합니다. 다음 챕터의 Distribution 섹션에서 설명하듯이, it is possible to prime the AssetBundle Cache with Bundles include within a project's installer.


WWW.LoadFromCacheOrDownload 를 사용할 때는 프로젝트의 애셋번들이 프로젝트의 최대 메모리 예산보다 2 ~ 3% 정도 작은 상태로 유지되도록 하는 것을 추천합니다. 그래야 메모리 사용량 스파이크 때문에 애플리케이션이 종료되는 것을 막을 수 있습니다. 대부분의 프로젝트에서 애셋번들은 5 MB 를 넘어서서는 안되며, 1 ~ 2 개 이상의 애셋번들이 동시에 다운로드되어서는 안 됩니다.


WWW.LoadFromCacheOrDownload 나 UnityWebRequest 를 사용할 때는 애셋번들을 로드한 후에 다운로드 코드가 적절히 Dispose 를 호출하도록 해야 합니다. C# 의 using 문은 WWW 와 UnityWebRequest 를 안전하게 dispose 할 수 있는 가장 편리한 방법입니다.


규모가 큰 엔지니어링 팀을 위한 프로젝트와 단일 캐싱 이나 다운로딩 요구들을 위해서는 커스텀 다운로드가 필요합니다. 커스텀 다운로더를 작성하는 것은 사소한 엔지니어링 작업이 아닙니다. 그리고 모든 커스텀 다운로더는 AssetBundle.LoadFromFile 과 호환되도록 만들어져야만 합니다. 세부사항을 원한다면 다음 챕터의 Distribution 섹션을 참고하십시오.


3.5. Loading Assets From AssetBundles


UnityEngine.Object 는 AssetBundle 오브젝트에 있는 여러 API 를 사용해 애셋번들로부터 로드될 수 있습니다 : LoadAsset, LoadAllAssets, LoadAssetWithSubAssets. 이러한 모든 API 들은 비동기 버전을 가지고 있습니다 - Async 라는 접미어가 있습니다: LoadAssetAsync, LoadAllAssetsAsync, LoadAssetWithSubAssetsAsync.


동기 API 는 항상 비동기 API 보다 적어도 한 프레임 단위에서는 빠릅니다. 이는 특히 유니티 5.1 이전 버전에서는 사실입니다. 유니티 5.2 전에는 모든 비동기 API 들이 한 프레임에 거의 하나의 오브젝트만을 로드했스니다. 이는 LoadAllAssetsAsync 와 LoadAssetWithSubAssetAsync 가 관련 동기 API 들보다 심각하게 느렸음을 의미합니다. 이 동작은 유니티 5.2 에서 교정되었습니다. 비동기 로딩은 이제 자신의 시간 분할( time-slice ) 제한이 걸릴 때까지 한 프레임에 여러 개의 오브젝트를 로드합니다. 그것의 기반이 되는 기술적 요인과 시간 분할과 관련한 세부사항을 살펴보고자 한다면 아래의 Low-level loading details 를 참고하시기 바랍니다.


LoadAllAssets 는 독립적인 다수개의 UnityEngine.Object 들을 로드할 때 사용됩니다. 그것은 애셋번들 내의 대부분의( 혹은 모든 ) 오브젝트들이 로드될 필요가 있을 경우에 사용되야 합니다. 다른 두 API 와 비교해 봤을 때, LoadAllAssets 는 LoadAssets 를 개별적으로 호출했을 때 보다는 약간 빠릅니다. 그러므로 로드될 애셋의 개수가 많지만 한 번에 로드될 필요가 있는 개수가 애셋번들의 내용은 2/3 보다 적을 때는 애셋번들을 다수 개의 작은 번들로 분리하고 LoadAllAssets 를 호출할 것을 권합니다.


LoadAssetWithSubAssets 는 여러 개의 내포된 오브젝트를 포함하고 있는 복합 애셋을 로드해야 할 때 사용해야 합니다. 그러한 예로는 FBX 모델이 있는데, 거기에는 내포된 애니메이션이나 내부에 여러 개의 내포된 스프라이트를 포함하는 스프라이트 아틀라스를 포함하고 있을 수 있습니다. 만약 오브젝트들이 같은 애셋으로부터 로드될 필요가 있지만 애셋번들 내에 관련없는 다른 오브젝트들이 존재한다면, 이 API 를 사용하십시오.


다른 경우에는 LoadAsset 이나 LoadAssetAsync 를 사용하십시오.


3.5.1. Low-loevle loading details


UnityEngine.Object 로딩은 메인 스레드에서 수행됩니다: 오브젝트의 데이터는 워커 스레드에서 저장소로부터 읽혀들여집니다. 유니티 시스템의 스레드에 민감하지 않은 부분들( 스크립팅, 그래픽스 )을 건드리는 것들은 워커 스레드에서 변환됩니다. 예를 들어 VBO 는 메쉬로부터 생성되며, 텍스쳐들은 압축해제됩니다.


5.3 버전 전에는 오브젝트 로딩이 직렬적이며 오브젝트 로딩의 일부분은 메인 스레드에서만 수행되었습니다. 이는 "Integration" 이라 불렸습니다. 워커 스레드가 오브젝트 데이터를 로딩하는 것을 마친 후에, 그것은 새롭게 로드된 오브젝트를 메인 스레드에서 통합하기 위해 중지되었으며, 메인 스레드 통합이 완료될 때까지 ( 다음 오브젝트를 로딩하지 않고 ) 중지된 상태로 남아 있었습니다.


5.3 버전부터는 오브젝트 로딩은 병행처리됩니다. 여러 개의 오브젝트들이 역직렬화되며, 워커 스레드 상에서 처리되고 통합됩니다. 오브젝트가 로딩을 마쳤을 때, 그것의 Awake 콜백이 호출되며 오브젝트는 다음 프레임 동안에 유니티 엔진의 나머지 부분에 대해 이용 가능하게 됩니다.


동기화된 AssetBundle.Load 메서드는 오브젝트 로딩이 완료될 때까지 메인 스레드를 중단시킬 것입니다. 5.3 버전 전에는 비동기 AssetBundle.LoadAsync 메서드는 오브젝트를 메인 스레드에서 통합하기 전까지 메인 스레드를 중단시키지 않을 것입니다. They will also time-slice Object loading so that Object integration does not occupy more than a certain number of milliseconds of frame time. 얼마만큼의 시간이 설정되느냐는 Application.backgroundLoadingProperty 라는 프라퍼티에 의해 설정됩니다.


    • ThreadProirity.High: 프레임당 최대 50 밀리세컨드.
    • ThreadPriority.Normal: 프레임당 최대 10 밀리세컨드.
    • ThreadPriotity.BelowNormal: 프레임당 최대 4 밀리세컨드.
    • ThreadPriority.Low: 프레임당 최대 2 밀리세컨드.


유니티 5.1 전 버전에서, 비동기 API 들은 프레임당 한 오브젝트만 통합했을 것입니다. 이는 버그로 간주되었으며, 유니티 5.2 에서 해결되었습니다. 유니티 5.2 부터는 오브젝트 로딩을 위한 프레임 타임 제한에 도달할 때까지 여러 개의 오브젝트가 로드될 것입니다. AssetBundle.LoadAsync 는 ( 모든 요소가 동일하다는 가정하에서 볼 때 ) 동기 API 보다는 완료되는 시간이 길 것입니다. 왜냐하면 LoadAsync 호출을 제출하는 것과 오브젝트가 엔진에 대해 이용가능한 상태가 되는 것 사이에 최소 한 프레임의 지연이 존재하기 때문입니다.


실제 오브젝트들과 애셋들을 가지고 테스트해 보면 다른 결과가 나옵니다. 5.2 전에는 특정한 큰 텍스쳐를 로우엔드 디바이스에서 로드하면, 동기 메서드를 사용했을 때 7 ms 가 나오고 비동기 메서드를 사용했을 때 70 ms 가 나왔습니다. 5.2 이후에는 그 차이가 0 에 가까워졌습니다.


3.5.2. AssetBundle dependencies


유니티 5 의 애셋번들 시스테멩서 애셋번들 사이의 종속성은 두 개의 API 를 통해 자동적으로 트래킹되는데, 이는 런타임 환경과 관련이 있습니다. 유니티 에디터에서는 AssetBundle 종속성이 AssetDatabase API 를 통해 질의될 수 있습니다. 애셋번들 할당과 종속성은 AssetImporter API 를 통해서 접근되거나 변경될 수 있습니다. 런타임에는 유니티가 애셋번들 빌드 동안에 생성된 종속성 정보를 로드할 수 있는 선택적인 API 를 제공합니다. 이는 ScriptableObject 기반의 AssetBundleManifest API 입니다.


부모 애셋번들의 UnityEngine.Object 들이 다른 애셋번들의 UnityEngine.Object 들에 대한 하나 이상의 참조를 가질 때, 한 애셋 번들은 다른 애셋번들에 대해 "종속적"입니다. 오브젝트간 참조에 대한 더 많은 정보를 원한다면, Assets, Objects and Serialization 기사의 Inter-Object references 섹션을 참고하십시오.


그 기사의 Serialization and instances 섹션에서 기술햇듯이, 애셋번들은 애셋번들에 포함되어 있는 개별 오브젝트의 파일 GUID 와 로컬 ID 에 의해 식별되는 소스 데이터를 위한 소스로서 기능합니다


오브젝느는 인스턴스 ID 가 처음 역참조될 때 로드되기 때문에, 그리고 그것의 애셋번들이 로드될 때 오브젝트는 유효한 인스턴스 ID 를 할당받기 때문에, 애셋번들이 로드되는 순서는 중요치 않습니다. 대신에 오브젝트 자체를 로드하기 전에 오브젝트의 종속성을 포함하는 모든 애셋번들을 로드하는 것은 중요합니다. 유니티는 부모 애셋번들이 로드될 때 자식 애셋번들을 자동으로 로드해 주지 않을 것입니다.


예:


머티리얼 A 가 텍스쳐 B 를 참조하고 있다고 가정합시다. 머티리얼 A 는 AssetBundle 1 에 패키징되어 있고, 텍스쳐 B 는 AssetBundle 2 에 패키징되어 있습니다.




이 경우, Asset Bundle 2 는 Asset Bundle 1 으로부터 머티리얼 A 를 로딩하기 전에 로드되어야만 합니다.


이는 Asset Bundle 2 가 Asset Bundle 1  전에 로드되어야만 한다든가 그 텍스쳐 B 가 Asset Bundle 2 로부터 명시적으로 로드되어야만 한다든가 하는 것을 암시하지는 않습니다. Asset Bundle 1 로부터 머티리얼 A 를 로딩하는 것보다 Asset Bundle 2 를 먼저 로드하기만 하면 충분합니다.


유니티는 Asset Bundle 1 이 로드될 때 자동으로 Asset Bundle 2 를 로드하지 않을 것입니다. 이는 스크립트를 통해 명시적으로 수행되어야만 합니다. Asset Bundle 1 과 2 를 로드하기 위해서 사용되는 특정 애셋번들 API 는 중요하지 않습니다. WWW.LoadFromCacheOrDownload 를 통해 로드된 애셋번들은 AssetBundle.LoadFromFile 이나 AssetBundle.LoadFromMemoryAsync 를 통해 로드된 애셋번들과 자유롭게 혼용될 수 있습니다.


3.5.3. AssetBundle manifest


BuildPipeline.BuildAssetBundles API 를 통해 애셋번들 빌드 파이프라인을 실행할 때, 유니티는 애셋번들의 종속성 정보를 포함하는 오브젝트를 직렬화합니다. 이 데이터는 개별 애셋번들에 저장되며, 이는 AssetBundleManifest 타입의 오브젝트를 포함합니다.


이 애셋은 애셋번들이 빌드된 부모 디렉토리와 같은 이름을 가지고 애셋번들 내에 저장될 것입니다. 만약 프로젝트가 그것의 애셋번들을 (projectroot)/build/Client/ 라는 폴더에 빌드한다면, 매니페이스를 포함하는 애셋번들은 (projectroot)/build/Client/Client.manifest 로 저장될 것입니다.


매니페스트를 포함하는 애셋번들은 다른 애셋번들들처럼 로드되거나 캐싱되거나 언로드될 수 있습니다.


AssetBundleManifest 오브젝트는 그 자체로 GetAllAssetBundles 라는 API 를 제공해 매니페스트와 함께 빌드된 모든 애셋번들들을 리스팅할 수 있도록 합니다. 그리고 특정 애셋번들의 종속성을 질의하기 위한 두 개의 메서드를 제공합니다.


AssetBundleManifest.GetAllDependencies 는 애셋번들의 종속성을 모두 반환합니다. 이는 애셋번들의 계층구조상의 모든 자손들의 종속성을 포함합니다.


AssetBundleManifest.GetDirectDependencies 는 애셋번들의 바로 아래 자손들의 종속성만을 반환합니다.


이 API 들은 모두 문자열 배열을 할당한다는 점에 주의하시기 바랍니다. 자주 사용하지는 마십시오. 그리고 애플리케이션 생명주기의 성능이 중요한 시점에는 사용하지 마십시오.


3.5.4. Recommandations


애플리케이션에서 성능이 중요한 부분에 도달하기 전에 필요한 오브젝트를 최대한 많이 로드하는 것이 좋습니다. 예를 들어 메인 게임 레벨이나 월드에 들어 가기 전에 로드하는 것이 좋습니다. 이는 모바일 플랫폼에서 특히 중요합니다. 이 환경에서 로컬 저장소에 대한 접근은 느리며 플레이를 하는 동안에 오브젝트를 마구 로드하고 언로드하는 것은 가비지 콜렉팅을 발생시킬 수 있습니다.


애플리케이션이 상호작용을 하는 동안에 오브젝트들을 로드하고 언로드해야만 하는 프로젝트의 경우, 오브젝트와 애셋번들을 언로드하는 것에 대한 더 많은 정보를 원한다면 AssetBundle usgae pattern 기사의 Managing loaded assets 섹션을 참고하십시오.

+ Recent posts