no image
언리얼 엔진 퍼포먼스 최적화의 첫걸음
최적화란?퍼포먼스 최적화는 일회성 작업이 아니라 반복적인 과정이다.가장 느린 병목 지점을 해결하면, 그 다음으로 느린 부분이 병목이 되고, 이를 다시 해결하는 과정을 반복하게 된다.즉, 끝이 없는 두더지 잡기와 같다. 최적화 전 준비: 테스트 환경 정리최적화를 시작하기 전에 테스트 환경을 정리하는 것이 매우 중요하다.불필요한 요소들이 성능 측정에 영향을 줄 수 있기 때문이다.예를 들어, 언리얼 엔진 에디터의 UI 자체가 성능에 영향을 줄 수 있다.따라서 최적화 테스트는 다음과 같은 환경에서 진행하는 것이 좋다:패키지된 빌드를 사용하거나최소한 Standalone Mode에서 테스트 1프레임의 기준 시간일반적인 게임은 60fps를 목표로 한다.이는 1초(1000ms)를 60프레임으로 나눈 값인 약 16.66..
2025.07.15
언리얼 사운드 시스템 기초
1. 개요프로젝트에서 게임 설정 관련된 작업을 시작하게 되었습니다. 가장 먼저 구현하고 싶었던 기능은 사운드 조절이었습니다. 이를 위해 언리얼 엔진의 사운드 시스템을 간단히 조사해보았고, 특히 Sound Class, Sound Mix, 그리고 이를 제어할 수 있는 C++ 함수들에 대해 처음으로 다뤄보게 되었습니다. 2. Sound ClassSound Class는 사운드를 논리적인 그룹으로 나누어 제어할 수 있게 해주는 시스템입니다. 예를 들어, 배경음(BGM), 효과음(SFX), 음성(Voice)을 각각의 사운드 클래스에 할당해두면, 이들 그룹의 볼륨을 개별적으로 제어할 수 있습니다. SC_BGM → 배경음용 Sound ClassSC_SFX → 효과음용 Sound ClassSC_UI → UI 효과음 전용..
2025.06.16
no image
온도 시스템
2025.06.04
언리얼 엔진의 입력 모드(FInputMode)
1. 개요언리얼 엔진에서는 플레이어가 키보드/마우스를 이용해 게임과 UI 중 어디에 입력을 보낼지 제어하기 위해 FInputMode 구조체를 사용합니다. UI 위젯을 띄웠을 때 플레이어가 게임 조작도 가능해야 하는지, 아니면 UI에만 집중해야 하는지를 정하는 설정입니다. 2. 주요 구조체 종류구조체설명FInputModeGameOnly게임 조작만 가능. UI 반응 XFInputModeUIOnlyUI에만 입력. 게임 입력은 무시FInputModeGameAndUI게임 조작 + UI 조작 둘 다 가능 3. 개념 설명3-1. 포커싱(Focus)UI 위젯 중 어떤 UI가 키보드 입력을 받을지 정하는 것.예를 들어 텍스트 입력창에 커서가 깜빡이는 상태가 “포커싱된” 상태.SetWidgetToFocus() 함수로 지정..
2025.05.21
no image
언리얼 엔진 레벨 전환 시 로딩 방식
1. 개요오픈 월드 생존 게임을 개발 중이며, 메인 메뉴에서 인게임으로 넘어갈 때 자연스럽고 끊김 없는 레벨 전환을 구현하고 싶어서 레벨 로딩 방식에 대해 정리하게 되었습니다. 이를 위해 언리얼 엔진에서 제공하는 다양한 레벨 로딩 방식을 조사하였습니다.2. 언리얼 엔진의 레벨 전환 방식들OpenLevel(): 전통적인 동기적 방식, 전체 레벨 교체Level Streaming: 비동기 방식, 필요한 레벨을 불러오거나 제거Seamless Travel:서버와 클라이언트의 상태를 유지한 채 전환하는 방식3. OpenLevel - 동기적 레벨 전환Level을 완전히 교체하는 방식호출 시 현재 레벨 언로드 후 새로운 레벨 로드새로운 레벨 로딩 완료까지 화면 렌더링 멈춤장점단점구현이 가장 간단함클린 상태에서 로딩되므..
2025.05.14
no image
언리얼 엔진의 맵 로딩
오늘은 언리얼 엔진에서 대형 맵(오픈 월드 환경)을 효율적으로 로딩하는 방법에 대해 정리하겠습니다. 특히 World Partition과 Level Streaming의 차이, 그리고 Git LFS와의 연계를 중심으로 고민했습니다. 1. 언리얼 엔진의 주요 맵 로딩 방식Level Streaming (기존 방식)Persistent Level과 여러 서브 레벨을 나눠 구성필요할 때만 특정 레벨을 로딩하거나 언로드Streaming Volume, Blueprint, 또는 C++ 코드로 로딩 제어World Partition (UE5 이상)맵 전체를 자동으로 그리드 단위로 분할하고, 스트리밍을 자동화수동으로 서브 레벨을 나눌 필요 없음HLOD, Data Layer, Runtime Grid 등을 활용한 고급 스트리밍 가..
2025.05.08
no image
최종 프로젝트 사전 설문 조사
이번 최종 프로젝트에서 리더를 맡게 되어 이런저런 고민이 많네요. 우선 팀을 한 방향으로 이끄는 것이 리더의 역할이라고 생각하여 사전 설문 조사를 실시하였고, 각 질문에 대한 의도와 결과를 공유해 보고자 합니다. 첫번째 질문은 모두 관심이 있는 문항들로 구성하여 이번 프로젝트의 궁극적인 목표를 알아보기 위한 것이었습니다. 이 설문조사에서 가장 중요한 질문을 묻고 있습니다.다음 질문은 기획 담당 인원들의 참고용으로 팀원들이 흥미를 가지고 있는 게임 장르와 스타일을 알아보기 위함이었습니다.두번째 질문은 팀원들이 관심 있어하는 분야를 알아보기 위함이었고 역할분담에 참고하기 위해 구성하였습니다. 생각보다 많은 인원들이 AI 구현을 희망하셨고 이또한 기획 담당 인원들에게 공유하여 기획에 참고하도록 하였습니다.세번..
2025.04.28
TIL
AI ROV(Reciprocal Velocity Obstacles)
언리얼 엔진의 AI ROV (RVO: Reciprocal Velocity Obstacles) 기능은 AI 에이전트들 사이의 충돌을 피하기 위한 이동 알고리즘입니다. 즉, 여러 AI 캐릭터가 동시에 움직일 때 서로 충돌하지 않고 자연스럽게 경로를 회피하도록 만들어주는 기능입니다. 이 기능은 특히 군중 시뮬레이션, RTS, MOBA 장르에서 자주 사용됩니다.RVO (Reciprocal Velocity Obstacles) 개념목적: AI가 다른 AI 또는 장애물과 충돌하지 않도록 경로를 조절함.기반 원리: 다른 에이전트의 속도를 예측해 충돌 가능성이 있는 경우, 서로의 속도를 적절히 조절해 충돌을 피함.Reciprocal의 의미: 단방향 회피가 아니라 쌍방 간 양보/회피.언리얼 엔진에서의 적용 방식언리얼 엔진..
2025.04.24

