콘텐츠로 이동

낮은 FPS 해결 및 최적화 가이드

프로젝트의 성능(FPS) 문제를 진단하고 해결하는 방법을 설명해요. GC Alloc 제거 및 Shader 메모리/빌드 시간 최적화도 다루고 있어요.


낮은 FPS 진단 프로세스

성능을 저하시키는 원인은 다양하므로, 항상 다음 프로세스를 따라 주세요.

  1. 실제로 무엇이 속도를 늦추는지 찾아 주세요
  2. 그것만 최적화해 주세요 (무작위로 수정하지 마세요)
  3. FPS를 다시 확인해 주세요
  4. 부작용 없이 FPS가 증가하면, 변경 사항을 유지하고 버전 관리에 Push해 주세요
  5. 1번으로 돌아가 주세요

1. CPU 또는 GPU Bound?

Game Window의 해상도RenderScale가능한 최저로 낮추었을 때:

결과 원인
FPS가 동일하게 유지됨 CPU Bound일 가능성이 높음
FPS가 크게 증가함 GPU Bound임이 확실

참고

대부분의 콘서트 프로젝트는 CPU Main Thread Bound예요.


2. 캐릭터 수

1~5명의 캐릭터는 일반적이며, NiloToon으로 인해 크게 느려지지 않아요.

NiloToonPerCharacterRenderController는 고정된 CPU Main Thread 비용이 있으며, Profiler에서 시간 비용의 합계를 확인할 수 있어요. 소품/아이템에 많은 NiloToonPerCharacterRenderController를 사용하는 경우, 총 CPU Main Thread 시간 비용에 주의해 주세요.

Profiler에서의 CPU 비용

4 캐릭터 + 16 소품 = 20개의 NiloToonPerCharacterRenderController가 Intel Core i7-14700 CPU에서 총 0.x ms의 CPU 비용을 발생시키는 상황


3. 하드웨어 요구 사항

Unity Editor용 PC 예시:

부품 사양
CPU Intel Core i7-14700
GPU NVIDIA RTX 4080 Super

이 사양은 중소규모 콘서트 프로젝트를 Editor에서 실행하기에 적합해요.


4. Editor vs Build

CPU의 경우, Editor와 Build 간에 상당한 CPU 성능 차이가 있을 수 있어요. Editor Play Mode는 일반적으로 Editor 전용 오버헤드가 더 많아 Build된 실행 파일에 비해 느려요. 가능하면 Build하여 CPU 성능을 테스트해 주세요.

GPU의 경우, Editor에서 성능을 테스트해도 괜찮아요. Editor와 Build 간 해상도가 동일하다면 GPU 성능에 큰 차이가 없어요.


5. 일반적인 CPU 병목 지점

CPU Bound 문제를 해결하려면 다음을 확인해 주세요.

줄이거나 비활성화할 것

  • Planar Reflection (각 Reflection이 추가 Camera를 사용)
  • 2개 이상의 Camera (하나의 3D Main Camera만 사용하는 것을 강력히 권장)
  • NiloToonPerCharacterRenderController가 있는 캐릭터가 너무 많은 경우 (예: > 5)
  • NiloToonPerCharacterRenderController가 있는 소품/아이템이 너무 많은 경우 (예: > 20)
  • 너무 무거운 MagicaCloth 1/2, VRM Spring Bone
  • 너무 무거운 Timeline / Director Update (보통 조명 애니메이션이 원인)
  • 너무 많은 가시 Light
  • 불필요한 Shadowmap이 활성화된 Light가 너무 많음
  • Frame Debugger에서 Non-SRP Batching Material
  • 높은 Spawn Count의 CPU 파티클 (Penlight 바다나 Confetti 등)
  • NiloToon의 "Keep play mode mat edit?" - Editor에서 SRP Batching을 방해
  • NiloToon의 High Quality Culling (NiloToon Renderer Feature의 Char Self Shadow 섹션) - 전체 0.x ms Camera SRP Culling 비용 발생

