언리얼 엔진의 맵 로딩

언리얼 거토
|2025. 5. 8. 12:58

오늘은 언리얼 엔진에서 대형 맵(오픈 월드 환경)을 효율적으로 로딩하는 방법에 대해 정리하겠습니다. 특히 World PartitionLevel Streaming의 차이, 그리고 Git LFS와의 연계를 중심으로 고민했습니다.

 

1. 언리얼 엔진의 주요 맵 로딩 방식

Level Streaming (기존 방식)

  • Persistent Level과 여러 서브 레벨을 나눠 구성
  • 필요할 때만 특정 레벨을 로딩하거나 언로드
  • Streaming Volume, Blueprint, 또는 C++ 코드로 로딩 제어

World Partition (UE5 이상)

  • 맵 전체를 자동으로 그리드 단위로 분할하고, 스트리밍을 자동화
  • 수동으로 서브 레벨을 나눌 필요 없음
  • HLOD, Data Layer, Runtime Grid 등을 활용한 고급 스트리밍 가능
  • 협업 시 섹션 단위 커밋 가능 → Git 충돌 최소화

2. Level Streaming

Level Streaming 언리얼 공식 문서

2-1. 핵심 개념 : Persistent Level과 Sub Level

  • Persistent Level: 게임의 기본 월드. 가장 처음 로딩되는 베이스 레벨이며, 항상 메모리에 존재함.
    • 예: Directional Light(태양), Sky Atmosphere(하늘 표현), Fog(안개), Sky Light(글로벌 조명), NavMesh GameMode/State 등 전역 씬 요소
  • Sub Level: Persistent Level에 속해 있는 개별 레벨들. 필요할 때만 로딩하거나 언로드됨.
    • 예: 지역별 실제 지형, 건물, NPC 등
MyWorld (Persistent Level)
├── Town_Sub (Sub Level)
├── Forest_Sub (Sub Level)
├── Dungeon_Sub (Sub Level)
  • Streaming: 필요한 데이터만 그때그때 불러오고, 필요 없으면 메모리에서 제거하는 방식

2-2. Level Streaming의 로딩 방식

자동 로딩

  • Trigger Box 형태의 Streaming Volumes를 맵에 배치
  • 플레이어가 볼륨 안에 들어오면 해당 Sub Level을 자동 로딩
  • 나가면 자동 언로드 가능

수동 로딩

  • Blueprint에서 Load Stream Level, Unload Stream Level
  • C++ 코드 제어
ULevelStreaming* StreamLevel = UGameplayStatics::GetStreamingLevel(World, "Dungeon_Sub");
if (StreamLevel)
{
    StreamLevel->SetShouldBeLoaded(true);
    StreamLevel->SetShouldBeVisible(true);
}

 

2-3. Level Streaming의 장/단점

구분 장점 단점
메모리 효율 필요한 레벨만 로딩하여 메모리 절약 전체 로딩 순서와 조건을 수동 관리해야 함
유연한 로딩 제어 Blueprint, C++ 등으로 세밀한 제어 가능 복잡한 로딩 로직은 유지보수가 어려움
작업 분담 서브 레벨 단위로 협업 가능 동시에 같은 레벨을 수정하면 충돌 발생
구현 난이도 World Partition보다 간단하고 직관적 오픈 월드 전체 자동 로딩에는 부적합
호환성 UE4 기반 프로젝트와 잘 맞음 UE5에서 새 기능(World Partition) 대비 기능 부족

3. World Partition

World Patrition 언리얼 공식 문서

3-1. 핵심 기능 및 개념

(1). 그리드 기반 스트리밍

  • 월드를 자동으로 일정한 그리드 셀 단위로 분할
  • Runtime Grid: "어떻게 셀을 나눌지" 정의하는 설정 시스템
  • 플레이어 위치에 따라 필요한 셀만 로드 / 언로드

(2). Editor에서의 시각적 스트리밍 관리

  • 에디터에서 World Partition 창을 통해 어떤 셀(섹터)이 활성화되는지 시각적으로 확인 가능
  • 개발 중에도 일부 영역만 로딩해서 작업 가능 → 메모리 부담↓, 로딩 속도↑