최적화란?

퍼포먼스 최적화는 일회성 작업이 아니라 반복적인 과정이다.
가장 느린 병목 지점을 해결하면, 그 다음으로 느린 부분이 병목이 되고, 이를 다시 해결하는 과정을 반복하게 된다.
즉, 끝이 없는 두더지 잡기와 같다.

 

최적화 전 준비: 테스트 환경 정리

최적화를 시작하기 전에 테스트 환경을 정리하는 것이 매우 중요하다.
불필요한 요소들이 성능 측정에 영향을 줄 수 있기 때문이다.

예를 들어, 언리얼 엔진 에디터의 UI 자체가 성능에 영향을 줄 수 있다.
따라서 최적화 테스트는 다음과 같은 환경에서 진행하는 것이 좋다:

  • 패키지된 빌드를 사용하거나
  • 최소한 Standalone Mode에서 테스트

 

1프레임의 기준 시간

일반적인 게임은 60fps를 목표로 한다.
이는 1초(1000ms)를 60프레임으로 나눈 값인 약 16.66ms 안에 게임의 모든 연산이 끝나야 한다는 뜻이다.

  • 만약 특정 프레임이 10ms에 끝났다면?
    → 아직 6.66ms의 여유가 있으므로, 추가적인 로직이나 연출이 들어가도 성능상 문제가 없다.

