언리얼 엔진 5

[UE5] GPU 최적화

언린이 2026. 3. 8. 16:19
반응형

1. GPU 최적화가 중요한 이유

언리얼 엔진 5는 Nanite, Lumen, Virtual Shadow Maps 등 차세대 렌더링 기술을 대거 도입하면서 시각적 품질을 비약적으로 끌어올렸습니다. 하지만 이러한 기술들은 GPU에 상당한 부하를 가하며, 적절한 최적화 없이는 목표 프레임레이트를 달성하기 어렵습니다.

60 FPS를 목표로 한다면 한 프레임당 약 16.67ms의 시간 예산이 주어집니다. 이 예산 안에서 지오메트리 래스터라이제이션, 라이팅, 셰도우, 포스트 프로세스, 업스케일링까지 모든 렌더링 패스가 완료되어야 합니다. GPU 최적화란 결국 이 프레임 예산을 효율적으로 배분하고, 불필요한 연산을 줄이며, 시각적 품질 대비 성능의 최적 지점을 찾는 작업입니다.

특히 UE5에서는 기존 UE4와 달리 GPU 주도(GPU-Driven) 렌더링 파이프라인이 핵심이 되었습니다. Nanite의 컴퓨트 셰이더 기반 래스터라이제이션, Lumen의 소프트웨어/하드웨어 레이 트레이싱, Virtual Shadow Maps의 페이지 기반 셰도우 시스템 등이 모두 GPU 리소스를 집중적으로 사용합니다. 따라서 GPU 프로파일링과 최적화에 대한 체계적인 이해가 없으면, 프로젝트 후반부에 성능 문제로 큰 어려움을 겪게 됩니다.

2. GPU 프로파일링 — 최적화의 출발점

프로파일링의 첫 번째 원칙은 "추측이 아닌 측정"입니다. 여러 설정을 동시에 바꾸면 어떤 변경이 실제로 효과가 있었는지 알 수 없습니다. 올바른 워크플로우는 프로파일링 → 병목 식별 → 수정 → 재프로파일링의 반복입니다.

2-1. 핵심 프로파일링 콘솔 명령어

UE5에서 GPU 성능을 분석하기 위한 주요 콘솔 명령어는 다음과 같습니다.

// 프레임 시간 분석 - Game Thread, Draw Thread, GPU 중 어디가 병목인지 파악
stat unit

// GPU 패스별 타이밍 분석 - 셰도우, Lumen, Nanite, BasePass, 포스트 프로세스 등
stat gpu

// 씬 렌더링 통계 - 드로우 콜 수, 메시 드로우 커맨드, 가시 프리미티브 수
stat scenerendering

// RHI 수준 메모리 사용량 및 드로우 프리미티브 콜
stat rhi

// 전체 프레임 캡처 - 어떤 렌더 패스가 성능을 소모하는지 상세 분석
profileGPU

위의 명령어들 중 stat unit을 가장 먼저 실행하여 병목 지점이 CPU인지 GPU인지 파악하는 것이 중요합니다. GPU가 병목이라면 stat gpuprofileGPU로 구체적인 렌더 패스를 추적합니다.

2-2. CPU 바운드 vs GPU 바운드 판별법

병목이 CPU인지 GPU인지 확실하지 않을 때 유용한 테스트 방법이 있습니다.

// 렌더 해상도를 150%로 올려 GPU 부하를 강제로 증가시킴
r.ScreenPercentage 150

위 명령어로 렌더 해상도를 올린 뒤에도 프레임 타임이 변하지 않는다면, 해당 장면은 CPU 바운드입니다. 반대로 프레임 타임이 눈에 띄게 증가한다면 GPU 바운드이며, 이 글에서 다루는 GPU 최적화 기법들이 직접적인 효과를 발휘합니다.

2-3. Unreal Insights를 활용한 심층 분석

런치 인자에 -trace=cpu,gpu,frame을 추가하면 시작 시점부터 자동으로 트레이싱 데이터를 수집합니다. 수집된 데이터는 Unreal Insights에서 시각적으로 분석할 수 있으며, 특정 구간에 대해 수동으로 태그를 남기려면 다음과 같이 합니다.

// 특정 구간에 사용자 정의 레이블 추가
Trace.RegionBegin MyCustomLabel
// ... 측정 대상 로직 ...
Trace.RegionEnd MyCustomLabel

위 명령어는 블루프린트 노드로도 제공되므로, 코드와 블루프린트 양쪽에서 원하는 구간의 성능을 정밀하게 측정할 수 있습니다.

2-4. 시각화 모드 활용

개발 빌드에서는 다양한 시각화 모드를 통해 렌더링 비용을 직관적으로 확인할 수 있습니다.

