반응형

섹션 9 : 일반적인 함정

이번 섹션에서는 프로젝트에서 에셋 번들을 사용할 때 일반적으로 발생하는 몇 가지 문제에 대해서 설명할 것이다.


에셋 복제(Asset Duplication) - 유니티 5의 에셋 번들 시스템은 오브젝트가 에셋 번들에 내장 되었을 때 객체의 모든 종속성을 발견하게 된다. 이것은 에셋 데이터베이스를 통해서 수행된다. 이 종속성 정보는 에셋 번들에 포함된 오브젝트 집합을 결정하는데 사용된다.


에셋 번들에 명시적으로 등록된 객체는 해당 에셋 번들에만 등록된다. 오브젝트의 에셋 임포터의 assetBundleName 속성이 비어있지 않은 문자열로 설정된 경우에만 객체가 "명시적으로 등록"되는 것이다.


에셋 번들에 명시적으로 등록되지 않은 오브젝트는 이 것을 참조하는 오브젝트가 포함된 모든 에셋 번들에 등록된다.


두 개의 서로 다른 오브젝트가 서로 다른 에셋 번들에 등록되어 있는데, 둘 다 하나의 객체를 참조하고 있다면 그 객체는 두 에셋 번들에 모두 복사된다. 이렇게 중복된 종속성 역시 인스턴스화 되는데, 이러한 인스턴스는 하나의 객체가 아니라 달라진 식별자로 인해 서로 다른 객체로 간주된다. 이로 인해서 응용 프로그램의 에셋 번들의 전체 크기가 증가하게 된다. 또한 응용 프로그램에서 부모를 모두 불러오는 경우 두 개의 오브젝트 사본이 메모리에 불러와진다.


이 문제를 해결할 수 있는 몇 가지 방법이 있는데 그것은 다음과 같다 :

1. 서로 다른 에셋 번들에 등록된 오브젝트들이 종속성을 공유하지 않도록해야 한다. 종속성을 공유하는 모든 오브젝트는 동일한 에셋 번들에 배치함으로써 종속성의 복제를 배제할 수 있다.

- 이 방법은 일반적으로 공유 종속성이 많은 프로젝트에서는 사용하기 부적절하다. 편리하고 효율적으로 만들기 위해서 과도하게 자주 다시 빌드하고 다시 다운로드해야 하는 한덩어리의 에셋 번들이 생성될 것이다.

2. 종속성을 공유하는 2개의 에셋 번들이 동시에 불러와지지 않도록 에셋 번들을 세그먼트화해야 한다.

- 이 방법은 레벨 기반 게임과 같은 특정 유형의 프로젝트에 적용할 수 있다. 하지만 여전히 프로젝트의 에셋 번들의 크기가 불필요하게 증가하고 빌드 시간과 로딩 시간이 증가하는 문제가 있다.

3. 모든 종속성 에셋이 자체 에셋 번들에 빌드되었는지 확인해야 한다. 이 방식은 에셋의 복제 위험을 완전히 제거하지만 복잡성 문제를 발생시킨다. 이것을 위해서 응용 프로그램은 에셋 번들 간의 종속성을 추적하고 AssetBundle.LoadAsset API를 호출하기 전에 올바른 에셋 번들이 불러와졌는지 확인해야 한다.


유니티 5에서, 오브젝트 의존성은 UnityEditor 네임 스페이스의 AssetDatabase API를 통해서 추적된다. 네임 스페이스의 이름이 의미하듯이 이 API는 유니티 에디터 상에서만 사용할 수 있으며 런타임 시에는 사용할 수 없다. AssetDatabase.GetDependencies는 특정 오브젝트나 에셋의 모든 즉각적인 종속성을 찾는데 사용할 수 있다. 참고로 이러한 종속성에는 자체 종속성이 있을 수 있다. 추가적으로 AssetImporter API를 사용하여 특정 오브젝트가 등록되어 있는 에셋 번들을 쿼리할 수 있다.


AssetDatabase와 AssetImporter API를 결합하여 모든 에셋 번들의 직접 또는 간접 종속성이 에셋 번들에 등록되도록 하거나, 두 개의 에셋 번들이 에셋 번들에 등록되지 않은 종속성을 공유하지 않도록하는 에디터 스크립트를 작성할 수 있다. 에셋을 복제하는데 소모되는 메모리 비용을 생각하면 모든 프로젝트에 이러한 스크립트가 있는 것이 좋다.


스프라이트 아틀라스 복제(Sprite Atlas Duplication) - 이 섹션에서는 자동으로 생성된 스프라이트 아틀라스와 함께 사용될 때 발생하는 유니티 5의 에셋 종속성 계산 코드의 단점에 대해서 설명한다.


자동으로 생성된 스프라이트 아틀라스느느 스프라이트 아틀라스가 생성된 스프라이트 오브젝트를 포함하는 에셋 번들에 등록된다. 만약 스프라이트 오브젝트가 여러 에셋 번들에 등록되어 있다면 스프라이트 아틀라스는 하나의 에셋 번들에 등록되지 않고 복제된다. 스프라이트 오브젝트가 에셋 번들에 등록되지 않은 경우라면 스프라이트 아틀라스는 에셋 번들에도 등록되지 않는다.