이 기준 시간(16.66ms)은 퍼포먼스 분석의 핵심 기준점이 된다.


Stat Tools 3종 세트

1. Stat Unit

  • 병목 지점이 CPU Bound인지 GPU Bound인지 쉽게 확인 가능.
  • 명령어: ~ → stat unit

 

2. Stat FPS

  • 프레임 속도를 숫자로 확인 가능.
  • 명령어: ~ → stat fps

 

3. Stat Game

  • Game thread, Draw thread 등 상세한 게임 로직 실행 시간 확인 가능.
  • 명령어: ~ → stat game

 


Unreal Insights

  • 고급 프로파일링 툴
  • 퍼포먼스를 시스템적으로 분석하고 싶을 때 사용

 

Unreal Insights는 UE가 설치된 경로의 Engine > Binaries > Win64에서 UnrealInsights.exe를 눌러 실행할 수 있다

 

에디터를 실행 중이라면 위 그림과 같은 방법으로 쉽게 실행할 수 있다

 

두 방법으로 Unreal Insights를 실행시키면 위와 같은 창이 뜨게 된다

 

Unreal Insights 창을 띄운 채로 PIE(Play In Editor)를 실행하면, 게임의 실행 과정을 실시간으로 추적하고 세부적인 퍼포먼스 데이터를 수집하는 분석이 시작된다.

 

다음 글에서는 현재 진행 중인 프로젝트를 활용해 퍼포먼스를 개선해 나가는 과정을 공유드리겠습니다:)

1. 개요

프로젝트에서 게임 설정 관련된 작업을 시작하게 되었습니다. 가장 먼저 구현하고 싶었던 기능은 사운드 조절이었습니다. 이를 위해 언리얼 엔진의 사운드 시스템을 간단히 조사해보았고, 특히 Sound Class, Sound Mix, 그리고 이를 제어할 수 있는 C++ 함수들에 대해 처음으로 다뤄보게 되었습니다.

 

2. Sound Class

Sound Class는 사운드를 논리적인 그룹으로 나누어 제어할 수 있게 해주는 시스템입니다. 예를 들어, 배경음(BGM), 효과음(SFX), 음성(Voice)을 각각의 사운드 클래스에 할당해두면, 이들 그룹의 볼륨을 개별적으로 제어할 수 있습니다.

 

  • SC_BGM → 배경음용 Sound Class
  • SC_SFX → 효과음용 Sound Class
  • SC_UI → UI 효과음 전용 Sound Class
  • SC_Master → 위 Sound Class를 Child Class로 둔 전체 마스터 볼륨 설정용 클래스

🔧 에디터에서의 설정 방법:

  1. Content Browser에서 우클릭 → Sounds → Sound Class 생성
  2. 생성한 Sound Class의 속성에서 Parent Class를 설정하거나 계층 구조를 구성 가능
  3. 사운드 에셋(Sound Cue 등)에서 해당 Sound Class를 지정

이렇게 분리해두면 C++이나 Blueprint에서 각 그룹의 볼륨을 따로 조절할 수 있습니다.

 

 

3. Sound Mix

Sound Mix는 Sound Class에 정의된 속성(예: 볼륨, 피치 등)을 일시적으로 덮어쓰기 할 수 있도록 도와주는 시스템입니다. 예를 들어 UI를 열었을 때 배경음을 살짝 줄이거나, 특정 이벤트 발생 시 효과음을 강조하는 식의 연출이 가능합니다.

