🚀 들어가며
이번 글에서는 렌더링 최적화 주제를 정리해보겠습니다.
- CPU 바운드(CPU Bound)
- SetPass Call
- Batching
- Culling
- Skinned Mesh
특히, GPU에 명령을 보내는 과정에서 발생하는 CPU 병목은 유니티 렌더링 최적화에서 매우 중요한 부분입니다.
🧠 Graphics Jobs
Player Settings의 Graphics Jobs 옵션은 렌더링 작업을 어떤 쓰레드에서 처리할지 결정합니다.
플랫폼에 따라 아래 쓰레드 중 하나에서 렌더링 작업이 처리됩니다.
- 메인 쓰레드
- 렌더 쓰레드
- Worker Thread
Graphics Jobs를 지원하는 플랫폼에서는 상당한 성능 향상을 얻을 수도 있습니다.
다만, 항상 프로파일링을 먼저 해봐야 합니다.
옵션을 켰을 때와 껐을 때 실제 성능 차이를 반드시 확인하는 것이 중요합니다.
🎯 CPU Bound 원인 찾기
유니티 프로파일러를 사용하면 게임이 CPU Bound 상태가 되는 원인을 확인할 수 있습니다.
예를 들어 아래와 같은 작업이 병목의 원인이 될 수 있습니다.
- GPU 명령 전달
- Culling
- Sorting
- Batching
원인을 정확히 파악한 뒤, 그에 맞는 최적화를 적용해야 합니다.
🔥 GPU로 명령 보내기
GPU에 명령을 보내는 작업은 CPU Bound의 가장 흔한 원인 중 하나입니다.
이 작업은 대부분 Render Thread에서 처리됩니다.
일부 플랫폼에서는 Worker Thread에서 처리되기도 합니다.
🎯 가장 비싼 작업: SetPass Call
GPU에 명령을 보낼 때 가장 비싼 작업 중 하나가 SetPass Call입니다.
즉, SetPass Call이 많아질수록, CPU 부담이 커질 가능성이 높습니다.
유니티 프로파일러를 사용하면 SetPass Call 수 / Batch 수를 확인할 수 있습니다.
🧠 Batch와 SetPass Call 관계
일반적으로는, Batch 수 감소 / Render State 공유 증가가 SetPass Call 감소로 이어집니다.
그리고 SetPass Call 감소는 CPU 성능 향상으로 연결되는 경우가 많습니다.
🎮 Batch 수 감소만으로도 의미가 있다
SetPass Call이 줄지 않더라도 Batch 수 감소 자체가 성능 향상에 도움이 될 수 있습니다.
왜냐하면, CPU는 여러 개의 작은 Batch보다, 하나의 큰 Batch를 더 효율적으로 처리할 수 있기 때문입니다.
🧠 Batch와 SetPass Call 줄이는 방법
지금까지 설명한 CPU Bound와 Batching 최적화 구조를 그림으로 정리해보면 다음과 같습니다.
핵심은 렌더링 최적화는 단순 Draw Call 감소가 아니라, CPU가 GPU에 명령을 전달하는 비용 자체를 줄이는 과정이라는 점입니다.