활성화해 볼 것

  • DX12 Graphics API (DX11은 일반적으로 Multi-Thread에서 더 느림)
  • DX12 Split Graphics Jobs - 렌더 루프 CPU 성능 크게 향상, 시각적 결과에 부정적 영향 없음
  • DX12 Graphics Jobs for Editor - 렌더 루프 CPU 성능 크게 향상
  • GPU ResidentDrawer - 동일한 MeshRenderer를 사용하는 대량(>10K)의 GameObject를 렌더링할 때만 CPU 성능 향상 가능. 프레임당 고정 CPU 비용이 있으므로 GPU Instancing을 대량으로 활용하지 않으면 오히려 성능이 저하됨
  • GPU Skinning (Batched)
  • Build에서 IL2CPP

디버깅 도구

CPU 병목을 찾으려면 ProfilerFrame Debugger 사용이 매우 적합해요. 이 두 도구가 대부분의 CPU 성능 문제를 찾는 데 도움이 돼요.


6. 일반적인 GPU 병목 지점

GPU 병목의 원인은 일반적으로 더 명확해요.

줄이거나 비활성화할 것

  • 높은 Game Window 해상도 (예: >= 4K)
  • 높은 RenderScale (예: >= 1)
  • 고해상도/RenderScale에서 활성화된 MSAA (MSAA를 비활성화하고 TAA/DLSS의 네이티브 AA 사용 시도)
  • Volumetric Light Beam / Volumetric Fog Overdraw가 너무 많고 겹쳐서 많은 픽셀을 커버
  • Forward+에서 가시 Light가 너무 많음
  • 고해상도 텍스처에 Mipmap 없음
  • 너무 무거운 Post-Processing (Volume을 비활성화하고 FPS 차이 확인)
  • 실시간 GI 솔루션 사용 (예: HTrace SSGI / WSGI)

활성화해 볼 것

  • Batched GPU Skinning - 모델에 많은 SkinnedMeshRenderer와 Blendshape가 있을 때 GPU 성능 향상
  • DLSS를 사용하여 실제 3D 해상도를 낮추기

참고

해상도 및 AA에 대한 자세한 예시 설정은 AA/DLSS 가이드를 참고해 주세요.


GC Alloc 0 달성

GC Alloc 0 달성

Terrain을 사용하는 프로젝트

모든 NiloToon Renderer Feature에서:

  • Perfect Culling For Shadow Casters 비활성화 - Terrain 충돌 방지
  • Terrain Crash Safe Guard 비활성화 - GC Alloc 제거

Terrain 사용 시 설정

Terrain을 사용하지 않는 프로젝트

모든 NiloToon Renderer Feature에서:

  • Perfect Culling For Shadow Casters 활성화 - Shadow 품질 향상
  • Terrain Crash Safe Guard 비활성화 - GC Alloc 제거

Terrain 미사용 시 설정


Shader 메모리 및 빌드 시간 줄이기

URP의 Lit Shader, ComplexLit Shader와 유사하게, NiloToon_Character.shader는 다양한 사용 사례를 지원하기 위해 많은 #pragma multi_compile#pragma shader_feature_local을 사용해요.

Shader 메모리 사용량과 빌드 시간은 필요한 on/off 기능 n개에 대해 ~2^n이 돼요. 이는 Shader Variant 수가 많은 기능이 활성화될수록 기하급수적으로 증가한다는 것을 의미해요.

모바일 빌드

모바일 빌드에서 Shader 메모리를 줄이는 것은 중요해요. 그렇지 않으면 메모리 부족 충돌이 발생할 수 있어요.

단계 0: Unity6.1 이상 사용

Unity6.1에서 NiloToon의 Fog multi_compile이 Non-Shader Variant 방식으로 최적화되어, 약간의 추가 Fragment 계산과 교환하여 메모리 사용량과 빌드 시간이 크게 줄어들어요.

단계 1: 빌드 Stripping 정보

Project Settings > Graphics > Shader Variant Log Level = Only SRP Shaders를 설정해 주세요.