// 시각화 모드 강제 활성화 (개발 빌드)
r.ForceDebugViewModes 1

// 셰이더 복잡도 히트맵 - 빨간 영역일수록 비용이 높음
viewmode shadercomplexity

위 명령어로 활성화되는 셰이더 복잡도 뷰는 픽셀당 셰이더 명령어 수를 기반으로 비용을 색상으로 표시합니다. 빨간색 영역은 셰이더 비용이 높다는 의미이므로, 해당 머티리얼의 복잡도를 낮추거나 LOD를 적용하는 등의 조치가 필요합니다.

3. Nanite 최적화

Nanite는 UE5의 가상화된 지오메트리 시스템으로, 컴퓨트 셰이더를 사용하여 픽셀 단위의 디테일을 제공하면서도 자동으로 LOD를 관리합니다. 하드웨어의 고정 기능 래스터라이저 대신 소프트웨어 래스터라이제이션을 사용하며, 수백만 개의 폴리곤을 효율적으로 처리할 수 있습니다.

3-1. Nanite의 성능 특성 이해하기

Nanite가 아무리 강력하더라도 만능은 아닙니다. Nanite는 지오메트리 처리(래스터라이제이션, 컬링, LOD)를 최적화하지만, 라이팅, 머티리얼, 반투명, 오버드로우 등의 비용은 그대로 남아 있습니다. 특히 다음 영역에서 성능 문제가 발생하기 쉽습니다.

첫째, 래스터 빈(Raster Bin) 관리입니다. Nanite는 변형(Deformation)이 없는 머티리얼들을 하나의 래스터 빈으로 묶어 한 번에 처리합니다. 그러나 월드 포지션 오프셋(WPO)이나 픽셀 뎁스 오프셋(PDO) 같은 변형 머티리얼을 사용하면, 각 머티리얼마다 별도의 래스터 빈이 필요해져 패스 수가 증가하고 렌더링 오버헤드가 커집니다.

둘째, 오버드로우 문제입니다. 나뭇잎이나 풀 같은 폴리지 에셋에서 오파시티 마스크를 사용하면, 마스크로 제거되는 픽셀까지 래스터라이제이션이 수행되어 오버드로우가 심각해질 수 있습니다. 특히 나무 아래에서 위를 올려다보는 것처럼 폴리지가 밀집된 앵글에서는 셰도우 페이지 효율 저하와 Nanite 성능 저하가 동시에 발생합니다.

3-2. Nanite 프로파일링 및 디버깅

Nanite의 성능 문제를 진단하기 위한 핵심 콘솔 명령어는 다음과 같습니다.

// Nanite 삼각형을 LOD 레벨별 색상으로 표시
r.Nanite.Visualize.Triangles 1

// 오버드로우 시각화 - 마스크 처리된 픽셀 포함
r.Nanite.Visualize.Overdraw 1

// 머티리얼별 렌더링 비용 확인 (Unreal Insights/profileGPU와 함께 사용)
r.nanite.showmeshdrawevents 1

// GPU 실시간 통계 오버레이 (r.ShaderPrint 1 필요)
NaniteStats primary
r.ShaderPrint 1

위 명령어 중 r.Nanite.Visualize.Overdraw는 폴리지 성능 진단에 특히 유용합니다. 오버드로우가 높게 나타나는 영역에서는 오파시티 마스크 대신 완전 불투명 버전의 메시를 사용하거나, 먼 거리에서의 LOD를 보다 적극적으로 적용하는 것이 효과적입니다.

3-3. Nanite 성능 튜닝 CVar

실제 프로젝트에서 Nanite 성능을 조절할 때 사용하는 주요 콘솔 변수들입니다.

// Nanite 비활성화 - 활성/비활성 성능 비교 테스트용
r.Nanite 0

// LOD 공격성 조절 - 기본값 1, 값이 클수록 적극적 LOD 적용
// 4로 설정하면 빠른 성능 모드 비교 가능
r.Nanite.MaxPixelsPerEdge 4

// Nanite 스트리밍 풀 크기 (MB 단위) - UE 5.5부터 런타임 조절 가능
r.Nanite.Streaming.StreamingPoolSize 512

위의 r.Nanite.MaxPixelsPerEdge 값을 올리면 더 먼 거리에서 LOD가 적용되어 GPU 부하가 줄어듭니다. 기본값인 1은 최고 품질을 의미하며, 성능 테스트 시 4로 설정하여 Nanite의 성능 영향도를 빠르게 파악할 수 있습니다.

3-4. Nanite 머티리얼 최적화 전략

Nanite 성능의 핵심은 머티리얼 관리에 있습니다. 실제 프로젝트에서 적용할 수 있는 전략은 다음과 같습니다.