🔸 주로 사용되는 예시:

  • UI 열릴 때 BGM은 30%로 줄이고, 효과음은 그대로 유지
  • 일시정지 시 모든 사운드 볼륨 감소
  • 전투 진입 시 효과음 강조

사운드 믹스는 사운드 클래스의 볼륨을 즉시 바꾸는 것이 아니라, 오버라이드 형태로 부드럽게 변화시킬 수 있어 매우 유용합니다.

4. C++로 SoundMix 제어하기

이번에 새롭게 알게 된 부분은 사운드 믹스를 코드로도 동적으로 제어할 수 있다는 점이었습니다. UGameplayStatics에서 제공하는 몇 가지 함수를 통해 이를 처리할 수 있습니다.

🔹 1) UGameplayStatics::PushSoundMixModifier(UObject* WorldContextObject, USoundMix* InSoundMix)

  • 기능: SoundMix를 활성화합니다.
  • 효과: 해당 믹스에 정의된 Sound Class의 오버라이드가 적용됨
  • 예시:
  • cpp
     
UGameplayStatics::PushSoundMixModifier(GetWorld(), MySoundMix);

🔹 2) UGameplayStatics::PopSoundMixModifier(UObject* WorldContextObject, USoundMix* InSoundMix)

  • 기능: 적용 중인 SoundMix를 해제합니다.
  • 효과: 해당 믹스에서 설정한 오버라이드가 사라지고 원래 설정으로 복귀
  • 예시:
  • cpp
     
UGameplayStatics::PopSoundMixModifier(GetWorld(), MySoundMix);

🔹 3) UGameplayStatics::SetSoundMixClassOverride(...)

UGameplayStatics::SetSoundMixClassOverride(
    GetWorld(),              // 월드 컨텍스트
    MySoundMix,              // 적용할 SoundMix
    MySoundClass,            // 대상 SoundClass
    0.2f,                    // 볼륨 (0.0 ~ 1.0)
    1.0f,                    // 피치 (기본값 1.0)
    0.5f                     // 페이드 시간 (초 단위)
);
 
  • 기능: 특정 SoundMix 내에서 특정 SoundClass의 속성을 오버라이드
  • 장점: 에디터에서 설정한 SoundMix를 수정하지 않고도 런타임에 유연한 조절 가능
  • 사용 예시: UI가 열릴 때 BGM SoundClass만 볼륨을 0.2로 변경

5. 마무리

 

  • 처음 써보니 사운드 시스템이 꽤 강력하고 유연하다는 점
  • 다음엔 SoundConcurrency나 Audio Volume도 함께 공부하고 싶다는 마무리

 

온도 시스템

언리얼 거토
|2025. 6. 4. 21:00

'TIL > C++와 UE' 카테고리의 다른 글

언리얼엔진 멀티플레이에서의 PlayerState  (0) 2025.04.08
GameInstanceSubsystem  (0) 2025.04.02
Object Pooling  (0) 2025.03.28
언리얼 엔진 레플리케이션(Replication)  (0) 2025.03.11
네트워킹 및 멀티 플레이어 개요  (0) 2025.03.10

1. 개요

언리얼 엔진에서는 플레이어가 키보드/마우스를 이용해 게임과 UI 중 어디에 입력을 보낼지 제어하기 위해 FInputMode 구조체를 사용합니다. UI 위젯을 띄웠을 때 플레이어가 게임 조작도 가능해야 하는지, 아니면 UI에만 집중해야 하는지를 정하는 설정입니다.

 

2. 주요 구조체 종류

구조체 설명
FInputModeGameOnly 게임 조작만 가능. UI 반응 X
FInputModeUIOnly UI에만 입력. 게임 입력은 무시
FInputModeGameAndUI 게임 조작 + UI 조작 둘 다 가능

 

3. 개념 설명

