본문 바로가기

진리는어디에

[Unity] Asset Bundle

!!NOTE!!

유니티 2018.2 이상 버전 부터 AssetBundleManager의 지원을 중단한다는 공식 발표가 있었습니다.
2019.3 버전 부터 '어드레서블 에셋 시스템'이라는 새로운 에셋 관리 시스템이 추가 되며 , 2018 LTS 릴리스에서도 지원 된다고 합니다. 아래 내용들은 예전에 이런 것들이 있었구나..하는 역사 공부 정도로만 봐주시면 됩니다.

어드레서블 에셋 시스템은 -> https://blogs.unity3d.com/kr/2019/07/15/addressable-asset-system/에 있습니다. 내용도 알차고 한글로 잘 씌여져 있는지라 제가 따로 포스팅을 쓸 건덕지가 없네요.

들러 주셔서 감사합니다. 좋은 하루 되세요.
 
이번 포스팅에서는 어셋 번들의 기본 개념과 유니티에서 어셋스토어를 통해 제공하고 있는 '어셋번들 매니저'를 이용하여 어셋번들을 만들고 로드하는 과정에 대해 알아 보도록 하겠습니다.

'어셋번들(Asset Bundle)' 이란?

어셋번들(Asset Bundle)은 유니티에서 사용하는 실행 어플리케이션과 별도로 배포/로딩 될 목적으로 저장된 어셋들과 씬들을 집합한 파일로써, 필요시에 로컬에서 직접 로딩 혹은 원격 저장소에서 다운로드 받은 후 로딩 할수 있는 기능을 제공합니다.
이를 통해 새로 빌드된 어플리케이션의 자체의 배포 없이, 변경 되거나 신규 추가된 데이터만을 필요시에 동적으로 배포 할수 있도록 해줍니다.
우리는 어셋 번들을 이용해 어플리케이션의 데이터가 변경 될때 마다 각 스토어에 검수를 받을 필요 없이 컨텐츠를 업데이트 한다던지, DLC 등을 쉽게 구현 할 수 있습니다.
좀 더 구체적으로, 어셋번들에 포함 될수 있는 어셋은 스크립트를 제외한 유니티에서 사용하는 거의 모든 것 - 모델, 머트리얼, 텍스쳐, 오디오 클립, 심지어는 커스텀 바이너리 데이터 까지 - 이며 스트리밍 기반의 비동기 로딩을 가능하게 도와 줍니다.
어셋번들의 기본적인 속성은 아래와 같습니다 :
  • 어셋번들은 전체가 다운로드 되고 캐싱 됩니다. 그렇다고 전체를 로드 할 필요는 없습니다. 번들 내에 필요한 어셋만 구분하여 로드할 수 있습니다.
  • 어셋번들에 포함된 어셋들은 서로 의존성을 가질 수도 있습니다. 그리고 그 의존성을 공유 할 수 있습니다. 예를 들어 게임 오브젝트 A와 B가 동일한 머트리얼과 텍스쳐 어셋을 공유 할 수 있다는 의미 입니다.
  • 각 어셋 번들은 파일의 사이즈 오버헤드와 번들을 관리하는데 들어가는 기술적 오버헤드를 가집니다.
  • 어셋 번들은 각 타겟 플랫폼에 맞추어 빌드 되어야 합니다.

어셋번들의 메니페스트(Manifest)와 의존성 관리

어셋번들에서 어셋의 의존성은 절대 누락되지 않습니다. 여기서 '의존성'이란 아래 그림과 같이 모델이 머트리얼을 참조하고, 머트리얼은 텍스쳐를 참조하는 각 어셋들의 참조 관계를 의미합니다. 

탱크 모델 어셋의 의존성 체인 : 모델 > 머트리얼 > 텍스쳐

서로 의존성을 가지고 있는 어셋은 명시적으로 어셋번들 이름이 지정되어 있지 않다고 하더라도 자동적으로 어셋번들에 포함되어 빌드 됩니다. 이런 방법은 모든 참조 어셋들에 대해 일일이 관리할 필요 없이 모델과 같은 최상위 어셋만 어셋번들을 명시적으로 지정해 주면 된다는 편리함이 있는 반면, 어셋번들에 포함되는 어셋들의 중복을 유발 할 수 있다는 단점이 있습니다.