첫째, 변형 머티리얼 최소화입니다. WPO(바람 효과 등)와 PDO를 사용하는 머티리얼은 별도의 래스터 빈을 생성하므로, 동적 버텍스 이동이 반드시 필요한 경우에만 사용해야 합니다.

둘째, 유사한 변형 머티리얼 병합입니다. 여러 머티리얼이 비슷한 변형 로직을 사용한다면, 가능한 한 하나의 머티리얼로 통합하여 래스터 빈 수를 줄이는 것이 효과적입니다.

셋째, 오파시티 마스크 제거입니다. 가능하다면 오파시티 마스크 대신 완전 불투명 메시를 사용하여 Nanite의 소프트웨어 래스터라이제이션 경로를 활용하는 것이 성능에 유리합니다.

넷째, 먼 거리 WPO 비활성화입니다. 바람 효과 같은 WPO는 먼 거리의 LOD에서는 시각적으로 구분이 어렵습니다. 마지막 1~2단계 LOD에서는 WPO를 비활성화하여 불필요한 연산을 제거할 수 있습니다.

4. Lumen 최적화

Lumen은 UE5의 글로벌 일루미네이션(GI) 및 리플렉션 시스템입니다. 라이트맵 베이킹 없이 실시간으로 조명 변화에 반응하는 동적 라이팅을 제공하지만, 그만큼 GPU 비용이 상당합니다.

4-1. Lumen의 동작 방식과 성능 비용

Lumen은 소프트웨어 레이 트레이싱(기본)과 하드웨어 레이 트레이싱(HWRT) 두 가지 모드를 지원합니다. 소프트웨어 모드에서는 Signed Distance Field(SDF)를 사용하여 레이를 추적하며, HWRT 모드에서는 GPU의 RT 코어를 활용하여 더 정확한 결과를 얻습니다.

Lumen의 주요 GPU 비용은 스크린 프로브 수집(Screen Probe Gather), 래디언스 캐시(Radiance Cache), 리플렉션 트레이싱에서 발생합니다. 프로젝트 설정 → 엔진 → 렌더링 → 글로벌 일루미네이션에서 Lumen 품질을 조절할 수 있으며, 품질을 낮추면 중급 하드웨어에서의 성능이 개선됩니다.

4-2. Lumen 성능 튜닝 CVar

Lumen 성능을 크게 개선할 수 있는 주요 콘솔 변수들입니다.

// 스크린 프로브 보간 방식 변경 - 쌍선형 보간 대신 확률적 선택
// 최대 30% 성능 향상 가능 (0.55ms 수준까지 감소 사례)
r.Lumen.ScreenProbeGather.StochasticInterpolation 1

// 래디언스 캐시 프로브 해상도 - 기본값 32, 최소 8까지 가능
r.Lumen.ScreenProbeGather.RadianceCache.ProbeResolution 16

// 비동기 컴퓨트 활성화 - 하드웨어에 따라 추가 성능 향상 가능
r.Lumen.AsyncCompute 1

위의 r.Lumen.ScreenProbeGather.StochasticInterpolation 설정은 가장 효과적인 Lumen 최적화 중 하나입니다. 가장 가까운 4개의 스크린 프로브 중 하나를 확률적으로 선택하는 방식으로, 쌍선형 보간 대비 최대 30%의 성능 향상이 보고되었습니다. 시각적 차이는 대부분의 경우 미미합니다.

4-3. 정적 씬에서의 Lumen 대안

프로젝트의 씬이 대부분 정적이라면, Lumen 대신 라이트맵 베이킹을 고려하는 것이 합리적입니다. 정적 라이트(Static Light)로 베이킹한 조명은 무버블 라이트(Movable Light) 기반의 Lumen 대비 GPU 비용이 현저히 낮습니다.

다만, 시간대 변화나 파괴 가능한 환경처럼 동적 요소가 있는 씬에서는 베이킹이 적합하지 않으므로, Lumen의 품질 설정을 적절히 낮추어 사용하는 것이 현실적인 선택입니다.

4-4. UE 5.6의 Lumen 개선 사항

UE 5.6에서는 Lumen의 래디언스 캐시 업데이트 타임 스플라이싱이 개선되어, 빠른 카메라 이동이나 디스오클루전(Disocclusion) 시 발생하던 주요 성능 스파이크가 수정되었습니다. 또한 HWRT(하드웨어 레이 트레이싱) 성능이 전반적으로 개선되었으며, GPU 인스턴스 컬링이 HWRT와 더 잘 연동되도록 구조가 변경되었습니다.

5. Virtual Shadow Maps 최적화

