본문 바로가기

레벨 스트리밍과 World Partition

Level Streaming과 World Partition의 로드 단위를 비교하고 대규모 월드의 영역을 필요할 때 불러옵니다.

이전 절에서 액터의 생성과 관리에 대해 알아보며, 게임 월드 내의 객체들을 어떻게 효율적으로 다룰 수 있는지 이해했습니다.

하지만 게임 월드가 매우 커지고 복잡해질 경우, 모든 액터와 모든 지형 데이터를 동시에 메모리에 로드하는 것은 불가능에 가깝습니다.

이 문제를 해결하기 위해 언리얼 엔진은 레벨 스트리밍(Level Streaming)과 월드 파티션(World Partition)을 제공합니다.

UE5의 넓은 연속 월드에는 World Partition을 검토할 수 있고, 제작자가 명시한 서브 레벨 경계에는 기존 Level Streaming을 사용할 수 있습니다.


레벨 스트리밍 (Level Streaming)

레벨 스트리밍은 메인 레벨(Persistent Level)에 필요한 서브 레벨(Sub-levels)들을 동적으로 로드하거나 언로드하여 메모리 사용량을 최적화하고 로딩 시간을 단축하는 기술입니다.

플레이어가 월드를 탐색함에 따라, 현재 위치 주변의 레벨만 메모리에 로드하고, 멀리 떨어진 레벨은 언로드하여 리소스를 절약합니다.

레벨 스트리밍의 작동 방식

퍼시스턴트 레벨 (Persistent Level): 해당 월드가 유지되는 동안 기준이 되는 메인 레벨입니다.

게임의 시작 지점, 전역 게임 로직, 공통 리소스 등이 포함될 수 있습니다.

서브 레벨 (Sub-levels): 퍼시스턴트 레벨에 동적으로 스트리밍될 작은 레벨들입니다.

각각의 서브 레벨은 특정 지역, 건물 내부, 던전 등을 포함할 수 있습니다.

스트리밍 볼륨 (Streaming Volume): 연결한 스트리밍 볼륨에 플레이어의 시점(Viewpoint)이 들어오거나 나갈 때 서브 레벨의 로드/언로드 요청을 제어하는 영역입니다. 액터 중심의 위치가 아니라 카메라 시점에 따른 판정이라는 점을 구분합니다.

레벨 스트리밍의 장점

  • 메모리 최적화: 모든 레벨 데이터를 동시에 로드할 필요가 없어 메모리 사용량을 크게 줄일 수 있습니다.
  • 로딩 시간 단축: 게임 시작 시 모든 것을 로드하는 대신, 필요한 부분만 점진적으로 로드하므로 초기 로딩 시간이 짧아집니다.
  • 끊김 없는 월드: 로딩 화면 없이 넓은 월드를 연속적으로 탐색하는 경험을 제공할 수 있습니다.
  • 협업 용이: 여러 팀원이 각자의 서브 레벨을 독립적으로 작업하고 나중에 병합할 수 있습니다.

레벨 스트리밍 구현 (C++)

아래 예제는 World Partition 셀이 아니라 기존 서브 레벨 스트리밍을 제어합니다. Levels 창에서 대상 서브 레벨을 현재 월드에 등록하고 Streaming Method를 Blueprint로 설정한 구성을 전제로 합니다. 임의의 맵 이름만 넘겨 등록하는 예제는 아닙니다.

MyLevelStreamer.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyLevelStreamer.generated.h"

UCLASS()
class MYPROJECT_API AMyLevelStreamer : public AActor
{
    GENERATED_BODY()

public:
    AMyLevelStreamer();

    // 스트리밍할 서브 레벨의 이름 (에디터에서 설정)
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Level Streaming")
    FName LevelToStreamName;

protected:
    virtual void BeginPlay() override;

public:
    // 레벨을 로드하는 함수
    UFUNCTION(BlueprintCallable, Category = "Level Streaming")
    void LoadMyLevel();

