[3D Programming with DirectX12] Chapter 16 : Instancing and Frustum Culling

Instancing과 Frustum Culling을 소개합니다.

해당 장에서는 인스턴싱과 절두체 컬링(Frustum Culling)을 알아본다. 전 장에서 공부했던 Dynamic Indexing도 같이 활용한다.

Hardware Instancing

게임 안에 스폰된 좀비들(주인장의 습작 게임속 화면)

게임 속에 여러 좀비들이 맵에 퍼져있다. 사실 이들은 모두 같은 오브젝트들인데, 좀비를 하나하나 그릴때마다 vertex와 index data를 만들어 사용한다면 엄청난 메모리 낭비가 될 것이다.

만약 하나의 vertex와 index정보를 저장해두고 렌더링 할 때마다 각기 다른 World Matrix와 material들을 넣어준다면 메모리를 아낄 수 있을 것이다.

사실 그럼에도 불구하고 Direct11 스타일의 Per-Object API 호출방식으로 인해 오버헤드가 발생하긴 하는데, 이전 장에서 배웠던 Dynamic Indexing을 사용해서 유연하게 성능을 올려보는게 Hardware Instancing의 목표이다.

Instance Data & Material Data

Instance Data & Material Data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct InstanceData
{
	DirectX::XMFLOAT4X4 World = MathHelper::Identity4x4();
	DirectX::XMFLOAT4X4 TexTransform = MathHelper::Identity4x4();
	UINT MaterialIndex;
	UINT InstancePad0;
	UINT InstancePad1;
	UINT InstancePad2;
};

struct MaterialData
{
	DirectX::XMFLOAT4 DiffuseAlbedo = { 1.0f, 1.0f, 1.0f, 1.0f };
	DirectX::XMFLOAT3 FresnelR0 = { 0.01f, 0.01f, 0.01f };
	float Roughness = 64.0f;

	// Used in texture mapping.
	DirectX::XMFLOAT4X4 MatTransform = MathHelper::Identity4x4();

	UINT DiffuseMapIndex = 0;
	UINT MaterialPad0;
	UINT MaterialPad1;
	UINT MaterialPad2;
};

해당 구조체 안에는 Vertex 이외에 필요한 정보들이 들어있다. Instance Data에는 오브젝트의 월드행렬, 텍스처 좌표, Material 인덱스가 들어있고, Material Data에는 material 정보가 들어있는데 여기에 이전에 사용했던 Dynamic Indexing이 사용된다.

Instancing 예시

Instancing을 적용하게 되면 불필요한 DrawCall을 줄일 수 있어 성능을 향상시킬 수 있다.


Frustum Culling(절두체 컬링)

차근차근 천천히 가보자

Frustum Culling은 카메라 시점에 보이지 않는 물체들을 잘라내는 과정이다. 게임 성능을 위해 이 과정은 필수적인데, 구현 과정 설명을 위한 설명을 위한 설명을 해야하기 때문에 차근차근 가보자.

Bounding Volumes

컴퓨터에서는 물체가 다른 물체랑 부딪히는걸 어떻게 알까? 간단하게 생각해보면 서로 표면이 겹치는 순간 부딪힌 것으로 판단하면 될 것이다.

Unity Collider 예시

그런데 3D 물체의 표면은 많으면 수만개의 폴리곤으로 이루어져있으므로 이것을 일일히 겹치는지 계산하는것은 말이 안된다. Unity 기능중 Collider를 보면 상대적으로 단순한 Cube, sphere, Cylinder 같은 도형들로만 동적 충돌 처리를 할 수 있는데 이것이 그 이유이다.

Box Volume & Sphere Volume

복잡한 물체의 충돌처리(표면 계산)을 위해서 간단한 도형으로 근사한 것을 Bounding Volume이라고 한다. 이번 장에서는 Cube와 Sphere 두 가지 Bounding을 알아볼 것이다.

Boxes

상자 모양의 volume을 만드는 방법은 크게 두 가지인데, 첫 번째는 AABB(Axis Aligned Bounding Box)이다.

AABB 설명 사진

좌표계 안에 위치한 vertex들의 최대/최소를 구해서 \(\mathbf{V_min} , \mathbf{V_max}\)를 구한다. 이 두 개의 점으로 만든 직육면체가 AABB이다.’

AABB OBB비교

사실 AABB는 실제 물체의 크기와 괴리가 있는 경우가 있다. 물체가 한 방향으로 튀어나와있는 경우에 끝의 vertex를 포함하기 때문이다. 그래서 나온 것이 OBB(Oriented Bounding Box)이다.

OBB는 원점 좌표와 extent 좌표, 회전 각을 가지고 있어서 로컬 축과 평행하지 않고 도형에 맞춘 Bounding box를 가질 수 있다.

Sphere

구 모양의 volume또한 크게 다르지 않다. 모든 vertex의 평균을 내서 중심점을 구하고, 가장 멀리 떨어진 vertex의 거리를 반지름으로 하는 구를 만들면 끝이다.

Frustum(절두체)

frustum

다음으로는 5장에서 소개했던 Frustum에 대해 알아보자. 간단하게 시야 범위를 나타내는 역할을 한다. 총 6면체로 되어있고 x축을 중심으로 left, right, y축을 중심으로 top, bottom, z축을 중심으로 near, far로 각 면을 부른다. 우리가 원근 투영을 선택한다고 할 때 해당 6면체 안에 위치하지 않은 오브젝트들은 화면에 보이지 않을 것이다.

Frustum Intersection

그렇다면 절두체와 Bounding Volume(앞서 설명한 Box와 Sphere)이 교차하는지 어떻게 알 수 있을까?

frustum/sphere Intersection

먼저 sphere의 경우 중심으로부터 평면까지의 거리 \(\mathbf{d}\)를 구한 후 \(\mathbf{r}\)과 비교했을 때, \(\mathbf{-d < r < d}\) 이면 해당 평면과 구가 교차하지 않는 것이다. 6개의 면에 대해서 모두 교차하지 않고 안에 위치하면 해당 구가 절두체 안에 있는 것으로 볼 수 있다.

frustum/box Intersection

박스에 경우에는 먼저, 평면의 법선과 가장 평행하면서 물체의 중앙을 지나는 벡터를 정한다. 사진에 경우에는 법선 방향으로 가장 멀리 있는 꼭짓점 \(\mathbf{P}\)와 가장 가까운 꼭짓점 \(\mathbf{Q}\)를 구하면, 선분 \(\overline{PQ}\)가 그 역할을 한다. 이 선분을 기준으로 P가 평면의 양의 방향에 있고 Q가 음의 방향에 있으면 박스가 해당 평면과 교차한다고 판단할 수 있다.

frustum culling

이제야 원래의 목적에 도달했다. 이제 frustum과 교차하거나 안에 있는 오브젝트들은 그리되, 밖에 있는 오브젝트들은 과감히 없애는 것을 통해 성능을 향상시킬 수 있고 이것을 frustum culling이라고 한다. 이것은 CPU단에서 일어나고 따라서 InstanceData 메모리를 아낄 수도 있다.

Demo 소개

이번 장의 연습문제는 실습 대신 간단한 수학 증명문제들로 이루어져있어서 따로 소개하지 않는대신 Demo를 간단하게 소개하며 글을 마치겠다. 여러가지 머터리얼을 사용하는 해골들과 1인칭 카메라이동으로 구성되어있다.

Demo.gif
태그
← [3D Programming with DirectX12] Chapter 15 : Building a first Person Camera and Dynamic indexing [3D Programming with DirectX12] Chapter 17 : Picking →