애셋번들 사용패턴 (AssetBundle usage patterns) 1- 번역

애셋번들 사용패턴 (AssetBundle usage patterns) – 번역

원문 링크

 

이번 장(Chapter)은 유니티5에서의 애셋, Resources 시스템, 리소스관리에 대한 다섯번째 시리즈입니다.

이전 장에서 애셋번들(AssetBundle)의 기초에 대한 내용과, 특히 애셋번들을 로드할때 사용하는 다양한 API의 로우-레벨(low-level)에서의 동작에 대한 내용을 다뤘습니다.
이번 장에서는 실제 애셋번들을 사용하면서 발생할 수 있는 문제와 해결책이될 수 있는 방안에 대해서 설명합니다.

 

4.1 로드한 애셋 관리하기 (Managing loaded Assets)

특히 메모리가 민감한 환경에서는 로드한 오브젝트(Object)의 크기와 수를 신중하게 관리하는 것이 매우 중요합니다.
유니티는 현재 활성화된 씬(Scene)에서 오브젝트를 제거하더라도 자동으로 메모리에서 해제하지 않습니다.
애셋 정리는 특정 시점에 처리되며, 수동으로 처리할 수도 있습니다.

애셋번들 자체는 매우 신중하게 관리해야합니다.
애셋번들은 로컬 저장소에 있는 파일(유니티 캐시(Cache) 또는 AssetBuddle.LoadFromFile을 통해서 로드된 파일)에 의해서 뒷받침 됩니다.
이 로컬 저정소는 최소한의 메모리 오버헤드(Memory Overhead)를 갖으며, 이는 보통 10-40킬로바이트(KB)를 초과하지 않습니다.
하지만, 이 오버헤드는 다수의 애셋번들이 존재하는 경우에 여전히 문제가될 수 있습니다.

대부분의 프로젝트에서 사용자가 콘텐츠에 대한 재경험(예: 레벨을 리플레이(replay)하는 경우)을 허용하고 있기 때문에, 애셋번들을 언제 로드하고 해제할지를 이해하는 것이 중요합니다.
애셋번들이 제대로 해제되지 않으면, 이로 인해서 메모리에 오브젝트 복제가 발생할 수 있습니다.
애셋번들이 제대로 해제(unload)되지 않으면, 텍스쳐가 누락되는 등의 특정 상황에서 원하지 않은 동작이 발생할 수 있습니다.
이때 이 문제가 왜 발생하는지를 이해하려면, 애셋, 오브젝트, 직렬화 장(Chapter)의 오브젝트간 참조 섹션을 참고하시기 바랍니다.

애셋과 애셋번들을 관리할때 이해해야하는 가장 중요한 점은, AssetBundle.Unload를 호출할때 true또는 false로 전달되는 매개변수에 따라서 동작이 달라진다는 점입니다.

이 API는 호출된 애셋번들의 헤더(header)정보를 해제합니다. 해당 매개변수는 이 애셋번들에 의해서 생성된 모든 오브젝트를 해제할지 여부를 지정합니다.
전달된 매개변수가 true인 경우, 해당 애셋번들로부터 로드된 모든 오브젝트는, 현재 씬(Scene)에서 사용중이라 하더라도, 그 즉시 해제됩니다.

예를 들어, 재질(Material) M이 애셋번들 AB에 의해서 로드되었고, 재질 M이 현재 활성화된 씬(Scene)에서 사용중이라고 가정합니다.

ab2a

AB.Unload(true)가 호출되면, 재질 M은 이 씬에서 제거되고, 삭제되어 메모리에서 해제됩니다.
그러나, AB.Unload(false)가 호출되면, 애셋번들의 헤더(header) 정보는 해제되지만, 재질 M은 씬에 남게되고 여전히 재 기능을 하게됩니다.
AssetBundle.Unload(false)를 호출하면 재질 M과 애셋번들 AB사이의 연결고리(링크)가 끊어집니다.
이때 다시, 애셋번들 AB가 로드되면, 이 애셋번들 AB에 포함된 오브젝트들의 사본이 새로 메모리에 로드됩니다.

ab2b

이때, 나중에 다시 애셋번들 AB가 로드되면, 이 애셋번들의 헤더 정보의 새로운 사본이 다시 로드됩니다.
그러나 재질 M은, 애셋번들 AB의 새로운 사본에서 로드되지 않습니다.
유니티는 애셋번들 AB의 새로운 사본과 재질 B의 어떠한 연결고리(링크)도 만들지 않습니다.

ab2c

재질 M을 다시 로드하기 위해서 AB.LoadAsset()을 호출하면, 유니티는 기존의 재질 M의 사본을, 애셋번들 AB에 있는 데이터의 인스턴스로 해석하지 않습니다.
따라서, 유니티는 재질 M의 새로운 사본을 로드하게되어, 두 개의 동일한 재질 M의 사본이 씬에 존재하게 됩니다.

ab2d

 

 