    // 레벨을 언로드하는 함수
    UFUNCTION(BlueprintCallable, Category = "Level Streaming")
    void UnloadMyLevel();
};
MyLevelStreamer.cpp
#include "MyLevelStreamer.h"
#include "Kismet/GameplayStatics.h" // UGameplayStatics::LoadStreamLevel 등 포함
#include "Engine/LevelStreaming.h"   // ULevelStreaming에 접근하기 위해 포함

AMyLevelStreamer::AMyLevelStreamer()
{
    PrimaryActorTick.bCanEverTick = false; // 이 액터는 틱이 필요 없을 수 있음
}

void AMyLevelStreamer::BeginPlay()
{
    Super::BeginPlay();
    // 필요에 따라 BeginPlay에서 자동으로 레벨을 로드할 수도 있습니다.
}

void AMyLevelStreamer::LoadMyLevel()
{
    if (LevelToStreamName.IsNone())
    {
        UE_LOG(LogTemp, Warning, TEXT("LevelToStreamName is not set for %s"), *GetName());
        return;
    }

    // 레벨 스트리밍 로드
    // LoadStreamLevel(월드 컨텍스트, 레벨 이름, 로드 후 표시, 로드 동안 대기, latent 정보)
    UGameplayStatics::LoadStreamLevel(this, LevelToStreamName, true, true, FLatentActionInfo());
    UE_LOG(LogTemp, Warning, TEXT("Attempting to load level: %s"), *LevelToStreamName.ToString());
}

void AMyLevelStreamer::UnloadMyLevel()
{
    if (LevelToStreamName.IsNone())
    {
        UE_LOG(LogTemp, Warning, TEXT("LevelToStreamName is not set for %s"), *GetName());
        return;
    }

    // 레벨 스트리밍 언로드
    UGameplayStatics::UnloadStreamLevel(this, LevelToStreamName, FLatentActionInfo(), false);
    UE_LOG(LogTemp, Warning, TEXT("Attempting to unload level: %s"), *LevelToStreamName.ToString());
}

이 코드의 LoadStreamLevel은 bShouldBlockOnLoad=true를 전달하므로 로딩 중 프레임 정지가 생길 수 있습니다. UnloadStreamLevel은 비차단 요청이며, 두 Attempting 로그는 대상 준비 완료를 확인한 결과가 아닙니다. 기본 FLatentActionInfo에는 완료 콜백이 없으므로, 확장 시 완료 확인과 중복 요청 식별을 설계합니다.

사용법

메인 레벨(Persistent Level)에서 AMyLevelStreamer 액터 블루프린트(BP_MyLevelStreamer)를 배치합니다.

BP_MyLevelStreamer의 디테일 패널에서 Level To Stream Name에 스트리밍할 서브 레벨의 이름을 지정합니다 (예: Level_Forest, Level_City).

레벨 블루프린트나 다른 액터의 로직에서 BP_MyLevelStreamer의 Load My Level 또는 Unload My Level 함수를 호출하여 스트리밍을 제어합니다.

일반적으로는 플레이어가 특정 트리거 볼륨(Trigger Volume)에 진입했을 때 이 함수들을 호출하도록 설정합니다.


월드 파티션 (World Partition, UE5 기준)

월드 파티션은 UE5에서 대규모 오픈 월드를 관리하는 기본 시스템입니다.

스트리밍을 활성화한 월드는 런타임 그리드와 Streaming Source의 범위, 액터의 Is Spatially Loaded 및 Runtime Data Layer 상태에 따라 로드 대상을 결정합니다. 플레이어만이 유일한 스트리밍 소스는 아닙니다.

월드 파티션의 주요 특징

  • 자동 셀 분할: 하나의 월드를 셀로 나눠 필요한 공간을 로드할 수 있습니다. 셀 크기·참조·로드 범위가 메모리 사용량에 영향을 줍니다.
  • 소스 기반 로드: 플레이어 등의 Streaming Source 주변을 로드합니다. 공간 로드를 사용하지 않는 액터는 거리 조건과 다르게 처리됩니다.
  • Data Layer: 액터 집합을 편집용 또는 런타임 상태별로 나눕니다. 런타임 로드 제어에는 Runtime Data Layer의 상태를 사용합니다.
  • One File Per Actor: 액터 단위 파일 분리로 충돌을 줄여 협업 효율이 높습니다.

