안동민 개발노트

본문 시작

환경 요소의 성능 분석

프레임 시간과 CPU·GPU·메모리 지표를 프로파일링하고 환경 요소별 비용을 분리해 실제 성능 병목을 찾습니다.

레벨 요소를 충분히 올렸다면, 이제는 보기 좋은 장면을 유지 가능한 성능으로 바꾸는 단계입니다.

레벨이 복잡해질수록 CPU/GPU/메모리 부담은 빠르게 커집니다.

그래서 성능 최적화(Performance Optimization)는 단순히 더 빠르게가 아니라, 다양한 기기에서 안정적인 프레임과 일관된 사용자 경험을 목표로 측정하고 개선하는 과정입니다.


성능 최적화의 중요성 및 목표

성능 최적화는 게임 개발의 전 과정에 걸쳐 지속적으로 이루어져야 하는 작업입니다.

  • 프레임 속도 (FPS) 유지: 플레이어가 쾌적하게 게임을 즐기려면 안정적인 프레임 속도(초당 프레임 수)가 필수적입니다. 목표 FPS (예: PC 60 FPS, 모바일 30 FPS)를 달성하고 유지해야 합니다.
  • 다양한 하드웨어 지원: 저사양 기기에서도 게임이 원활하게 작동하도록 하여 더 많은 플레이어에게 접근성을 제공합니다.
  • 배터리 효율 (모바일): 모바일 게임의 경우, 최적화는 배터리 소모를 줄여 플레이 시간을 늘리는 데 기여합니다.
  • 개발 효율성: 최적화된 프로젝트는 빌드 시간 단축, 에디터 성능 향상 등 개발 과정 자체의 효율성도 높입니다.
  • 버그 감소: 성능 저하로 인한 물리 버그, 로딩 지연 등의 문제를 예방합니다.

성능 분석을 위한 기본 개념

성능 분석을 시작하기 전에 몇 가지 핵심 개념을 이해해야 합니다.

CPU (Central Processing Unit)

  • 역할: 게임 로직, 물리 시뮬레이션, AI 계산, 애니메이션 블렌딩, 드로우 콜(Draw Call) 준비 등 게임의 진행과 렌더링 제출에 필요한 작업을 담당합니다.
  • CPU 바운드 (CPU Bound): CPU가 GPU보다 느려 게임의 전체 프레임 속도를 제한하는 상태를 의미합니다.
  • 주요 병목 요인
    • 과도한 블루프린트/C++ 로직: Event Tick에서 너무 복잡한 계산을 수행.
    • 많은 액터 수: 레벨에 배치된 액터 수가 너무 많거나, 복잡한 로직을 가진 액터가 많을 때.
    • 물리 시뮬레이션: 동시에 많은 오브젝트가 물리 시뮬레이션될 때.
    • AI 계산: 복잡한 AI 로직이나 많은 수의 AI 캐릭터.
    • 드로우 콜: CPU가 GPU에게 렌더링할 오브젝트 목록을 전달하는 횟수. 드로우 콜 수가 많으면 CPU 오버헤드가 증가합니다.

GPU (Graphics Processing Unit)

  • 역할: 메시 렌더링, 셰이더 계산, 포스트 프로세싱, 그림자, 광원 계산 등 주요 그래픽 연산을 수행합니다. 그래픽 작업에도 CPU의 준비와 제출 비용이 있습니다.
  • GPU 바운드 (GPU Bound): GPU가 CPU보다 느려 게임의 전체 프레임 속도를 제한하는 상태를 의미합니다.
  • 주요 병목 요인
    • 폴리곤 수: 화면에 보이는 총 폴리곤 수가 너무 많을 때.
    • 오버드로우 (Overdraw): 투명하거나 반투명한 오브젝트(파티클, 유리, 식물)가 많이 겹쳐 렌더링될 때.
    • 복잡한 셰이더/머티리얼: 연산량이 많은 복잡한 머티리얼 사용.
    • 그림자: 다수의 동적 그림자 또는 고해상도 그림자.
    • 포스트 프로세싱: 블룸, 앰비언트 오클루전, 스크린 스페이스 리플렉션 등 고비용 후처리 효과.
    • 광원: 동적 광원 수가 많거나, 넓은 범위에 영향을 미치는 광원.