예를 들어 두개의 모델이 하나의 머트리얼을 공유한다고 가정해 보겠습니다. 그리고 각각의 모델은 다른 어셋번들에 포함되도록 명시적으로 지정되어 있고, 머트리얼에는 명시적으로 어셋번들이 지정 되어 있지 않다고 하겠습니다. 이런 경우 머트리얼은 자동적으로 두 어셋번들에 각각 독립적으로 추가 됩니다. 결국 머트리얼의 공유라는 것이 의미가 없어집니다. 이런것을 방지하기 위해서는 머트리얼은 명시적으로 어셋번들에 할당 되어야 합니다. 

어셋번들의 의존성과 기타 다른 정보들은 메니페스트(Manifest)에 저장됩니다. 메니페스트는 일종의 컨텐츠 테이블 같은 것으로써, 어셋번들이 빌드 되면 유니티는 많은 양의 데이터를 생성하고 해당 데이터들의 상세정보가 메니페스트에 저장됩니다. 메니페스트는 어셋번들의 타겟 빌드마다 따로 만들어지며 이 메니페스트 파일을 통해 모든 어셋번들에 대한 질의와 의존성 참조가 이루어 집니다. 추후 뒤에 나오는 어셋번들의 빌드 과정이후 각 결과 폴더를 살펴 보면 어셋번들 하나당 .manifest라는 확장자를 가진 파일이 만들어 지는 것을 확인 할 수 있습니다.

어셋번들 매니저(Asset Bundle Manager)?

어셋번들을 사용 할때 가장 많은 노력이 필요한 부분은 어셋번들을 빌드하고 정상적으로 로딩 되는지 테스트 하는 부분입니다. 개발 중 어셋번들에 포함 되는 어셋들은 얼마든지 변경되거나 추가, 삭제 될 수 있습니다. 기본적으로  이런 경우 전체 어셋들을 다시 빌드하고, 원격 저장소에 업로드하고, 정상적인 다운로드와 로딩을 테스트 하는 과정을 반복해야 합니다. '어셋번들 매니저'(AssetBundle Manager)는 이와 같은 복잡하고 반복적인 작업을 단순한 클릭과 간단한 스크립트 작업으로 해결할 수 있도록 도와 줍니다. 어셋번들을 만들고 사용하는 과정을 요약하면 아래와 같습니다 :

  1. 유니티 에디터에서 어셋번들에 포함될 어셋들을 지정
  2. 어셋번들 빌드
  3. 외부 저장소에 어셋번들을 업로드
  4. 어플리케이션에서 어셋번들을 다운로드
  5. 어플리케이션에서 어셋번들을 로드

어셋번들 매니저를 이용하면 위 과정중 1번. 어셋번들에 포함될 어셋들을 지정하는 작업외에는 모든 부분을 어셋번들 매니저에게 맡길수 있습니다.

1. 어셋번들에 포함될 어셋들을 지정

어셋들을 어셋번들로 빌드하기 위한 첫번째 과정은 해당 어셋이 어떤 어셋번들에 포함될 것인지, 어셋번들의 이름을 지정해 주는 것입니다. 여러분들은 이것을 위해서 유니티 에디터에서 간단한 설정 몇가지만 해주면 됩니다. 프로젝트(Project) 탭의 어셋을 클릭하면 인스펙터(Inspector)창에 해당 아래와 같은 어셋의 프리뷰를 볼수 있습니다.

어셋을 어셋번들에 포함되게 하기 위해서는 Asset Bundle Name 드롭 다운 메뉴를 이용하여 어셋이 어떤 어셋번들에 포함 될 것인지 지정해 주기만 하면 됩니다.

  1. 드롭 다운 메뉴를 클릭
  2. 포함 될 어셋번들의 이름을 선택.
    새로운 번들을 만들고 싶다면 'New...'를 선택 후 이름을 할당해 주고, 제외하고 싶다면 'None'을 선택
  3. 사용되지 않는 어셋번들을 지우고 싶다면 'Remove Unused Name' 선택