HLOD는 먼 셀의 시각적 대리 표현을 만드는 기능이고, One File Per Actor는 편집 파일 분리를 위한 기능입니다. 둘은 같은 런타임 로드 상태를 뜻하지 않습니다.

월드 파티션 사용 절차 (UE5)

새로운 레벨을 생성하거나 기존 레벨을 엽니다.

Window > World Settings를 엽니다.

World Partition이 활성화된 템플릿인지 확인합니다. (새 UE5 오픈 월드 템플릿은 기본 활성화)

Window > World Partition 도구를 열어 셀 로드 범위, Data Layer 상태, HLOD 구성을 점검합니다.

UE4 참고: 구버전 프로젝트의 World Composition은 레거시 개념으로만 이해하면 충분합니다.

사용할 월드 구조는 공간 규모뿐 아니라 명시적 연출 제어와 팀의 제작 방식에 맞춰 선택합니다.

C++와 월드 파티션

월드 파티션은 엔진이 스트리밍을 자동 관리하므로, C++에서는 상태 확인과 예외 제어에 집중하는 방식이 일반적입니다.

  • 상태 확인: GetCurrentLevelName은 현재 레벨 이름 하나를 반환합니다. GetStreamingLevels는 스트리밍 객체 목록이므로 각 항목의 로드·표시 상태를 따로 확인해야 합니다. World Partition은 해당 Streaming Source의 완료 상태 등 파티션 API를 사용해 필요한 영역의 준비를 판단합니다.
  • 액터 존재 여부 확인: 스트리밍된 레벨 내의 액터에 접근하기 전에 해당 레벨이 제대로 로드되었는지 확인하는 로직을 추가하는 것이 중요합니다.

로드 단위와 준비 상태

로드 요청·로드 상태·플레이 준비를 구분합니다

등록한 Level_Forest 요청→로드/표시/필요한 게임 준비 검사→진행 또는 대기/실패의 요청 상태이다. Attempting 로그를 완료로 바꾸지 않고 WP 단위는 별도 보존한다.

UNREAL C++ · CH4-4

로드 요청·로드 상태·플레이 준비를 구분합니다

Level Streaming의 서브 레벨과 World Partition의 셀·액터 집합은 로드 단위와 조건이 다릅니다. 필요한 영역의 준비 상태를 별도로 확인합니다.

요청 뒤 대상 범위의 준비 조건을 확인한다기존 LevelStreaming 예제는 현재 월드에 서브레벨을 등록하고 Blueprint 방식으로 제어하는 설정을 전제로 한다. 로드 요청 뒤 로드·표시 및 필요한 게임 준비 상태를 확인한다. 조건을 만족하면 다음 플레이 단계로 진행하고 아니면 대기·실패 원인을 확인한다. 요청에서 준비 성공으로 바로가는 화살표는 없다.등록 · 제어 방식현재 월드의 서브 레벨로드 요청Attempting 로그대상 준비?준비 조건 확인충족미충족다음 플레이 단계필요한 대상 유효성 유지대기 · 실패 확인대상명 · 상태 재확인
요청 뒤 대상 범위의 준비 조건을 확인한다기존 LevelStreaming 예제는 현재 월드에 서브레벨을 등록하고 Blueprint 방식으로 제어하는 설정을 전제로 한다. 로드 요청 뒤 로드·표시 및 필요한 게임 준비 상태를 확인한다. 조건을 만족하면 다음 플레이 단계로 진행하고 아니면 대기·실패 원인을 확인한다. 요청에서 준비 성공으로 바로가는 화살표는 없다.등록 · 제어 방식현재 월드의 서브 레벨로드 요청Attempting 로그대상 준비?준비 조건 확인충족미충족다음 플레이 단계필요한 대상 유효성 유지대기 · 실패 확인대상명 · 상태 재확인