Virtual Shadow Maps(VSM)는 UE5에서 도입된 고해상도 셰도우 기술로, Nanite의 가상화된 지오메트리와 짝을 이루어 카메라 근처의 세밀한 그림자부터 지평선까지의 원거리 그림자를 효율적으로 렌더링합니다.

5-1. VSM의 페이지 기반 구조

VSM은 물리적 메모리로 고정 크기의 2D 텍스처 풀을 미리 할당하고, 셰이더에서 바인드리스 방식으로 접근합니다. 런타임에 셰이더는 가상 좌표(Virtual Coordinates)를 사용하며, 이를 페이지 테이블을 통해 물리 좌표로 변환합니다. 참조된 데이터가 물리 메모리에 상주하지 않으면 페이지 폴트가 발생하고, 해당 페이지가 로드됩니다.

이 구조 덕분에 필요한 셰도우 영역만 렌더링되므로, 전통적인 캐스케이드 셰도우 맵(CSM)보다 넓은 범위를 높은 해상도로 커버할 수 있습니다.

5-2. VSM 성능 튜닝 CVar

VSM 관련 주요 콘솔 변수입니다.

// VSM 활성화
r.Shadow.Virtual.Enable 1

// VSM만 사용하도록 강제 (기존 CSM 비활성화)
r.Shadow.Virtual.ForceOnlyVirtualShadowMaps 1

// 원거리 셰도우 컬링 비활성화 - 셰도우 팝인 제거
r.Shadow.Virtual.UseFarShadowCulling 0

// 스크린 레이 길이 0 - 셰도우 변화가 오직 오브젝트 형상에 의해서만 발생
r.Shadow.Virtual.ScreenRayLength 0

위 설정에서 r.Shadow.Virtual.ForceOnlyVirtualShadowMaps를 1로 설정하면 기존 CSM이 비활성화되고 VSM만 사용됩니다. 이 경우 VSM이 모든 셰도우를 담당하므로 일관된 품질을 얻을 수 있지만, 성능 비용도 VSM에 집중됩니다. 프로젝트의 셰도우 요구사항에 따라 CSM과 혼용할지 VSM 단독으로 갈지 결정해야 합니다.

5-3. VSM 콘텐츠 최적화 팁

VSM의 성능을 향상시키기 위한 콘텐츠 측면의 최적화 전략입니다.

첫째, 동적 캐스케이드 셰도우 거리를 줄이는 것입니다. 메인 디렉셔널 라이트의 Dynamic Shadow Distance를 5000 유닛 정도로 제한하면 셰도우 렌더링 비용이 크게 감소합니다.

둘째, 먼 거리 LOD에서 그림자 캐스팅 비활성화입니다. 마지막 1~2단계 LOD에서는 Cast Shadow를 비활성화하고, 대신 메인 라이트에 컨택트 셰도우(Contact Shadow)를 활성화하여 근접 디테일을 보완합니다.

셋째, 소규모 폴리지에 컬 디스턴스를 적용하여 일정 거리 이상에서는 아예 렌더링하지 않도록 설정합니다. 이는 VSM뿐 아니라 전체 렌더링 비용을 줄이는 데도 효과적입니다.

6. 텍스처 스트리밍과 가상 텍스처

텍스처는 GPU 메모리(VRAM)를 가장 많이 차지하는 에셋 중 하나이며, 텍스처 관리 방식은 GPU 성능과 메모리 사용량 모두에 직접적인 영향을 미칩니다.

6-1. 텍스처 스트리밍 시스템

언리얼 엔진의 텍스처 스트리밍 시스템은 밉맵(Mipmap)을 활용하여 텍스처 해상도를 동적으로 조절합니다. 카메라와 가까운 오브젝트에는 고해상도 밉을, 먼 오브젝트에는 저해상도 밉을 로드하여 VRAM 사용량을 관리합니다.

"Texture Streaming Pool Over Budget" 경고가 발생한다면, 텍스처 풀의 크기가 부족하다는 의미입니다. 이 문제를 해결하는 방법은 크게 두 가지입니다.

첫째, 텍스처 풀 크기 확대입니다.

; WindowsEngine.ini에서 VRAM의 70%를 텍스처 풀로 할당
[TextureStreaming]
PoolSizeVRAMPercentage=70

둘째, 텍스처 자체의 최적화입니다. 아티스트는 흔히 예상 사용 해상도의 4배 크기로 텍스처를 제작합니다. 4K 텍스처를 1/4 크기로 줄여도 시각적 차이가 거의 없는 경우가 많으므로, 텍스처 해상도를 적극적으로 검토하여 불필요하게 큰 텍스처를 줄이면 상당한 성능 개선을 얻을 수 있습니다.

6-2. 텍스처 압축 포맷 선택