(3). Data Layers 지원

  • Data Layers: 월드 안의 오브젝트들을 논리적으로 묶는 레이어 시스템
  • 월드 파티션의 "자동 셀 스트리밍"과 별도로, 게임 상황에 따라 특정 그룹을 통째로 로딩하거나 언로드
  • 같은 위치라도 레이어에 따라 다르게 표현 가능 → 환경에 따라 다른 월드 구성 가능 (예: 낮/밤, 계절)
  • Data Layers 언리얼 공식 문서

(4). HLOD(Hierarchcal Level of Detail) 지원

  • HLOD: 멀리 있는 오브젝트들을 간단한 형태(저해상도)로 자동으로 묶고 표시하는 시스템
  • 퍼포먼스 최적화에 매우 유용
  • HLOD 언리얼 공식 문서

(5). Streaming Source

  • 플레이어의 위치뿐만 아니라, 카메라 또는 특정 객체를 기준으로 월드 스트리밍을 제어
  • 기본적으로는 플레이어의 위치를 기준, but 추가하고 싶다면 UWorldPartitionSubsystem 에 등록

3-2.World Partition의 장/단점

구분 장점 단점
레벨 구조 하나의 .umap으로 월드 전체 구성 가능
→ Sub Level 분할 없이 관리
내부적으로 수천 개의 셀 .uasset 생성됨
→ 구조 단순해 보이지만 파일은 훨씬 많아짐
로딩 효율 플레이어 위치 기반 자동 로딩/언로딩으로
거대한 오픈 월드 구현에 최적
셀 단위 자동 로딩은 특정 상황(이벤트, 퍼즐)에서 세밀한 제어가 어려움
협업 효율 셀 단위로 동시에 여러 작업자가 병렬 작업 가능 → 작업 영역 분담 쉬움 같은 셀을 수정하면 충돌 발생, 병합 불가능 /
셀이 자동으로 나뉘기 때문에 명확한 소유권이 불분명
Git LFS와 충돌 시 치명적
성능 최적화 HLOD, Data Layer, Runtime Grid 등
최신 최적화 기능 내장
기능이 많고 설정이 복잡해 숙련되지 않으면 디버깅과 튜닝 어려움
작업 단순화 Sub Level을 수동으로 나누고
스트리밍 설정하는 작업이 필요 없음
자동화된 셀 구조는 개발자가 직접 컨트롤하기 어려운 영역도 있음
버전 관리 (Git) Sub Level 방식보다 .umap 충돌 가능성은 낮음 (파일 하나니까) Git LFS에서 수천 개의 셀 .uasset 추적
→ LFS 용량 폭발, 속도 저하, 충돌 빈번

3-2-1. 참고: World Partition에서의 파일 구조

항목 내용
.umap 파일 월드의 "메인 레벨" 메타 정보. 단 하나 존재. 기존의 Persistent + Sub Level 구조 대신 하나로 통합.
셀 .uasset 파일 World Partition이 맵을 자동으로 그리드 셀로 쪼개어 각각의 셀을 .uasset 파일로 저장. 수백~수천 개 생성.
HLOD .uasset 파일 자동 생성된 계층적 LOD 정보. 별도의 디렉터리에 다수의 .uasset 파일로 저장됨.
Data Layer 파일 선택적으로 사용하는 경우, 레이어별 콘텐츠 구성을 위한 추가 .uasset 파일 생성 가능.

3-3. Git 문제 대처 방법 및 협업 전략

(1). .gitattributes 설정으로 셀 제외

# 기본적으로 모든 바이너리 자산은 LFS로 추적
*.uasset filter=lfs diff=lfs merge=lfs -text
*.umap filter=lfs diff=lfs merge=lfs -text

# ⛔ World Partition 셀은 일반 Git으로 제외
Content/Maps/YourMapName/_WPGrid/*.uasset !filter !diff !merge text

# (선택) HLOD 관련 파일도 제외
Content/Maps/YourMapName/HLOD/*.uasset !filter !diff !merge text

 

(2). 협업 워크 플로우

전략 설명
작업 셀 분담 World Partition 창에서 각자 영역 미리 Lock(에디터 기능)
셀 자동 커밋 방지 수정 안 한 셀은 커밋 제외 또는 무시 설정
대형 자산 분리 저장 Git 외부 저장소(S3, GDrive 등)와 스크립트 연동
자동 배포/백업 스크립트 구성 Rsync, Python, Bash 등으로 데이터 통제
수정 범위 사전 공유 Discord/Slack 등으로 오늘 작업 셀 공유
변경 사항 리뷰 병합 전 .umap 외 변경 사항도 검토 필수