이 흐름은 본문의 서브 레벨 요청 예입니다. World Partition은 별도 Streaming Source 범위와 목표 상태의 완료를 확인합니다. 표시 여부만으로 모든 충돌·내비게이션·게임 데이터 준비를 보장하지 않으며, 표의 두 로드 단위를 한 API로 제어하지 않습니다.

스트리밍의 로드 단위와 준비 판정
구분Level StreamingWorld Partition
로드 단위현재 월드에 등록한 서브 레벨런타임 그리드의 셀과 액터 집합
로드 조건코드·블루프린트·볼륨과 Streaming MethodStreaming Source·공간 로드 설정·Runtime Data Layer
준비 확인로드 상태와 표시 상태를 구분필요한 소스 범위의 스트리밍 완료와 활성 상태 확인
참조 경계언로드될 액터를 사용할 때 유효성 확인액터 간 참조로 함께 로드되는 묶음도 확인
남길 상태언로드 전에 진행 상태의 별도 보관 결정셀·액터 수명과 분리해 퀘스트 등 상태 보관
로드 단위
Level Streaming: 현재 월드에 등록한 서브 레벨
World Partition: 런타임 그리드의 셀과 액터 집합
로드 조건
Level Streaming: 코드·블루프린트·볼륨과 Streaming Method
World Partition: Streaming Source·공간 로드 설정·Runtime Data Layer
준비 확인
Level Streaming: 로드 상태와 표시 상태를 구분
World Partition: 필요한 소스 범위의 스트리밍 완료와 활성 상태 확인
참조 경계
Level Streaming: 언로드될 액터를 사용할 때 유효성 확인
World Partition: 액터 간 참조로 함께 로드되는 묶음도 확인
남길 상태
Level Streaming: 언로드 전에 진행 상태의 별도 보관 결정
World Partition: 셀·액터 수명과 분리해 퀘스트 등 상태 보관

Loaded와 보이는 상태는 다릅니다. One File Per Actor는 편집 협업 기능입니다. 본문의 Attempting 로그와 기본 FLatentActionInfo는 준비 완료 콜백이 아니며, 로드 예제는 bShouldBlockOnLoad=true입니다.

이 예의 조건

  • 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
  • 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
관계도의 보충 설명
원 도표의 제목·노드·관계·조건·주석
범위원문
관계·조건 설명기존 LevelStreaming 예제는 현재 월드에 서브 레벨을 등록하고 Blueprint 방식으로 제어하는 설정을 전제로 한다. 로드 요청 뒤 로드·표시 및 필요한 게임 준비 상태를 확인한다. 조건을 만족하면 다음 플레이 단계로 진행하고 아니면 대기·실패 원인을 확인한다. 요청에서 준비 성공으로 바로 가는 화살표는 없다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
레벨 요청

등록된 Level_Forest의 로드를 요청한다.

  • 이름: Level_Forest
  • 상태: 요청 중
  • Attempting 로그는 완료 근거가 아니다.
준비 검사

로드·표시와 필요한 게임 준비를 확인한다.

  • 검사: loaded/visible/게임 준비
  • 미준비: 대기 또는 실패 정책
  • 로드만 끝났다고 모든 Actor의 게임 준비를 보장하지 않는다.
진행 허용

선택한 조건이 맞을 때 후속 동작을 진행한다.

  • 허용: 검증한 준비 조건
  • WP: 별도 스트리밍 단위
  • 전통 레벨 요청을 World Partition 전체 정책으로 일반화하지 않는다.

로드 요청·로드 상태·플레이 준비를 구분합니다

등록한 Level_Forest 요청→로드/표시/필요한 게임 준비 검사→진행 또는 대기/실패의 요청 상태이다. Attempting 로그를 완료로 바꾸지 않고 WP 단위는 별도 보존한다.

UNREAL C++ · CH4-4

로드 요청·로드 상태·플레이 준비를 구분합니다