2. 어셋번들 베리언트(Asset Bundle Variant) 사용

어셋번들은 어셋 리소스를 저장하고 로드하는데 마주하는 많은 어려움들을 해결하는데 도움을 줍니다. 특히 이번 장에서 알아볼 어셋번들 베리언트는 타겟 디바이스나 로컬라이징, 유저 설정에 따라 다양한 어셋번들중 특정 버젼을 쉽게 로딩 할수 있도록 도와 줍니다. 예를 들어 어플리케이션이 한국에서 실행 되느냐 미국에서 실행 되느냐에 따라 메뉴가 한글이 될수도 있고 영어가 될수 있습니다. 이런 경우 모든 언어에 대응하는 텍스트 어셋번들을 만들고 배포하는 것이 아니라 한글버젼 어셋번들과 영어버젼 어셋번들을 만들고 어셋번들 베리언트를 이용해 구분하여 필요한 국가의 언어팩만 로드 할 수 있습니다.어셋번들 베리언트를 이용하기 위해서는 :

  • 'Asset Bundle Name'은 동일해야 합니다
  • 유일하게 달라야 할 부분은 Asset Bundle Variant 부분 입니다.
  • 어셋번들 베리언트를 이용한 어셋번들간에 호환성을 가지려면 어셋번들에 포함 되는 컨텐츠의 폴더와 모든 어셋들은 같은 이름과 같은 계층구조를 가져야 합니다.

Project 탭

어셋번들 실전에서 사용하기

지금까지 어셋 번들의 기본 개념에 대해서 알아 보았습니다. 이번 장에서는 우리가 어셋 번들과 관련된 작업을 함에 있어서 큰 도움을 줄수 있는 '어셋번들 매니저'(AssetBundleManager)를 이용하여 어셋 번들과 번들에 포함된 어셋들을 로드하는 방법에 대해서 알아보도록 하겠습니다. 

이전 장에서 우리는 어셋 번들을 사용하기 위해서는 빌드를 해야 하고, 원격 저장소 혹은 로컬 저장소에 배포를 해야 하며, 우리의 어플리케이션 내에서 API를 사용하여 로드를 해야 함을 배웠습니다. 만일 어셋 번들에 포함되는 어셋 중 하나라도 변경이 된다면, 변경이 발생할 때 마다 우리는 빌드 -> 배포 -> 테스트와 같은 지루하고 오랜 시간이 걸리는 작업을 반복 해야 합니다. 어셋 번들 매니저는 '시뮬레이션 모드'와 '로컬 어셋 번들' 서버를 제공함으로써 실제 빌드, 배포 과정을 거치지 않고도 정상적으로 어플리케이션이 어셋번들과 연동되는지 테스트 해볼수 있는 기능을 제공합니다.

  1. 시뮬레이션 모드
    시뮬레이션 모드가 활성화 되면 어셋번들 매니저는 프로젝트에 포함된 어셋들을 빌드하는 시뮬레이션을 수행합니다. 단순히 유니티 에디터 메뉴에서 “Assets/AssetBundles/Simulation Mode”를 체크해주면 시뮬레이션 모드가 활성화 됩니다. 시뮬레이션 모드에서는 실제 어셋번들 빌드를 수행하는 것이 아닌 프로젝트 런타임 시점에 빌드과정에 대해 시뮬레이션만 진행하는 것이므로 실제 빌드 보다 훨씬 빠른 속도를 제공합니다. 단, 주의할 점은 어셋번들 베리언트를 사용시 시뮬레이션 모드에서는 동작을 하지 않습니다.
  2. 로컬 어셋 번들 서버
    로컬 어셋 번들 서버는 보다 정확한 어셋 번들 배포 시뮬레이션을 제공합니다. 로컬 어셋 번들 서버를 사용하기 위해서는 유니티 에디터 메뉴에서 “Assets/AssetBundles/Local AssetBundle Server”를 활성화 하고 어셋 번들 빌드을 빌드하고 빌드된 어셋번들을 기본 폴더(프로젝트 최상위 폴더/AssetBundles)에 저장하는 과정이 필요합니다. 로컬 어셋 번들 서버가 활성화 되면 빌드된 어셋번들은 에디터와 모든 로컬 빌드에서 접근이 가능합니다. 로컬 어셋 번들 서버는 어셋 번들 베리언트를 로컬에서 테스트 해볼수 있는 유일한 방법이며 샘플로 제공된 씬을 구동하기 위해서 로컬 어셋 번들을 활성화 시키는 과정이 반드시 필요한 경우도 있습니다.