3-1. 포커싱(Focus)

  • UI 위젯 중 어떤 UI가 키보드 입력을 받을지 정하는 것.
  • 예를 들어 텍스트 입력창에 커서가 깜빡이는 상태가 “포커싱된” 상태.
  • SetWidgetToFocus() 함수로 지정.
FInputModeUIOnly InputMode;
InputMode.SetWidgetToFocus(PauseWidget->TakeWidget())

PC->SetInputMode(InputMode);
PC->bShowMouseCursor = true;

 

TakeWidget()은 UUserWidget 내부의 Slate 루트 위젯을 받아옴( UUserWidget → SWidget 변환)


Slate 위젯
- UI를 구성하기 위한 저수준 UI 프레임워크
- 실질적으로 화면에 표시되는 UI의 렌더링과 입력 처리를 담당 -> 입력 포커싱도 그 일부
- 포커싱은 Slate 시스템 레벨에서 처리되는 기능

 

3-2. 마우스 락(Mouse Lock)

  • 마우스 커서를 화면 안에 가두는 것.
  • 예: FPS 게임에서 마우스가 화면 밖으로 나가는 걸 방지.
설정값 설명
DoNotLock 마우스가 화면 밖으로 자유롭게 나감
LockAlways 마우스를 항상 화면 안에 가둠
LockOnCapture 마우스를 클릭했을 때만 화면 안에 가둠
InputMode.SetLockMouseToViewportBehavior(EMouseLockMode::LockAlways);
 
 

3-3. 마우스 캡쳐(Mouse Capture)

  • 마우스 움직임이 엔진에 의해 직접 추적되고 처리되는 상태.
  • FPS처럼 커서는 안 보이지만 마우스 움직임으로 카메라가 도는 게임이 대표적.
  • 캡처된 마우스는 커서가 보이지 않고, 마우스 좌표도 고정된 상태로 처리됨.

📌 FInputModeGameAndUI에서는 아래 함수로 마우스 캡처 중 커서를 숨길지 설정 가능:

FInputModeGameAndUI InputMode;
InputMode.SetHideCursorDuringCapture(false); // 캡쳐 중 커서 숨김

 

 

1. 개요

오픈 월드 생존 게임을 개발 중이며, 메인 메뉴에서 인게임으로 넘어갈 때 자연스럽고 끊김 없는 레벨 전환을 구현하고 싶어서 레벨 로딩 방식에 대해 정리하게 되었습니다. 이를 위해 언리얼 엔진에서 제공하는 다양한 레벨 로딩 방식을 조사하였습니다.


2. 언리얼 엔진의 레벨 전환 방식들

  • OpenLevel(): 전통적인 동기적 방식, 전체 레벨 교체
  • Level Streaming: 비동기 방식, 필요한 레벨을 불러오거나 제거
  • Seamless Travel:서버와 클라이언트의 상태를 유지한 채 전환하는 방식

3. OpenLevel - 동기적 레벨 전환

  • Level을 완전히 교체하는 방식
  • 호출 시 현재 레벨 언로드 후 새로운 레벨 로드
  • 새로운 레벨 로딩 완료까지 화면 렌더링 멈춤
장점 단점
구현이 가장 간단함
클린 상태에서 로딩되므로 디버깅 용이
로딩중 화면 멈춤(로딩 화면 구현 필요)
메모리 재로딩 비용 큼
네트워크 게임에서 클라이언트 재연결 필요

4. Level Streaming - 비동기적 레벨 전환

  • 기존 레벨을 유지하고 백그라운드에서 다른 레벨 불러오기 가능
    • LoadStreamLevel() / UnloadStreamLevel() 함수
  • 원하는 시점에 해당 레벨을 보이게 만들거나 숨기기 가능
    • LoadStreamLevel() / LevelStreamingDynamic의 파라미터 조절
    • SetShouldBeVisible() / SetShouldBeLoaded() 함수로 처리
// 파라미터 조절 방식
LoadStreamLevel(LevelName = "Cave_Level",  
                MakeVisibleAfterLoad = false,  // ← 핵심!
                ShouldBlockOnLoad = false)

