오늘은 언리얼 엔진에서 대형 맵(오픈 월드 환경)을 효율적으로 로딩하는 방법에 대해 정리하겠습니다. 특히 World Partition과 Level Streaming의 차이, 그리고 Git LFS와의 연계를 중심으로 고민했습니다.
1. 언리얼 엔진의 주요 맵 로딩 방식
Level Streaming (기존 방식)
- Persistent Level과 여러 서브 레벨을 나눠 구성
- 필요할 때만 특정 레벨을 로딩하거나 언로드
- Streaming Volume, Blueprint, 또는 C++ 코드로 로딩 제어
World Partition (UE5 이상)
- 맵 전체를 자동으로 그리드 단위로 분할하고, 스트리밍을 자동화
- 수동으로 서브 레벨을 나눌 필요 없음
- HLOD, Data Layer, Runtime Grid 등을 활용한 고급 스트리밍 가능
- 협업 시 섹션 단위 커밋 가능 → Git 충돌 최소화
2. 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
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 외 변경 사항도 검토 필수 |
'TIL > Unreal Engine' 카테고리의 다른 글
언리얼 엔진의 입력 모드(FInputMode) (0) | 2025.05.21 |
---|---|
언리얼 엔진 레벨 전환 시 로딩 방식 (0) | 2025.05.14 |
AI ROV(Reciprocal Velocity Obstacles) (0) | 2025.04.24 |
Unreal Engine에서 SFX 임포트 및 어테뉴에이션 세팅하기 (Feat. 발소리와 BGM) (0) | 2025.04.23 |
Chaos Destruction (0) | 2025.03.26 |