언리얼 엔진의 성능 분석 도구

언리얼 엔진은 CPU와 GPU 병목 현상을 진단할 수 있는 다양한 도구를 제공합니다.

Stat 명령어

PIE를 실행한 뒤 콘솔에 입력하여 실시간 통계를 확인합니다. 콘솔 키는 키보드 배열과 프로젝트 설정에 따라 다르며, 일반적으로 백틱(~) 키를 사용합니다.

  • Stat FPS: 현재 프레임 속도(FPS)를 표시합니다. 가장 기본적인 성능 지표입니다.
  • Stat Unit
    • Game: CPU에서 게임 로직(블루프린트, AI, 물리) 처리 시간 (밀리초).
    • Draw: CPU에서 렌더링 명령을 GPU에 전달하는 시간 (드로우 콜 준비).
    • GPU: GPU에서 그래픽 렌더링 시간 (밀리초).
    • Frame: 총 프레임 시간 (밀리초).
    • 활용: Game 시간이 높으면 CPU 바운드, GPU 시간이 높으면 GPU 바운드를 의심할 수 있습니다. Draw 시간이 높으면 렌더 스레드의 작업과 대기를 더 조사합니다. Game·Draw·GPU는 겹쳐 실행될 수 있어 합산하지 않으며, Frame에는 동기화·프레임 제한에 따른 대기도 영향을 줍니다.
    • 예산 기준: 60FPS 목표는 한 프레임 약 16.67ms, 30FPS 목표는 약 33.33ms입니다. 같은 맵, 같은 카메라, 같은 해상도와 Scalability 조건에서 여러 프레임을 보고 가장 긴 축을 먼저 판정합니다.
  • Stat Engine: 엔진의 전반적인 카운터와 시간을 확인합니다. 개별 함수나 스레드의 병목은 해당 Stat 그룹과 Unreal Insights로 좁힙니다.
  • Stat SceneRendering: 장면 렌더링 통계를 확인하는 출발점입니다. GPU 패스별 시간은 Stat GPU, ProfileGPU 또는 GPU 트레이스로 확인합니다.
  • Stat RHI: 하위 수준 렌더링 인터페이스 통계를 보여줍니다.
  • RHI별 통계: Stat D3D12RHI 같은 그룹의 제공 여부와 항목은 엔진 버전·RHI·빌드에 따라 다릅니다. 사용 중인 빌드의 통계 목록에서 확인합니다.
  • Unreal Insights: Game이나 Draw 축이 길 때 GameThread, RenderThread, RHIThread의 실제 호출 위치와 지속 시간을 타임라인으로 확인합니다.

ProfileGPU

  • 역할: GPU 렌더링 파이프라인의 각 패스의 측정 시간을 확인하는 도구입니다. 캡처 오버헤드와 프레임 변동을 고려해 여러 표본을 비교합니다.
  • 사용법: 게임 플레이 중 콘솔에 ProfileGPU를 입력합니다. 버전에 따라 GPU Visualizer, 로그 또는 Insights 연동으로 결과를 확인합니다.
  • 활용: Translucency (투명도, 파티클), PostProcess (후처리), ShadowDepths (그림자 깊이), BasePass (주요 메시 렌더링) 등 어느 렌더링 단계가 가장 많은 시간을 소모하는지 파악하여 원인 후보를 찾고, 해당 요소를 하나씩 변경해 인과관계를 확인합니다.

뷰포트 시각화 모드