크게 보면 방법은 3가지입니다.
- 렌더링할 오브젝트 수 줄이기
- 오브젝트 렌더링 횟수 줄이기
- 더 적은 Batch로 오브젝트 합치기
프로젝트마다 적합한 방법은 다르므로 반드시 직접 테스트하고 프로파일링하는 것이 중요합니다.
🎯 렌더링되는 오브젝트 수 줄이기
가장 단순하면서 효과적인 최적화 방법입니다.
🔥 단순히 오브젝트 수 줄이기
예를 들어, 군중 시스템에서 캐릭터 수를 줄이는 것만으로도 큰 성능 향상을 얻을 수 있습니다.
복잡한 최적화보다 씬 구성 자체를 단순화하는 것이 더 효과적인 경우도 많습니다.
🎮 Far Clip Plane 활용
카메라의 Far Clip Plane을 줄이면, 먼 거리의 오브젝트를 렌더링하지 않게 됩니다.
즉, 렌더링해야 하는 오브젝트 수 자체를 줄일 수 있습니다.
필요하다면, Fog 효과를 함께 사용해서 자연스럽게 처리할 수 있습니다.
🧠 Layer Cull Distance
Layer Cull Distance를 사용하면 레이어별로 서로 다른 컬링 거리를 설정할 수 있습니다.
예를 들어, 아래와 같은 방식으로 세밀한 제어가 가능합니다.
- 작은 오브젝트는 가까운 거리에서만 렌더링
- 큰 오브젝트는 먼 거리까지 렌더링
🔥 Occlusion Culling
Occlusion Culling은 다른 오브젝트에 가려진 오브젝트를 렌더링하지 않는 기술입니다.
예
- 큰 건물 뒤 오브젝트
- 벽 뒤 캐릭터
등을 렌더링하지 않게 됩니다.
적절한 씬에서는 성능 향상 효과가 매우 큽니다.
다만, 추가 CPU 오버헤드 / 복잡한 설정이 발생할 수도 있습니다.
즉, 모든 프로젝트에서 무조건 좋은 것은 아닙니다.
🎮 직접 비활성화하는 것도 중요하다
유니티 시스템에만 의존하는 것보다 개발자가 직접 제어하는 것이 더 효율적인 경우도 많습니다.
예를 들어, 컷씬에서만 사용하는 오브젝트를 평소에는 비활성화하는 방식입니다.
🧠 오브젝트 렌더링 횟수 줄이기
실시간 라이팅, 그림자, Reflection은 매우 비싼 기능입니다.
왜냐하면, 하나의 오브젝트가 여러 번 렌더링될 수 있기 때문입니다.
🎯 Rendering Path
렌더링 비용은 Rendering Path에 따라 달라집니다.
대표적으로
- Forward Rendering
- Deferred Rendering
방식이 존재합니다.
일반적으로는 아래가 적합한 경우가 많습니다.
- 고성능 하드웨어 + 실시간 조명 많음 → Deferred
- 저사양 하드웨어 → Forward
하지만, 프로젝트 특성에 따라 달라질 수 있으므로 반드시 테스트가 필요합니다.
🔥 Dynamic Lighting
동적 라이팅은 매우 비쌉니다.
움직이지 않는 배경 오브젝트라면, Baking을 사용하는 것이 좋습니다.
Baking은 미리 라이팅 결과를 계산해두는 방식입니다.
즉, 실시간 계산 비용을 줄일 수 있습니다.
🎮 그림자(Shadow) 최적화
실시간 그림자 역시 매우 비싼 기능입니다.
예를 들어, Shadow Distance 감소 / 그림자 품질 조절만으로도 성능을 크게 향상시킬 수 있습니다.
🔥 Reflection Probe
Reflection Probe는 사실적인 반사 효과를 제공합니다.
하지만, Batch 측면에서 매우 비싼 기능입니다.
따라서, 성능이 중요한 구간에서는 Reflection 사용을 최소화하는 것이 좋습니다.
🧠 더 적은 Batch로 오브젝트 합치기
조건이 맞으면 여러 오브젝트를 하나의 Batch로 처리할 수 있습니다.
배치에 필요한 조건은 다음과 같습니다.
- 동일한 Material 인스턴스
- 동일한 텍스처
- 동일한 Shader 상태
🎯 Static Batching
스태틱 배칭은 움직이지 않는 오브젝트를 Batch로 묶는 기술입니다.
예를 들면, 바위, 건물, 배경 오브젝트 등을 배치로 묶을 수 있습니다.
장점:
👉 Draw Call 감소
단점:
👉 메모리 사용량 증가 가능
즉, 메모리 사용량까지 함께 프로파일링해야 합니다.
🔥 Dynamic Batching
움직이는 동적 오브젝트도 Batch 처리 가능합니다.
하지만, CPU 비용이 증가할 수 있습니다.
즉, Dynamic Batching은 항상 좋은 것이 아닙니다.
프로젝트에 따라 오히려 CPU 사용량이 증가할 수도 있습니다.
🎮 UI Batching
Unity UI의 배칭은 레이아웃 구조에 영향을 크게 받습니다.
즉, UI 구조 자체가 비효율적이면 배칭이 깨질 수 있습니다.
🔥 GPU Instancing
동일한 오브젝트를 매우 효율적으로 렌더링하는 기술입니다.
예를 들면, 나무, 풀, 반복되는 배경 오브젝트 같은 상황에서 매우 효과적입니다.
다만, 모든 하드웨어에서 지원되는 것은 아닙니다.
🎮 Texture Atlasing
여러 텍스처를 하나의 큰 텍스처로 합치는 기술입니다.
이를 통해, 여러 오브젝트가 동일한 텍스처를 공유하게 되어 Batching이 가능해집니다.
특히, 2D 게임 및 UI 시스템에서 자주 사용됩니다.
🧠 Renderer.material 주의
스크립트에서
Renderer.material
에 접근하면 Material이 복제됩니다.
즉, Batch가 깨질 수 있습니다.
Batch 유지가 필요하다면
Renderer.sharedMaterial
사용을 고려해야 합니다.
🎯 Culling, Sorting, Batching
다음 작업들도 CPU 비용을 발생시킬 수 있습니다.
- Culling
- Sorting
- Batching
🔥 불필요한 카메라 비활성화
활성화된 모든 카메라는 오버헤드를 발생시킵니다.
즉, 사용하지 않는 카메라는 비활성화하는 것이 좋습니다.
🎮 Batching도 비용이 있다
Batching은 성능 향상에 도움이 되지만 그 자체로 CPU 비용이 발생할 수 있습니다.
즉, 자동 배칭을 무조건 사용하는 것이 정답은 아닙니다.
🧠 Skinned Meshes
SkinnedMeshRenderer는 본 애니메이션(Bone Animation)에 사용됩니다.
주로 애니메이션 캐릭터에 사용됩니다.
하지만, 매우 비싼 기능입니다.
🎯 정말 필요한가?
애니메이션이 필요하지 않은 오브젝트라면 SkinnedMeshRenderer 대신 MeshRenderer를 사용하는 것이 좋습니다.
이것만으로도 상당한 성능 향상을 얻을 수 있습니다.
🔥 특정 상황에서만 애니메이션 사용
예를 들어
- 카메라 근처에서만 애니메이션
- 특정 이벤트에서만 애니메이션
을 적용할 수 있습니다.
멀리 있는 캐릭터는 로우 폴리 메쉬 또는 일반 MeshRenderer로 교체하는 것도 가능합니다.
🎮 정점 수 줄이기
Skinning 비용은 정점 수에 따라 증가합니다.
즉, 캐릭터 폴리곤 수 자체를 줄이는 것이 중요합니다.
🔥 GPU Skinning
일부 플랫폼에서는 Skinning 작업을 GPU에서 처리할 수도 있습니다.
플랫폼에 따라 충분히 테스트해볼 가치가 있는 옵션입니다.
🎯 핵심 정리
- SetPass Call은 CPU 바운드의 주요 원인 중 하나입니다.
- Batch 수 감소는 성능 향상에 도움이 됩니다.
- Occlusion Culling과 Layer Cull Distance는 렌더링 오브젝트 수를 줄여줍니다.
- 실시간 라이팅과 Reflection은 매우 비싼 기능입니다.
- Static/Dynamic Batching은 상황에 따라 비용이 발생할 수 있습니다.
- SkinnedMeshRenderer는 매우 비싼 컴포넌트입니다.
🧩 마무리
렌더링 최적화는 단순히 Draw Call만 줄이는 작업이 아닙니다.
실제로는 다양한 요소가 함께 영향을 줍니다.
- GPU 명령 전달
- Batching
- Culling
- 라이팅
- Skinned Mesh 처리
즉, 무조건 최적화를 적용하기보다, 프로파일링을 통해 병목 원인을 먼저 찾는 것이 가장 중요합니다.