FSoftObjectPaths
- Asset의 전체 이름으로 된 String이 들어있는 구조체
- Property를 만들 시 UObject*로 나타냄
- Cooking과 REdirector가 처리되기 때문에 Device에서 정상 동작을 보장한다.
FSoftObjPtr
- FSoftObjectPaths를 감싸고 있는 TWeakObjPtr
- Editor UI에서 특정 Class만 선택되도록 할 수 있다.
- 실제 대상 Asset은 Get 함수로 Raw Object를 반환
- 일반적으로는 Artist나 Designer가 수동으로 Setup 하는 것이 베스트
- 다만 다음 조건에서는 Asset Registry나 Object Library를 사용하는 것이 좋다.
- 특정 조건을 만족하는 질의를 모든 Asset Load 없이 시행하려는 경우
- 다만 다음 조건에서는 Asset Registry나 Object Library를 사용하는 것이 좋다.
Asset Registry
- Asset에 대한 MetaData를 저장하고 검색, 질의를 가능케 하는 System
- 보통 Editor의 Contents Browser에서 정보를 표기하기 위해 사용됨.
- 하지만 GamePlay 코드 상에서도 Load되지 않은 Asset에 대한 MetaData 질의를 하는데 사용 할 수 있다.
- MetaData 질의에 사용하기 위해서는 해당 Data의 PROPERTY()에 AssetRegistrySearchable Tag를 추가해줘야 함.
- 질의 결과는 FAssetData Object로 반환
- Object 정보 뿐 아니라 Mark 된 Property가 들어있는 Key-Value Map도 포함되어 있다.
Object Library
- Load된 Object와 그렇지 않은 Object를 합친 리스트가 FAssetData에 있는 경우로, 공유 Base Class를 상속한다.
- 검색할 경로를 입력해 Load하면, 그 경로에 있는 모든 Asset이 Object Library에 추가된다.
- Contents 폴더 일부분을 각기 다른 유형으로 지정하고 사용하면
Artist/Designer가 Master List를 건들지 않고 Asset을 추가할 수 있다.- 이 때, Master List는 Asset을 로드하고 있는 게임 내 고유한(Singleton) List를 지칭한다.
-
더보기
if (!ObjectLibrary) { ObjectLibrary = UObjectLibrary::CreateLibrary(BaseClass, false, GIsEditor); ObjectLibrary->AddToRoot(); } ObjectLibrary->LoadAssetDataFromPath(TEXT("/Game/PathWithAllObjectsOfSameType"); if (bFullyLoad) { ObjectLibrary->LoadAssetsFromAssetData(); }
- 위 코드는 새 Object Library를 생성하고, BaseClass를 할당하여 주어진 경로의 모든 Asset Data를 로드한다.
- Option을 통해 실제 Asset Load도 가능.
- Asset이 작은 경우에는 통째로 Load한다.
- Asset이 Cooking 중인 경우에는 모두 Cooking이 된 후에 Load도 가능하다.
- Cooking 도중 Asset Registry 질의를 하고 반환된 Asset을 Load하는 한,
Object Library는 개발 환경에서나 라이브 환경에서나 동일하게 동작한다.
- Object Library에 Asset Data가 들어가 있는 상태라면, 질의를 통해 특정 Asset만 선택적으로 Load 할 수도 있다.
-
더보기
TArray<FAssetData> AssetDatas; ObjectLibrary->GetAssetDataList(AssetDatas); for (int32 i = 0; i < AssetDatas.Num(); ++i) { FAssetData& AssetData = AssetDatas[i]; const FString* FoundTypeNameString = AssetData.TagsAndValues.Find(GET_MEMBER_NAME_CHECKED(UAssetObject,TypeName)); if (FoundTypeNameString && FoundTypeNameString->Contains(TEXT("FooType"))) { return AssetData; } }
- 위 코드는 TypeName에 "FooType"이 들어있는 것들을 검색하고, 그 중 첫번째 것을 반환한다.
- AssetData가 생긴 후,
ToStringReference()를 호출하고 FSoftObjectPath로 변환하면 Async Load가 가능하다.
- AssetData가 생긴 후,
- 위 코드는 TypeName에 "FooType"이 들어있는 것들을 검색하고, 그 중 첫번째 것을 반환한다.
StreambleManager
- 가장 간단한 Async Load
- 이 외의 방법으로는 Async Load Package, BulkData가 있다.
- 게임 전역으로 유일한 Singleton Object에 생성하는 것이 좋다.
- DefaultEngine.ini나 자체적인 SingletonClass 등
-
더보기
[/Script/Engine.StreamableManager] ; 스트리밍 풀의 최대 크기를 메가바이트 단위로 설정합니다. s.Streaming.PoolSize=2000 ; 애셋을 스트리밍할 때 사용할 수 있는 동시 스트리밍 요청의 최대 개수를 설정합니다. s.AsyncLoadingThreadCount=8 ; 스트리밍 대기 시간을 초 단위로 설정합니다. 이는 에셋이 스트리밍 될 때까지의 지연 시간을 조정합니다. s.Streaming.HLODStrategy=2 ; 스트리밍 세그먼트 크기를 설정합니다. 더 큰 크기는 스트리밍 프로세스를 최적화할 수 있지만 메모리 사용량이 증가할 수 있습니다. s.Streaming.SegmentedStreamingThreshold=20
#include "Engine/StreamableManager.h" #include "Engine/AssetManager.h" void MyFunction() { FStreamableManager& StreamableManager = UAssetManager::GetStreamableManager(); // 비동기 로드를 위한 에셋 경로 FString AssetPath = TEXT("Path/To/Your/Asset"); // 에셋 로드 StreamableManager.RequestAsyncLoad(AssetPath, FStreamableDelegate::CreateLambda([]() { // 에셋 로드 완료 후 수행할 작업 UE_LOG(LogTemp, Log, TEXT("Asset Loaded Successfully!")); })); }
-
- DefaultEngine.ini나 자체적인 SingletonClass 등
- FSoftObjPath를 전달하면 Load가 시작 함.
- 작은 Object는 SynchronousLoad로도 충분 함.
- 하지만 큰 Object는 Main Thread를 오래 점유하므로 RequestAsyncLoad를 사용해서 호출해야 한다.
- RequestAsyncLoad는 완료 시 Delegate를 호출하도록 세팅 할 수 있다.
-
더보기
void UGameCheatManager::GrantItems() { TArray<FSoftObjectPath> ItemsToStream; FStreamableManager& Streamable = UGameGlobals::Get().StreamableManager; for(int32 i = 0; i < ItemList.Num(); ++i) { ItemsToStream.AddUnique(ItemList[i].ToStringReference()); } Streamable.RequestAsyncLoad(ItemsToStream, FStreamableDelegate::CreateUObject(this, &UGameCheatManager::GrantItemsDeferred)); } void UGameCheatManager::GrantItemsDeferred() { for(int32 i = 0; i < ItemList.Num(); ++i) { UGameItemData* ItemData = ItemList[i].Get(); if(ItemData) { MyPC->GrantItem(ItemData); } } }
- 예시에서 ItemList는 TArray<TSoftObjectPtr<UGameItem>>이며, Editor에서 Designer에 의해 수정되었다.
- 위 코드는 ItemList를 순회하여 StringReferences로 변환시키고, 다음 Load를 위해 대기열에 등록한다.
- ItemList가 모두 Load되거나 Load에 실패하면 전달 된 Delegate를 호출한다.
- 그러면 Delegate는보통 Load 된 ItemList를 다시 순회하여 역참조를 구하고, 플레이어에게 전달해준다.
- StreamableManager는 Dlegate가 호출될 때까지 Load하는 Asset에 대한 Reference를 유지한다.
- 이는 Delegate 호출 전에 Garbage Collecting이 되는 일 없도록 방지하기 위함이다.
- Delegate가 호출된 후에는 Reference가 해제되므로 반드시 어딘가에 Hard Reference를 해줘야 한다.
*Async Load 방식들에 대한 비교
StreamableManager
- Runtime 중 Dynamic Asset Loading이나 Memory Resource가 제한된 환경에 적합하다.
- 모바일이나 VR 환경
- 주로 스킨, 무기, 추가 레벨 등에서 사용.
- 반대로 초기 Game/Level Loading 등 한번만 Load하면 되지만 그 용량이 큰 경우에는 부적합하다.
Async Load Package
- 전체 Game Level이나 World를 Async Load 할 때 적합
- 보통 Map 전환 시 Loading Screen과 함께 사용하면 Load 지연을 인지하지 못하게 할 수 있다.
- 또는 Game이나 Level 시작 시 필요한 Asset들을 Load할 때에도 적합하다.
- 반대로 소규모, 또는 개별로 발생하는 Load에는 부적합하다.
- Animation Clip, Texture 등
BulkData
- 큰 Texture, Sound, Video와 같은 대용량 Resource 사용에 적합하다.
- GamePlay 중 Memory에 직접 Load되어 성능 최적화에 기여 한다.
- Media Player 또는 Video Streaming Service에서 async로 대용량 미디어 파일을 Load하고 재생할 때 유효
- 모든 경우의 Synchronous Data 처리에 부적합하다.
- Load 속도가 비교적 느리기 때문
'UE5 > Architecture' 카테고리의 다른 글
[Architecture] String (0) | 2024.05.06 |
---|---|
[Architecture] Asset Registry (1) | 2024.05.06 |
[Architecture] Asset Reference (0) | 2024.05.06 |
[Architecture] Module(+ Package) (0) | 2024.05.03 |
[Architecture] DataAsset과 Asset Manager (0) | 2024.05.03 |