블루프린트 성능 최적화 기법
지금까지 물리 시뮬레이션, 콜리전, 트레이싱, 날씨/시간 시스템, 동적 환경 상호작용 등 다양한 요소를 구현해 봤습니다. 이 요소들은 몰입감을 높이지만 동시에 성능(Performance)에 큰 영향을 줄 수 있습니다. 특히 블루프린트로 복잡한 로직을 구성할 때 최적화를 놓치면 프레임 드롭이나 스터터(Stutter)가 발생하기 쉽습니다.
이번 절에서는 블루프린트 성능 최적화 기본 기법을 정리합니다. C++로 옮기지 않아도 블루프린트 단계에서 상당한 최적화를 달성할 수 있으며, 물리/환경 상호작용 같은 동적 요소를 다룰 때 특히 중요합니다.
왜 블루프린트 최적화가 필요한가?
블루프린트는 빠르고 직관적인 개발이 가능하지만, C++에 비해 상대적으로 낮은 성능을 가집니다. 이는 블루프린트가 가상 머신 위에서 해석되어 실행되기 때문입니다. 따라서 복잡하거나 반복적인 로직을 블루프린트로 작성할 때는 성능을 염두에 두어야 합니다.
최적화의 목표- 프레임 레이트 안정화: 게임이 부드럽게 실행되도록 일관된 프레임 레이트를 유지합니다.
- 리소스 사용량 감소: CPU, GPU, 메모리 등의 리소스 사용량을 줄여 다양한 하드웨어에서 게임이 잘 작동하도록 합니다.
- 게임 반응성 향상: 입력 지연을 줄이고, 게임 내 상호작용이 즉각적으로 반응하도록 합니다.
블루프린트 성능 최적화 기본 기법
Event Tick의 신중한 사용 및 비활성화
Event Tick은 매 프레임마다 호출되는 이벤트이므로 흔한 병목 후보입니다. 다만 최적화는 먼저 stat unit 등으로 Game, Draw, GPU 중 어느 축이 느린지 나눈 뒤, Game Thread가 문제일 때 Tick과 블루프린트 호출 빈도를 좁혀 보는 순서가 안전합니다.
- 불필요한 틱 비활성화: 액터가 항상 움직이거나 업데이트될 필요가 없다면
클래스 디폴트(Class Defaults)에서Can Ever Tick을 체크 해제합니다. - 필요할 때만 틱 활성화/비활성화: 캐릭터가 정지 상태일 때는 틱을 비활성화하고, 움직이기 시작할 때 다시 활성화하는 등, 필요한 순간에만
Set Actor Tick Enabled노드를 사용하여 틱을 켜고 끄는 로직을 구현합니다. - 느린 틱(
Set Tick Interval): 매 프레임 업데이트가 필요하지 않은 로직(예: 먼 거리의 AI 시야 체크, 특정 환경 효과 업데이트)은Set Tick Interval노드를 사용하여 틱 주기를 늦춥니다. (예: 0.1초마다 틱)
캐싱(Caching) 및 변수 재사용
반복적으로 참조하는 액터, 컴포넌트, 또는 복잡한 계산 결과는 변수에 저장하여 반복적인 Get 노드 호출이나 재계산을 피합니다.
Cast결과 캐싱: 캐스트 자체보다 더 큰 문제는 Tick이나 큰 루프 안에서 반복 캐스팅하거나, 무거운 Blueprint 클래스를 직접 참조해 로드 의존성을 키우는 것입니다. 한 번 확인한 참조는 변수에 저장하고, 가능하면 기본 C++ 클래스, 가벼운 부모 Blueprint, 인터페이스로 의존성을 줄입니다.(Event BeginPlay 또는 On Component Begin Overlap) -> Cast To BP_PlayerCharacter -> Set PlayerCharacterRef (변수)- 반복되는 계산 결과 저장: 루프 안에서 동일한 값을 반복적으로 계산하지 않도록, 루프 외부에서 한 번 계산하여 변수에 저장하고 루프 내에서는 이 변수를 사용합니다.
루프(Loop)와 배열/맵 처리 최적화
For Each Loop나 While Loop는 많은 요소를 처리할 때 성능 저하의 주범이 될 수 있습니다.
- 불필요한 루프 최소화: 루프를 돌기 전에 처리할 필요가 없는 데이터를 필터링합니다.
Break노드 활용: 원하는 결과를 찾으면 즉시 루프를 중단합니다.- 접근 패턴에 맞는 자료구조 선택: 전체 순회가 중심이면
Array가 단순하고, 특정 키로 자주 찾는 구조라면Map이 맞습니다. 자료구조는 “무엇이 더 빠른가”보다 “어떻게 접근하는가”를 기준으로 고릅니다. - Large Array의 부분 처리: 매우 큰 배열을 매 프레임 순회하는 것을 피하고,
Set Timer by Event등을 사용하여 여러 프레임에 걸쳐 나누어 처리합니다.
콜리전 및 트레이싱 최적화
물리 및 환경 상호작용의 핵심인 콜리전과 트레이싱은 올바르게 설정하지 않으면 성능 문제를 일으킵니다.
- 정확한 콜리전 프리셋 및 채널 사용:
BlockAll대신Custom설정을 사용하여 필요한 오브젝트 타입에만 응답하도록 합니다.Ignore할 것은 확실히Ignore합니다. - 단순한 콜리전 메시 사용: 스태틱 메시에
Complex Collision as Simple을 사용하는 것을 피하고,Box,Sphere,Capsule등 단순한 형태로 최적화된 콜리전 메시를 사용합니다. - 트레이스 거리 제한:
Line Trace나Shape Trace를 사용할 때End지점을 실제 필요한 최소한의 거리로 제한합니다. - 필요할 때만 트레이스: 매 프레임마다 트레이스를 실행하는 대신, 특정 이벤트 발생 시에만 (예: 공격 버튼 누를 때, AI가 플레이어를 인지할 때) 트레이스를 실행합니다.
Multi Trace대신Single Trace고려:Multi Line Trace는 모든 히트 결과를 반환하므로 비용이 더 큽니다. 가장 가까운 하나만 필요하다면Single Line Trace를 사용합니다.
타이머(Timer) 및 딜레이(Delay) 활용
Event Tick을 대체하여 주기적인 또는 지연된 실행이 필요한 로직에 활용합니다.
Set Timer by Event/Set Timer by Function Name: 일정 시간 간격으로 반복 실행되는 로직이나, 한 번만 지연 실행되는 로직에 사용합니다. Timer는 호출 빈도를 낮출 때 효과가 있으며, 같은 빈도로 많은 작업을 실행하면 Tick을 바꾼 것만으로 비용이 사라지지는 않습니다.Delay: 특정 노드를 일정 시간 지연시킨 후 실행해야 할 때 사용합니다. 간단한 일회성 지연에 편리합니다.
컴포넌트 활성화/비활성화
불필요하게 리소스를 소모하는 컴포넌트(예: 파티클 시스템, 오디오 컴포넌트, 물리 컴포넌트)는 필요할 때만 활성화하고 사용 후에는 비활성화합니다.
Set Active(파티클 시스템, 오디오 등)Set Simulate PhysicsSet Component Tick Enabled
오브젝트 풀링(Object Pooling)
총알, 파티클 이펙트, 파편 등 게임 플레이 중 빈번하게 생성/파괴되는 액터의 경우, Spawn Actor와 Destroy Actor를 반복하는 대신 오브젝트 풀링을 사용하면 성능 오버헤드를 크게 줄일 수 있습니다.
- 미리 액터들을 생성해두고(Pool), 필요할 때 풀에서 가져와 사용하고, 사용이 끝나면 파괴하는 대신 풀로 반환하여 재활용합니다.
검색, UI, 로딩 의존성 점검
GetAllActorsOfClass반복 호출 금지: 많은 액터가 있는 월드에서 Tick이나 짧은 주기로 전체 검색을 반복하면 비용이 커집니다.BeginPlay초기화, Overlap/Event 기반 등록, Subsystem의 목록 관리처럼 참조를 모아 두는 구조를 우선 고려합니다.- UMG Binding 줄이기: Raw Property Binding은 매 프레임 폴링될 수 있으므로 자주 바뀌지 않는 값은 이벤트 기반 업데이트, MVVM FieldNotify, Invalidation/Retainer 같은 방식으로 갱신 시점을 좁힙니다.
- 하드 레퍼런스와 로딩 hitch: 블루프린트가 큰 에셋이나 무거운 클래스를 직접 참조하면 로딩 시점과 메모리 사용량이 커질 수 있습니다. 필요할 때는 Soft Object/Class Reference와 Async Load, 로딩 화면 또는 사전 로드를 함께 설계합니다.
- Blueprint Nativization 주의: UE4.27에는 있었지만 UE5에서는 제거되었습니다. UE5 프로젝트에서는 구조 개선, C++ 이관, 프로파일링 기반 최적화로 대체합니다.
디버그 기능 비활성화
개발 단계에서 유용한 디버그 드로잉(예: Draw Debug Type for traces)이나 Print String 노드는 게임 출시 전에 반드시 비활성화하거나 제거해야 합니다. 이들은 런타임 성능에 영향을 미칩니다.
적절한 클래스 선택
PawnvsCharacter: 사람 형태의 움직임이 아니라면Character대신Pawn을 사용하고,CharacterMovementComponent대신FloatingPawnMovement나ProjectileMovementComponent등 더 가벼운 이동 컴포넌트를 사용합니다.ActorvsStatic Mesh Actor: 단순히 메시와 콜리전을 가진 정적인 오브젝트라면Static Mesh Actor를 사용하는 것이 더 최적화되어 있습니다. 커스텀 로직이 필요할 때만Actor블루프린트를 사용합니다.
프로파일링 툴 활용
최적화는 어디가 문제인지를 아는 것에서 시작합니다. 언리얼 엔진은 강력한 프로파일링 툴을 제공합니다.
Stat Unit/Stat FPS: 기본적인 프레임 레이트 및 CPU/GPU 시간을 보여줍니다.Stat Game/stat script/stat tickgroups: 게임 스레드, 스크립트 실행, Tick 그룹의 부담을 좁혀 봅니다.dumpticks: Tick을 가진 액터와 컴포넌트 목록을 확인할 때 사용합니다.stat startfile/stat stopfile: 프로파일링 캡처를 저장해 Unreal Insights에서 분석합니다.Unreal Insights: 더 정밀한 CPU 및 메모리 프로파일링 툴입니다.
이러한 툴을 사용하여 성능 병목 현상이 발생하는 부분을 정확히 파악하고, 해당 부분의 블루프린트 로직을 위에서 언급된 최적화 기법들을 사용하여 개선해야 합니다.
블루프린트 최적화는 지속적인 과정입니다. 게임을 개발하면서 주기적으로 성능을 측정하고, 잠재적인 병목 현상을 미리 예측하여 최적화된 로직을 설계하는 습관을 들이는 것이 중요합니다.
이번 절에서는 언리얼 엔진 블루프린트의 성능을 최적화하기 위한 다양한 기법들을 알아보았습니다. Event Tick의 신중한 사용, 캐싱, 루프 최적화, 콜리전 설정, 타이머 활용, 오브젝트 풀링 등은 블루프린트 기반 게임의 안정적인 프레임 레이트와 부드러운 플레이 경험을 보장하는 데 필수적입니다.
블루프린트 성능 최적화 기법은 입력 이벤트, 상태 변경, 실행 위치, 디버그 기준으로 점검합니다.
블루프린트 성능 최적화 기법에서 놓치기 쉬운 기준은 보충 점검 항목으로 다시 확인합니다.