Programming/D3D12

[책공부] Picking + chap 17 연습 문제

Dorasima 2024. 2. 22. 15:32

(사실 이해했는지 모르겠다. 어렴풋이 느껴질 뿐... 그래도 그 느낌을 정리한다.)

 

1. Picking

- 화면을 마우스로 클릭해서 model을 선택하는 것을 목표로 한다.

- 마우스 입력은 Client Area의 2D 좌표로 받고, Model은 App 상에서 3D로 존재하고, 좌표계도 다르다. 

(Client Area -> World Coordinates)

 

- 아이디어는 NDC위의 점을 클릭한 것을, 원점(카메라 위치)에서 View Frustum의 Projection Screen위의 한 점으로 지나가는 반직선(Ray)으로 변환하는 것이다.

- 카메라 위치에서 Projection Screen을 지나 View Frustum을 가로지르는 반직선(Ray)과, Model의 충돌을 적절한 좌표계 변환과 + DirectXCollision 라이브러리를 이용해 판별을 해내는 것이다.

 

2. Projection Matrix과 Ray

- 카메라에서 View Frustum 안쪽으로 쏘아지는 반직선은 View Frustum 속성, 혹은 View - Projection Matrix를 이용하여 구한다. 시야각, 가로/세로 비율, NearZ(Projection Screen과의 거리)  등

- 대충 순서를 적으면

1) Projection Frustum에서 NDC로 (정확히는 Client Area를 거치는 것 까지 포함해서) 바꾸는 Viewport Transform을 역으로 해서 클릭 좌표(NDC)를 Projection Frustum로 변환된 값을 구한다.

2) View Frustum 속성(시야각, 종횡비)을 이용해서 Projection Frustum으로 어떤식으로 Ray가 뻗어나갈지 Direction을 구한다.

(교재에서는 Projection Screen위의 점 보다 비례식과 투영행렬의 성분을 이용해서 깔끔하게 정리한 식을 사용하여 Ray를 구한다.)

 

 

3. App에서 해줘야 하는 것

- 화면 클릭을 위와 같은 방법으로 Ray를 구한 다음, DirectXCollision과 적절한 좌표계 변환을 이용해서 intersection 판별을 한다.

-  교재에서는 Model의 Bounding Box 뿐만 아니라, 해당 model의 mesh의 어떤 삼각형을 클릭했는지 확인하기 위해서 VertexBuffer를 돌아다니면서 Ray - Triangle Intersection을 테스트하였다.

 

4. 언급할 만한  예제에서 사용한 방법(구조)

- 선택한 삼각형의 하이라이트를 주기 위해서, Render Item의 Visible 속성과, 새로운 Material, PSOs, RenderLayer를 설정하였다.

 

5. 연습 문제

(클릭하면 커집니다.)

 

연습문제 1

- Pick 한 Mesh 판별을 BoundingBox가 아니라 BoundingSphere로 하라는 것이다.

- 코드는 별로 달라질 게 없다.

 

연습 문제 2

- Ray와 BoundingBox의 충돌검사를 어떻게 하는지 확인해 보라는 것이다.

- 대충 DirectXCollision.ini에 있는 거를 보는데... SIMD에 익숙하지 않아서 뭔지 잘 모르겠다.

더보기

1) Box의 Center에서 Ray의 Origin으로 차이 벡터를 구한다.

2) Ray의 방향벡터가 각 축에 대해서 얼마나 평행한지 계산한다.

 

3) Ray의 방향벡터의 각 성분의 역수를 가지는 벡터를 만든다.

4) Ray의 Box 상대 좌표에서 Box의 각 축별 확장값 벡터를 뺀다.

5) 그리고 그것을 3) 번의 Ray 방향 성분 역수 벡터와 곱한다.

6) Ray의 Box 상대 좌표에서 Box의 각 축별 확장값 벡터를 더한다.

7) 그리고 그것을 3)번의 Ray 방향 성분 역수 벡터와 곱한다.

 

8) 5)와 7)벡터에서 가장 작은 축 성분 값을 골라낸다.

9) 그리고 2) 벡터를 이용해서 각 축에 대해서 평행했던 축만 성분을 골라낸다. (나머지는 모두 최솟값으로 채운다.)

10) 5)와 7)벡터에서 가장 큰 축 성분 값을 골라낸다.

11) 그리고 2) 벡터를 이용해서 각 축에 대해서 평행했던 축만 성분을 골라낸다. (나머지는 모두 최댓값으로 채운다.)

 

12)  9) 벡터에서 x,y,z 중에 가장 큰 성분을 골라낸다.

13) 11) 벡터에서 x,y,z 중에 가장 작은 성분을 골라낸다.

 

14) 12)의 결과가 13)보다 크다면 충돌이 일어나지 않은 것이다.

15) 13)의 결과가 0보다 작다면 충돌이 일어나지 않은 것이다.

16) 만약 Ray의 Vector가 기본 축에 평행하고 && 1)의 결과가 BoundingBox Extents 내부에 있지 않으면 충돌이 일어나지 않은 것이다.

 

17) 12)의 결과가 13)보다 작으면 충돌이 일어난 것이다. 해당하는 성분 값이 Ray Origin과 Bounding Box가 충돌하는 Point의 거리이다.

 

연습 문제 3

- Octree에 대해서 정리하라는 문제다.

- 이진트리 같은 그런 자료구조다. 이진트리는 선형이고, 사진(?) 트리는 평면인 듯하고, 팔진트리는 공간이다.

- 용량을 많이 쓰면 (메타데이터가 많으면, 자료구조를 이것저것) 탐색이 빠르다는 것을 이용한다.

- Model의 위치가 World에서 정해질 때, World공간을 8개로 hierarchical 하게 분리하는 것이다.

 

- 예제를 경우로 예를 들면, Ray가 쏘아졌(?)을 때 Octree 중에 하나를 맞는다.

- 그러면 그 안에서 어떤 친구가 Ray에 맞았는지 하위 Octree를 확인한다.

- 또 그 안에서 어떤 친구가 Ray에 맞았는지 하위 Octree를 확인한다.

- 이걸 Depth만큼 반복을 하다 보면 최하위 Octree에 도달하고, 얘는 Model을 진짜로 가지고 있는 친구인 것이다.

- 이제 최하위에 있는 Octree가 가진 Model들만 Ray에 맞는지 확인하면 되는 것이다.

 

6. 메모용

 

더보기

책 : DirectX 12를 이용한 3D 게임 프로그래밍 입문