
Soft Reference를 사용하면 Asset을 즉시 로드하지 않고 경로 형태로 관리할 수 있었다.
하지만 Soft Reference를 통해 해당 Asset을 사용하기 위해서는 어떤 시점에 로드할 것인지를 직접 결정해야 한다.
이때 필요한 개념이 바로 Loading 방식이다.

Unreal Engine에서 Asset을 로드하는 방식은 크게 두 가지로 나뉜다.

동기 로딩은 Asset이 완전히 로드될 때까지 기다리는 방식이다.
USkeletalMesh* LoadedMesh = Data->Mesh.LoadSynchronous();
if (LoadedMesh)
{
SkeletalMeshComponent->SetSkeletalMesh(LoadedMesh);
}
이 코드를 실행하면 해당 Asset이 메모리에 로드될 때까지 스레드는 대기 상태(Block)가 된다.
따라서 동기 로딩은 로딩 중 처리가 오래 걸릴 경우 프레임이 멈추거나 끊길 수 있다.
비동기 로딩은 게임의 실행 흐름을 유지한 채, 백그라운드 스레드에서 Asset을 로드하는 방식이다.
따라서 Asset 로드를 요청하더라도, 게임은 멈추지 않고 계속 진행된다.
하지만 이 방식에서는 Asset이 언제 로드될지 보장되지 않기 때문에, 로드 완료 시점을 처리하기 위한 콜백 또는 Delegate 구조가 필요하다.
예를 들어 이런 식으로 되어있는 데이터 테이블이 있다고 가정해보자.
| RowName | Name | Mesh |
|---|---|---|
| Warrior | Warrior | /Game/Characters/Warrior.Warrior |
| Mage | Mage | /Game/Characters/Mage.Mage |
이때 Mesh는 TSoftObjectPtr 형태로 저장되어 있으며, 실제 Asset이 아니라 경로(Path)만을 참조하고 있다.
UPROPERTY(EditAnywhere)
UDataTable* CharacterDataTable;
UPROPERTY(VisibleAnywhere)
TSoftObjectPtr<USkeletalMesh> SelectedMesh;
void ACharacterBase::BeginPlay()
{
Super::BeginPlay();
if (!CharacterDataTable) return;
TArray<FName> RowNames = CharacterDataTable->GetRowNames();
int32 Index = FMath::RandRange(0, RowNames.Num() - 1);
FCharacterDataRow* SelectedRow = CharacterDataTable->FindRow<FCharacterDataRow>(RowNames[Index], TEXT(""));
if (!SelectedRow) return;
SelectedMesh = SelectedRow->Mesh;
auto& AssetLoader = UAssetManager::GetStreamableManager();
AssetLoader.RequestAsyncLoad(
SelectedMesh.ToSoftObjectPath(),
FStreamableDelegate::CreateUObject(this, &AABPawn::OnMeshLoaded)
);
}
void ACharacterBase::OnMeshLoaded()
{
if (SelectedMesh.IsValid())
{
SkelMesh->SetSkeletalMesh(SelectedMesh.Get());
}
}
이런 식으로 Soft Reference와 Async Loading을 함께 사용하면 Asset을 즉시 로드하지 않고, 필요한 순간에만 로드하는 구조를 만들 수 있다.
이는 특히 데이터 중심 설계에서 성능과 메모리 최적화를 위해 필수적이다.