대부분의 프로젝트에서, 이 동작은 바람직하지 않습니다.
따라서 대부분의 프로젝트에서는 AssetBundle.Unload(true)를 사용하고 오브젝트가 중복해서 로드되지 않도록하는 방법을 채택해야합니다.
일반적으로 많이 사용되는 두 가지 방법은 다음과 같습니다:

  1. 레벨(level)간 또는 로딩 화면 등과 같이, 프로그램의 전체 라이프타임 중에 일시적으로 사용되는 애셋번들을 해제하는 시점을 잘-정의하는 것입니다. 이 옵션은 간단하고 가장 일반적으로 사용하는 옵션입니다.
  2. 개별 오브젝트의 참조-카운드(reference-count)를 관리하고, 애셋번들을 구성하는 모든 오브젝트가 해제되었을 경우에만 해당 애셋번들을 해제하는 방법입니다. 이 방법을 통해서, 메모리 복제 없이, 프로그램에서 개별 오브젝트를 해제하고 다시 로드하는 것이 가능합니다.

 

만일 프로그램에서 AssetBundle.Unload(false)를 사용해야만 한다면, 개별 오브젝트를 해제할 수 있는 두 가지 방법이 있습니다:

  1. 씬과 코드(code) 모두에서, 사용하지 않는 오브젝트에 대한 참조 값을 모두 제거합니다. 이 작업이 완료된 후, Resources.UnloadUnusedAssets를 호출합니다.
  2. Additive 씬을 로드하지 않습니다. 이렇게하면, 현재 씬에 있는 모든 오브젝트를 제거하고 Resources.UnloadUnusedAssets가 자동으로 호출됩니다.

어떤 프로젝트가, 게임 모드나 레벨과 레벨 사이 등과 같이, 사용자가 여러 오브젝트의 로드 및 해제를 위해서 대기해야하는 시점에 대해서 적절하게 분석한 결과를 가지고 있는 경우, 이 분석결과를 필요한 만큼의 오브젝트를 해제하고 새 오브젝트를 로드하는데 활용해야 합니다.

이렇게하는 가장 간단한 방법은, 프로젝트를 개별 씬(Scene) 단위로 나누고, 이 씬에서 사용하는(의존성이 있는)모든 리소스 및 오브젝트와 함께, 해당 씬을 애셋번들로 빌드하는 것입니다.
이제 프로그램은 “로딩”씬으로 진입해서 기존 씬에 포함된 애셋번들을 완전히 해제한 다음, 새로운 씬을 포함하는 애셋번들을 로드합니다.

이 과정이 가장 단순한 흐름이지만, 몇몇 프로젝트에서는 좀 더 복잡한 애셋번들 관리를 요구할수도 있습니다.
하지만 모든 상황에 적용되는, 보편적인 애셋번들 디자인 패턴은 존재하지 않습니다. 모든 프로젝트의 데이터는 서로 다르기 때문입니다.
여러 오브젝트를 애셋번들로 그룹 지을때, 동일한 시점에 로드되거나 업데이트되는 오브젝트들을 묶는것부터 시작하는 것이 좋습니다.

예를 들어, 롤 플레잉(role-playing) 게임을 생각해보겠습니다.
개별 맵과 컷씬(cutscene)은 씬 단위로 애셋번들로 그룹지을 수 있지만, 몇몇 오브젝트들은 대부분에 씬에서 사용되는 경우가 있을 수 있습니다.
애셋번들은 특정 장면, 인-게임 UI, 여러 캐릭터 모델 및 텍스쳐 등을 제공하려는 목적으로 빌드될 수 있습니다.
나중에 예로 든 오브젝트와 애셋들은 두 번째 그룹의 애셋번들로 묶고, 게임이 시작되면 로드해서 게임이 종료되기 전까지 유지시킵니다.

애셋번들을 해제한 후에 그 애셋번들에 있는 오브젝트를 다시 로드하면, 또 다른 문제가 발생할 수 있습니다.
이 경우, 리로드(reload)에 실패하고, 해당 오브젝트는 유니티 에디터의 계층 뷰에서 (Missing)오브젝트로 남게됩니다.

이 문제는 주로, 모바일 앱이 중지되었다가(화면잠금 등으로) 다시 시작되거나, PC의 화면을 잠근 다음 다시 시작하는 경우 등, 그래픽 컨텍스트(Context)의 대한 제어권을 잃어버렸다가 다시 제어권을 얻을 때 발생합니다.
이 경우, 유니티는 반드시 해당 텍스쳐와 쉐이더를 GPU에 다시 업로드해야합니다.
그런데 이때 이러한 애셋들이 포함된 애셋번들을 사용할 수 없는 경우, 해당 프로그램(게임)은 그 오브젝트를 “쉐이더 누락”상태인 자홍색으로 렌더링 합니다.

 

내용 끝까지 읽어주셔서 감사합니다.
배너 클릭은 저에게 많은 힘이 됩니다.
감사합니다 🙂

 

다음글 – 애셋번들 배포 (Distribution)

RonnieJ

프리랜서 IT강사로 활동하고 있습니다. 게임 개발, C++/C#, 1인 기업에 관심이 많습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

Please turn AdBlock off

Notice for AdBlock users

Please turn AdBlock off