언리얼 엔진(UE) 은 에셋을 자동으로 로드하고 언로드합니다. 덕분에 개발자는 필요한 에셋을 즉시 언리얼 엔진에 요청할 수 있습니다. 그러나 에셋을 검색, 로드, 검사할 시기와 방법을 개발자가 정확하게 제어하려는 경우가 있습니다. 이러한 경우에는 에셋 매니저(Asset Manager) 가 유용합니다.
에셋 매니저는 에디터와 패키지로 만든 게임에 고유한 글로벌 오브젝트입니다. 특정 프로젝트에 맞게 오버라이드하고 커스터마이징할 수 있으며, 프로젝트 컨텍스트에 따라 콘텐츠를 청크로 분할할 수 있는 에셋 관리 프레임워크로서 기능합니다. 또한, 언리얼 엔진에서 지원되는 느슨한 패키지 아키텍처의 장점도 제공합니다. 디스크 및 메모리 사용량을 검사하는 데 유용한 툴 세트 외에도, 게임을 배포할 때 쿠킹 및 청킹을 고려하여 에셋 구성을 최적화하는 데 필요한 정보를 제공합니다.
언리얼 엔진의 에셋 관리 시스템은 모든 에셋을 두 가지 타입(프라이머리 에셋 및 세컨더리 에셋 )으로 구분합니다. 에셋 매니저는 GetPrimaryAssetId
함수를 호출하여 확보한 프라이머리 에셋 ID 에서 프라이머리 에셋을 직접 조작할 수 있습니다. 특정한 UObject
클래스로 제작한 에셋을 프라이머리 에셋으로 지정하려면 'GetPrimaryAssetId' 함수를 오버라이드하여 유효한 FPrimaryAssetId
구조체를 반환하면 됩니다. 에셋 매니저는 세컨더리 에셋을 직접 처리하지 않습니다. 즉, 프라이머리 에셋이 세컨더리 에셋을 참조하거나 사용하려는 경우 언리얼 엔진이 자동으로 세컨더리 에셋을 로드합니다. 기본적으로 UWorld
에셋(레벨)만 프라이머리 에셋이고 나머지 에셋은 모두 세컨더리 에셋입니다. 세컨더리 에셋을 프라이머리 에셋으로 변경하려면 해당 클래스의 GetPrimaryAssetId
함수를 오버라이드하여 유효한 FPrimaryAssetId
구조체를 반환해야 합니다. 프라이머리 에셋 ID는 에셋 그룹을 알려주는 고유한 프라이머리 에셋 타입과 해당 프라이머리 에셋의 이름 등 두 요소로 구성됩니다. 프라이머리 에셋 이름은 콘텐츠 브라우저(Content Browser) 에 표시되는 에셋 이름을 기본값으로 사용합니다.
에셋 매니저(Asset Manager)는 두 가지 타입의 에셋을 처리합니다. 하나는 블루프린트 클래스, 다른 하나는 레벨이나 UDataAsset
클래스의 에셋 인스턴스인 데이터 에셋 같은 블루프린트 이외의 에셋입니다. 각 프라이머리 에셋 타입에는 특정한 베이스 클래스가 연결되며 환경설정에 블루프린트 클래스를 저장할지 여부가 지정됩니다(아래의 설명 참조).
새로운 블루프린트 프라이머리 에셋을 생성하려는 경우 콘텐츠 브라우저 로 이동하여 GetPrimaryAssetId
함수를 오버라이드하는 클래스의 후손인 새 블루프린트 클래스를 생성하면 됩니다. 이와 같은 베이스 클래스가 될 수 있는 요소로는 프라이머리 데이터 에셋이나 그 자손 외에도 GetPrimaryAssetId
를 오버라이드하는 액터 서브클래스가 있습니다. 블루프린트 프라이머리 에셋에 액세스하려는 경우 C++ 코드에서 GetPrimaryAssetObjectClass
같은 함수를 호출하거나, 이름에 'Class'라는 단어가 포함된 블루프린트 에셋 매니저 함수를 사용하면 됩니다. 블루프린트 프라이머리 에셋 클래스를 확보하고 나면 다른 블루프린트 클래스처럼 취급하여 새 인스턴스를 스폰하는 데 사용하거나, Get Defaults 함수를 사용하여 블루프린트와 연결된 클래스 디폴트 오브젝트의 읽기 전용 데이터에 액세스할 수 있습니다.
블루프린트 클래스를 인스턴스화할 필요가 없는 경우 UPrimaryDataAsset
으로부터 상속받은 데이터 전용 블루프린트에 데이터를 저장할 수 있습니다. 또한 베이스 클래스에서 자손 클래스(예: 블루프린트 기반 자손 클래스)를 도출할 수도 있습니다. 예를 들어 C++에서 UPrimaryDataAsset
을 확장하는 UMyShape
같은 베이스 클래스를 생성하고, UMyShape
가 부모인 BP_MyRectangle
이라는 블루프린트 기반 서브클래스를 생성한 다음, BP_MySquare
라는 BP_MyRectangle
의 블루프린트 기반 자손을 생성할 수 있습니다. 디폴트 세팅을 유지할 경우 마지막으로 생성되는 클래스의 PrimaryAssetId는 MyShape:BP_MySquare
입니다.
프라이머리 에셋 타입이 블루프린트 데이터를 저장할 필요가 없는 경우에는 블루프린트 이외의 에셋을 사용하면 됩니다. 블루프린트 이외의 에셋은 코드로 액세스하기가 더 간편하고 메모리 효율도 더 우수합니다. 에디터에서 블루프린트 이외의 프라이머리 에셋을 새로 생성하려는 경우 고급 콘텐츠 브라우저 창에서 새 데이터 에셋을 생성하거나 커스텀 UI를 사용하여 새 레벨을 생성하면 됩니다. 에셋이 생성되는 원리는 블루프린트 클래스가 생성되는 원리와 다릅니다. 다시 말해서, 생성한 에셋은 클래스 자체가 아니라 클래스의 인스턴스입니다. 클래스에 액세스하려는 경우 GetPrimaryAssetObject
같은 C++ 함수나 이름에 'Class'가 포함되지 않은 블루프린트 함수로 로드하면 됩니다. 클래스가 로드되면 직접 액세스하여 해당 클래스의 데이터를 읽을 수 있습니다.
<aside> 📌
이러한 에셋은 클래스가 아니라 인스턴스이므로 클래스나 다른 에셋을 상속받을 수 없습니다. 예를 들어 명시적으로 오버라이드하는 값을 제외하고 부모의 값을 상속받는 자손 에셋을 생성하고 싶다면 블루프린트 클래스를 대신 사용해야 합니다.
</aside>
에셋 매니저 오브젝트는 프라이머리 에셋의 검색 및 로드 프로세스를 관리하는 싱글톤입니다. 언리얼 엔진에 포함된 베이스 에셋 매니저 클래스는 기본적인 관리 기능만 갖추고 있지만, 프로젝트에 필요한 경우 그에 맞게 확장할 수도 있습니다. 에셋 매니저에 포함된 스트리머블 매니저(Streamable Manager) 구조체는 오브젝트를 비동기식으로 로드하는 작업을 실제로 수행할 뿐만 아니라, 오브젝트가 필요 없어져 언로드될 수 있을 때까지 스트리머블 핸들(Streamable Handle) 을 사용하여 오브젝트를 메모리에 보존합니다. 싱글톤 에셋 매니저와 달리 언리얼 엔진의 다양한 부분에는 서로 다른 용도의 스트리머블 매니저가 여럿 존재합니다.
에셋 번들(Asset Bundle) 이란 프라이머리 에셋과 관련된 특정 에셋의 이름이 지정된 목록입니다. 에셋 번들을 생성하려면 메타 태그가 'AssetBundles'인 UObject
의 TSoftObjectPtr
또는 FStringAssetReference
멤버로 구성된 UPROPERTY
섹션에 태그를 지정해야 합니다. 태그 값은 세컨더리 에셋을 저장할 번들의 이름을 나타냅니다. 예를 들어 MeshPtr
이라는 멤버 변수에 저장된 아래의 스태틱 메시 에셋은 UObject를 저장했을 때 'TestBundle'이라는 에셋 번들에 추가됩니다.
/** 메시 */
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = Display, AssetRegistrySearchable, meta = (AssetBundles = "TestBundle"))
TSoftObjectPtr<UStaticMesh> MeshPtr;
에셋 번들을 사용하는 두 번째 방법은 런타임 시점에 프로젝트의 에셋 매니저 클래스로 등록하는 것입니다. 이 경우 프로그래머가 FAssetBundleData
구조체를 채워 에셋 매니저에 전달하는 코드를 작성해야 합니다. 프로그래머는 이러한 목적으로 UpdateAssetBundleData
함수를 오버라이드하거나 번들의 세컨더리 에셋과 연결하려는 프라이머리 에셋 ID로 AddDynamicAsset
을 호출할 수 있습니다.
대부분의 프라이머리 에셋은 콘텐츠 브라우저 에 표시되고 디스크에 저장된 에셋 파일로 존재하므로 아티스트나 디자이너가 편집할 수 있습니다. 프로그래머가 이런 용도로 사용할 수 있는 클래스를 생성하는 가장 간단한 방법은 UDataAsset
자손 클래스인 UPrimaryDataAsset
으로부터 상속받는 것입니다. UPrimaryDataAsset
에는 에셋 번들 데이터를 로드하고 저장하는 기능이 내장되어 있습니다. 다른 베이스 클래스(예: APawn
)를 사용하려는 경우 UPrimaryDataAsset
을 살펴보는 것이 좋습니다. 이 함수는 에셋 번들을 클래스에 사용하기 위해 구현해야 하는 기능을 알 수 있는 가장 간단한 예시이기 때문입니다. 아래의 클래스는 가상 게임의 존 타입을 지정하는 방법을 알 수 있는 예시입니다. 존 타입은 게임의 전체 맵 화면에 월드를 시각적으로 표현할 때 사용할 아트 에셋을 게임에 알려줍니다.