퍼포먼스는 프로젝트가 타깃 하드웨어에서 얼마나 원활하게 실행되는지 설명합니다. 언리얼 엔진은 게임 월드의 이미지를 화면에 반복적으로 그려서, 즉 반복적으로 렌더링하여 실시간으로 시뮬레이션합니다. 언리얼 엔진은 플립북처럼 프레임을 빠르게 연속으로 표시하여 움직이는 효과를 만들어냅니다. 렌더링되는 프레임의 퍼포먼스는 초당 프레임(Frames Per Second)과 프레임 시간(Frame Time)을 확인하는 방법, 이렇게 두 가지 방식으로 측정할 수 있습니다. 그러면 특정 초당 프레임 수를 목표로 삼은 애플리케이션의 퍼포먼스를 이해하고, 프레임 내에서 밀리초 단위로 측정되는 시간이 어디에 사용되는지 파악할 수 있습니다.
1초 이내에 렌더링하는 프레임 수가 많을수록 사용자에게 모션이 더 부드럽게 보이고 애플리케이션의 반응성이 향상됩니다. 애플리케이션은 일반적으로 퍼포먼스 버짓과 타깃 하드웨어를 고려할 때 초당 30프레임, 60프레임, 120프레임을 목표로 합니다. 가능한 최고의 사용자 경험을 제공하려면 프레임 레이트가 더 높아야 하지만, 일관성도 유지해야 합니다. 이 문서는 렌더링 퍼포먼스 고려 사항에 대한 입문서이자 언리얼 엔진 애플리케이션의 렌더링 퍼포먼스를 분석하고 관리하는 여러 가지 툴에 대한 안내서입니다.
퍼포먼스 이해하기
언리얼 엔진의 로직 대부분은 다음 두 가지에 따라 달라집니다.
현재 프레임에서 일어나는 일
이전 프레임 이후로 경과한 시간
몇 가지 예를 들자면 프레임이 렌더링될 때 다음과 같은 일이 발생할 수 있습니다.
사용자가 캐릭터나 비히클을 이동할 수 있습니다.
사용자가 오브젝트와 상호작용할 수 있습니다.
AI가 제어하는 엔티티가 이동하거나 다양한 액션을 수행할 수 있습니다.
사용자 UI가 변경될 수 있습니다.
화면의 오브젝트가 애니메이션에서 앞으로 나아갈 수도 있고 여러 애니메이션을 함께 블렌딩할 수도 있습니다.
피직스 시뮬레이션이 피직스 오브젝트의 위치나 회전을 변경할 수 있습니다.
이러한 작업이 발생할 때마다 컴퓨터가 각 프레임을 그릴 때 수행해야 하는 작업이 늘어납니다. 또한, 다양한 렌더링 세팅에 따라 각 프레임을 그리는 과정을 더 복잡하게 또는 덜 복잡하게 만들 수 있습니다. 몇 가지 조정할 수 있는 부분은 다음과 같습니다.
오브젝트와 텍스처의 디테일이 향상되면 컴퓨터가 각 관련 픽셀의 최종 색상을 계산하는 시간이 더 오래 걸립니다.
포스트 프로세싱 이펙트를 추가하면 렌더링의 다양한 단계에서 각 추가 패스를 이미지에 실행해야 합니다.
고퀄리티 조명과 셰이딩을 사용하면 씬이 더 사실적으로 보이지만, 라이팅 계산 복잡성도 증가합니다.
애플리케이션이 프레임마다 수행할 작업을 더 많이 지시할수록, 단일 프레임을 렌더링하는 데 걸리는 시간이 늘어납니다. 프레임 렌더링에 특히 오랜 시간이 걸리면 전체 프레임 레이트가 느려져서 애플리케이션이 원활하지 않고 반응성이 떨어지는 것처럼 보이게 됩니다.
초당 프레임 및 프레임 시간 측정하기
초당 프레임과 프레임 시간을 추적하려면 이러한 측정값이 뷰포트에 표시되도록 활성화하면 됩니다. 뷰포트의 햄버거 메뉴에서 FPS 표시(Show FPS)를 활성화하고, 통계(Stat) > 엔진(Engine)을 클릭한 다음, FPS와 유닛(Unit)을 활성화합니다.
하드웨어 제한 및 프레임 레이트 저하
프레임 레이트가 느려지는 것은 단일 프레임에 처리할 것이 너무 많아져서 발생한 결과이며, 일반적으로 화면에 프레임이 그려질 때마다 반복되어야 하는 작업 때문에 발생합니다. 렌더링하는 각 프레임을 몇 밀리초 후에 다른 기차가 도착하니 곧 역에서 출발할 예정인 기차로 생각해 보세요. 그러나 이 열차의 경우, 열차가 출발하기 전에 반드시 티켓을 구매한 승객이 모두 탑승해야 합니다. 게임플레이든 렌더링 로직이든 해당 프레임에 수행하는 각 작업은 탑승해야 하는 또 다른 승객과 같습니다.
한 프레임에 처리 시간을 너무 많이 사용하는 것은 탑승할 승객이 너무 많아 아직 승객이 모두 탑승하지 못했기에 기차가 멈춰 서는 상황과도 같습니다. 이렇게 하면 다음 열차가 들어올 수 없게 됩니다. 그 결과가 화면에서는 프레임 레이트 저하로 나타납니다. 이러한 현상은 순간적으로 발생하여 화면이 한 프레임에서 너무 오랫동안 눈에 띄게 멈추는 멈춤 현상을 유발할 수도 있고, 프레임마다 꾸준히 발생하여 전반적으로 낮은 프레임 레이트로 이어질 수도 있습니다.
다음과 같은 컴퓨팅 리소스는 잠재적으로 병목 현상을 일으킬 수 있습니다.
CPU: 컴퓨터의 중앙 처리 장치(CPU)가 단일 프레임에 하나 이상의 스레드에서 너무 많은 작업을 수행합니다. 이는 애플리케이션의 UI, 게임플레이 로직 또는 기타 핵심 로직이 비효율적으로 실행되고 있거나, 한 프레임에 이러한 작업을 너무 많이 수행한다는 의미입니다.
GPU: 컴퓨터의 그래픽 처리 장치(GPU)가 단일 프레임에 너무 많은 작업을 수행합니다. 이는 게임의 렌더링 또는 포스트 프로세싱이 비효율적으로 실행되고 있거나, GPU가 따라잡기에는 너무 많은 작업을 처리하고 있음을 나타냅니다.
메모리 크기(RAM): 컴퓨터의 랜덤 액세스 메모리(RAM)가 가득 차서 비우기 전까지는 작업을 완료할 수 없습니다. 이런 상황은 퍼포먼스 멈춤 현상보다는 메모리 부족 예외와 크래시로 이어지는 경향이 있습니다. 가비지 컬렉션이나 에셋 스트리밍과 같은 일부 시스템은 탄력적이어서 클린업 작업을 상황에 따라 지연합니다. 이러한 시스템은 RAM이 가득 차면 클린업 및 다시 채우기 작업을 더 자주 수행해야 하므로 CPU 워크로드가 증가합니다.
메모리 속도(RAM): CPU는 물리적으로 코어와 함께 배치된 작은 데이터 청크에서 작동하며 필요에 따라 이러한 데이터 청크를 RAM과 교환합니다. 이러한 작업은 CPU와 RAM 간의 청크 교환보다 훨씬 빠르게 일어날 수 있습니다(예를 들어, CPU는 새 데이터를 로드하는 데 걸리는 시간과 같은 시간 동안, 로드된 데이터를 20번 조작할 수 있습니다). RAM이 느리고 로직이 상호작용해야 하는 연속된 메모리 청크 간의 교환 빈도가 높을수록 CPU 코어가 메모리 버스를 기다리며 아무것도 하지 않고 유휴 상태로 있는 시간도 늘어납니다.
GPU 메모리(VRAM): GPU의 RAM이 가득 차서 비워질 때까지 작업을 완료할 수 없습니다. 이런 상황은 일반적으로 텍스처가 많은 공간을 차지하여 텍스처 메모리에 과부하가 걸리기 때문에 발생합니다.
하드 드라이브 액세스: 오브젝트를 메모리에 추가하려면 먼저 하드 드라이브 또는 기타 스토리지 디바이스에서 오브젝트를 로드해야 합니다. 스토리지 디바이스에 너무 자주 액세스해야 하는 경우, 작업을 완료하지 못하게 됩니다.
네트워크 대역폭: 컴퓨터의 인터넷 연결이 느리거나 불안정하여 안정적인 패킷을 조합하거나 재전송하는 데 프레임마다 더 많은 CPU 작업이 소요됩니다. 이로 인해 작업이 여러 프레임으로 분산되지 않아 순간적으로 작업량이 몰리거나, 로컬 퍼포먼스에 병목 현상이 없는데도 화면이 끊기는 현상이 발생할 수 있습니다.
CPU 바운드와 GPU 바운드 비교
애플리케이션의 퍼포먼스가 CPU와 GPU 중 어느 쪽의 제약을 더 많이 받는지에 따라, 애플리케이션이 어느 한쪽에 바운드되어 있다고 표현합니다. CPU가 병목 현상을 일으킬 가능성이 더 크다면 CPU 바운드(CPU-bound)입니다. GPU가 병목 현상을 일으킬 가능성이 더 크다면 GPU 바운드(GPU-bound)입니다. Vsync가 켜져 있고 CPU와 GPU 모두 모니터가 표시할 수 있는 프레임보다 빠르게 프레임을 생성할 수 있는 경우, 애플리케이션은 디스플레이 바운드가 됩니다. 이는 주로 타깃 플랫폼과 해당 리소스에 따라 달라집니다.
처리량 급증
처리량 급증은 한 프레임 동안 CPU 또는 GPU가 소비하는 시간이 잠깐 순식간에 증가하는 것을 의미합니다.
고비용 작업과 저비용 작업 비교
일반적으로 고비용 작업은 실행 시 비교적 대량의 컴퓨팅 리소스를 소모합니다. 이는 더 많은 처리 시간 또는 더 많은 양의 메모리를 의미할 수 있습니다. 저비용 작업에는 대량의 컴퓨팅 리소스가 필요하지 않습니다. 이러한 용어는 비슷한 작업을 수행하는 프로세스를 비교할 때 종종 사용됩니다.
실시간 애플리케이션의 메모리
나나이트의 버추얼 지오메트리처럼 솔리드 스테이트 드라이브(SSD)에서 직접 스트리밍되는 일부 예외를 제외하면, 처리하거나 렌더링할 수 있는 모든 것은 애플리케이션의 메모리에 존재합니다. 쉽게 생각하자면, 화면으로 볼 수 있고 화면에서 움직일 수 있다면, 그 사본이 컴퓨터의 메모리에 존재하고, 텍스처, 셰이더, 메시와 같은 해당 오브젝트의 렌더링 리소스는 GPU 메모리에 존재한다고 할 수 있습니다.
퍼포먼스 및 전력 사용량
전력 사용량은 하드웨어 아키텍처에 따라 다르지만, 일반적으로 처리 부하가 많고 초당 렌더링 프레임이 많을수록 전력 소비가 증가합니다. 모바일 및 HMI 세팅에서는 디바이스의 전력 소비량이 주요 관심사이므로 애플리케이션을 최대한 효율적으로 실행하는 것이 좋습니다. 플레이어는 다른 게임보다 스마트폰 배터리를 빨리 소모하는 게임을 부정적으로 평가할 수 있습니다. 또한 더 많은 에너지 사용으로 스마트폰이 뜨거워지면 열 스로틀링이 활성화되어 스마트폰이 다시 식을 때까지 CPU가 더 느리게 실행될 수 있습니다.
프로파일링 툴
프로파일링은 CPU 또는 GPU 처리, 메모리 사용량이나 네트워크 대역폭과 같은 애플리케이션의 시스템 리소스 사용을 분석하는 작업입니다. 언리얼 엔진은 여러 가지 프로파일링 툴세트를 제공합니다.
툴 | Description |
언리얼 인사이트 | 프레임 단위로 퍼포먼스 데이터를 기록하고 검토합니다. |
통계 명령 | 화면에 퍼포먼스 통계를 표시합니다. |
Android 디바이스에서 언리얼 인사이트를 사용하는 방법에 대한 자세한 내용은 Android 디바이스에서 언리얼 인사이트 사용하기 페이지를 참조하세요.
다음과 같은 서드 파티 툴을 사용하여 프로파일링할 수도 있습니다.
프로파일링은 게임이 사용하는 것과 같은 CPU, RAM, 디스크를 사용한다는 점을 명심하세요. 프로파일러를 연결한 상태에서 게임을 실행하면 퍼포먼스가 다소 저하될 수 있습니다. 하지만 이는 오히려 이점이 될 수도 있습니다. 이러한 상태에서도 퍼포먼스 목표를 달성하는 경우 실제로는 목표를 초과 달성한 것이므로 예기치 않은 시스템 변동이 발생해도 게임을 계속 진행할 여유 리소스가 남는다는 의미이기 때문입니다.
언리얼 인사이트
언리얼 인사이트(Unreal Insights)는 언리얼 엔진에서 사용할 수 있는 탄탄하고 강력한 프로파일링 툴세트로서 개별 스레드, 메모리 사용량, 네트워크 대역폭을 프로파일링하는 툴을 제공합니다. CPU 또는 GPU에서 개별 작업 수행에 걸리는 시간(밀리초), 메모리 인사이트(Memory Insight)에서 할당되는 메모리 양, 네트워크 인사이트(Network Insights)에서의 원격 측정 및 패킷 데이터 분석을 확인할 수 있습니다. 또한 태스크 그래프, 컨텍스트 스위치, 슬레이트 UI 엘리먼트를 프로파일링하는 특수 모드도 있어 애플리케이션의 퍼포먼스를 심층 분석할 수 있습니다.
통계 명령
통계(Stats)는 실행 중인 UE 애플리케이션 내에서 화면에 통계를 출력하는 데 사용할 일련의 콘솔 명령을 말합니다. 다음을 포함하나 이에 국한되지 않는 다양한 작업과 시스템 통계 명령이 있습니다.
메모리 트래킹(Memory tracking)
GPU 및 CPU 로드(GPU and CPU load)
게임플레이 틱(Gameplay ticks)
UI
애니메이션(Animations)
통계 명령어를 사용하는 것이 언리얼 인사이트나 RenderDoc으로 작업하는 것만큼 강력하지는 않지만, 애플리케이션을 실행하거나 테스트할 때 애플리케이션에서 일어나는 일에 대한 데이터를 가장 빠르게 얻는 방법입니다.
통계 명령의 전체 목록은 통계 명령 페이지를 참조하세요.
RenderDoc
RenderDoc은 UE에 연결하여 싱글 프레임 캡처의 출력을 제공할 수 있는 오픈 소스 그래픽 디버거입니다. RenderDoc은 다음과 같은 다양한 작업을 수행할 수 있습니다.
텍스처, 모델, 셰이더를 검사합니다.
개별 드로 이벤트를 표시합니다.
프레임을 캡처하는 순간 애플리케이션의 파이프라인 상태에 대한 분석을 제공합니다.
언리얼 인사이트는 어떤 렌더링 작업에 가장 많은 프로세싱 및 메모리 리소스를 사용하는지 대략적으로 알려주는 반면, RenderDoc은 렌더링 작업을 자세히 진단하고 버그가 발생하는 위치를 정확히 파악하는 데 더 적합합니다. 예를 들어, 렌더링 아티팩트가 타깃 디바이스에 나타나지만 에디터에서 플레이(Play-In-Editor)에는 나타나지 않는 경우, RenderDoc을 사용하여 양쪽의 프레임을 캡처하고 데이터를 비교하면 양쪽에서 어떤 차이점 때문에 아티팩트가 표시되는지 파악할 수 있습니다.
퍼포먼스 환경설정 툴
프로젝트의 렌더링 및 엔진 퀄리티 세팅 조정에 대한 많은 지침은 콘솔 명령 및 변수에서 확인할 수 있습니다. 이 섹션에서는 툴의 사용법에 대한 소개와 자세한 이해를 위한 리소스를 제공합니다.
콘솔 명령 및 변수
콘솔은 언리얼 엔진에 있는 명령줄로서, 세팅을 변경하고 디버그 명령을 실행하고 게임이 실행되는 동안 정보를 가져오는 데 사용할 수 있습니다. 언리얼 에디터에서 콘솔 명령을 사용할 수도 있고, 패키지로 만든 프로젝트의 개발자 빌드나 디버그 빌드에서 물결표(~)를 눌러 사용할 수도 있습니다. 그러면 명령줄이 나타나고 명령을 입력하라는 메시지가 표시됩니다.
UE의 명령은 검색/자동 완성 기능을 지원하므로 명령의 일부를 입력하여 찾고 있는 명령어 목록의 범위를 좁힐 수 있습니다. 예를 들어, Stat이라고 입력하면 Stat 명령어 목록이 나타납니다.
콘솔 변수(CVar)는 콘솔 명령을 사용하여 편집할 수 있는 환경설정 변수입니다. 콘솔에서 CVar를 바로 변경하려면, 변수의 환경설정 경로를 입력한 다음 해당 변수에 설정할 값을 제공하면 됩니다. 예를 들어 다음과 같이 할 수 있습니다.
r.TemporalAA.Quality 0
위의 명령은 r.TemporalAA.Quality
CVar를 0으로 설정하여 템포럴 안티 에일리어싱을 효과적으로 비활성화합니다. 이렇게 하면 오브젝트의 에지가 더 딱딱하고 픽셀화되어 보입니다.
콘솔에 대한 자세한 내용은 다음 페이지를 참조하세요.
콘솔 변수 및 명령어 - 콘솔로 작업하는 방법의 개요를 자세히 설명합니다.
콘솔 명령 레퍼런스 - 콘솔 명령어 전체 목록입니다.
콘솔 변수 레퍼런스 - 콘솔 변수 전체 목록입니다.
콘솔 변수 에디터 - 언리얼 에디터에서 직접 콘솔 변수를 편집하는 플러그인입니다.
또한, 블루프린트 및 C++에서 콘솔 명령을 사용하면 언제든지 변수를 변경할 수 있습니다. 설령 배포 빌드에서 콘솔이 비활성화되어 있어도 가능합니다. 이는 애플리케이션이 실행되는 동안 세팅 스케일을 선택적으로 조정하는 데 유용할 수 있습니다.
OutputLog
언리얼 에디터에서 콘솔로 작업할 때는 명령과 로그 기록이 포함된 출력 로그를 표시하면 진행 상황을 더 쉽게 이해할 수 있습니다.
언리얼 에디터에서 출력 로그를 보려면 창(Window) > 출력 로그(Output Log)를 클릭합니다. 그러면 출력 로그가 에디터 하단에 도킹됩니다.
저장된 로그 파일은 프로젝트의 Saved/Logs
폴더에 나타납니다.
환경설정 파일
콘솔 변수는 환경설정(.ini
) 파일에 키-값 쌍으로 저장되며, 게임 빌드에 디폴트 세팅을 제공합니다. 자세한 내용은 환경설정 파일을 참조하세요.
Device Profiles
디바이스 프로파일은 프로젝트가 타기팅하는 특정 디바이스용 세팅이 포함된 환경설정 파일입니다. 이는 Android_Mid
와 같은 대규모 디바이스 버킷처럼 광범위한 프로파일이 될 수도 있고 개별 하드웨어처럼 정밀한 프로파일이 될 수도 있습니다. 각 디바이스 프로파일에는 특정 디바이스에만 적용되는 일련의 세팅 오버라이드가 있습니다.
언리얼 엔진의 디바이스 프로파일은 주로 Adreno 7xx 시리즈와 같은 GPU 제품군이 중심이지만, 필요에 따라 지원되는 하드웨어에 맞춰 커스텀 디바이스 프로파일을 추가하고 그에 대한 규칙을 정의할 수 있습니다.
자세한 내용은 Android용 디바이스 프로파일 및 엔진 퀄리티 커스터마이징을 참조하세요.
추가 참고 자료
애플리케이션의 퍼포먼스에 영향을 줄 수 있는 상황과 요인에 대한 자세한 내용은 일반적인 퍼포먼스 고려 사항을 참조하세요.
팁 및 모범 사례
일찍 자주 테스트하기
테스트할 때 프로젝트에서 지원하는 각 플랫폼에 특정한 버그가 발생할 가능성이 있음을 예상하세요. 언리얼 에디터도 정확한 프리뷰를 제공하려고 최선을 다하기는 하지만, 무엇보다도 타깃 하드웨어에서 직접 프로파일링하는 것이 최선입니다. 하드웨어에서의 테스트 없이 프로젝트를 오래 진행할수록 인지하지 못한 버그가 발생할 가능성이 커집니다.