타겟 플랫폼에 맞는 텍스처 압축 포맷을 사용하는 것도 중요합니다. PC와 콘솔에서는 BC7 포맷이 품질과 압축률의 균형이 뛰어나며, 모바일에서는 ASTC 포맷이 적합합니다. 적절한 압축 포맷은 VRAM 사용량을 줄이면서도 시각적 품질 저하를 최소화합니다.

6-3. 스트리밍 가상 텍스처 (SVT)

스트리밍 가상 텍스처(Streaming Virtual Texture, SVT)는 텍스처를 타일 단위로 분할하여 필요한 영역만, 필요한 밉 레벨로 로드하는 기술입니다. 일반 텍스처 스트리밍이 텍스처 전체를 단위로 관리하는 것과 달리, SVT는 타일 수준의 세밀한 관리가 가능합니다.

SVT의 가장 큰 장점은 극적인 VRAM 절약입니다. 실제 프로젝트에서 SVT 적용 후 VRAM 사용량이 8GB에서 3.5GB로 감소한 사례가 보고되었으며, GPU 및 CPU 오버헤드 증가는 거의 없었습니다. SVT는 고유 텍스처가 많은 대규모 오픈 월드에서 특히 효과적이며, 셰이더 복잡도를 줄이는 데에도 기여합니다.

프로젝트 설정에서 Virtual Texture Support를 활성화한 뒤, 사용하고자 하는 텍스처의 Virtual Texture Streaming 옵션을 켜면 됩니다.

6-4. 런타임 가상 텍스처 (RVT)

런타임 가상 텍스처(Runtime Virtual Texture, RVT)는 SVT와는 다른 개념으로, 머티리얼의 렌더링 결과를 캐시하는 용도로 사용됩니다. 대표적인 활용 사례는 랜드스케이프의 자동 머티리얼 블렌딩입니다.

랜드스케이프에 3개 이상의 레이어를 블렌딩하면 셰이더 비용이 급격히 증가합니다. RVT를 사용하면 블렌딩 결과를 캐시하여 매 프레임 재계산하지 않아도 됩니다. 또한 메시 데칼을 RVT로 렌더링하면 오클루전 쿼리와 메시 렌더링 비용을 프레임마다 지불하지 않아도 됩니다.

다만 RVT 업데이트 시 프레임 타임 스파이크가 발생할 수 있으며, 이는 주로 카메라가 빠르게 이동하거나 텔레포트할 때 나타납니다. 이 점을 인지하고 RVT 업데이트 빈도와 해상도를 적절히 조절해야 합니다.

7. 포스트 프로세스 최적화

포스트 프로세스는 최종 이미지에 적용되는 후처리 효과들로, 블룸, 뎁스 오브 필드, 앰비언트 오클루전, 모션 블러, TSR 등이 포함됩니다. 각 효과는 개별적으로는 비용이 크지 않더라도, 누적되면 상당한 GPU 시간을 소모합니다.

7-1. TSR (Temporal Super Resolution) 최적화

TSR은 UE5에서 도입된 시간적 업스케일링 기술로, 낮은 해상도로 렌더링한 결과를 고해상도로 업스케일링합니다. 업스케일된 1080p 이미지가 네이티브 4K 대비 약 2.3배 높은 FPS를 달성할 수 있어, 성능 향상에 매우 효과적입니다.

그러나 TSR은 여러 과거 프레임의 데이터를 참조하므로, 안정적인 프레임 페이싱이 필수적입니다. 프레임레이트가 불안정하면 고스팅(잔상)과 블러링이 발생합니다.

TSR 최적화 시 주의할 점은 안티앨리어싱 품질 설정입니다. High나 Epic으로 설정하면 TSR 셰이더 자체의 비용이 크게 증가하여 목표 프레임레이트를 초과할 수 있습니다. TSR이 지나치게 비싼 경우 대안으로 UE4의 TAAU(Temporal Anti-Aliasing Upscaler)나 AMD FSR 3을 고려할 수 있습니다. FSR 3은 TSR과 유사한 결과물을 더 낮은 비용으로 제공합니다.

UE 5.4에서는 TSR의 "History Resurrection" 기능이 도입되어, 과거 프레임의 히스토리 데이터를 더 오래 유지하면서 최신 프레임에서 더 나은 매치가 발견되면 교체하는 방식으로 안정성이 크게 개선되었습니다.

7-2. 불필요한 포스트 프로세스 효과 비활성화

모든 포스트 프로세스 효과가 프로젝트에 필요한 것은 아닙니다. 특히 VR 프로젝트에서는 모든 포스트 프로세스를 비활성화하고, Auto Exposure를 Manual로, 안티앨리어싱을 TSR로 설정하는 것이 권장됩니다.