레벨 에디터 뷰포트 좌측 상단의 뷰 모드(View Mode) 드롭다운 메뉴에서 선택할 수 있습니다.

  • Shader Complexity & Quads / Quad Overdraw: 픽셀 처리와 겹침이 많은 영역을 찾습니다. 제공되는 모드와 색상 범례를 확인하며, 색상을 GPU 밀리초로 해석하지 않습니다.
  • Shader Complexity (셰이더 복잡도): 머티리얼의 셰이더 연산 복잡도를 색상으로 보여줍니다. 명령 수와 겹침에 대한 비용 추정이며, 텍스처 접근 등 실제 GPU 비용 전체를 나타내지는 않습니다.
  • Light Complexity (광원 복잡도): 표면에 영향을 주는 비정적 광원의 수를 색상으로 보여줍니다. 동적 광원이 많은 영역을 식별합니다.
  • Show > Collision 및 충돌 뷰 모드: 오브젝트의 충돌 메시를 시각적으로 보여줍니다. 불필요하게 복잡한 Complex Collision을 찾아낼 수 있습니다.
  • LOD Coloration (LOD 색상): 각 메시의 현재 LOD 레벨을 색상으로 보여줍니다. LOD가 적절하게 작동하는지, 너무 낮은 LOD가 사용되거나 너무 높은 LOD가 멀리서 사용되는지 확인합니다.
  • 활용: 시각적으로 병목 현상이 예상되는 부분을 빠르게 식별할 수 있습니다.

도구를 선택할 때는 질문 → 도구 → 지표 → 액션 순서로 매핑하면, 병목 원인을 추측이 아닌 데이터로 좁힐 수 있습니다.

Game은 Tick, AI, 물리, 블루프린트 호출을, Draw는 드로우콜과 렌더 제출을, GPU는 ShadowDepths, BasePass, PostProcess 같은 패스 비용을 먼저 확인합니다.


환경 요소별 성능 분석 포인트

이제 실제 환경 요소들을 위 도구들을 사용하여 어떻게 분석하는지 알아봅시다.

메시 (Meshes)

  • Stat SceneRendering / Stat RHI: 제공되는 draw·primitive 관련 카운터를 확인합니다. BasePass 시간 자체를 폴리곤 수로 읽지 말고, Nanite 사용 여부와 실제 카운터의 집계 범위를 함께 확인합니다.
  • LOD Coloration 뷰 모드: 메시 LOD가 적절하게 작동하는지 확인합니다. 너무 멀리 있는 오브젝트가 높은 LOD로 렌더링되고 있지 않은지 확인합니다.
  • 해결책
    • 불필요한 메시 폴리곤 감소 (리토폴로지, 최적화).
    • 적절한 LOD 설정 및 생성.
    • 하나의 메시로 합칠 수 있는 인접한 작은 메시들을 액터 병합 (Merge Actors) 기능으로 합쳐 드로우 콜 감소.

머티리얼 및 셰이더 (Materials & Shaders)

  • Shader Complexity 뷰 모드: 복잡한 셰이더를 사용한 오브젝트를 식별합니다.
  • ProfileGPU: BasePass 등 해당 머티리얼이 쓰이는 패스를 비교합니다. 패스 전체 시간만으로 개별 머티리얼의 비용을 확정할 수는 없습니다.
  • 해결책
    • 복잡한 셰이더 연산 (특히 픽셀 셰이더) 최소화.
    • 텍스처 샘플러 수 줄이기.
    • 불필요한 노드 제거.
    • Translucent (투명) 머티리얼 사용 최소화 (오버드로우 유발).

광원 (Lighting)

  • Light Complexity 뷰 모드: 동적 광원이 너무 많은 영역을 식별합니다.
  • ProfileGPU: 현재 렌더링 경로에서 조명·그림자에 해당하는 패스 비용을 분석합니다. VSM 등 방식에 따라 패스 이름과 구성이 달라집니다.
  • 해결책
    • 라이트맵 기반이면 Static/Stationary를 검토하고, 동적 조명이 필요하면 Movable 비용을 측정. Lumen GI에서는 사전 계산 정적 조명과의 차이를 먼저 확인.
    • 광원의 Attenuation Radius를 필요한 만큼만 작게 설정.
    • 그림자 품질 설정 조정.

파티클 및 특수 효과 (Particles & VFX)

  • Shader Complexity & Quads / Quad Overdraw: 투명 파티클의 오버드로우 정도를 확인합니다.
  • ProfileGPU: Translucency 등 관련 패스를 확인하여 반투명 오브젝트의 렌더링 비용을 분석합니다.
  • 해결책
    • 파티클 스폰 속도 및 최대 파티클 수 제한.
    • 파티클 재질의 오버드로우 최소화 (Masked 재질 고려).
    • Niagara Effect Type과 Scalability의 거리·인스턴스 컬링 설정.
    • 플랫폼과 기능 제약을 확인한 뒤 GPU Compute Sim 비교. GPU 시뮬레이션에서도 시스템·이미터의 CPU 비용은 남음.

