본문 바로가기

UE4

[UE4] Asset 비동기 로딩 (FStreamableManager::RequestAsyncLoad)

0. 설명

 

FStreamableManager::RequestAsyncLoad 함수를 이용한 Asset async load 코드 예제.
BeginPlay시 임의의 SkeletalMesh를 비동기 로드하고, 이를 SkeletalMeshComponent에 SetSkeletal 하는 코드.
 

1) GEngine / UAssetManager

UAssetManager는 UEngine 클래스의 멤버 변수이며, UEngine 클래스는 다음과 같이 전역 변수로 존재한다.
// Runtime/Engine/Classes/Engine/Engine.h

/**
 * Abstract base class of all Engine classes, responsible for management of systems critical to editor or game systems.
 * Also defines default classes for certain engine systems.
 */
UCLASS(abstract, config=Engine, defaultconfig, transient)
class ENGINE_API UEngine
    : public UObject, public FExec
{
    // ...

    UPROPERTY()
    class UAssetManager *AssetManager;

    // ...
};

/** Global engine pointer. Can be 0 so don't use without checking. */
extern ENGINE_API class UEngine* GEngine;
 
UAssetManager 역시 Singleton 개념을 가지고 있다.
 

2) UAssetManager::RequestAsyncLoad

RequestAsyncLoad 함수의 시그너쳐는 다음과 같다.
// Runtime/Engine/Classes/Engine/StreamableManager.h

TSharedPtr<FStreamableHandle> UAssetManager::RequestAsyncLoad
(
    // 디스크로부터 로드할 애셋 스트림
    const FStringAssetReference& TargetToStream,
    // 비동기 수행 완료시 호출할 델리게이트
    FStreamableDelegate DelegateToCall = FStreamDelegate(),
    // 우선순위, 높을수록 빨리 완료
    TAsyncLoadPriority Priority = 0,
    // true : AssetManager는 FStreamableHandle을 명시적으로 release하기 전까지 active 상태로 보관
    bool bManageActiveHandle = false,
    // 반환 핸들의 이름이자 디버깅 도구에서 드러날 이름
    const FString& DebugName = L"RequestAsyncLoad SingleDelegate"
)
 
첫번째 인자인 TargetToStream을 제외하고는 모두 default paremeter임을 확인할 수 있다.
 

1. Code

///////////////////////////////////////////////////////////////////////////////////////////////
// Header
///////////////////////////////////////////////////////////////////////////////////////////////

// Load from DefaultGame.ini
UPROPERTY(Config)
TArray<FStringAssetReference> CharacterAssets;


///////////////////////////////////////////////////////////////////////////////////////////////
// CPP
///////////////////////////////////////////////////////////////////////////////////////////////

// Called when the game starts or when spawned
void AABPawn::BeginPlay()
{
    Super::BeginPlay();

    // pick character SkeletalMesh index
    CharacterSKIndex = FMath::RandRange(0, CharacterAssets.Num() - 1);

    // FStreamableManager
    auto& assetLoader = UAssetManager::GetStreamableManager();
    assetLoader.RequestAsyncLoad(
        CharacterAssets[CharacterSKIndex],
        FStreamableDelegate::CreateUObject(this, &AABPawn::CharacterMeshDeferred)
    );
}

void AABPawn::CharacterMeshDeferred()
{
    TAssetPtr<USkeletalMesh> NewCharacter(CharacterAssets[CharacterSKIndex]);
    if (NewCharacter)
    {
        SkelMesh->SetSkeletalMesh(NewCharacter.Get());
    }
}
 
언리얼 엔진에서 런타임에 애셋을 로딩하는 것은 UAssetManager::FStreamableManager 이다.
Line 23에서 UAssetManager::FStreamableManager를 GetStreamableManager 함수를 통해 얻어오는 것을 확인할 수 있다.
 
Line 26의 Delegate 및 바인딩에 대해서 사전 지식이 없다면 다음의 문서를 참고하기 바란다.
 

2. 참고

위 Code의 Line6에서 읽어들인 DefaultGame.ini는 다음과 같다.
[/Script/ArenaBattle.ABPawn]
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Barbarous.SK_CharM_Barbarous
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/sk_CharM_Base.sk_CharM_Base
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Bladed.SK_CharM_Bladed
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Cardboard.SK_CharM_Cardboard
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Forge.SK_CharM_Forge
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_FrostGiant.SK_CharM_FrostGiant
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Golden.SK_CharM_Golden
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Natural.SK_CharM_Natural
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Pit.SK_CharM_Pit
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Ragged0.SK_CharM_Ragged0
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_RaggedElite.SK_CharM_RaggedElite
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Ram.SK_CharM_Ram
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Robo.SK_CharM_Robo
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Shell.SK_CharM_Shell
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_solid.SK_CharM_solid
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Standard.SK_CharM_Standard
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Tusk.SK_CharM_Tusk
+CharacterAssets=/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Warrior.SK_CharM_Warrior
 
위 ini에서 보여지듯, 앞에 + 기호가 붙으면 TArray 형식으로 ini로부터 값을 읽어들일 수 있다.

'UE4' 카테고리의 다른 글

[UE4] Actor::RootComponent  (0) 2023.04.24
[UE4] ConstructorHelper::FObjectFinder/FClassFinder  (0) 2023.04.24
[UE4] FTimerManager::SetTimer/ClearTimer/GetTimerElapsed  (0) 2023.04.24
[UE4] World 내 Object/Actor 순회  (0) 2023.04.24
[UE4] MyLogMacro.h  (0) 2023.04.24