스프라이트 아틀라스가 중복되지 않도록 하려면 동일한 스프라이트 아틀라스에 태그가 지정된 모든 스프라이트가 하나의 에셋 번들에 등록되어 있는지 확인해야 한다.


유니티 5.2.2p3 이전 버전

자동으로 생성된 스프라이트 아틀라스는 에셋 번들에 등록되지 않는다. 그렇기 때문에 구성 스프라이트를 포함하는 모든 에셋 번들 및 해당 구성 스프라이트를 참조하는 모든 에셋 번들에 포함된다. 이 문제 때문에 유니티 스프라이트 패커를 사용하는 모든 유니티 5 프로젝트에 대해서 5.2.2p4, 5.3 또는 최신 버전의 유니티로 업드레이드하는 것을 강력히 권장한다.


만약 업그레이드를 할 수 없는 상황에 놓인 프로젝트의 경우에 이 문제에 대한 두 가지 해결 방법이 있다.

1. 쉬운 방법 : 유니티의 내장 스프라이트 패커의 사용을 피할 것. 외부 도구에 의해 생성된 스프라이트 아틀라스는 정상적인 에셋이 될 것이고, 에셋 번들에 적절하게 등록될 수 있다.

2. 어려운 방법 : 자동으로 아틀라스화된 스프라이트를 사용하는 모든 오브젝트를 스프라이트와 동일한 에셋 번들에 등록하라.

- 이렇게 하면 생성도니 스프라이트 아틀라스가 다른 에셋 번들의 간접적인 종속성으로 보이지 않으며 복제되지 않게 된다.

- 이 해결책은 유니티의 스프라이트 패커를 사용하는 워크 플로우를 보존하지만 에셋을 다른 에셋 번들로 분리하는 개발자의 능력을 저하시키며, 아틀라스를 참조하는 컴포넌트에서 데이터가 변경될 때마다 전체 스프라이트 어트리뷰트의 재 다운로드를 강제한다. 아틀라스 자체는 변경되지 않는다.


안드로이드 텍스처(Android Texture) - 안드로이드 환경은 기기 별로 매우 세분화되어 있기 때문에, 텍스처를 여러 가지 형식으로 압축해야하는 경우가 있다. 모든 안드로이드 기기가 ETC1을 지원하지만 ETC1은 알파 채널이 있는 텍스처를 지원하지 않는다. 만약 응용 프로그램이 OpenGL ES2 지원이 필요하지 않다면, 이 문제를 해결하는 가장 깔끔한 방법은 모든 안드로이드 OpenGL ES3 장치에서 지원되는 ETC2를 사용하는 것이다.


대부분의 응용 프로그램은 ETC2 지원을 사용할 수 없는 구형 기기에서 제공되어야 한다. 이 문제를 해결하는 한 가지 방법은 유니티 5의 에셋 번들 Variants를 사용하는 것이다(다른 옵션에 대한 자세한 내용은 유니티 안드로이드 최적화 가이드를 참조).


에셋 번들 Variants를 사용하려면 ETC1을 사용하여 깨끗하게 압축할 수 없는 모든 텍스처를 텍스처 전용 에셋 번들로 분리해야 한다. 그 다음 DXT5, PVRTC, ATITC와 같은 공급 업체별 텍스처 압축 형식을 사용하여 안드로이드 환경 별 비-ETC-가능 슬라이스를 지원하기 위해 이러한 에셋 번들의 충분한 variants를 만들어야 한다. 각 에셋 번들 Variants에 대해 포함된 텍스처의 텍스처 임포터 설정을 Variants에 적합한 압축 포맷으로 변경한다.


런타임 시에, SystemInfo.SupportsTextureFormat API를 사용하여 다양한 텍스처 압축 형식에 대한 지원을 감지할 수 있다. 이 정보는 지우너되는 형식으로 압축된 텍스처가 포함된 에셋 번들 Variants를 선택하고 불러오는데 사용해야 한다.


안드로이드 텍스처 압축 형식에 대한 자세한 내용은 이곳(here)을 참조하라.


iOS 파일 처리 과용(iOS File Handle Overuse) - 이 섹션에서 설명하는 문제는 유니티 5.3.2p2에서 수정되었다. 현재 버전의 유니티는 이 문제의 영향을 받지 않는다.


유니티 5.3.2p2 이전 버전에서는 유니티가 에셋 번들이 불러와지는 전체 시간동안 에셋 번들에 대한 열린 파일 핸들을 보유한다. 이것은 사실 대부분의 플랫폼에서는 문제가 되지 않지만, iOS는 프로세스가 동시에 열 수 있는 파일의 핸들 수를 255개까지만 제한하기 때문에 이 한도를 초과하여 에셋 번들을 불러오면 로딩 호출이 "Too Many Open File Handles" 오류와 함께 실패한다.


이것은 수백 또는 수천개의 에셋 번들에서 콘텐츠를 나누려는 프로젝트에서 발생하는 일반적인 문제였다.


새로운 버전의 유니티로 업그레이드할 수 없는 프로젝트에 대한 임시 해결책은 다음과 같다.

1. 관련된 에셋 번들을 합쳐서 사용중인 에셋 번들의 수를 줄인다.

2. AssetBundle.Unload(false)를 사용하여 에셋 번들의 파일 핸들을 닫고 로드된 오브젝트의 라이프 사이클을 수동으로 관리한다.


반응형

+ Recent posts