// 함수 사용 방식
if (StreamingLevel)
{
    StreamingLevel->SetShouldBeVisible(false);  // 일단 숨긴 상태로 로딩
    StreamingLevel->SetShouldBeLoaded(true);    // 로딩만 함

    // 나중에 이 타이밍에서 보이게 만들기
    StreamingLevel->SetShouldBeVisible(true);
}
장점 단점
비동기적 방식으로 자연스러운 로딩 가능
메모리 관리 효율적
레벨 간 의존성 주의 필요
면밀한 월드 구조 설계 필요

5. Seamless Travel - 네트워크 상태 유지 전환 방식

  • 서버가 맵 이동 시 클라이언트와의 연결 유지해야 할 때 사용
    • 매커니즘: Actor Preservation ("보존 가능한 액터" 목록을 만들고, 이 액터들을 파괴하지 않고 유지)
    • APlayerController를 유지한 채로 레벨 전환.
    • ServerTravel() 또는 ClientTravel()에서 ?Seamless 옵션 사용
  • Transition Map: 전환 중 임시로 로딩되는 맵. Seamless Travel 중 발생하는 공백을 보완
    • 목적: 원활한 레벨전환, 플레이어 상태 유지(캐릭터, 인벤토리 등), 경량화된 임시 맵
장점 단점
멀티플레이에서 상태 유지 가능
클라이언트 재접속 없이 전환 가능
여러 리소스를 병렬로 로딩 가능
Transition Map 구성 필요
디버깅 난이도 어려움

 

언리얼 엔진 공식 문서: Travellling in Multiplayer


6. BONUS: 더 부드러운 레벨 전환 방법

방법  설명
Preloading Assets 게임 시작 시 미리 로딩할 리소스를 AssetManager로 관리
LevelStreamingDynamic "동적"으로 원하는 시점에 로딩 → 전환
Camera Fade 연출 PlayerController->ClientStartCameraFade() 사용해서 전환 부드럽게 보이기

언리얼 엔진의 맵 로딩

언리얼 거토
|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 외 변경 사항도 검토 필수

 

최종 프로젝트 사전 설문 조사

언리얼 거토
|2025. 4. 28. 22:28

이번 최종 프로젝트에서 리더를 맡게 되어 이런저런 고민이 많네요. 우선 팀을 한 방향으로 이끄는 것이 리더의 역할이라고 생각하여 사전 설문 조사를 실시하였고, 각 질문에 대한 의도와 결과를 공유해 보고자 합니다.

 

첫번째 질문은 모두 관심이 있는 문항들로 구성하여 이번 프로젝트의 궁극적인 목표를 알아보기 위한 것이었습니다. 이 설문조사에서 가장 중요한 질문을 묻고 있습니다.


다음 질문은 기획 담당 인원들의 참고용으로 팀원들이 흥미를 가지고 있는 게임 장르와 스타일을 알아보기 위함이었습니다.


두번째 질문은 팀원들이 관심 있어하는 분야를 알아보기 위함이었고 역할분담에 참고하기 위해 구성하였습니다. 생각보다 많은 인원들이 AI 구현을 희망하셨고 이또한 기획 담당 인원들에게 공유하여 기획에 참고하도록 하였습니다.


세번째 질문입니다. 위 결과를 팀원들에게 공유하여 협업시 주의해야할 사항들을 인지시키려는 의도였습니다.


이어지는 질문의 의도는 팀원들에게 좋은 경험이 있었다면 이를 이번 프로젝트에서도 반영해보고 실천해고자했습니다. 


위 질문은 첫번째 질문과 이어지기도 하는데, 팀원들의 목표를 모으기 위함이었고 저희는 재밌는 게임을 완성도 있게 만들자! 라는 결론을 지었습니다.


최근 취업 준비로 인해 팀원들의 개인 학습 시간을 보장해주어야한다는 생각에 간단히 추가해본 질문입니다.

 

 