물리 시뮬레이션 (Physics Simulation)

  • Stat Physics: 현재 버전이 제공하는 물리 통계를 확인하고, 상세 원인은 Insights와 Chaos Visual Debugger로 추적합니다.
  • 충돌 시각화: 불필요하게 복잡한 충돌 메시를 식별합니다.
  • 해결책
    • Simple Collision 적극 활용, Complex Collision 사용 제한.
    • Simulate Physics 활성화 오브젝트 수 제한.
    • 물리 오브젝트 슬립 활용.
    • 고속 오브젝트에만 CCD 사용.

포스트 프로세싱 비용 분석

  • ProfileGPU: PostProcess 항목을 확인하여 후처리 효과의 비용을 분석합니다.
  • 해결책
    • 불필요한 후처리 효과 비활성화.
    • 품질·해상도·샘플 수를 조정해 재측정. Intensity는 주로 외형 강도이므로 낮추기만 해서는 비용이 줄지 않을 수 있음.

성능 분석 및 최적화 워크플로우

목표 설정: 프로젝트의 목표 플랫폼과 목표 FPS를 명확히 합니다.

측정 및 분석
  • 문제가 발생할 것으로 예상되는 영역(가장 복잡한 레벨, 오브젝트가 많은 곳)에서 테스트를 진행합니다.
  • Stat Unit, ProfileGPU, 뷰포트 시각화 모드 등 도구를 사용하여 병목 현상을 식별합니다.
  • CPU 바운드인지, GPU 바운드인지 먼저 파악합니다.

원인 식별: 분석된 데이터를 바탕으로 병목의 구체적인 원인(예: 과도한 오버드로우, 복잡한 셰이더, 너무 많은 물리 오브젝트)을 식별합니다.

최적화 적용: 식별된 원인에 맞춰 이 절에서 제시된 최적화 전략들을 적용합니다.

재측정 및 반복: 최적화를 적용한 후 다시 성능을 측정하여 개선 여부를 확인합니다.

만족할 만한 결과가 나올 때까지 이 과정을 반복합니다.

프로파일링 의사결정 순서 (실무용)

  1. Stat Unit으로 Game, Draw, GPU 중 어디가 프레임 예산을 넘는지 먼저 고정합니다.
  2. CPU 병목이면 Insights에서 액터 틱, 물리, AI, 블루프린트 중 실제로 큰 항목을 먼저 줄입니다.
  3. Draw 병목이면 드로우콜, 컴포넌트 수, 머티리얼 섹션, HLOD/Instancing 가능성을 확인합니다.
  4. GPU 병목이면 캡처에서 큰 패스를 골라 오버드로우, 그림자, 후처리, 반투명 중 해당 원인을 줄입니다.
  5. 최적화 1회마다 동일한 카메라 위치/시나리오로 재측정하여 개선 폭을 기록합니다.
  6. 목표 FPS에 도달하면 품질 옵션(Scalability)별 하한선도 함께 검증합니다.

Stat Unit의 Game, Draw, GPU 값을 먼저 나누면 어떤 도구로 더 깊게 볼지 결정하기 쉽습니다.

성능 병목 점검 체크리스트

  • Stat Unit 측정 결과를 스크린샷/로그로 남기고 개선 전후를 비교했는가?
  • 병목 원인을 추정이 아니라 ProfileGPU/시각화 모드로 확인했는가?
  • 최적화 후 아트 품질 저하(깜빡임, 그림자 깨짐, 반사 품질 저하)를 검수했는가?
  • 저사양/중간/고사양 프리셋에서 동일한 기능이 안정적으로 동작하는가?
  • 팀 내 성능 기준(FPS, 메모리, 로딩 시간)을 문서화했는가?

변경 전후 기록

기록 항목같은 조건에서 남길 값
재현 조건빌드·장치·맵·카메라·해상도·품질 프리셋
병목 후보Frame, Game, Draw, GPU와 해당 캡처 구간
변경 내용한 번에 바꾼 설정·에셋과 되돌릴 기준
재측정프레임 분포·메모리와 화면 품질·기능 회귀