일반 프로젝트에서도 stat gpu 명령어로 포스트 프로세스 패스의 비용을 확인하고, 시각적 기여도가 낮은 효과를 우선적으로 비활성화하는 것이 효과적입니다. 모션 블러, 렌즈 플레어, 색수차(Chromatic Aberration) 등은 비활성화해도 게임 경험에 큰 영향이 없는 경우가 많습니다.

8. 드로우 콜 및 인스턴싱 최적화

드로우 콜(Draw Call)은 CPU가 GPU에게 렌더링 명령을 보내는 단위입니다. 드로우 콜 자체가 GPU를 느리게 만드는 것은 아니지만, 과도한 드로우 콜은 CPU 오버헤드를 증가시켜 GPU가 유휴 상태에 놓이게 만듭니다. 즉, CPU가 드로우 콜을 처리하는 시간이 GPU가 실제 메시를 그리는 시간보다 길어지면 GPU가 "굶주리는(starved)" 상태가 됩니다.

8-1. 자동 인스턴싱과 배칭

UE 5.5부터는 정적 메시 에셋의 자동 배칭 기능이 도입되었습니다. 기존에 최대 16001개였던 드로우 콜이 같은 조건에서 8002개로 줄어든 사례가 보고되었습니다. 이 자동 배칭은 CPU측 오클루전 컬링 이후에 수행되므로, 가려진 인스턴스가 배칭에 포함되는 문제는 발생하지 않습니다.

수동으로 인스턴싱을 적용할 때는 Instanced Static Mesh(ISM) 또는 Hierarchical Instanced Static Mesh(HISM)를 사용합니다. ISM은 GPU측 오클루전 컬링이 ExecuteIndirect를 통해 구현되어 있어, 개별 인스턴스를 GPU에서 컬링할 수 있습니다. HISM은 여기에 계층적 공간 분할을 추가하여 CPU측 컬링 효율을 높입니다.

8-2. 드로우 콜 최적화 전략

효과적인 드로우 콜 최적화를 위한 전략입니다.

첫째, 반복 배치되는 메시를 우선 대상으로 인스턴싱을 적용합니다. 같은 메시가 여러 번 배치된다면 ISM이나 HISM으로 전환하는 것이 가장 직접적인 방법입니다.

둘째, 머티리얼 변형을 줄입니다. 트랜스폼과 머티리얼이 동일한 정적 지오메트리는 자동으로 배칭될 수 있으므로, 머티리얼 수를 최소화하면 배칭과 스테이트 재사용 효율이 높아집니다.

셋째, HLOD(Hierarchical Level of Detail) 시스템을 활용합니다. HLOD는 먼 거리에서 여러 정적 메시를 하나의 메시로 대체하여 드로우 콜을 줄입니다.

넷째, stat scenerendering으로 드로우 콜 수를 모니터링합니다. 일반적으로 2000 이상의 드로우 콜은 인스턴싱이나 메시 병합이 필요하다는 신호입니다.

8-3. 오클루전 컬링

Nanite는 HZB(Hierarchical Z-Buffer)를 사용하여 GPU에서 효율적으로 오클루전 컬링을 수행합니다. 각 오브젝트의 바운딩 박스를 스크린 스페이스에서 여러 뎁스 레벨에 걸쳐 검사하여 가려진 오브젝트를 제거합니다.

비Nanite 메시의 경우, CPU측과 GPU측 컬링이 모두 적용됩니다. HZB 오클루전 컬링(r.HZBOcclusion)은 고정 비용이 높지만 오브젝트당 비용은 낮으므로, 오브젝트 수가 적은 씬에서는 오히려 비활성화하는 것이 유리할 수 있습니다.

// HZB 오클루전 컬링 토글 - 비활성화 시 성능이 더 나은지 비교
r.HZBOcclusion 0

위 명령어로 HZB를 비활성화한 뒤 성능을 비교하면, 현재 씬에서 HZB의 효과가 양수인지 음수인지 판단할 수 있습니다.

9. Scalability 설정과 CVar 우선순위

UE5에서는 Scalability 시스템을 통해 품질 프리셋(Low, Medium, High, Epic, Cinematic)별로 렌더링 설정을 자동으로 조절할 수 있습니다.

9-1. CVar 우선순위 체계

콘솔 변수(CVar)에는 우선순위 체계가 있으며, 낮은 것부터 높은 순서로 다음과 같습니다.

Constructor → Scalability → GameSetting → ProjectSetting → DeviceProfile → ConsoleVariablesIni → Commandline → Code → Console

