이 글은 Unity 프로젝트를 위한 최적화 팁을 소개하는 시리즈 중 세 번째 글입니다. 더 적은 리소스로 더 높은 프레임 속도로 실행하기 위한 가이드로 활용하세요. 이러한 모범 사례를 시도해 본 후에는 시리즈의 다른 페이지도 확인해 보세요:
대상 하드웨어의 한계와 그래픽 렌더링을 최적화하기 위해 GPU를 프로파일링하는 방법을 이해합니다. 다음 팁과 모범 사례를 참고하여 GPU의 작업 부하를 줄여보세요.
화면에 게임 오브젝트를 그리기 위해 Unity는 그래픽 API(예: OpenGL, Vulkan 또는 Direct3D)에 드로우 호출을 실행합니다. 각 추첨 호출은 리소스 집약적입니다.
머티리얼 전환과 같은 드로 콜 사이의 상태 변경으로 인해 CPU 측에서 성능 오버헤드가 발생할 수 있습니다. PC 및 콘솔 하드웨어는 많은 드로우 콜을 푸시할 수 있지만, 각 콜의 오버헤드는 여전히 높기 때문에 이를 줄이기 위해 노력해야 합니다. 모바일 디바이스에서는 드로우 콜 최적화가 매우 중요합니다. 드로우 콜 일괄 처리를 통해 이를 달성할 수 있습니다.
드로우 호출 일괄 처리는 이러한 상태 변경을 최소화하고 오브젝트 렌더링에 드는 CPU 비용을 줄여줍니다. Unity는 고해상도 렌더 파이프라인 (HDRP) 또는 유니버설 렌더 파이프라인 (URP)과 함께 여러 기술을 사용하여 여러 오브젝트를 더 적은 수의 배치로 결합할 수 있습니다:
- SRP 일괄 처리: 고급 아래의 파이프라인 에셋에서 SRP 배처를 활성화합니다. 호환되는 셰이더를 사용할 때 SRP 배처는 드로 콜 사이의 GPU 설정을 줄이고 머티리얼 데이터를 GPU 메모리에 영구적으로 유지합니다. 이렇게 하면 CPU 렌더링 시간도 크게 단축할 수 있습니다. 최소한의 키워드로 더 적은 수의 셰이더 배 리언트를 사용하여 SRP 배칭을 개선하세요. 프로젝트에서 이 렌더링 워크플로를 어떻게 활용할 수 있는지 알아보려면 SRP 설명서를 참조하세요.
- GPU 인스턴싱 동일한 메시와 머티리얼을 가진 동일한 오브젝트가 많은 경우 GPU 인스턴싱을 사용하여 그래픽 하드웨어를 통해 일괄 처리할 수 있습니다. GPU 인스턴싱을 활성화하려면 인스펙터의 프로젝트 창에서 머티리얼을 선택한 다음 인스턴싱 활성화에 체크합니다.
- 정적 일괄 처리: 움직이지 않는 지오메트리의 경우 Unity는 동일한 머티리얼을 공유하는 메시의 드로 콜을 줄일 수 있습니다. 동적 일괄 처리보다 효율적이지만 메모리를 더 많이 사용합니다. 인스펙터에서 움직이지 않는 모든 메시를 배치 스태틱으로 표시합니다. 유니티는 빌드 시 모든 스태틱 메시를 하나의 큰 메시로 결합합니다. 또한 StaticBatchingUtility 클래스를 사용하면 런타임에 이러한 정적 배치를 생성할 수 있습니다(예: 절차적 수준의 움직이지 않는 파트를 생성한 후).
- 동적 일괄 처리: 작은 메시의 경우 Unity는 CPU에서 버텍스를 그룹화하고 변형한 다음 한 번에 모두 그릴 수 있습니다. 그러나 충분한 로우 폴리 메시(각각 버텍스 300개 이하, 총 버텍스 속성 900개 이하)가 없는 경우 이 방법을 사용해서는 안 된다는 점에 유의하세요. 그렇지 않으면 이 기능을 활성화하면 배치할 작은 메시를 찾는 데 CPU 시간이 낭비됩니다.
몇 가지 간단한 방법으로 일괄 처리를 극대화할 수 있습니다:
- 씬에서 텍스처를 가능한 한 적게 사용합니다. 텍스처 수가 적을수록 필요한 고유 머티리얼 수가 줄어들어 배치가 더 쉬워집니다. 또한 가능하면 텍스처 아틀라스를 사용하세요.
- 항상 가능한 가장 큰 아틀라스 크기로 라이트맵을 구워야 합니다. 라이트맵이 적을수록 머티리얼 상태 변경이 덜 필요하지만 메모리 사용량을 주의 깊게 살펴봐야 합니다.
- 의도치 않게 자료를 인스턴스화하지 않도록 주의하세요. 액세스 Renderer.material 에 액세스하면 머티리얼이 복제되고 새 사본에 대한 참조가 반환됩니다. 이렇게 하면 이미 자료가 포함된 기존 배치가 중단됩니다. 배치된 오브젝트의 머티리얼에 액세스하려면 다음을 사용하십시오.Renderer.sharedMaterial 를 대신 사용하세요.
- 최적화 중에 프로파일러 또는 렌더링 통계를 사용하여 총 드로우 콜 수 대비 정적 및 동적 배치 수를 주시하세요.
자세한 내용은 그리기 호출 일괄 처리 문서를 참조하세요.
프레임 디버거를 사용하여 단일 프레임에서 재생을 정지하고 Unity가 씬을 구성하는 과정을 단계별로 살펴보세요. 이를 통해 최적화 기회를 파악할 수 있습니다. 불필요하게 렌더링되는 게임 오브젝트를 찾아서 비활성화하여 프레임당 드로우 호출을 줄이세요.
프레임 디버거의 주요 장점 중 하나는 드로우 호출을 씬의 특정 게임 오브젝트와 연관시킬 수 있다는 점입니다. 이를 통해 외부 프레임 디버거에서는 불가능할 수 있는 특정 문제를 더 쉽게 조사할 수 있습니다.
참고: 프레임 디버거는 개별 드로우 호출이나 상태 변경 사항을 표시하지 않습니다. 네이티브 GPU 프로파일러만이 상세한 드로 콜 및 타이밍 정보를 제공할 수 있지만, 프레임 디버거는 파이프라인 문제나 배치 문제를 디버깅하는 데 매우 유용할 수 있습니다.
자세한 내용은 프레임 디버거 문서를 참조하세요.
채우기 속도는 GPU가 초당 화면에 렌더링할 수 있는 픽셀 수를 나타냅니다. 게임에서 채우기 속도가 제한되어 있다면, 이는 GPU가 처리할 수 있는 것보다 프레임당 더 많은 픽셀을 그리려고 한다는 의미입니다.
같은 픽셀 위에 여러 번 그리는 것을 오버드로라고 합니다. 오버드로는 채우기 속도를 감소시키고 추가 메모리 대역폭을 소모합니다. 초과 인출의 가장 일반적인 원인은 다음과 같습니다:
- 불투명 또는 투명 지오메트리 겹치기
- 여러 렌더링 패스를 사용하는 복잡한 셰이더
- 최적화되지 않은 파티클
- 겹치는 UI 요소
오버드로의 영향을 최소화해야 하지만, 오버드로를 해결하기 위한 만능 방법은 없습니다. 다음 기술을 실험하여 그 영향을 줄이세요.
다른 플랫폼과 마찬가지로 콘솔에서의 최적화는 종종 드로우 콜 배치를 줄이는 것을 의미합니다. 다음은 도움이 될 수 있는 몇 가지 기술입니다:
- 사용 오클루전 컬링 을 사용하여 전경 오브젝트 뒤에 숨겨진 오브젝트를 제거하고 오버드로를 줄입니다. 이 작업에는 추가 CPU 처리가 필요하므로 프로파일러를 사용하여 작업을 GPU에서 CPU로 옮기는 것이 실제로 이로운지 확인하세요.
- 동일한 메시와 머티리얼을 공유하는 오브젝트가 많은 경우 GPU 인스턴싱을 사용하면 배치 작업을 줄일 수도 있습니다. 씬의 모델 수를 제한하면 성능을 향상시킬 수 있습니다. 예술적으로 완성하면 반복적으로 보이지 않으면서도 복잡한 장면을 만들 수 있습니다.
- SRP 배처는 바인드와 GPU 그리기 명령을 일괄 처리하여 그리기 호출 사이의 GPU 설정을 줄일 수 있습니다. 이 SRP 일괄 처리의 이점을 누리려면 필요한 만큼의 머티리얼을 사용하되 호환되는 소수의 셰이더(예: URP 및 HDRP의 조명 및 조명 해제 셰이더)로 제한하세요.
컬링은 각 카메라마다 발생하며 특히 여러 대의 카메라가 동시에 활성화된 경우 성능에 큰 영향을 미칠 수 있습니다. 유니티는 두 가지 유형의 컬링을 사용합니다:
- 프러스텀 컬링은 모든 카메라에서 자동으로 수행됩니다. 이를 통해 게임 오브젝트 외부의 뷰 프러스텀 외부의 게임 오브젝트가 렌더링되지 않도록 하여 성능을 절약합니다.
- Camera.layerCullDistances를 통해 레이어별 컬링 거리를 수동으로 설정할 수 있습니다. 이를 통해 기본값보다 짧은 거리에서 작은 게임 오브젝트를 컬링할 수 있습니다.farClipPlane 프로퍼티를 사용하면 됩니다. 이렇게 하려면 게임 오브젝트를 레이어로 구성합니다. .layerCullDistances 배열을 사용하여 32개의 레이어 각각에 farClipPlane보다 작은 값을 할당합니다(또는 0을 사용하여 멀리 클립 평면을 기본값으로 설정합니다).
- Unity는 먼저 레이어별로 컬링합니다. 카메라가 사용하는 레이어에 게임 오브젝트만 유지합니다. 그 후 프러스텀 컬링은 카메라 프러스텀 외부의 모든 게임 오브젝트를 제거합니다.
- 프러스텀 컬링은 사용 가능한 워커 스레드를 활용하는 일련의 작업으로 수행됩니다. 각 레이어 컬링 테스트는 빠르게 진행됩니다(기본적으로 비트 마스크 작업만 수행). 그러나 이 비용은 게임 오브젝트가 많을 경우 여전히 증가할 수 있습니다. 이것이 프로젝트에 문제가 되는 경우, 월드를 "섹터"로 나누고 카메라 프러스텀 외부의 섹터를 비활성화하는 시스템을 구현하여 Unity의 레이어/프러스텀 컬링 시스템에 대한 부담을 일부 완화해야 할 수 있습니다.
- 오클루전 컬링은 카메라가 게임 오브젝트를 볼 수 없는 경우 게임 뷰에서 모든 게임 오브젝트를 제거합니다. 다른 오브젝트 뒤에 숨겨진 오브젝트는 여전히 렌더링 및 리소스 비용이 발생할 수 있습니다. 오클루전 컬링을 사용하여 폐기합니다.
- 예를 들어, 문이 닫혀 있어 카메라가 방 안을 볼 수 없는 경우 방을 렌더링할 필요가 없습니다. 오클루전 컬링을 활성화하면 성능이 크게 향상되지만 디스크 공간, CPU 시간 및 RAM을 더 많이 사용할 수 있습니다. Unity는 빌드 중에 오클루전 데이터를 베이크한 다음 씬을 로드하는 동안 디스크에서 RAM으로 로드해야 합니다.
- 카메라 뷰 외부의 프러스텀 컬링은 자동이지만, 오클루전 컬링은 구워지는 프로세스입니다. 오브젝트를 스태틱, 오클루더 또는 오클루디로 표시한 다음 창 > 렌더링 > 오클루전 컬링 대화 상자를 통해 구우면 됩니다.
자세한 내용은 오클루전 컬링 작업 튜토리얼을 참조하세요.
동적 해상도 카메라 허용 설정을 사용하면 개별 렌더링 타깃의 크기를 동적으로 조정하여 GPU의 작업 부하를 줄일 수 있습니다. 애플리케이션의 프레임 속도가 감소하는 경우 해상도를 서서히 낮추어 일관된 프레임 속도를 유지할 수 있습니다.
성능 데이터에 따르면 GPU 바인딩으로 인해 프레임 속도가 곧 감소할 것으로 예상되는 경우 Unity는 이 스케일링을 트리거합니다. 스크립트를 사용하여 이 스케일링을 수동으로 선제적으로 트리거할 수도 있습니다. 이 기능은 애플리케이션에서 GPU를 많이 사용하는 섹션에 접근할 때 유용합니다. 점진적으로 스케일링하면 동적 해상도가 거의 눈에 띄지 않을 수 있습니다.
지원되는 플랫폼 목록은 동적 해상도 매뉴얼 페이지를 참조하세요.
게임 도중 두 개 이상의 시점으로 렌더링해야 하는 경우가 있습니다. 예를 들어, 1인칭 슈팅 게임(FPS)에서는 플레이어의 무기와 환경을 서로 다른 시야각(FOV)으로 분리하여 그리는 것이 일반적입니다. 이렇게 하면 전경 오브젝트가 배경의 광각 FOV를 통해 왜곡되어 보이지 않습니다.
다음을 사용할 수 있습니다. 카메라 스태킹 를 사용하여 둘 이상의 카메라 뷰를 렌더링할 수 있습니다. 하지만 여전히 각 카메라마다 상당한 컬링과 렌더링이 수행됩니다. 각 카메라는 의미 있는 작업을 수행하든 그렇지 않든 약간의 오버헤드가 발생합니다.
렌더링에 필요한 카메라 컴포넌트만 사용합니다. 모바일 플랫폼에서 모든 활성 카메라는 아무것도 렌더링하지 않을 때에도 최대 1ms의 CPU 시간을 사용할 수 있습니다.
오브젝트가 원거리로 이동하면 LOD( 레벨 오브 디테일 )를 조정하거나 더 단순한 머티리얼과 셰이더로 저해상도 메시를 사용하도록 전환할 수 있습니다. 이렇게 하면 GPU 성능이 강화됩니다.
자세한 내용은 Unity Learn의 LOD 작업 과정을 참조하세요.
포스트 프로세싱 효과를 프로파일링하여 GPU에서 비용을 확인합니다. 블룸 및 뎁스 오브 필드와 같은 일부 전체 화면 효과는 비용이 많이 들 수 있으므로 시각적 품질과 성능 간에 원하는 균형을 찾을 때까지 실험해 볼 가치가 있습니다.
포스트 프로세싱은 런타임에 큰 변동이 없습니다. 볼륨 오버라이드를 결정한 후에는 총 프레임 예산의 정적 부분을 포스트 프로세싱 효과에 할당합니다.
테셀레이션은 모양을 더 작은 버전으로 세분화하여 지오메트리를 개선함으로써 디테일을 향상시킬 수 있습니다. 테셀레이션이 가장 적합한 예시로는 Unity 데모 ' 사자의 서'의 나무 껍질 등이 있지만, GPU 비용이 많이 들기 때문에 콘솔에서는 테셀레이션을 피하는 것이 좋습니다.
사자의 서 데모에 대한 자세한 내용은 여기에서 확인하세요.
테셀레이션 셰이더와 마찬가지로 지오메트리 및 버텍스 셰이더는 GPU에서 프레임당 두 번, 즉 뎁스 프리패스 중 한 번과 섀도 패스 중 한 번 실행할 수 있습니다.
GPU에서 버텍스 데이터를 생성하거나 수정하려는 경우, 특히 지오메트리 셰이더에 비해 컴퓨팅 셰이더가 더 나은 선택인 경우가 많습니다. 컴퓨팅 셰이더에서 작업을 수행하면 지오메트리를 실제로 렌더링하는 버텍스 셰이더가 훨씬 더 빠르게 작동할 수 있습니다.
셰이더 핵심 개념에 대해 자세히 알아보세요.
GPU에 드로우 호출을 보내면 해당 작업은 여러 개의 웨이브 프론트로 분할되어 Unity가 GPU 내의 사용 가능한 SIMD에 분산합니다. 각 SIMD에는 동시에 실행할 수 있는 최대 웨이브프론트 수가 있습니다.
파면 점유율은 최대치를 기준으로 현재 사용 중인 파면의 수를 나타냅니다. GPU의 잠재력을 얼마나 잘 활용하고 있는지 측정합니다. 콘솔 개발용 프로파일링 툴은 파면 점유율을 매우 상세하게 보여줍니다.
위의 예제에서 Unity의 사자의 책에서 버텍스 셰이더 파면은 녹색으로 표시되고 픽셀 셰이더 파면은 파란색으로 표시됩니다. 아래쪽 그래프에서 많은 버텍스 셰이더 파면이 픽셀 셰이더 활동 없이 나타납니다. 이는 GPU의 활용도가 낮음을 나타냅니다.
픽셀을 생성하지 않는 버텍스 셰이더 작업을 많이 수행한다면 비효율적일 수 있습니다. 웨이브프론트 점유율이 낮다고 해서 반드시 나쁜 것은 아니지만, 셰이더를 최적화하고 다른 병목 현상을 확인하는 데 사용할 수 있는 지표입니다. 예를 들어 메모리 또는 컴퓨팅 작업으로 인해 멈춤 현상이 발생하는 경우 점유율을 높이면 성능이 향상될 수 있습니다. 반면에 비행 중 파면이 너무 많으면 캐시 스래싱이 발생하여 성능이 저하될 수 있습니다.
GPU를 제대로 활용하지 못하는 구간이 있는 경우 비동기 컴퓨팅을 활용하여 셰이더 작업을 그래픽 대기열에 병렬로 이동시킬 수 있습니다. 예를 들어 섀도 맵을 생성하는 동안 GPU는 깊이 전용 렌더링을 수행합니다. 이 시점에서 픽셀 셰이더 작업은 거의 이루어지지 않으며 많은 웨이브프론트가 비어 있습니다.
일부 컴퓨팅 셰이더 작업을 뎁스 전용 렌더링과 동기화할 수 있다면 전체적으로 GPU를 더 효율적으로 사용할 수 있습니다. 사용하지 않는 웨이브프론트는 스크린 스페이스 앰비언트 오클루전 (SSAO) 또는 현재 작업을 보완하는 모든 작업에 도움이 될 수 있습니다.
유나이트의 하이엔드 콘솔 성능 최적화에 대한 이 세션을 시청하세요.
가장 포괄적인 가이드 중 하나로, PC 및 콘솔용 게임을 최적화하는 방법에 대한 80개 이상의 실행 가능한 팁을 모았습니다. 유니티의 성공 및 가속화 솔루션 전문 엔지니어가 작성한 이 심층적인 팁은 Unity를 최대한 활용하고 게임 성능을 향상하는 데 도움이 될 것입니다.