유니티(Unity)/최적화

그래픽스 퍼포먼스 최적화(2) CPU 최적화

Whiny 2021. 7. 20. 15:43

화면에 오브젝트를 렌더링 하려면 CPU가 많은 작업을 처리해야 합니다.

 

CPU가 하는 작업

- 광원 계산

- 셰이더, 셰이더 파라미터 설정

- 드로잉 커맨드를 그래픽 드라이브에 전송

- 커맨드가 그래픽 카드에 전송되도록 준비 

- 등등...

 

오브젝트 별 CPU 사용은 리소스를 많이 사용하는데 보이는 오브젝트가 많다면 CPU에 무리가 갈 수 있습니다.

 

예시)

1000개의 삼각형을 그릴때, 하나의 삼각형을 하나의 메시에 넣는 것(메시 1000개를 그림)보다

모든 삼각형을 하나의 메시(메시를 결합하여 1개만 그림)에 넣는 것이 CPU를 효율적으로 사용할 수 있습니다.

두 경우 GPU 코스트는 비슷함


CPU 작업량을 줄이는 방법

1. 가까이 있는 오브젝트를 수동이나 Unity의 드로우 콜 배칭을 활용해 결합

2. 큰 텍스처 아틀라스에 개별텍스처를 넣어 오브젝트의 메터리얼 수를 줄임

3. 오브젝트가 여러 번 렌더링 되는 요소(반사, 그림자, 픽셀 별 광원)를 덜 사용함

 

1번부터 하나씩 살펴봅시다.


드로우 콜 배칭

 

드로우 콜(Draw call)

- CPU가 OpenGL이나 DirectX의 함수를 호출하여 GPU에게 그리기(Draw call)을 요청하는 것

 

그래픽 API의 모든 드로우 콜은 중요 작업을 수행함으로 CPU 코스트가 크다.

Why?

드로우 콜 간에 수행되는 스테이트 변경으로 인해 그래픽 드라이버에서 리소스가 많이 사용되는 확인 및 이동 단계를 수행하기 때문

 

드로우 콜 발생조건

1. 메쉬가 여러개일때

2. 머터리얼이 여러 개일 때(얼굴, 눈)

3. 셰이더에 의한 경우(2-Pass, 외곽선을 그리고 본체 그리기)

 

드로우 콜을 줄이기 위해 게임 엔진은 배치(Batches)를 제공한다.

 

배치(Batches)

 - 드로우 콜과 많이 혼용돼서 사용하지만 드로우 콜을 포함하는 상위 개념(넓은 의미의 드로우 콜)

 - Draw Call + Set VB/IB + Set Transform + Set Pass Call (Set Shader + Set Texture 0~7 + Set Blending + Set Z enable..)

 

Set pass call

 - 머터리얼과 셰이더에 관련된 것에 대한 Batch

예시1: 머터리얼을 공유하는 오브젝트 5개

 - Batch는 5개, Set Pass Call 1개 , 총 Batch 6개

예시2: 머터리얼을 공유하지 않는 오브젝트 5개

 - Batch는 5개, Set Pass Call 5개 , 총 Batch 10개

 

따라서, 큰 텍스처 아틀라스에 개별텍스처를 넣어 오브젝트의 메터리얼 수를 줄이는 것이 중요하다.

텍스처 아틀라스 예시


배칭(Batching)

- 여러 개의 드로우 콜을 하나의 드로우 콜로 묶어서 처리하는 작업

- 동적 배칭: 메시가 충분히 작은 경우 메시의 버텍스가 CPU에서 트랜스폼되고, 유사한 메시가 그룹화되어 한꺼번에 드로우 됨

- 정적 배칭: 움직이지 않는 게임 오브젝트를 큰 메시로 합쳐서 빠른 방법으로 렌더링함

 


동적 배칭(Dynamic Batching)

 - 동일한 머터리얼을 공유하고, 특정 조건을 만족하면, 유니티에서 자동적으로 일어나는 배칭

 - 정적 배칭에비해 조건이 까다롭고 눈에 띄는 효율은 아님

 - 동일한 모델일 필요X, 작은 것들을 한번에 렌더링한다고 보면 된다.

 - 가장 많은 효과를 보는 곳은 파티클 메쉬

 - 오브젝트 버텍스를 CPU에서 월드 공간으로 변환하는 방법으로 작동하기 때문에, 이 작업이 드로우 콜을 수행하는 것보다 더 작은 경우에만 유리함

더보기

동적 배칭 조건 정리

 

1. 리소스 사용량이 버텍스마다 일정하므로, 900미만의 버텍스 속성/300개 미만의 버텍스가 포함된 메시에만 적용

 - 셰이더가 버텍스 포지션, 노멀 및 싱글 UV를 사용하면 버텍스를 300개까지 배칭 가능

 - 셰이더가 버텍스 포지션, 노멀, UV0, UV1 및 탄젠트를 사용하는 경우 180개까지 배칭 가능

 

2. 트랜스폼에 미러링이 포함된 게임 오브젝트는 배칭되지 않습니다.

 - 스케일 +1인 오브젝트A와 -1인 오브젝트B를 함께 배칭할 수 없음

 

3. 다른 머터리얼을 사용하면 같은 오브젝트도 함께 배칭되지 않습니다.

 - 섀도우 캐스터 렌더링 예외

 

4. 라이트맵이 있는 오브젝트에는 라이트맵 인덱스와 라이트맵 오프셋/스케일이라는 추가 렌더러 파라미터가 있는데, 동적 라이트맵이 적용된 오브젝트는 배칭할 라이트맵위치와 정확히 똑같은 위치를 가리켜야합니다.

 

5. 멀티 패스 셰이더는 배칭을 중단합니다.

 - 거의 모든 Unity 셰이더는 포워드 렌더링 시에 몇가지 광원을 지원하여 추가 패스를 대신 수행함

 - 픽셀당 추가 라이트에 대한 드로우 콜은 배칭 되지 않습니다.

 - 광원 프리패스(Legacy Deferred) 렌더링 경로는 오브젝트를 두번 드로우 해야하기 때문에 동적 배칭이 불가능함


정적 배칭(Static Batching)

 - 동일한 머터리얼을 공유하고, 움직이지 않는 오브젝트 모든 크기의 지오메트리에 대해 드로우 콜을 줄일 수 있다.

 - 일반적으로 동적 배칭 보다 효율적이지만 메모리를 더 많이 사용함

 - 눈에 띄는 성능 차이를 보이기 때문에, CPU 오버헤드가 크다면 사용하면 좋다.

 - 사용하려면 특정 오브젝트가 움직이지 않음(정적/ 이동,회전,스케일하지 않음)을 명시적으로 지정해야함

 - 모든 배경을 하나로 합쳐서 내보내는 경우, 화면에 일부분이 보이더라도 전체를 무조건 그리기 때문에 시야각에 들어오는 구역별로 적절히 나누는 작업이 필요하다.

인스펙터창에서 스태틱 플래그 체크


조명(Lighting) 최적화

 

라이트맵(Light map)

- 고정된 조명과 오브젝트의 경우에 라이트 맵을 최대한 활용한다. (ex. 실내 형광등)

- 픽셀당 계산하는 것보다 실행속도가 빠릅니다 / 다만 라이트맵을 bake하는 과정이 필요함

 

라이트 렌더 모드 설정

 - important / Not Important 설정

 - 동적 라이팅만 Important 설정 (ex. 손전등)