이 우선순위 때문에 에디터의 콘솔에서 직접 입력한 값은 가장 높은 우선순위를 가지지만, 에디터를 재시작하면 사라집니다. DefaultEngine.ini에 설정한 값은 ConsoleVariablesIni 우선순위를 가지며, Scalability 설정보다 높습니다.

9-2. DefaultEngine.ini에서 기본값 설정

프로젝트 전체에 적용할 기본 CVar 값은 DefaultEngine.ini에 설정하는 것이 권장됩니다.

[ConsoleVariables]
r.Nanite.MaxPixelsPerEdge=1
r.Lumen.ScreenProbeGather.StochasticInterpolation=1
r.Shadow.Virtual.ForceOnlyVirtualShadowMaps=1

위처럼 설정하면 프로젝트를 열 때마다 자동으로 해당 값이 적용됩니다. 런치 시 실행할 명령어는 -ExecCmds="stat fps,stat unit" 형식으로 커맨드라인에 추가할 수 있습니다.

10. 일반 C++과의 비교 — GPU 최적화 관점

일반 C++에서의 GPU 프로그래밍(DirectX, Vulkan, OpenGL 직접 사용)과 UE5의 GPU 최적화는 근본적인 개념은 공유하지만, 접근 방식에 큰 차이가 있습니다.

공통점으로, 프레임 버짓 관리, 드로우 콜 최소화, 오클루전 컬링, LOD, 텍스처 밉맵 등의 개념은 동일합니다. 프로파일링 도구를 활용하여 병목을 식별하고, 데이터 주도적으로 최적화하는 워크플로우도 같습니다.

차이점으로, 일반 C++에서는 D3D12나 Vulkan API를 직접 호출하여 커맨드 버퍼를 구성하고, PSO(Pipeline State Object)를 관리하며, 리소스 배리어를 수동으로 처리해야 합니다. 반면 UE5에서는 이러한 저수준 작업이 RHI(Rendering Hardware Interface) 레이어로 추상화되어 있으며, 개발자는 콘솔 변수(CVar)와 프로젝트 설정을 통해 높은 수준에서 렌더링 동작을 제어합니다.

예를 들어, 일반 C++에서 오클루전 컬링을 구현하려면 뎁스 버퍼 다운샘플링, HZB 생성, 각 오브젝트의 바운딩 박스에 대한 가시성 테스트 셰이더를 직접 작성해야 합니다. UE5에서는 Nanite가 이 모든 과정을 자동으로 처리하며, 개발자는 r.HZBOcclusion 같은 CVar로 동작을 제어합니다.

또한 일반 C++에서는 텍스처 스트리밍을 위해 밉맵 로딩 스케줄러, 비동기 파일 I/O, GPU 메모리 관리자를 직접 구현해야 합니다. UE5에서는 텍스처 스트리밍 시스템과 가상 텍스처가 이를 자동으로 관리하며, 개발자는 풀 사이즈나 압축 포맷 같은 설정만 조절하면 됩니다.

이러한 추상화 덕분에 UE5에서의 GPU 최적화는 저수준 코드 작성보다는 프로파일링 도구 활용, CVar 튜닝, 콘텐츠 가이드라인 준수에 더 초점을 맞추게 됩니다.

11. 유니티 엔진과의 비교

유니티에도 GPU 최적화를 위한 유사한 시스템들이 존재하지만, 구조와 접근 방식에 차이가 있습니다.

유니티의 LOD 시스템은 LOD Group 컴포넌트를 사용하여 수동으로 LOD 레벨을 설정합니다. 각 LOD 단계마다 별도의 메시를 준비하고 전환 거리를 지정해야 합니다. 반면 UE5의 Nanite는 이 과정을 완전히 자동화하여, 원본 하이폴리 메시를 그대로 사용하면서 픽셀 수준에서 자동으로 LOD가 적용됩니다.

라이팅 측면에서, 유니티는 Light Probe와 Reflection Probe 기반의 GI 시스템, 그리고 HDRP의 Screen Space Global Illumination(SSGI)을 제공합니다. UE5의 Lumen은 SDF 기반 소프트웨어 레이 트레이싱이나 HWRT를 통해 전체 씬에 대한 동적 GI를 제공하므로, 프로브 배치 없이도 실시간 조명 변화에 대응할 수 있다는 구조적 강점이 있습니다.

셰도우 시스템에서, 유니티의 기본은 캐스케이드 셰도우 맵(CSM)이며 URP/HDRP에서 설정을 세밀하게 조절할 수 있습니다. UE5의 VSM은 페이지 기반 가상화 구조를 통해 Nanite 지오메트리와 긴밀하게 연동되며, 근거리부터 원거리까지 일관된 셰도우 품질을 자동으로 제공합니다.