어셋 번들 매니저가 제공하는 기능들을 살펴 보았으니 지금 부터는 로드에 필요한 API들에 대해 어셋 번들 매니저 샘플 예제를 통해 살펴 보도록 하겠습니다. 먼저 어셋 번들 매니저가 제공하는 API를 살펴 보도록 하죠 (AssetBundleManager/AssetBundleManager.cs 참고) :

  • Initialize() : 어셋번들 메니페스트(http://docs.unity3d.com/ScriptReference/AssetBundleManifest.html) 객체를 초기화 합니다.
  • LoadAssetAsync() : 어셋번들로 부터 지정된 어셋과 의존성을 가지고 있는 모든 다른 어셋들을 로드 합니다.
  • LoadLevelAsync() : 어셋번들로 부터 지정된 신과 의존성을 가지고 있는 모든 다른 어셋들을 로드 합니다.
  • LoadDependencies() : 지정된 어셋번들이 의존성을 가지고 있는 모든 다른 어셋번들들을 로드 합니다.
  • BaseDownloadingURL : 기본 다운로드 URL 경로를 지정합니다.
  • SimulateAssetBundleInEditor : 유니티 에디터의 시뮬레이션 모드를 활성화 합니다.
  • ActiveVariants : 어셋번들 베리언트를 저장합니다.
  • RemapVariantName() : 어셋번들 베리언트 네임을 이용하여 적합한 어셋번들 이름을 리턴합니다.

AssetBundleManager 패키지에는 위 API들의 사용 예를 보여주는 샘플 파일들이 AssetBundleSample 폴더에 포함되어 있습니다. 샘플에는 세가지 기본 예제 씬과 세가지 예제들을 종합적으로 보여 주는 예제 씬이 'AssetBundleSample/Scenes'에 있습니다 :

  • AssetLoader : 어셋번들로 부터 일반 어셋을 어떻게 로드하는지 보여 줍니다.
  • SceneLoader : 어셋번들로 부터 씬을 어떻게 로드하는지 보여 줍니다.
  • VariantLoader : 어셋번들 베리언트를 이용하여 어셋을 로드하는 방법을 보여 줍니다.
  • LoadTanks : 위 세가지 예제를 조합하여 보여 줍니다.

각각의 씬들은 LoadAssets.cs, LoadScenes.cs, LoadVariants.cs, LoadTanks.cs 스크립트에 구현 되어 있습니다.

예제 1. 어셋 로딩하기

  1. 유니티 에디터 메뉴 "Assets > AssetBundles > Simulation Mode" 에서 시뮬레이션 모드 활성화 합니다.
  2. 프로젝트 탭에서 "AssetBundleSample/Scenes/AssetLoader" 씬을 엽니다. 플레이 모드를 실행하기 전에 씬엔 메인 카메라와 라이트, 로더 게임 오브젝트 외에는 아무것도 없음을 주목해주세요.
  3. 플레이 버튼을 눌러 프로젝트를 실행 합니다. 이때 어셋번들로 부터 큐브를 로딩하여 씬에 보여 줍니다.
  4. 씬과 관련된 스크립트는 'LoadAssets.cs'에서 확인 할 수 있습니다.
AssetBundleSample/Scripts/LoadAssets.cs
"AssetBundleSample/Scripts/LoadAssets.cs" 스크립트를 에디터에서 열어 주세요. LoadAssets 클래스에는 두개의 public 변수가 있습니다.
  • public string assetBundleName : 로드 될 어셋 번들의 이름
  • public string assetName : 로드 될 어셋의 이름

이 스크립트는 Start() 함수와 Start() 함수에 의해 호출 되는 두개의 코루틴으로 구성되어 있습니다. 

  • Initialize() 함수에서는 DontDestroyOnLoad()를 호출 하고 난 후, 어셋 번들의 패스와 어셋 번들 매니페스트를 초기화 합니다. 필요해 보이지 않는 DontDestroyOnLoad()를 굳이 사용하는 이유는, 어셋번들 로딩을 관리하는 이 게임 오브젝트가 씬이 변경된다거나 할 때 지워지는 것을 방지하기 위해서 입니다.
  • InstantiateGameObjectAsync() 함수에서는 어셋과 어셋번들의 이름을 인자로 받아 AssetBundleManager.LoadAssetAsync() 함수를 호출 합니다. 이때 리턴 값이 null이 아닌 경우 해당 객체(프리팹)을 인스턴스 화 합니다.

여기서 주의 깊게 볼 한가지는 프로젝트 탭 "AssetBundleSample/Assets"에 있는 "MyCube" 어셋은 "MyMaterial"에 의존성을 가지고 있고, "MyMaterial"은 "UnityLogo"에 의존성을 가지고 있는데, 우리가 한 일은 단지 "MyCube"만을 로드 했을 뿐이지만 어셋번들 매니저는 메니페스트를 통해 의존성을 파악하고 관련 모든 어셋들을 정확하게 로드해 준다는 것입니다. 또 한가지는 어떻게 어셋 번들의 패스가 셋팅 되는가 입니다. "LoadeAsset" 클래스의 코드에서는 씬이 로딩 될때 실행 환경이 에디터이거나 개발 버젼 빌드일 경우 어셋번들 위치를 로컬 어셋번들로 셋팅하는 것입니다(보다 정확하고 다양한 정보를 원하신다면 퍼블리싱 빌드 문서를 참고 해주세요).

시뮬레이션 모드가 활성화 되어 있는 동안 에디터에서 플레이 모드를 실행 시키면 어셋번들은 실제 빌드와 다운로드 과정을 거치지 않고 단지 위과정들을 시뮬레이션만 합니다.

예제 2. 씬 로딩하기

  1. 유니티 에디터 메뉴 "Assets > AssetBundles > Simulation Mode" 에서 시뮬레이션 모드 활성화 합니다.
  2. 프로젝트 탭에서 "AssetBundleSample/Scenes/SceneLoader" 씬을 엽니다. 플레이 모드를 실행하기 전에 씬엔 메인 카메라와 라이트, 로더 게임 오브젝트 외에는 아무것도 없음을 주목해주세요.
  3. 플레이 버튼을 눌러 프로젝트를 실행 합니다. 이때 어셋번들로 부터 큐브와 펑면을 로딩하여 씬에 보여 줍니다.
  4. 씬과 관련된 스크립트는 'LoadScene.cs'에서 확인 할 수 있습니다.
AssetBundleSample/Scripts/LoadAssets.cs
"AssetBundleSample/Scripts/LoadScene.cs" 스크립트를 에디터에서 열어 주세요. LoadScene 클래스에는 두개의 public 변수가 있습니다.
  • public string sceneAssetBundle : 로드 될 어셋 번들의 이름
  • public string sceneName : 로드 될 씬의 이름

이 스크립트는 Start() 함수와 Start() 함수에 의해 호출 되는 두개의 코루틴으로 구성되어 있습니다. 

  • Initialize() 함수에서는 DontDestroyOnLoad()와 어셋 번들의 패스를 셋팅하고 어셋번들 메니페스트를 초기화 합니다.
  • InitializeLevelAsync() 함수에서는 씬의 이름과 isAdditive 변수를 인자로 받아 AssetBundleManager.LoadAssetAsync() 함수를 호출 합니다. 이때 리턴 되는 씬이 null인 경우 콘솔창에 에러 메시지를 출력하고 코루틴은 종료 됩니다. 
    InitializeLevelAsync()함수는 isAddtive 인자에 따라 내부적으로 Application.LoadLevelAdditiveAsync() 함수 혹은 Application.LoadLevelAsync()함수를 호출합니다. 두 함수 모두 씬 이름을 인자로 받아 씬을 백그라운드에서 비동기 로딩한다는 것은 같지만 LoadLevelAdditiveAsync()함수의 경우는 기존 씬에 로딩 되어 있는 게임 오브젝트들을 삭제하지 않고 추가만 한다는 것에 차이가 있습니다.
    만일 여러분께서 InializeLevelAsync() 함수의 isAdditive 인자를 false로 수정한 후 실행 한다면 Hierarchy 탭에 기존 신에서 로드 되어 있던 카메라와 라이트 오브젝트가 사라지고 큐브와 바닥만 로드 되어 있는 것을 확인 할수 있을겁니다.

어셋 번들 매니저를 이용한 씬 로딩 역시 예제 1과 동일하게  의존성에 따라 필요한 어셋들을 자동적으로 로드 합니다. 우리가 로드한 것은 "TestScene" 하나지만 "TestScene"에 포함되어 있던 "Cube"와 그외 모든 어셋들이 로드 됩니다.

예제 3. 어셋번들 베리언트 사용하기

이번 장은 예제에 대한 본격적인 설명에 들어가기 앞서 약간의 부연 설명이 필요합니다. 어셋번들 베리언트는 시뮬레이션 모드에서는 구동되지 않고 로컬 어셋번들 서버를 사용하거나 실제 원격 저장 공간을 이용해야 합니다. 때문에 필수적으로 어셋번들이 빌드 되어야 합니다. 이전에 언급 되었듯이 어셋번들과 번들에 포함된 베리언트를 빌드하기 위해서는 빌드 대상 어셋들에 어셋번들 이름이 지정되어 있어야 합니다. 물론 베리언트를 사용할 어셋이라면 어셋번들 베리언트 네임 역시 지정되어야 합니다.

어셋에 어셋번들 이름과 베리언트가 지정되면 에디터 메뉴 "Assets/AssetBundles/BuildAssetBundles"를 통해 어셋번들을 빌드 할 수 있습니다. 기본적으로 어셋번들은 현재 빌드 타겟에 최적화 되어 빌드 된 후 "프로젝트 폴더/AssetBundles" 폴더 아래에 빌드 타겟별로 그룹화(Android/OSX..) 되어 저장됩니다.

편의성과 새로 빌드된 어셋번들을 배포 과정 없이 테스트 해보기 위해 로컬 어셋 번들 서버가 활성화 되어 있어야 합니다. 에디터 메뉴 "Assets/AssetBundles/Local AssetBundle Server"를 통해 로컬 어셋번들 서버를 활성화 할 수 있습니다. 로컬 어셋 번들 서버 역시 일반 원격 서버와 마찬가지로 접근 권한이라던지 방화벽과 같은 일반 다른 원격 서버와 동일한 제약 사항을 적용 받습니다. 로컬 어셋번들 서버가 정상적으로 활성화 된다면 이제 부터 어셋번들 다운로드를 로컬에서 테스트 해볼수 있습니다.

  1. 에디터 메뉴 "Assets/AssetBundles/Simulation Mode"에서 시뮬레이션 모드를 비활성화 시킵니다.
  2. 에디터 메뉴 "Assets/AssetBundles/Local AssetBundle Server"에서 로컬 어셋번들 서버를 활성화 시킵니다.
  3. 프로젝트 탭의 "AssetBundleSample/Scenes/VariantLoder" 신을 엽니다. 플레이 모드를 실행하기 전에 씬엔 메인 카메라와 라이트, 로더 게임 오브젝트 외에는 아무것도 없음을 주목해주세요.
  4. 플레이 버튼을 눌러 프로젝트를 실행 합니다.
  5. "Load SD"를 선택 합니다. 빨간색 큐브와 저해상도 스프라이트가 로드 된것을 확인합니다.
  6. 플레이 모드를 빠져나온 후 다시 플레이 버튼을 눌러 프로젝트를 실행합니다.
  7. "Load HD"를 선택 합니다. 이번에는 녹색 큐브와 고해상도 스프라이트가 로드 된것을 확인합니다.
    (만일 해당도나 큐브의 색이 바뀌지 않았다면 로컬 어셋번들 서버 활성화 여부, 빌드 여부를 체크해 주세요)
  8. 씬과 관련된 스크립트는 'LoadVariants.cs'에서 확인 할 수 있습니다.

"AssetBundleSample/Scripts/LoadVariants.cs"

"AssetBundleSample/Scripts/LoadVariants.cs" 스크립트를 에디터에서 열어 주세요. LoadVariants 클래스에는 두개의 public 변수와 두개의 private 변수를 가지고 있습니다.

  • public string variantSceneAssetBundle : 로드 될 어셋 번들의 이름
  • public string variantSceneName : 로드 될 신의 이름
  • private string[] activeVariants : "Load SD" 혹은 "Load HD" 버튼이 눌러지면 해당 어셋번들 네임을 저장하여 AssetBundleManager.ActiveVariants 변수에 셋팅 됩니다.
  • private bool bundlesLoaded : 버튼 UI의 디스플레이 여부를 판단하는 변수. 어셋번들이 로드 되고 난후 버튼을 숨기는데 사용 됩니다.

이 스크립트는 BeginExample()과 Start()에 의해 호출되는 두개의 코루틴으로 구성됩니다. BeginExample()함수는 "Load SD" 또는 "Load HD" 버튼을 누름으로써 호출 됩니다.

  • Initialize() 함수에서는 DontDestroyOnLoad()와 어셋 번들의 패스를 셋팅하고 어셋번들 메니페스트를 초기화 합니다.
  • BeginExample() 함수에서 Initialize() 함수와 InitailizeLevelAsync() 함수가 호출되는 가운데 AssetBundleManager.ActiveVariants 변수가 셋팅 됩니다. 여기에서 셋팅 되는 값은 OnGUI()의 "Load SD" 또는 "Load HD" 버튼을 누를때 "sd" 또는 "hd"로 셋팅이 됩니다.

여기서 우리가 주의 깊게 살펴봐야 하는 부분은 어셋번들에서 베리언트에 따라 어떻게 구분 되어 씬에 로드 될수 있는가 입니다. 어셋번들 베리언트를 지정하게 되면 "."을 구분자로 하여 어셋번들 이름이 메니페스트에 저장 됩니다. 이 예에서는 "AssetBundleSample/SampleAssets/Variants" 하위의 "MyAssets-HD" 폴더와 "MyAssets-SD"  폴더의 하위 어셋들이 어셋 각각 "variants/myassets.hd" 와 "variants/myassets.sd"와 같은 이름을 가집니다. AssetBundleManager는  "."을 구분자로 어셋번들 이름과 AssetBundleManager.ActiveVarintans에 지정된 베리언트 이름이 일치하는 어셋을 로드합니다.

AssetBundleManager.ActiveVariants는 여러 개의 엔트리를 가지는 것도 가능합니다. 예를 들어 my-material.sd, my-material.hd, my-text.english, my-text.danish, my-text.catalan, my-text.welsh와 같이 어셋번들 베리언트가 지정되었다고 하면, ActiveVariants는 "hd"와 "danish" 혹은 "sd"와 "english"와 같이 다양한 조합을 선택할 수 있습니다. 이와 같은 방법으로 어셋번들 매니저는 hd 혹은 sd의 해상도와 언어 선택을 개별적으로 처리 할 수 있습니다.

만일 ActiveVariants에 아무런 어셋번들 베리언트 네임이 셋팅되어 있지 않다면 어셋번들 매니저는 베리언트 이름을 무시하고 지정된 이름의 어셋번들 중 가장 첫번째에 검색되는 어셋번들을 로드 합니다. 또한 동일한 어셋번들 네임을 가진 다른 베리언트들이 동시에 지정되어 있다면 - 예를 들어 "sd"와 "hd"가 동시에 지정 - 어셋번들 매니저는 ActiveVariants에 셋팅되어 있는 베리언트 네임 중 가장 앞에 있는 어셋번들을 로드 합니다.

예제 4. 탱크

이번 장에서는 이전까지 살펴 보았던 부분들을 되세기며 기본적인 씬과 어셋들을 로드하고 특정 게임 오브젝트에 대해서는 어셋번들 베리언트를 사용하여 해상도와 컨텐츠, 로컬라이징에 따른 언어팩을 선택 할수 있는 통합 예제를 살펴 보도록하겠습니다.

  1. 에디터 메뉴 "Assets/AssetBundles/Simulation Mode"에서 시뮬레이션 모드를 비활성화 시킵니다.
  2. 에디터 메뉴 "Assets/AssetBundles/Local AssetBundle Server"에서 로컬 어셋번들 서버를 활성화 시킵니다.
  3. 프로젝트 탭의 "AssetBundleSample/Scenes/TanksLoder" 신을 엽니다.
    씬엔 메인 카메라와 라이트, "Loader" 게임 오브젝트 외에는 아무것도 없음을 주목해주세요.
  4. 플레이 버튼을 눌러 프로젝트를 실행 합니다.
  5. 해상도와 스타일, 언어를 각각 선택 합니다.
  6. 선택에 따라 각각의 어셋이 로드된것을 확인 합니다. 만일 명시적으로 선택된 옵션이 없는 경우 어셋번들 매니저가 자동으로(예제 3에서 살펴본 룰에 따라) 한가지를 선택, 콘솔창에 경고를 출력하는 것을 확인 합니다.
  7. 씬과 관련된 스크립트는 'LoadTanks.cs'에서 확인 할 수 있습니다.
    "AssetBundleSample/Scripts/LoadTanks.cs" 스크립트를 에디터에서 열어 주세요.

이 스크립트는 이전 예제의 "LoadScenes.cs", "LoadAssets.cs"와 매우 비슷합니다. 이전 예제에서는 하나의 어셋번들만 로드 했지만 이 예제에서는 씬을 가지고 있는 어셋과 텍스트 어엣을 가지고 있는 어셋번들 두개를 로드 합니다. 이전 예제에서 이미 살펴 보았던 어셋과 씬의 로딩을 통합하여 하나의 클래스에서 호출하는 것 외에는 이전 예제들과 크게 다른 점은 없기 때문에 많은 설명이 필요하진 않습니다.

  • public string sceneAssetBundle : 로드 될 씬 어셋번들의 이름
  • public string sceneName : 로드 될 신의 이름
  • public string textAssetBundle : 로드 될 텍스트 어셋번들의 이름
  • public string textAssetName : 로드 될 텍스트 어셋의 이름
  • private string[] activeVariants : 어셋번들 매니저에게 전달 될 활성화 될 어셋번들 베리언트의 이름 배열
  • private bool bundlesLoaded : 버튼 UI 표시/숨김에 사용될 변수
  • private bool sd, hd, normal, desert, english, danish : ActiveVarinat에 셋팅 될 옵션 선택 여부
  • private string tankAlbedoStyle, tankAlbedoResolution, language : ActiveVarinat에 셋팅 될 옵션 선택 여부

이 스크립트는 BeginExample() 함수와 Start()에서 호출 되는 세개의 코루틴으로 구성되어 있습니다. BeginExample() 함수는 "Load Scene" 버튼을 클릭 시 호출 됩니다.

  • Initialize() 함수에서는 DontDestroyOnLoad()와 어셋 번들의 패스를 셋팅하고 어셋번들 메니페스트를 초기화 합니다.
  • BeginExample() 함수에서 Initialize() 함수와 InitialzeLeveAsync() 함수 가운데 AssetBundleManager.ActiveVariants 변수가 셋팅 되며 세부 내용은 이전 장에서 살펴 봤던것과 동일 합니다.
  • InitialzeLeveAsync() 함수와 InstantiateGameObjectAsync() 함수를 호출하여 신과 텍스트 어셋을 로드 합니다.

마치며

이상 어셋번들의 기본 개념과 어셋번들의 빌드/배포/로드를 도와 주는 어셋번들 매니저의 사용 방법에 대해 알아 보았습니다. 보다 자세한 정보를 얻고 싶다면 다음 링크를 참고해 주세요.

원문 : http://unity3d.com/kr/learn/tutorials/topics/scripting/assetbundles-and-assetbundle-manager?playlist=17117

문제 해결 : 어셋번들 로드 시 쉐이더가 정상적으로 표현 되지 않는 문제 

유익한 글이었다면 공감(❤) 버튼 꾹!! 추가 문의 사항은 댓글로!!