NiloToon의 Stripping 시스템이 플레이어/Asset Bundle 빌드 시 더 많은 정보를 로그로 남겨요.

  1. 빌드 후, Console 창의 검색바에 NiloToon_Character를 붙여넣어 주세요
  2. ForwardLit Pass의 Total Variant Count를 확인해 주세요
  3. NiloToon Stripping 설정을 편집해 주세요
  4. 다시 빌드하고 ForwardLit Pass의 Total Variant Count를 확인하여 Shader Variant 변경을 확인해 주세요

단계 2: URP 모범 사례

모든 Quality Settings에 포함된 URP Asset에 대해:

  • 빌드에서 모든 URP Asset에서 기능을 비활성화 - URP가 해당 기능이 비활성화된 Variant만 유지
  • 빌드에서 모든 URP Asset에서 기능을 활성화 - URP가 해당 기능이 활성화된 Variant만 유지

혼합 설정 주의

하나의 URP Asset에서 기능을 ON, 다른 URP Asset에서 OFF로 설정하면, URP가 해당 기능을 Strip하지 않고 ON+OFF 양쪽 Variant를 모두 유지하므로 빌드 시간과 Shader 메모리가 약 2배가 돼요!

단계 3: NiloToonShaderStrippingSettingSO

NiloToon_Character Shader의 multi_compile 메모리 사용량을 줄이려면 NiloToonShaderStrippingSettingSO를 사용해 주세요.

  1. Project Window에서 우클릭하여 NiloToonShaderStrippingSettingSO 생성
  2. 빌드에 포함된 모든 NiloToonAllInOne Renderer Feature에 드래그
  3. 빌드에 불필요한 기능을 플랫폼별로 비활성화 - 각 키워드를 끄면 런타임 Shader 메모리 사용량과 빌드 시간이 약 40~50% 감소

검증 방법

제대로 동작하는지 확인하려면, 대상 플랫폼에서 모든 기능을 먼저 비활성화하고 빌드한 뒤 Memory Profiler로 NiloToon_Character Shader 메모리 사용량이 크게 줄었는지 확인해 주세요. 정상 동작 시 약 10~50MB까지 줄어야 해요. 그 후 실제로 필요한 키워드를 다시 추가하고 빌드해 주세요.

단계 4: XR 패키지 제거

XR이 필요 없다면 Package Manager에서 XR 관련 패키지를 제거해 주세요. Unity가 XR 관련 키워드를 Strip하는 데 도움이 돼요.

단계 5: Material 최적화

NiloToon의 Shader에는 많은 shader_feature가 있지만, 빌드에 포함된 Material에서 활성화하지 않으면 Shader 메모리/성능 비용/빌드 시간이 증가하지 않아요.

모든 Material에서 고유한 Shader 키워드 조합이 많을수록 런타임에 더 많은 메모리가 필요하고 빌드 시간도 길어져요.

Addressables 사용 시

NiloToonShaderStrippingSettingSO 설정 후 다음 Addressables 빌드에서 변경 사항이 보이지 않으면:

  1. 이전에 빌드된 모든 Addressables 데이터를 정리해 주세요
  2. 다시 빌드해 주세요

Addressables는 NiloToonShaderStrippingSettingSO의 편집을 콘텐츠 자산 변경으로 간주하지 않으므로, 마지막 빌드의 캐시가 여전히 '유효'하여 빌드를 클릭해도 아무것도 하지 않아요.

단계 6: 빌드 CPU 사용률 낮추기

빌드 시 Unity는 각 CPU Thread마다 하나의 Unity Shader Compiler를 생성하여 Shader 컴파일 속도를 최대화해요. 빌드 중 PC의 응답성을 유지하면서 Shader 컴파일 속도를 늦추려면 다음 Editor Command Line Argument를 사용해 주세요.

-job-worker-count 8

UnityHub에서 대상 프로젝트를 선택하고 Add command line arguments를 클릭하여 위 인자를 입력해 주세요.

적절한 값 선택

8에서 시작하여 다른 작업(예: 게임 플레이)을 하면서 빌드가 PC를 너무 느리게 만들 때까지 +4씩 늘려 보세요. PC가 빌드 전용 머신이라면 이 인자를 사용하지 마세요.