(사실 이해했는지 모르겠다. 어렴풋이 느껴질 뿐... 그래도 그 느낌을 정리한다.)
1. Instancing
- 이전 챕터에서 배운 Dynamic Indexing과 Texture Array와 StructuredBuffer를 함께 이용한다.
- 똑같은 물체를 여러 개 그리기 위해, App에서 API에게 Drawcall을 여러 번 요청하는 것보다 좋은 방법이라고 한다.
- Vertex Buffer와 Index Buffer를 Input - Assembly에 걸어 놓고, DrawIndexedInstanced를 호출할 때, 두 번째 매개변수에 1 이외에 값을 넣는다면,
- Vertex Shader의 SV_InstanceID 시멘틱에서 횟수를 알려주면서 여러번 삼각형을 그리게 된다.
- 이걸 일종의 Index로 이용해서, Instance Data로 만든 Structured Buffer에 인덱스로 접근한다. Material Data Index ( + Texture Array Index), World Mat 등을 얻어서 똑같은 Geometry를 다른 속성으로 그릴 수 있게 된다.
2. Frustum Culling
- GPU에서도 frustum Culling을 자동으로 해준다. 하지만 해당 작업은 삼각형 별로 이루어지고, 결국에는 이런저런 렌더링 파이프라인 단계를 거쳐서, 삼각형을 그린 다음에 잘라낸다는 것이다.
- App 단에서 가벼운 규칙으로 Model 별로 frustum Culling을 미리 해준다면? 훨씬 가벼운 Drawcall 이 GPU에게 넘어갈 것이다.
- 이것을 해내기 위해서 DirextXMath에서 제공하는 DirectXCollision 라이브러리를 이용한다.
- Axis-Aligned-Bounding-Box / Oriented-Bounding-Box / Bounding Sphere / Frustum 등 도형으로 포함(CONTAINS) / 교차(INTERSECTS) / 분리(DISJOINT)를 판별할 수 있는 기능을 제공한다.
Directxcollision.h 헤더 - Win32 apps | Microsoft Learn
- 이를 이용해서 현재 카메라가 바라보는 Camera Frustum과 물체의 위치를 판별하여 현재 Frame에 해당 Model 혹은 Instance에 대하여 Draw Call을 걸지 판단하는 것이다.
3. App에서 해줘야 하는 것
- 인스턴싱을 할 때 필요한 Instance Data, 인스턴싱을 할 때 사용할 Material Data, Texture Array 등은 이전 예제와 마찬가지로 Root Signature를 알맞게 정의한다.
- 이전 예제와 마찬가지로 Cbv는 SetGraphicsRootConstantBufferView / Srv는 SetGraphicsRootShaderResourceView / Texture Array는 SetGraphicsRootDescriptorTable으로 Root Signature를 생성할 때 정의했던 파라미터 번호를 매개변수로 Pipeline에 설정해 준다.
- Model 혹은 Instance를 Frustum Culling을 할 때 비교할 Bounding Struct를 설정한다.
- Bounding Struct 끼리 Constains()를 호출해서 관계를 알아내기 전에, 항상 같은 좌표계로 변환을 한 다음에 판별을 해야 한다. (당연한 소리)
4. 언급할 만한 예제에서 사용한 방법(구조)
- Instance Data는 챕터에서 함께 진행한 Frustum Culling으로 프레임마다 내용이 바뀔 수 있어 Upload Buffer로 생성했다.
- 프레임 마다 내용이 바뀌기 때문에 FrameResource에서 관리를 하는데, 예제에서는 Render Item이 하나일 때를 가정하고 작성하여서, 여러 개의 Render Item을 관리하고 싶다면 더 여러 개를 소유하던가, 구조를 개선해야 할 것이다.
- 예제에서는 Camera가 바라보는 공간을 Projection Matrix로 구한 BoundingFrustum으로 생성하였다. BoundingFrustum::CreateFromMatrix()과 App이 가지고 있는 Projection Matrix로 BoundingFrustum을 편하게 생성한다.
- Model에 대해서는, AABB로 정의하였다. Geometry를 가져올 때, XMVECTOR 기능을 이용해서 편하게 각 성분별 최대 최소 값을 구해 AABB를 구한다. Instance Data를 정의할 때 AABB에 좌표변환 Matrix를 적용시켜서 BoundingBox를 채워 넣는다.
- Contains()을 호출할 좌표계는 각 Instance의 Local 좌표계에서 비교하기로 하였고, 그러므로 BoundingFrustum은 InverseViewMatrix와 각 Instance의 inverseWorld으로 변환을 해주면 된다.
5. 연습 문제
(클릭하면 커집니다.)
연습 문제 1
- BoundingBox를 BoundingSphere로 바꿔서 frustum culling을 해보는 것이다.
- 코드는 BoundingBox를 생성할 때 처럼 Center를 구하고, 그 Center를 기준으로 다시 Vertex를 루프하며 BoundingSphere를 만족하는 최소 반지름을 찾는 것이다.
연습 문제 2
- Homogenous Coordinates로 변환하는 점(백터) * 행렬을 성분별로 나눈걸 다음과 같이 정리하면, 문제와 교재에서 알려준 답이 그대로 나온다.
(어떤 도형을 나타내는 방정식이 어떤 느낌인지 모르면 이해가 잘 안될 수도?)
연습 문제 3
- Intersects 혹은 Contains을 어떤식으로 판별 하는지 간단하게 정리하... 려다가 너무 많고 한번에 알아보기 어려워서 나중에 추후에 더 공부가 필요하다고 느껴지면 그때 하도록 하겠다. ㄹㅇㅋㅋ
- BoundingSphere, BoundingSphere, BoundingBox, BoundingOrientedBox, BoundingFrustum, BoundingFrustum, Triangle, Plane, Ray, Point
연습 문제 4
- a : 교재에서 보여준 식이 r 이라면... 한쪽 방향으로 r이니까 다른 한쪽으로도 r이 또 있으니 2r일 것이다.
- b : 사영할 직교축 벡터의 각이 달라지는데... 그러면 안되지 않을까?
- c : 평면은 법선 벡터와 그 위의 한점으로 정의가 되는데... 그 법선 벡터에 사영을 했을 때 2r의 길이를 구하고, 평면과 박스 중심의 거리를 비교하면 될 것이다.
- d : 잘은 모르지만... 평면 법선벡터에서 축성분만 살리면 되니깐 요런 느낌 아닐까?
6. 메모용
- Shader에서 struct 멤버 맨 앞에 nointerpolation 키워드를 붙이면, rasterization 단계에서 삼각형을 따라 그릴 때 값이 보간 되지 않는다. Index 역할을 하는 멤버이면 해당 키워드를 이용하자.
-
'Programming > D3D12' 카테고리의 다른 글
[책공부] Cube Mapping + chap 18 연습 문제 (0) | 2024.02.26 |
---|---|
[책공부] Picking + chap 17 연습 문제 (0) | 2024.02.22 |
[책공부] Dynamic Indexing / FPS Camera + chap 15 연습 문제 (0) | 2024.02.19 |
[책공부] Tessellation + chap 14 연습 문제 (0) | 2024.02.14 |
[책공부] Compute Shader + chap 13 연습 문제 (0) | 2024.02.02 |