포스트

드로우 콜

드로우 콜과 배칭을 이해한다면 게임의 최적화와 CPU 병목 현상을 줄일 수 있습니다.

드로우 콜

드로우 콜이란 CPU가 GPU에게 오브젝트를 렌더링을 지시하는 명령을 말한다.
GPU는 독립적으로 작업을 수행하고 있다. 그래서 CPU의 명령을 바로 처리할 수 없다.
따라서 드로우 콜과 같은 CPU의 명령은 커맨드 버퍼에 저장되었다가 GPU가 현재 작업을 완료한 시점에 전달된다.


드로우 콜 호출 시 CPU에서 GPU로 메시, 셰이더, 트랜스폼, 알파 블랜딩의 여부 등 다양한 데이터를 전달해야 한다.
이 정보들을 그래픽스 칩셋에 맞는 신호로 전달해야 하는데 이를 DirectX와 같은 그래픽스 API가 수행한다.

신호 변환에 걸리는 시간은 CPU 경계의 오버헤드다.
즉, GPU보다 CPU 성능에 영향을 받는다.

따라서 CPU 경계에서 병목 현상이 발생하면 드로우 콜의 횟수를 살펴보는 것이 좋다.



컬링

컬링뷰 바깥으로 벗어난 오브젝트를 렌더링 대상에서 제외하는 연산이다.

렌더링 대상의 수를 줄이기 때문에 드로우 콜 감소 효과가 있다.
렌더링 시간 자체도 줄어들기 때문에 컬링은 중요하다.

컬링에는 백페이스 컬링, 절두체 컬링, 오클루전 컬링이 있다.


백페이스 컬링

백페이스 컬링은 3D 오브젝트에서 뒷면을 렌더링하지 않는 방법이다.

모든 폴리곤은 전면과 후면을 가진다.
하지만 카메라에 보이는 것은 전면뿐이므로 후면은 렌더링하지 않는다.

백페이스 컬링의 효과로 폴리곤의 수를 감소시킬 수 있다.


절두체 컬링

절두체 컬링은 카메라 뷰의 절두체를 기준으로 절두체 바깥에 위치한 오브젝트를 렌더링하지 않는 방법이다.

카메라와 가까운 절두체 면을 근거리 클리핑 평면, 카메라와 먼 절두체 면을 원거리 클리핑 평면이라고 한다.

이미지를 보면 절두체 바깥에 위치한 원통형 메시와 캡슐형 메시는 렌더링되지 않는 것을 확인할 수 있다.

절두체 컬링은 기본적인 컬링으로 대부분의 게임 엔진에서 자동으로 수행해준다.


오클루전 컬링

오클루전 컬링은 오브젝트에 가려진 오브젝트를 렌더링하지 않는 방법이다.
가리는 오브젝트를 오클루더, 가려지는 오브젝트를 오클루디라고 한다.

오클루더의 정보는 사전에 미리 연산해둬야 하고 occluder static 오브젝트만이 오클루더가 될 수 있다.

유니티에서는 window-Rendering-Occlusion Culling에서 Bake를 실행하여 사전에 필요한 연산을 수행하고, 오클루전 컬링을 적용할 수 있다.

오클루전 컬링을 적용하면 오클루더에 가려지는 오클루디를 렌더링 대상에서 제외함으로서 드로우콜이 감소하는 효과를 얻는다.


LOD(Level Of Detail)

LOD는 오브젝트의 디테일을 레벨에 따라 다르게 표현하는 방식이다.

뷰 절두체 내에 있는 오브젝트라도 카메라에서 멀어져 화면 상에 차지하는 비중이 없다면 오브젝트 자체를 컬링시키는 수단으로 사용할 수도 있다.

다음은 빨간 구 메시에 LOD Group 컴포넌트를 부착하고 카메라에 차지하는 비율이 20% 미만이면 컬링되도록 설정한 이미지다.

LOD는 오브젝트마다 직접 적용해야 해서 절두체 컬링이나 오클루전 컬링과 같은 근본적인 최적화 해결책이 되기엔 어렵다.

오클루전 컬링은 건물 내부에서 효과적이라면 LOD는 탁 트인 맵에서 매우 효과적이다.



배칭

여러 배치를 묶어서 하나의 배치를 만드는 것을 배칭이라고 한다.
쉽게 설명하면 여러 드로우 콜을 묶어서 하나의 드로우 콜로 만든다.

다른 메시를 사용하더라도 머티리얼이 동일하다면 하나의 배치로 구성할 수 있다.
즉, 배칭을 하기 위해서는 하나의 머티리얼을 여러 메시가 공유해서 사용해야 한다.


정적 배칭

정적 오브젝트를 위한 배칭 기법이다. 배경 오브젝트들이 일반적으로 정적 오브젝트에 해당한다.

정적 배칭을 적용하기 위해서는 인스펙터에서 static을 체크해야 한다.
이를 통해 정적 오브젝트가 되어 정적 배칭의 대상이 된다.

런타임에 수행할 정점 연산이 없기 때문에 아래에 설명하는 동적 배칭보다 훨씬 효율적이다.

정적 배칭을 하게 되면 여러 메시를 합쳐서 내부적으로 하나의 메시로 만들게 된다.
이 메시를 위한 메모리가 추가로 필요하다. 메모리를 희생하면서 드로우 콜을 줄이는 셈이다.


동적 배칭

동적 배칭은 정적 오브젝트가 아닌 경우 동일한 머티리얼을 사용하는 메시에 한해서 적용할 수 있다.

동적 배칭을 사용하기 위해서는 인스펙터에서 Dynamic Batching을 체크해야 한다.

매 프레임, 씬에서 동적 오브젝트들의 정점을 모아서 합치는 과정이 있다.
모은 정점들을 동적 배칭에 쓰이는 정점 버퍼와 인덱스 버퍼에 담으면 GPU가 이를 렌더링한다.

즉, 매번 데이터 구축과 갱신이 발생하기 때문에 매 프레임마다 오버헤드가 발생한다.

일반적으로는 정점 쉐이더에서 월드 공간으로 변환하는 과정이 GPU에서 일어난다.
동적 배칭을 사용하게 되면 정점 쉐이더에서 월드 공간으로 변환하는 과정이 CPU에서 일어난다.
따라서 이 연산 과정이 드로우 콜보다 오래 걸린다면 동적 배칭을 사용하는 것이 역효과를 가져온다.


GPU 인스턴싱

인스턴싱이란 동일한 메시의 복사본을 만드는 작업이다.
한 번의 드로우 콜로 여러 메시의 복사본을 렌더링한다는 점은 배칭과 동일하다.

배칭은 CPU에서 지오메트리 정보를 연산해 합친 메시를 새로 생성하고 이를 GPU에 전달한다.
GPU 인스턴싱은 단순히 인스턴싱 되는 메시들의 트랜스폼 정보를 별도의 버퍼에 저장한다.
GPU는 이 버퍼와 원본 메시를 가져다 여러 오브젝트들을 한 번에 처리해서 렌더링한다.

인스턴싱 처리를 GPU에서 처리하기 때문에 GPU에서 메시를 재구성하는 오버헤드나 메모리 측면에서 이점이 있다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.