낮은 FPS 해결 및 최적화 가이드¶
프로젝트의 성능(FPS) 문제를 진단하고 해결하는 방법을 설명해요. GC Alloc 제거 및 Shader 메모리/빌드 시간 최적화도 다루고 있어요.
낮은 FPS 진단 프로세스¶
성능을 저하시키는 원인은 다양하므로, 항상 다음 프로세스를 따라 주세요.
- 실제로 무엇이 속도를 늦추는지 찾아 주세요
- 그것만 최적화해 주세요 (무작위로 수정하지 마세요)
- FPS를 다시 확인해 주세요
- 부작용 없이 FPS가 증가하면, 변경 사항을 유지하고 버전 관리에 Push해 주세요
- 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 시간 비용에 주의해 주세요.

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 병목을 찾으려면 Profiler와 Frame 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 달성¶

Terrain을 사용하는 프로젝트¶
모든 NiloToon Renderer Feature에서:
- Perfect Culling For Shadow Casters 비활성화 - Terrain 충돌 방지
- Terrain Crash Safe Guard 비활성화 - GC Alloc 제거

Terrain을 사용하지 않는 프로젝트¶
모든 NiloToon Renderer Feature에서:
- Perfect Culling For Shadow Casters 활성화 - Shadow 품질 향상
- Terrain Crash Safe Guard 비활성화 - GC Alloc 제거

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 빌드 시 더 많은 정보를 로그로 남겨요.
- 빌드 후, Console 창의 검색바에 NiloToon_Character를 붙여넣어 주세요
- ForwardLit Pass의 Total Variant Count를 확인해 주세요
- NiloToon Stripping 설정을 편집해 주세요
- 다시 빌드하고 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를 사용해 주세요.
- Project Window에서 우클릭하여 NiloToonShaderStrippingSettingSO 생성
- 빌드에 포함된 모든 NiloToonAllInOne Renderer Feature에 드래그
- 빌드에 불필요한 기능을 플랫폼별로 비활성화 - 각 키워드를 끄면 런타임 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 빌드에서 변경 사항이 보이지 않으면:
- 이전에 빌드된 모든 Addressables 데이터를 정리해 주세요
- 다시 빌드해 주세요
Addressables는 NiloToonShaderStrippingSettingSO의 편집을 콘텐츠 자산 변경으로 간주하지 않으므로, 마지막 빌드의 캐시가 여전히 '유효'하여 빌드를 클릭해도 아무것도 하지 않아요.
단계 6: 빌드 CPU 사용률 낮추기¶
빌드 시 Unity는 각 CPU Thread마다 하나의 Unity Shader Compiler를 생성하여 Shader 컴파일 속도를 최대화해요. 빌드 중 PC의 응답성을 유지하면서 Shader 컴파일 속도를 늦추려면 다음 Editor Command Line Argument를 사용해 주세요.
UnityHub에서 대상 프로젝트를 선택하고 Add command line arguments를 클릭하여 위 인자를 입력해 주세요.
적절한 값 선택
8에서 시작하여 다른 작업(예: 게임 플레이)을 하면서 빌드가 PC를 너무 느리게 만들 때까지 +4씩 늘려 보세요. PC가 빌드 전용 머신이라면 이 인자를 사용하지 마세요.