Level Streaming의 서브 레벨과 World Partition의 셀·액터 집합은 로드 단위와 조건이 다릅니다. 필요한 영역의 준비 상태를 별도로 확인합니다.

요청 뒤 대상 범위의 준비 조건을 확인한다기존 LevelStreaming 예제는 현재 월드에 서브레벨을 등록하고 Blueprint 방식으로 제어하는 설정을 전제로 한다. 로드 요청 뒤 로드·표시 및 필요한 게임 준비 상태를 확인한다. 조건을 만족하면 다음 플레이 단계로 진행하고 아니면 대기·실패 원인을 확인한다. 요청에서 준비 성공으로 바로가는 화살표는 없다.등록 · 제어 방식현재 월드의 서브 레벨로드 요청Attempting 로그대상 준비?준비 조건 확인충족미충족다음 플레이 단계필요한 대상 유효성 유지대기 · 실패 확인대상명 · 상태 재확인
요청 뒤 대상 범위의 준비 조건을 확인한다기존 LevelStreaming 예제는 현재 월드에 서브레벨을 등록하고 Blueprint 방식으로 제어하는 설정을 전제로 한다. 로드 요청 뒤 로드·표시 및 필요한 게임 준비 상태를 확인한다. 조건을 만족하면 다음 플레이 단계로 진행하고 아니면 대기·실패 원인을 확인한다. 요청에서 준비 성공으로 바로가는 화살표는 없다.등록 · 제어 방식현재 월드의 서브 레벨로드 요청Attempting 로그대상 준비?준비 조건 확인충족미충족다음 플레이 단계필요한 대상 유효성 유지대기 · 실패 확인대상명 · 상태 재확인

이 흐름은 본문의 서브 레벨 요청 예입니다. World Partition은 별도 Streaming Source 범위와 목표 상태의 완료를 확인합니다. 표시 여부만으로 모든 충돌·내비게이션·게임 데이터 준비를 보장하지 않으며, 표의 두 로드 단위를 한 API로 제어하지 않습니다.

스트리밍의 로드 단위와 준비 판정
구분Level StreamingWorld Partition
로드 단위현재 월드에 등록한 서브 레벨런타임 그리드의 셀과 액터 집합
로드 조건코드·블루프린트·볼륨과 Streaming MethodStreaming Source·공간 로드 설정·Runtime Data Layer
준비 확인로드 상태와 표시 상태를 구분필요한 소스 범위의 스트리밍 완료와 활성 상태 확인
참조 경계언로드될 액터를 사용할 때 유효성 확인액터 간 참조로 함께 로드되는 묶음도 확인
남길 상태언로드 전에 진행 상태의 별도 보관 결정셀·액터 수명과 분리해 퀘스트 등 상태 보관
로드 단위
Level Streaming: 현재 월드에 등록한 서브 레벨
World Partition: 런타임 그리드의 셀과 액터 집합
로드 조건
Level Streaming: 코드·블루프린트·볼륨과 Streaming Method
World Partition: Streaming Source·공간 로드 설정·Runtime Data Layer
준비 확인
Level Streaming: 로드 상태와 표시 상태를 구분
World Partition: 필요한 소스 범위의 스트리밍 완료와 활성 상태 확인
참조 경계
Level Streaming: 언로드될 액터를 사용할 때 유효성 확인
World Partition: 액터 간 참조로 함께 로드되는 묶음도 확인
남길 상태
Level Streaming: 언로드 전에 진행 상태의 별도 보관 결정
World Partition: 셀·액터 수명과 분리해 퀘스트 등 상태 보관

Loaded와 보이는 상태는 다릅니다. One File Per Actor는 편집 협업 기능입니다. 본문의 Attempting 로그와 기본 FLatentActionInfo는 준비 완료 콜백이 아니며, 로드 예제는 bShouldBlockOnLoad=true입니다.

이 예의 조건

  • 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
  • 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.

관계도의 보충 설명