생각보다 많은 인원의 리더 역할을 맡게 되었는데, 체계적으로 프로젝트를 이끌고 싶습니다. 이 설문조사는 실질적으로 팀을 운영하기전에 팀의 성향을 알아보는데 정말 많은 도움이 되었습니다.

'TIL' 카테고리의 다른 글

5일차  (2) 2024.12.20
4일차  (1) 2024.12.19
3일차  (1) 2024.12.18
2일차  (0) 2024.12.17
내일배움캠프 언리얼 엔진 1일차  (2) 2024.12.16

언리얼 엔진의 AI ROV (RVO: Reciprocal Velocity Obstacles) 기능은 AI 에이전트들 사이의 충돌을 피하기 위한 이동 알고리즘입니다. 즉, 여러 AI 캐릭터가 동시에 움직일 때 서로 충돌하지 않고 자연스럽게 경로를 회피하도록 만들어주는 기능입니다. 이 기능은 특히 군중 시뮬레이션, RTS, MOBA 장르에서 자주 사용됩니다.


RVO (Reciprocal Velocity Obstacles) 개념

  • 목적: AI가 다른 AI 또는 장애물과 충돌하지 않도록 경로를 조절함.
  • 기반 원리: 다른 에이전트의 속도를 예측해 충돌 가능성이 있는 경우, 서로의 속도를 적절히 조절해 충돌을 피함.
  • Reciprocal의 의미: 단방향 회피가 아니라 쌍방 간 양보/회피.

언리얼 엔진에서의 적용 방식

언리얼 엔진에서는 UCrowdFollowingComponent를 통해 RVO가 지원됩니다.
NavMesh를 기반으로 이동하되, AI 간 충돌을 회피하도록 설정할 수 있습니다.

1. 사용 전제 조건

  • NavMeshBoundsVolume이 제대로 설정되어 있어야 함
  • AIController의 MovementComponent가 UCrowdFollowingComponent 여야 함
// AIController 생성자에서 설정 예시
AAIControllerWithRVO::AAIControllerWithRVO()
{
    CrowdFollowingComponent = CreateDefaultSubobject<UCrowdFollowingComponent>(TEXT("CrowdFollowingComponent"));
    SetMoveBlockDetection(true);  // 옵션에 따라 설정
}

2. 캐릭터의 CharacterMovementComponent 설정

CharacterMovementComponent에서 아래 항목을 설정해야 합니다:

CharacterMovement->bUseRVOAvoidance = true;           // RVO 회피 기능 사용
CharacterMovement->AvoidanceWeight = 0.5f;            // 회피 우선순위 (0.0~1.0)
CharacterMovement->AvoidanceConsiderationRadius = 500.f;  // 고려 반경
CharacterMovement->AvoidanceGroup.SetGroup(1);        // 회피 그룹 설정 (비트마스크)

3. Avoidance Priority (우선순위)

  • AvoidanceWeight와 함께 사용하는 값.
  • AI가 서로 충돌할 경우, 우선순위가 높은 쪽이 덜 피하고, 낮은 쪽이 더 피함.
CharacterMovement->SetAvoidancePriority(10);  // 낮을수록 먼저 피함

4. Editor 상에서도 설정 가능

  • CharacterMovementComponent → Avoidance 카테고리에서 설정 가능
  • Use RVO Avoidance 체크박스
  • Avoidance Weight, Avoidance Priority 수치 입력

5. 디버깅

  • ShowDebug crowd 콘솔 명령어로 군중 및 RVO 회피 동작 시각화 가능

요약

항목 설명
기능명 RVO (Reciprocal Velocity Obstacle)
목적 AI끼리 충돌하지 않고 자연스럽게 회피
관련 컴포넌트 UCrowdFollowingComponent, CharacterMovementComponent
주요 설정 bUseRVOAvoidance, AvoidanceWeight, AvoidancePriority
디버그 명령어 ShowDebug crowd
필수 요소 NavMesh, MovementComponent가 Crowd용으로 설정되어야 함