Show
기억저장고Unity Unity AssetBundle 생성/불러오기옵피채 2021. 6. 19. 02:27 Unity에서 AssetBundle을 사용하는데 많이 어려움을 겪었다. 나는 FBX를 AssetBundle로 저장해서 서버에 올린다음에 WebGL로 불러오는 작업을 했었다. 정말 어려웠다... 다 어려운방법들을 알려줘서.. 이해를 잘 못했다. (지금도 못함) *WebGL 플레이중 FBX 받는법 1. FBX를 AssetBundle로 묶는다. 2. AssetBundle을 서버에 올린다. 3. WebGL 플레이 중 AssetBundle을 다운받는다 4. 받은 AssetBundle안에 있는 FBX를 꺼낸다. 이 순서로 진행해야한다. 바로 서버에있는 FBX를 받고적용시키는거는 안돼더라.. 서버에서 Assetbundle 받을때 서버에서 .unity3d(에셋번들확장자) 확장자 접근권한 설정해줘야한다. 1. AssetBundle 저장방법 *AssetBundle Browser 설치 (Window - PackageManager -(All packages) - AssetBundleBrowser검색 - install *PackageManager에서 검색안될때 Git으로 설치 PackageManager - 왼쪽의 (+)버튼클릭 - Add Package from Git URL - 입력 - Git으로 Package 설치 중 오류 있을때 해결방법 https://learnandcreate.tistory.com/729 유니티 패키지 설치 오류(No ‘git’ executable was found) 유니티 패키지 설치 오류(No ‘git’ executable was found) 깃에 공개된 패키지를 패키지 매니저(package manager)의 git URL를 사용하여 설치를 시도할때 또는 깃에 공개되어있는 패키지를 사용하는 프 learnandcreate.tistory.com 1. "Asset Bundle Browser"를 PackageManager에서 import 2. window>assetbundle browser 클릭 3. Build 탭 선택 후 다음과 같이 세팅 AssetBundles Build 탭 세팅4. 원하는 FBX파일 선택 후 assetbundle browser 의 Configure로 끌어다 놓기 (FBX이름으로 AssetBundle이름 생성됨) 5. "unity3d" 타이핑 - 1번 : 번들이름 (AssetBundle 생성하면 설정한 이름으로 생성됨) - 2번 : unity3d 라고 작성 6. Build 탭에서 Build버튼 클릭 하면 AssetBundle 만들어짐 - 저장위치 : Output Path 2. AssetBundle 불러오기 2-1. AssetBundle 불러오는 방법 (AssetBundle을 저장할때 "unity3d"라고 뒤에 붙여줬었음)
2-2. AssetBundle 안에 있는 내용 불러오는 방법 (FBX) 이 글은 유니티 튜토리얼을 번역한 글 입니다. 원문은 여기에서 확인하실 수 있습니다. 이 글은 총 5개의 챕터로 구성되며 아래와 같습니다.
이 시리즈의 이전 챕터에서는 에셋번들 기초에 대해 다뤘는데, 특히 다양한 로딩 API의 저수준 동작들에 대해 이야기했습니다. 이번 챕터에는 에셋번들을 실제로 사용하는 방법에 있어서 발생하는 문제와 해결법에 대해 이야기할 것 입니다. 4.1 로드된 에셋의 관리메모리에 민감한 환경에서 로드된 오브젝트의 크기와 갯수를 조심스레 다루는 것은 특히 중대한 문제입니다. 유니티는 현재 씬에서 오브젝트가 제거되더라도 자동으로 해당 오브젝트를 언로드하지 않습니다. 에셋의 정리는 특정 시간에 발생하게 되고, 수동으로도 발생시킬 수 있습니다. 에셋번들 자체는 조심스럽게 다뤄져야 합니다. 로컬 저장 공간에 있는(유니티 캐쉬에 있거나AssetBundle.LoadFromFile에 의해 로드된 것) 파일의 에셋번들은 최소한의 메모리 오버헤드가 있는데, 거의 10~40 KB 를 넘지 않습니다. 이러한 숫자도 에셋번들이 많은 경우에는 문제가 될 수 있습니다. 대부분의 프로젝트에서 유저들은 컨텐츠를 다시 경험할 수 있기 때문에(특정 레벨을 다시 플레이하는 등), 에셋번들을 언제 로드하고 언로드하는지를 아는 것이 중요합니다. 만약 에셋번들이 부적절하게 언로드된다면, 메모리에서 오브젝트가 중복되는 문제를 야기시킬 수 있습니다. 부적절한 에셋번들의 언로드는 특정 환경에서 바람직하지 못한 동작을 할 수도 있는데, 예를 들면 텍스쳐가 없는 상태(missing)가 될 수도 있다는 말입니다. 왜 이러한 일이 일어나는지에 대해 알고 싶으면, 에셋과 오브젝트, 그리고 직렬화 챕터의 오브젝트 내부의 참조들 섹션을 참고해 보십시오. 에셋과 에셋번들을 관리할 때 가장 중요한 것은 AssetBundle.Unload 를 true나 false 인자를 사용해서 호출할 때의 동작의 차이를 이해해야 한다는 것 입니다. 이 API는 호출된 에셋번들의 헤더 정보를 언로드합니다. 여기에 사용되는 매개변수는 이 에셋번들의 모든 생성된 오브젝트를 같이 언로드할 것인지를 가리킵니다. true인 경우에 그 에셋번들에서 만들어진 모든 객체들 또한 즉시 언로드 됩니다 – 그 객체들이 현재 씬에서 사용되고 있더라도 말이죠. 예를 들어, 매터리얼 M이 에셋번들 AB에서 로드 되었고, 매터리얼 M이 현재 씬에서 사용되고 있다고 가정해보겠습니다.
만약 프로젝트에 오브젝트를 로드하고 언로드하기 위해 유저를 기다리게 할 수 있는 잘 정의된 지점이 있다면(예를 들어 게임 모드나 레벨 사이), 이러한 지점들은 가능한 많은 오브젝트를 언로드하고 새로운 오브젝트를 로드하도록 사용되어야 합니다. 이렇게 하기 위한 가장 간단한 방법은 프로젝트의 불연속적인 덩어리들을 씬에 넣고, 이 씬과 연결된 모든 참조들을 에셋번들로 빌드하는 것 입니다. 그리고나서 애플리케이션은 “로딩” 씬으로 들어가서 이전 씬에 있던 에셋번들을 모두 언로드하고, 새로운 씬의 에셋번들을 로드합니다. 이 방식이 가장 간단한 방법이지만, 일부 프로젝트는 좀 더 복잡한 에셋번들 관리가 필요합니다. 통괄적으로(universal) 쓰일 수 있는 에셋번들 디자인 패턴은 없습니다. 각 프로젝트의 데이터는 다릅니다. 에셋번들에 오브젝트를 어떻게 그룹화해서 넣을지를 결정할 때, 동시에 로드되거나 업데이트 되어야하는 오브젝트들을 에셋번들에 넣는 것이 일반적으로 최선입니다. 예를 들어, RPG(role-playing game)를 생각해보자. 각 맵과 컷씬은 에셋번들로 그룹화될 수 있는데, 일부 오브젝트는 대부분의 씬에서 필요할 것 입니다. 에셋번들은 초상화, 인게임 UI, 다른 캐릭터 모델과 텍스쳐를 제공하기 위해 만들어 질 수 있습니다. 이런 오브젝트과 에셋들은 에셋번들의 두번 째 셋으로 그룹화될 수 있고, 이는 시작 시에 로드되고 앱의 생명주기 동안 로드된 채 남아 있습니다. 또 다른 문제는 에셋번들이 언로드 된 후에 다시 그 에셋번들로부터 오브젝트를 다시 로드하려고 하는 경우에 발생할 수 있습니다. 이러한 경우에, 다시 로드하는 것은 실패하게 되고 그 오브젝트는 유니티 에디터의 hierarchy에서 (Missing) 오브젝트 상태로 보이게 됩니다. 이는 주로 유니티가 그래픽 컨텍스트에 대한 제어를 잃었다가 다시 얻었을 때 발생하는데, 모바일 앱이 중지 되거나 유저가 PC를 잠금 상태로 변환했을 때가 이에 해당합니다. 이러한 경우에, 유니티는 텍스쳐와 셰이더를 GPU에 다시 업로드해야 합니다. 만약 이런 에셋을 위한 소스 에셋번들이 사용 불가능한 상태라면, 애플리케이션은 씬의 오브젝트를 “missing shader” 상태인 magenta 색상으로 그리게 됩니다. 4.2 배포프로젝트의 에셋번들을 고객에게 배포하는 기본적인 2가지 방법이 있습니다 : 프로젝트와 동시에 설치하는 것 또는 설치 후에 다운로드하는 방법입니다. 에셋번들을 설치에 포함 시킬 지 아니면 설치 후에 전달할 지에 대한 결정은 프로젝트가 구동할 플랫폼의 수용성(capabilities)과 제한(restrictions)에 따르게 됩니다. 모바일 프로젝트는 주로 설치 후에 다운로드 하는 방식을 선택하는데, 이는 초기 설치 크기를 줄이기 위함과 무선 다운로드 크기 제한1을 맞추기 위함입니다. 콘솔과 PC 프로젝트는 일반적으로 에셋번들을 초기 설치에 포함시킵니다. 적절한 아키텍쳐는 초기에 에셋번들을 어떤 형태로 전달했는지에 상관없이 설치 후에 새로운 컨텐츠나 수정된 컨텐츠를 패치할 수 있도록 해줍니다. 여기에 대한 더 자세한 내용을 알고 싶으면, 이 글의 에셋번들로 패치하기 섹션을 살펴보세요. 4.2.1. 프로젝트와 같이 전달에셋번들을 프로젝트에 같이 담아서 전달하는 것이 가장 간단한 배포 방법입니다. 왜냐하면 어떤 추가적인 다운로드 관리 코드가 필요없기 때문이죠. 설치 시에 왜 에셋번들을 포함시켜야 하는 지에 대한 2가지 주요한 이유는 다음과 같습니다 :
4.2.1.1. Streaming Assets설치 시에 유니티 애플리케이션에 어떤 형태의 컨텐츠를 포함시키는 가장 쉬운 방법은 해당 컨텐츠를 빌드 전에 /Assets/StreamingAssets/ 폴더에 넣는 것 입니다. 빌드 시에 StreamingAssets 폴더에 포함되어 있는 모든 것들은 최종 애플리케이션에 복사되어 질 것 입니다. 이 폴더는 최종 애플리케이션에 에셋번들 뿐만 아니라 어떤 종류의 컨텐츠도 저장해서 쓸 수 있습니다. 로컬 저장 공간에 있는 StreamingAssets 폴더의 전체 경로는 런타임에 Application.streamingAssetsPath 속성을 이용해서 접근할 수 있습니다. 그렇게해서 대부분의 플랫폼에서 AssetBundle.LoadFromFile을 통해 에셋번들을 로드할 수 있습니다. 4.2.2. 설치 후 다운로드(Downloaded post-install)모바일 장치에 에셋번들을 전달할 때 많이 사용되는 방법은 앱 설치 후 번들을 다운로드하는 방법입니다. 이는 또한 설치 후에 전체 애플리케이션을 다시 다운로드할 필요 없이, 새로운 컨텐츠나 정제된 컨텐츠를 업데이트할 수 있도록 해줍니다. 모바일 플랫폼에서는, 애플리케이션 이진파일은 비싸고 긴 재인증 프로세스를 거쳐야만 합니다. 따라서, 설치 후 다운로드를 위한 좋은 시스템을 개발하는 것은 매우 중요합니다. 에셋번들을 전달하는 가장 간단한 방법은 웹서버에 그 번들을 두고 WWW.LoadFromCacheOrDownload나 UnityWebRequest를 통해서 전달하는 것 입니다. 유니티는 다운로드된 에셋번들을 로컬 저장 공간에 자동으로 저장합니다. 만약 다운로드한 에셋번들이 LZMA로 압축되어 있다면, 추후에 빠르게 로딩하기 위해 압축을 해제한 상태로 저장되게 됩니다. 만약 다운로드한 번들이 LZ4로 압축되어 있다면, 압축된 상태 그대로 저장되게 됩니다. 캐쉬가 가득차게 되면, 유니티는 가장 오래 전에 사용된 에셋번들을 캐쉬에서 지우게 됩니다. 더 자세한 내용은 내장 캐쉬 섹션에서 보세요. WWW.LoadFromCacheOrDownload에는 결함이 있다는 것을 알아두세요. 에셋번들의 로드 섹션에 설명했듯이, WWW 오브젝트는 에셋번들을 다운로드하는 동안 동일한 크기의 메모리를 소비하게 됩니다. 이는 수용할 수 없는 메모리의 급증을 유발할 수 있습니다. 이를 피하기 위한 3가지 방법은 다음과 같습니다 :
가능하다면 UnityWebRequest를 써서 시작하는 것을 일반적으로 추천드리지만, 유니티 5.2 이하에서는 WWW.LoadFromCacheOrDownload를 추천드립니다. 유니티 기본 시스템 API의 메모리 소비, 캐쉬 동작, 성능이 특정 프로젝트에서 수용할 수 없을 정도이거나, 어떤 요구사항을 만족하기 위해 플랫폼 종속적인 코드를 실행시켜야만 하는 프로젝트의 경우에만 커스텀 다운로드 시스템에 투자를 하세요. UnityWebRequest나 WWW.LoadFromCacheOrDownload의 사용을 막을 수도 있는 상황에 대한 예 입니다 :
4.2.3. 내장 캐쉬두 API는 모두 매개변수로 에셋번들의 버전 번호를 받는 오버로드 메서드를 가지고 있습니다. 이 번호는 에셋번들의 내부에 저장되어 있지 않고, 에셋번들 시스템에 의해 생성되지도 않습니다. 캐쉬 시스템은 WWW.LoadFromCacheOrDownload나 UnityWebRequest로 전달된 가장 최근의 버전 번호를 유지하고 있습니다. 둘 중 어떤 API가 버전 번호를 넘겨받아서 호출되면, 캐쉬 시스템은 캐쉬된 에셋번들이 있는지 체크합니다. 만약 있다면, 에셋번들이 처음 캐쉬된 경우에 전달된 버전 번호와 현재 호출에 사용된 버전 번호를 비교해 봅니다. 이 번호가 같다면, 시스템은 캐쉬된 에셋번들을 로드하게 됩니다. 만약 번호가 다르다면, 캐쉬된 에셋번들이 없음을 의미하고, 유니티는 새로운 복사본을 다운로드하게 됩니다. 이 새로운 복사본은 새로운 버전 번호와 관계가 맺어집니다. 캐쉬 시스템에 있는 에셋번들은 파일명으로만 식별되고, 다운로드되는 전체 url과는 상관없습니다. 이는 같은 파일명의 에셋번들이 여러 다른 곳에 저장되어도 괜찮다는 의미입니다. 예를 들어, 하나의 에셋번들이 한 Content Delivery Network(CDN)의 여러 서버에 위치할 수 있습니다. 파일명이 같은 한, 캐쉬 시스템은 이들을 같은 에셋번들로 취급합니다. 에셋번들에 버전 번호를 할당하는 적절한 전략을 결정하고, 이 버전 번호를 WWW.LoadFromCacheOrDownload에 전달하는 것은 개별 애플리케이션에 달려있는 부분입니다. 대부분의 애플리케이션은 유니티 5의 AssetBundleManifest API를 사용할 수 있습니다. 이 API는 에셋번들의 컨텐츠에 대한 MD5 해쉬를 계산해서 각 에셋번들의 버전 번호를 생성할 수 있습니다. 에셋번들이 바뀔 때마다, 해쉬 값 또한 변하게 되고, 이는 에셋번들을 다운로드해야 함을 가리킵니다. 메모 : 유니티 내장 캐쉬 구현의 변덕(quirk)2 때문에, 오래된 에셋번들은 캐쉬가 가득 찰 때까지는 지워지지 않습니다. 유니티는 추후 릴리즈에서 이런 변덕에 대해 언급할 예정입니다. Caching.maximumAvailableDiskSpace 은 expirationDelay보다 덜 최근에 사용된 에셋번들을 삭제하기 시작하기 전에 캐쉬가 사용할 수 있는 로컬 저장 공간의 크기를 결정합니다. 여기에는 바이트 단위를 사용합니다. 한계 용량에 도달하게 되면, 유니티는 캐쉬 중에서 최근에 가장 적게 열었던 에셋번들(또는 Caching.MarkAsUsed를 통해 사용됐다고 표시된 에셋번들)을 삭제하게 됩니다. 유니티는 새로운 다운로드를 완료하기에 충분한 용량이 되기 전까지 캐쉬된 에셋번들을 삭제할 것 입니다. 메모 : 유니티 5.3에서, 내장 유니티 캐쉬를 조절하는 것은 매우 힘든 일 입니다. 캐쉬에서 특정 에셋번들을 삭제하는 것은 불가능합니다. 삭제는 시간적인 만기에 의해서, 디스크 사용 공간의 초과에 의해서, 또는 Caching.CleanCache(Caching.CleanCache 는 현재 캐쉬에 있는 모든 에셋번들을 삭제할 것 입니다.)에 의해서 발생합니다. 이는 개발 중이거나 라이브 동작 중일 때 문제가 될 수 있는데, 유니티가 애플리케이션에서 더 이상 사용되지 않는 에셋번들을 자동으로 지워주지 않기 때문입니다. 4.2.3.1. Cache Priming에셋번들은 파일명으로 식별되기 때문에, 애플리케이션에 같이 포함되는 에셋번들의 캐쉬를 가장 주요한 것으로 설정하는 것이 가능합니다. 이를 위해서, /Assets/StreamingAssets/에 있는 각 에셋번들의 최초 버전을 저장하십시오. 이 과정은 프로젝트와 같이 전달 섹션에 있는 상세 내용과 같습니다. 4.2.4. 커스텀 다운로더커스텀 다운로더를 작성하는 것은 어떻게 에셋번들이 다운로드되고, 압축 해제되고 저장되는 지에 대한 모든 제어를 애플리케이션에 줄 수 있습니다. 커스텀 다운로더를 작성하는 것은 야심찬 애플리케이션을 만드는 큰 팀에 한해서만 추천드립니다. 커스텀 다운로더를 작성할 때 생각해야 할 4가지 주요 문제에 대해 이야기 해보겠습니다 :
에셋번들의 패치에 대한 정보를 원하시면, 에셋번들로 패치하기 섹션을 살펴보십시오. 4.2.4.1 다운로드대부분의 애플리케이션에서, HTTP가 에셋번들을 다운로드하기에 가장 간단한 방법입니다. 하지만, HTTP 기반의 다운로더를 구현하는 것은 간단한 일이 아닙니다. 커스텀 다운로더는 메모리 초과 할당, 쓰레드 초과 사용, 쓰레드 초과 깨움(excessive thread wakeups)을 피해야만 합니다. 유니티의 WWW 클래스는 여기에서 철저히 설명하는 이유에 의해 부적절 합니다. WWW의 높은 메모리 비용 때문에, 유니티의 애플리케이션에서 WWW.LoadFromCacheOrDownload를 사용하지 않는다면 WWW 클래스는 피해야 합니다. 커스텀 다운로더를 작성할 때 3개의 옵션이 있습니다 :
4.2.4.1.1. C# 클래스애플리케이션이 HTTPS/SSL 지원을 필요로 하지 않는다면, C#의 WebClient 클래스는 에셋번들을 다운로드하는데게 가장 간단한 메커니즘을 제공합니다. 초과 메모리 할당 없이, 비동기적으로 어떤 파일을 다운로드해서 로컬 저장 공간에 바로 넣는 것이 가능합니다. WebClient를 이용해서 에셋번들을 다운로드하려면, 클래스의 인스턴스를 할당하고, 에셋번들을 다운로드하기 위한 URL과 목적지 경로를 전달해야 합니다. 요청의 매개변수를 통한 더 많은 제어가 필요한 경우에는 C#의 HttpWebRequest를 사용해서 다운로더를 작성하는 것이 가능합니다 :
플랫폼 메모 : iOS, 안드로이드, 윈도우즈 폰의 경우에만 유니티의 C# 런타임이 C# HTTP 클래스에 대한 HTTPS/SSL 지원을 합니다. PC에서는 C# 클래스를 통해서 HTTPS 서버에 접근하려고 하면 인증서 검증 에러(certificate validation errors)가 발생합니다. 4.2.4.1.2. 에셋 스토어 패키지일부 에셋 스토어 패키지는 HTTP, HTTPS와 다른 프로토콜을 통해서 파일을 다운로드하도록 네이티브 코드 구현을 제공하고 있습니다. 유니티를 위한 커스텀 네이티브 코드 플러그인을 제작하기 전에 사용 가능한 에셋 스토어 패키지를 평가해보는 것을 추천드립니다. 4.2.4.1.3. 커스텀 네이티브 플러그인커스텀 네이티브 플러그인을 작성하는 것은 유니티에서 데이터를 다운로드하기 위한 가장 시간이 많이 들고 가장 유연한 방법입니다. 높은 프로그래밍 시간과 높은 기술 위험도가 있기 때문에, 이 방법은 애플리케이션의 요구 사항을 만족할 다른 방법이 없는 경우에만 추천됩니다. 예를 들어, 유니티의 C# SSL 지원이 없는 윈도우즈, OSX, 리눅스 같은 플랫폼에서 애플리케이션이 SSL 통신을 해야만 하는 경우에, 커스텀 네이티브 플러그인이 필요할 수도 있습니다. 4.2.4.2. 저장 공간Application.streamingAssetPath는 쓰기 불가능하고 에셋번들 캐쉬로써는 나쁜 선택입니다. streamingAssetsPath의 위치에 대한 예는 다음과 같습니다 :
4.3. 에셋 할당 전략프로젝트의 에셋을 에셋번들로 어떻게 나눌 것인가에 대한 결정을 하는 것은 간단한 일이 아닙니다. 여기에서 지나치게 단순한 전략을 채용하는 유혹에 빠지기 쉬운데요, 예를 들면 모든 오브젝트를 하나의 에셋번들에 담는 것 처럼 말이죠. 그런데 이러한 해결책은 심각한 결함이 존재합니다 :
중요 결정은 어떻게 에셋번들에 오브젝트를 그룹핑 하는가 입니다. 주요한 전략은 다음과 같습니다 :
하나의 프로젝트에서 다른 카테고리의 컨텐츠를 위해 이러한 전략들을 섞어 쓸 수 있다는 것을 알아 두십시오. 예를 들어, 다른 플랫폼에 사용될 UI 요소들을 에셋번들에 같이 그룹핑하고, 인터렉티브 컨텐츠는 레벨이나 씬에 따라 그룹핑할 수 있습니다. 어떤 전략을 채용했는지와 상관없이, 따를 수 있는 가이드 라인이 여기에 있습니다 :
예 : 모델과 여기에 사용되는 애니메이션과 텍스쳐
일단 위의 가이드라인을 지키고 나면, 특정 시점에 에셋번들의 컨텐츠의 50% 미만이 사용된다면 이 에셋번들을 나누는 것을 고려해 보세요. 또한 동시에 로드되는 작은 에셋번들(5~10개 미만)을 결합하는 것도 고려해 보세요. 4.3.1. 논리적인 실체로 그룹핑(Logical entity grouping)논리적 실체로 그룹핑하는 방법은 프로젝트의 기능적인 부분에 기반하여 오브젝트를 그룹핑하는 전략입니다. 이 전략을 채용하면, 애플리케이션의 다른 부분은 다른 에셋번들로 분리되게 됩니다. 예 :
논리적 실체 그룹핑은 가장 흔한 에셋번들 전략이고, 이는 특히 다음과 같은 경우에 적합합니다 :
예 :
논리적 실체에 의해 에셋을 그룹핑하는 것의 장점은 변하지 않은 컨텐츠를 재 다운로드할 필요없이 쉽게 개별 실체를 업데이트할 수 있다는 것 입니다. 이러한 이유 때문에 이 전략이 특히 DLC에 맞다는 것 입니다. 이 전략은 또한 가장 메모리 효율적인 경향도 있는데, 애플리케이션이 현재 사용하는 실체에 대한 에셋번들만을 로드하기 때문입니다. 하지만, 이는 구현하기에 가장 다루기 어려운 전략입니다. 왜냐하면 에셋번들에 오브젝트를 할당하는 개발자가 정확히 어떻게, 그리고 언제 각 개별 오브젝트가 프로젝트에서 사용되는지에 익숙해야하만 하기 때문입니다. 4.3.2. 타입 그룹핑(Type Grouping)타입 그룹핑은 가장 간단한 전략입니다. 이 전략을 쓰면, 비슷하거나 같은 타입의 오브젝트들은 같은 에셋번들에 위치하게 됩니다. 예를 들어, 다른 오디오 트랙을 에셋번들에 넣거나, 다른 언어 파일을 에셋번들에 넣는 식으로 말이죠. 이 전략이 간단하기는 하지만, 빌드 시간, 로드 시간, 업데이트라는 측면에서는 종종 가장 비효율적 입니다. 이는 로컬라이지이션 파일같이 작고 동시에 업데이트되는 파일에 가장 자주 쓰입니다. 4.3.3. 동시 컨텐츠 그룹핑(Concurrent content grouping)동시 컨텐츠 그룹핑은 동시에 로드되고 사용되는 컨텐츠를 하나의 에셋번들에 넣는 전략입니다. 이 전략은 프로젝트의 컨텐츠가 매우 지역적인 경우(컨텐츠가 특정 위치나 시간 외에 거의 나타나지 않는 경우)에 가장 일반적으로 사용됩니다. 예로는 각 레벨마다 유일한 아트, 캐릭터, 사운드 이펙트를 사용하는 레벨 기반의 게임이 있을 수 있겠네요. 동시 컨텐츠 그룹핑을 수행하는 가장 흔한 방법은 씬에 기반한 에셋번들을 만드는 것인데, 각 씬에 기반한 에셋번들은 씬의 전체 또는 대부분의 의존성을 포함하고 있습니다. 컨텐츠가 강하게 지역적이지 않은 프로젝트에서, 그리고 애플리케이션의 생명주기 동안 컨텐츠가 나오는 위치가 바뀌는 경우에는 동시 컨텐츠 그룹핑은 논리적 실체 그룹핑으로 수렴하게 됩니다. 둘 다 에셋번들의 컨텐츠의 효율을 최대화하는데에 필수적인 전략입니다. 이러한 시나리오의 예로는 오픈 월드 게임이 있을 수 있습니다. 오픈 월드 게임에서 캐릭터는 랜덤하게 생성되고 월드 공간에 분포됩니다. 이러한 경우에, 어떤 캐릭터들이 동시에 나타날지 예측하기 쉽지 않고, 따라서 캐릭터들은 일반적으로 다른 전략을 이용해서 그룹핑 되어야 합니다. 4.4. 에셋번들로 패치하기패치 시스템에서 풀어야 할
더 어려운 문제는 어떤 에셋번들을 변경해야하는지 파악하는 것 입니다. 패치 시스템에는 두 정보 리스트가 필요합니다 :
패쳐(patcher)는 서버에 있는 에셋번들의 리스트를 다운로드하고 이미 있는 에셋번들 리스트와 비교해야 합니다. 없는 에셋번들이나, 버전 정보가 바뀐 에셋번들은 다시 다운로드되어야 합니다. 유니티 5의 에셋번들 시스템은 빌드가 끝나면 하나의 추가적인 에셋번들을 생성합니다. 이 여분의 에셋번들은 AssetBundleManifest 오브젝트를 포함하고 있습니다. 이 매니페스트 오브젝트는 에셋번들의 리스트와 그들의 해쉬 값을 포함하고 있고, 클라이언트에 가능한 에셋번들의 리스트와 버전 정보를 전달하는 데에 사용될 수 있습니다. 에셋번들 매니페스트 번들에 대한 더 자세한 내용을 알고 싶으시면 유니티 매뉴얼을 참고하세요. 에셋번들의 변화를 탐지하기 위한 커스텀 시스템을 작성하는 것도 가능합니다. 커스텀 시스템을 만드는 대부분의 개발자는 에셋번들 파일 리스트를 위한 산업 표준(industry-standard) 데이터 포맷을 사용해야하는데, 여기에는 JSON같은 것이 있고, 체크섬을 계산하기 위해 표준 C# 클래스를 사용하는데 예를 들면 MD5가 있습니다. 4.4.1. 차이 패치 (Differential patching)4.4.2. iOS On-Demand ResourcesOn-Demand Resources 는 컨텐츠를 iOS와 TVOS 장치에 제공하기 위한 애플 API입니다. 이는 iOS 9 장치에서 쓸 수 있습니다. 이 기능은 앱스토어에 런치하기 위해 현재 요구되는 조건은 아니지만, TVOS 앱에서는 런치에 필요한 요구조건 입니다. 애플의 On-Demand Resources 시스템에 대한 일반적인 아웃라인은 애플 개발자 사이트에서 찾아 볼 수 있습니다. 유니티 5.2.1 에서, App Slicing과 On-Demand Resources 둘 다에 대한 지원은 Asset Catalogs라는 다른 애플 시스템에 만들어져 있습니다. 유니티 에디터에서 콜백을 등록한 뒤에 iOS 애플리케이션을 위한 빌드 파이프라인은 Asset Catalogs에 자동으로 위치할 파일들을 보고하고 특정 On-Demand Resources 태그를 할당합니다. 4.5. 일반적인 실수이 섹션에서는 에셋번들을 사용하는 프로젝트에서 일반적으로 나타나는 몇몇 문제에 대해 다룹니다. 4.5.1. 에셋 중복유니티 5의 에셋번들 시스템은 어떤 오브젝트가 에셋번들 안에 들어 있다면, 이 오브젝트에 대한 모든 의존 관계를 가려버립니다. 이는 Asset Database를 사용할 때 발생합니다. 이러한 의존 관계 정보는 하나의 에셋번들에 포함될 오브젝트들을 결정하는 데에 사용됩니다. 하나의 에셋번들에 명시적으로 할당된 오브젝트들은 그 에셋번들에만 빌드될 것 입니다. 오브젝트가 “명시적으로 할당되었다”라는 것은 오브젝트의 에셋 임포터가 assetBundleName 속성을 비어있지 않은 스트링으로 가지고 있을 때를 말합니다. 이는 유니티 에디터의 해당 오브젝트 인스펙터에서 에셋번들을 선택하거나 에디터 스크립트에서 선택함으로써 이루어집니다. 만약 두 개의 다른 오브젝트가 각각 다른 에셋번들에 할당되었는데, 둘다 공통의 오브젝트에 대한 참조를 가지고 있다면, 그 의존 관계의 오브젝트는 두 에셋번들에 복제되게 됩니다. 복제된 의존 관계의 오브젝트는 인스턴스화 되는데, 이는 두 개의 복제된 의존 관계 오브젝트가 다른 식별자를 가진 별개의 오브젝트로 간주됨을 의미합니다. 이는 애플리케이션의 에셋번들 총 크기를 증가시킬 것 입니다. 또한 애플리케이션에서 이 두개의 오브젝트를 로드하게 되면 두개의 다른 복제본이 메모리에 로드되게 됩니다. 이를 해결하기 위한 몇 가지 방법이 있습니다 :
유니티 5에서, UnityEditor 네임스페이스에 있는 AssetDatabase API를 통해 오브젝트 간의 의존 관계를 추적할 수 있습니다. 네임스페이스가 함축하고 있듯이, 이 API는 런타임이 아닌 유니티 에디터에서만 사용 가능합니다. AssetDatabase.GetDependencies는 특정 오브젝트나 에셋의 모든 직접적인 의존 관계를 얻는 데에 사용될 수 있습니다. 이러한 의존 관계에는 스스로에 대한 의존 관계도 포함되어 있음을 기억하십시오. 추가로, AssetImporter API는 에셋번들에 어떤 특정 오브젝트가 할당됐는지 확인하기 위해 사용될 수 있습니다. AssetDatabase와 AssetImporter API를 조합하면, 에셋번들의 모든 직접 또는 간접 의존 관계가 어떤 에셋번들에 할당되도록 하거나, 의존 관계를 공유하는 두 개의 에셋번들이 존재하지 않도록 하는 에디터 스크립트를 작성하는 것이 가능합니다. 중복되는 에셋의 메모리 비용 때문에, 모든 프로젝트에서 그러한 스크립트를 사용하기를 추천드립니다. 4.5.2. 스프라이트 아틀라스 중복이어지는 섹션에서는 유니티 5의 에셋 의존 관계 계산 코드가 자동 생성되는 스프라이트 아틀라스과 함께 사용될 때의 변덕에 대해 다룹니다. 유니티 5.2.2p4와 유니티 5.3에서는 이런 동작을 해결하기 위한 패치가 이루어 졌습니다. 유니티 5.2.2p4과 5.3 그리고 그 이상 자동 생성된 스프라이트 아틀라스는 자신이 생성된 스프라이트 오브젝트를 포함하고 있는 에셋번들에 할당됩니다. 만약 그 스프라이트 오브젝트가 여러 개의 에셋번들에 할당되어 있다면, 스프라이트 아틀라스는 하나의 에셋번들에 할당되지 않고 중복되게 됩니다. 스프라이트 아틀라스가 중복되지 않게 하려면, 같은 아틀라스로 태그된 모든 스프라이트가 같은 에셋번들에 할당되도록 하십시오. 유니티 5.2.2p3와 그 이하 자동 생성된 스프라이트 아틀라스는 절대 어떤 한 에셋번들에 할당되지 않습니다. 이 때문에, 이 아틀라스는 이를 구성하고 있는 스프라이트가 포함된 에셋번들과, 이 스프라이트들이 참조하고 있는 에셋번들에도 포함되어 집니다. 이러한 문제때문에, 유니티의 스프라이트 패커를 사용하는 모든 유니티 5 프로젝트는 유니티 5.2.2p4나 5.3 또는 그 이상의 새로운 버전으로 업그레이드하기를 강력하게 추천하는 바입니다. 업그레이드할 수 없는 프로젝트의 경우에는 2가지 회피 방법이 있습니다 :
4.5.3. 안드로이드 텍스쳐안드로이드 생태계의 심각한 디바이스 파편화 때문에, 텍스쳐를 몇몇 다른 포맷으로 압축하는 것은 종종 필수적입니다. 모든 안드로이드 장치가 ETC1을 지원하지만, ETC1은 텍스쳐의 알파 채널을 지원하지 않습니다. 애플리케이션이 OpenGL ES 2 지원을 필요로하지 않는다면, 이 문제를 해결하기 위한 가장 명확한 방법은 ETC2를 사용하는 것이고, 이는 OpenGL ES 3를 지원하는 모든 안드로이드 장치에서 사용 가능합니다. 대부분의 애플리케이션은 ETC 지원이 안되는 오래된 기종에도 설치할 필요가 있습니다. 이를 해결하기 위한 하나의 방법은 유니티 5의 AssetBundle Variants를 사용하는 것 입니다. (다른 옵션에 대한 자세한 내용을 알고 싶으면, 유니티의 안드로이드 최적화 가이드를 봐주세요.) AssetBundle Variants를 사용하기 위해서, 확실하게 ETC1으로 압축할 수 없는 모든 텍스쳐들은 텍스쳐만 있는 에셋번들로 분리해야 합니다. 다음으로, 안드로이드 생태계에서 ETC2를 수용할 수 없는 장치를 지원하기 위해 충분한 에셋번들 variants를 만들어야 합니다. 이 때 제조사 특유의 압축 포맷을 사용할 수 있는데, DXT5, PVRTC, ATITC 등이 있습니다. 각 에셋번들 variant에 대해서, 포함된 텍스쳐의 TextureImporter 셋팅의 압축 포맷을 variant에 적절하게 변경하십시오. 안드로이드 텍스쳐 압축 포맷에 대한 더 자세한 내용은 여기에서 보실 수 있습니다. 4.5.4. iOS 파일 핸들 남용이 섹션에 나오는 내용은 유니티 5.3.2p2에서 수정되었습니다. 현재 유니티 버전은 이 이슈에 영향을 받지 않습니다. 유니티 5.3.2p2 이전 버전에서는, 에셋번들이 로드되어 있는 전체 시간 동안 유니티가 그 에셋번들에 대한 파일 핸들을 유지하고 있었습니다. 이는 대부분의 플랫폼에서는 문제가 되지 않습니다. 하지만, iOS에서는 한 프로세스에서 동시에 열 수 있는 파일 핸들의 수가 255개로 제한되어 있습니다. 만약 에셋번들을 로드하다가 이러한 제한을 초과하게 되면, “Too Many Open File Handles” 에러를 내뿜으로 로딩 콜이 실패하게 됩니다. 이는 컨텐츠를 수백개 또는 수천개의 에셋번들로 나누려고하는 프로젝트에서 흔히 발생할 수 있는 문제였습니다. 패치된 버전의 유니티로 업그레이드할 수 없는 프로젝트에서는, 임시 방편이 있습니다 :
4.6. 에셋번들 Variants유니티 5의 에셋번들 시스템의 주요 특징은 AssetBundle Variants의 도입입니다. Variants의 목적은 애플리케이션을 런타임 환경에 더 잘 맞게 컨텐츠를 조절하도록 하는 것 입니다. 오브젝트를 로딩하고 Instance ID 참조를 풀 때, Variants는 다른 에셋번들 파일에 있는 다른 UnityEngine.Object를 마치 “같은” 오브젝트 인 것 처럼 보이게 해줍니다. 개념상, 이는 두 개의 UnityEngine.Object가 같은 File GUID와 Local ID를 공유하는 것처럼 보이게 해주고, 스트링 Variant ID를 이용해 로드할 실제 UnityEngine.Object를 식별합니다. 이 시스템의 2가지 주된 사용 사례가 있습니다 :
4.6.1. 한계에셋번들 Variant 시스템의 핵심 한계는 구별되는 에셋으로부터 Variants를 빌드할 필요가 있다는 점 입니다. 이 한계는 에셋의 임포트 셋팅에 대한 차이만으로도 적용 가능합니다. 만약 Variant A와 Variant B의 차이가 유니티 텍스쳐 임포터에서 설정한 텍스쳐 압축 알고리즘이 유일한 차이라면, Variant A와 Variant B는 완전히 다른 에셋입니다. 이는 Variant A와 Variant B는 디스크 상에서 별도 파일로 저장되어야 함을 의미합니다. 이러한 한계점은 소스 컨트롤에 의해 유지되어야 하는 특정 에셋에 대한 여러 개의 복제본을 가지는 큰 프로젝트의 관리를 복잡하게 만듭니다. 개발자가 그 에셋의 컨텐츠를 바꾸려고 하면, 해당 에셋의 모든 복제본이 업데이트 되어야 합니다. 이 문제에 대해 내장된 회피 수단은 존재하지 않습니다. 대부분의 팀은 그 팀만의 에셋번들 Variants 형태를 구현합니다. 이는 에셋번들의 파일명 뒤에 잘 정의된 접미사를 붙임으로써 할 수 있습니다. 이 때 접미사를 붙이는 이유는 그 에셋번들에 특정 variant를 식별하기 위함입니다. 커스텀 코드는 이러한 에셋번들을 빌드할 때, 포함되는 에셋의 임포터 셋티을 프로그램적으로 변경합니다. 일부 개발자들은 프리팹에 붙어있는 컴포넌트의 인자를 변경하기 위해 자신의 커스텀 시스템을 확장하기도 합니다. 4.7. 압축 또는 비압축?에셋번들을 압축할지 말지에 대해서는 신중한 고려가 필요합니다. 중요한 질문은 다음과 같습니다 :
4.8. 에셋번들과 WebGL유니티는 WebGL 프로젝트에서는 압축된 에셋번들을 사용하지 말 것을 강력히 추천합니다. 유니티 5.3에서, WebGL 프로젝트에서 모든 에셋번들의 압축 해제와 로딩은 메인 쓰레드에서 발생합니다. 이는 유니티 5.3의 WebGL 익스포트 옵션에서는 워커 쓰레드를 지원하지 않기 때문입니다. ( 에셋번들의 다운로드는 브라우저로 위임되어 XMLHttpRequest 자바스크립트 API를 통해 이루어지고, 유니티의 메인 쓰레드 밖에서 발생할 것 입니다.) 이는 WebGL에서 압축된 에셋번들을 매우 비쌈을 의미합니다. 대게는 에셋번들을 압축하지 않은 상태로 빌드하고, 애플리케이션의 컨텐츠를 제공하는 웹 서버가 에셋번들을 gzip 압축 형태로 제공하도록 설정하는 것이 훨씬 빠릅니다. gzip 압축이 LZMA와 같은 압축률을 낼 수는 없지만, 에셋번들은 브라우저에 의해 워커 쓰레드에서 압축 해제 되고, 유니티 애플리케이션은 에셋번들의 압축을 해제하는 동안 오랫 동안 멈춰있는 경험을 하지 않아도 됩니다.
출처: https://code-kooc.tistory.com/entry/번역-에셋번들-사용-패턴 [코드쿡] |