원 도표의 제목·노드·관계·조건·주석
범위원문
관계·조건 설명기존 LevelStreaming 예제는 현재 월드에 서브 레벨을 등록하고 Blueprint 방식으로 제어하는 설정을 전제로 한다. 로드 요청 뒤 로드·표시 및 필요한 게임 준비 상태를 확인한다. 조건을 만족하면 다음 플레이 단계로 진행하고 아니면 대기·실패 원인을 확인한다. 요청에서 준비 성공으로 바로 가는 화살표는 없다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
레벨 요청

등록된 Level_Forest의 로드를 요청한다.

  • 이름: Level_Forest
  • 상태: 요청 중
  • Attempting 로그는 완료 근거가 아니다.
준비 검사

로드·표시와 필요한 게임 준비를 확인한다.

  • 검사: loaded/visible/게임 준비
  • 미준비: 대기 또는 실패 정책
  • 로드만 끝났다고 모든 Actor의 게임 준비를 보장하지 않는다.
진행 허용

선택한 조건이 맞을 때 후속 동작을 진행한다.

  • 허용: 검증한 준비 조건
  • WP: 별도 스트리밍 단위
  • 전통 레벨 요청을 World Partition 전체 정책으로 일반화하지 않는다.

예시: 로그 다음에 필요한 확인

퍼시스턴트 레벨에 Level_Forest를 등록하고 Blueprint 스트리밍 방식으로 둔 뒤, 예제 액터의 이름을 같은 값으로 지정합니다. LoadMyLevel()을 호출했을 때 Attempting 로그는 함수가 로드 요청을 보냈다는 사실을 알려 줍니다. 숲의 로드·표시 상태와 필요한 액터의 유효성, 플레이에 필요한 충돌·내비게이션 상태는 따로 확인합니다. Always Loaded로 설정한 서브 레벨은 이 예의 동적 요청과 볼륨 제어를 같은 방식으로 따르지 않습니다.

World Partition을 쓰는 별도 월드에서는 목적지에 스트리밍 소스를 준비하고 필요한 목표 상태를 설정합니다. 그 소스 범위의 완료 확인은 모든 월드 셀의 완료 판정이 아니며, 퀘스트 진행 값은 언로드되는 액터와 수명을 분리해 보관할지 결정합니다.

준비와 상태 보관 판단하기

A 지역의 보물상자를 연 뒤 다른 지역으로 이동하여 A의 액터가 언로드되었습니다. 퀘스트 진행도는 계속 남아야 합니다. 상자 액터의 멤버에만 그 진행도를 남기는 선택으로 충분할까요? 또한 World Partition 창에서 편집할 셀을 로드했거나 One File Per Actor로 저장했다는 사실만으로 목적지의 런타임 플레이 준비가 끝났다고 할 수 있는지도 설명하세요.

수명과 준비 범위의 풀이

언로드될 액터와 별개로 유지할 상태 보관 위치와 복원 시점을 정해야 합니다. 예를 들어 같은 실행 동안의 지속 상태를 담당하는 객체가 상자 식별자별 진행도를 보관하고, 새로 로드된 상자에 적용하는 흐름을 설계할 수 있습니다. 편집용 셀 로드와 파일 분리는 런타임 소스 범위의 로드·활성 및 게임 준비 확인을 대신하지 않습니다. 상자에 대한 원래 참조도 언로드 뒤 사용하기 전에 유효성을 다시 확인합니다.

공식 World Partition 문서는 기존 레벨의 변환 절차도 따로 제시합니다. World Settings를 열었다는 사실만으로 일반 레벨이 자동 변환되지는 않으며, 변환할 때는 원본 보존과 별도 결과 검토를 준비합니다. 이 절은 변환 명령을 실제 실행한 결과를 제시하지 않습니다.

고속 이동이나 텔레포트에서는 목적지의 Streaming Source로 미리 준비하는 방식을 검토합니다. 대상 기기에서 I/O 지연·프레임 정지·메모리, 충돌·내비게이션 준비와 HLOD 전환을 함께 확인해야 하며, 스트리밍 사용 자체가 끊김 없는 플레이를 보장하지는 않습니다.