텍스처 관리에서, 유니티도 밉맵 스트리밍(Quality Settings → Texture Streaming)을 지원하지만, UE5의 SVT처럼 타일 단위로 세밀하게 관리하는 가상 텍스처 시스템은 제공하지 않습니다. 대규모 오픈 월드에서 고유 텍스처가 많을 때 UE5의 SVT가 VRAM 관리 면에서 더 유리합니다.

언리얼 엔진만의 강점은, Nanite-Lumen-VSM이 하나의 통합된 GPU 주도 렌더링 파이프라인으로 설계되어 서로 긴밀하게 연동된다는 점입니다. 예를 들어 Nanite의 가상화된 지오메트리는 VSM의 효율적인 셰도우 페이지 관리와 직접 연결되며, Lumen의 SDF 트레이싱은 Nanite 메시에서 자동 생성된 SDF를 활용합니다. 이러한 시스템 간의 긴밀한 통합은 개별 기능의 합을 넘는 최적화 효과를 제공합니다.

12. 주의사항

12-1. "한꺼번에 바꾸기" 금지

가장 흔한 실수는 여러 설정을 동시에 변경하는 것입니다. 프로파일링 → 단일 변경 → 재프로파일링의 순환을 반드시 지켜야 합니다. 여러 설정을 동시에 바꾸면 어떤 변경이 효과가 있었는지 알 수 없으며, 오히려 성능이 악화될 수도 있습니다.

12-2. Nanite가 항상 정답은 아님

Nanite는 고밀도 정적 지오메트리에 최적화되어 있습니다. 파편화된 지오메트리, 복잡한 토폴로지, 시각적으로 의미 없는 미세한 디테일이 있는 메시에서는 오히려 성능이 저하될 수 있습니다. r.Nanite 0으로 비활성화한 뒤 성능을 비교하여 Nanite가 실제로 도움이 되는지 반드시 검증해야 합니다.

12-3. TSR과 프레임 페이싱

TSR과 Lumen은 과거 프레임 데이터를 참조하는 시스템입니다. 프레임레이트가 불안정하면 고스팅, 블러링, GI 깜빡임 등의 아티팩트가 발생합니다. GPU 최적화의 목표는 단순히 평균 FPS를 올리는 것이 아니라, 일관된 프레임 타임을 유지하는 것임을 주의하셔야 합니다.

12-4. CVar 우선순위에 의한 설정 충돌

콘솔에서 직접 입력한 CVar 값은 에디터 재시작 시 사라지므로, 영구적으로 적용하려면 DefaultEngine.ini에 설정해야 합니다. 또한 Scalability 설정이 개별 CVar보다 낮은 우선순위를 가지므로, ConsoleVariablesIni에 설정한 값이 Scalability 프리셋에 의해 덮어씌워지지 않는지 확인해야 합니다.

12-5. RVT 업데이트 스파이크

런타임 가상 텍스처(RVT)는 카메라 이동 시 업데이트 스파이크를 발생시킬 수 있습니다. 특히 텔레포트나 빠른 카메라 전환이 빈번한 게임에서는 RVT의 업데이트 빈도와 해상도를 반드시 테스트하고 조절해야 합니다.

12-6. 셰이더 복잡도와 랜드스케이프 레이어

랜드스케이프에 3개 이상의 블렌딩 레이어를 사용하면 셰이더 비용이 급격히 증가할 수 있습니다. viewmode shadercomplexity로 확인한 뒤, 비용이 높은 경우 RVT를 사용하여 블렌딩 결과를 캐시하는 것이 해결책입니다.

 

 

이 글에서 다룬 GPU 최적화 기법들을 요약하면, 프로파일링으로 병목을 식별하고, Nanite는 머티리얼과 래스터 빈을 관리하며, Lumen은 품질 CVar를 튜닝하고, VSM은 콘텐츠 설정을 최적화하며, 텍스처는 SVT와 적절한 압축 포맷을 활용하고, 포스트 프로세스는 불필요한 효과를 제거하며, 드로우 콜은 인스턴싱과 HLOD로 줄이는 것이 핵심입니다. 실제 프로젝트에서는 이 모든 기법을 한꺼번에 적용하기보다, 프로파일링 결과를 기반으로 가장 큰 병목부터 순차적으로 해결해 나가는 것이 가장 효과적인 접근법입니다.

반응형

'언리얼 엔진 5' 카테고리의 다른 글

[UE5] 직렬화와 세이브 시스템  (1) 2026.03.15
[UE5] Enhanced Input System  (0) 2026.03.09
[UE5] Render Thread 최적화  (0) 2026.03.05
[UE5] Game Thread 최적화  (0) 2026.03.04
[UE5] 프로파일링 - Unreal Insights  (0) 2026.03.03