Collision With Ray
Triangle and Ray
코드
설명
DirectX 예제에 코드 가 유명한 것으로 알고 있다. 위 코드는 그건 아니고 어디서 본 코드를 약간 변형한 것이다. 이 방법은 koreascience 에서 제안한 것처럼 uv 체크만 바꿔서 평행사변형 충돌 체크로 확장 할 수도 있다.
다른 파라미터는 직관적인데 farT
는 설명이 필요하다. 이는 반직선의 길이를 의미하며(그래서 엄밀하게는 반직선이 아니다) 가장 가까운 면을 찾을 때 이 값을 업데이트 하며 사용하면 된다.
평면과의 교점
normal
이 만드는 평면과 ray_pos
에서 ray_dir
방향의 반직선과의 교점을 계산한다. 교점계산은 평면에 반직선을 투영시켜서 구하며 식은 다음과 같다.
이때 분모가 0 이되면 안되는데, normal
과 ray_dir
이 평행한 경우에 해당한다. 이를 첫번째 분기에서 체크한다.
ray_pos
에서 시작하는 선은 뒤로가면 안되므로 \(\vec{\mathrm{RayDir}}\) 의 계수가 양수가 되어야한다. 또한 그 길이가 farT
보다 작아야한다. 이를 두번째 분기에서 체크한다.
삼각형 내부 판별
\(\mathrm{A} = \begin{bmatrix} \vec{v_{10} } & \vec{v_{20}} \end{bmatrix}\) 이고, \(\vec{hv_0} = \mathrm{HitPos} - \mathrm{v}_0\) 라고하자. 그러면 \(u\), \(v\) 는 다음의 식으로 표현할 수 있다.
\[\mathrm{A} \begin{bmatrix} u \\ v \end{bmatrix} = \vec{hv_0}\]이때 \(\mathrm{A}\) 의 Rank 가 2 이므로 Left Inverse 를 사용해 위 식을 풀 수 있다.
\[\begin{multline} \begin{bmatrix} u \\ v \end{bmatrix} = (\mathrm{A}^T \mathrm{A})^{-1} \mathrm{A}^T \vec{hv_0} = \begin{bmatrix} \vec{v_{10} } \cdot \vec{v_{10}} & \vec{v_{10} } \cdot \vec{v_{20}} \\ \vec{v_{20} } \cdot \vec{v_{10}} & \vec{v_{20} } \cdot \vec{v_{20}} \\ \end{bmatrix} ^{-1} \begin{bmatrix} \vec{v_{10} } \\ \vec{v_{20} } \\ \end{bmatrix} \vec{hv_0} \\ \\ \shoveleft = \cfrac {1} { \vec{v_{10} } \cdot \vec{v_{10}} \times \vec{v_{20} } \cdot \vec{v_{20}} - \vec{v_{10} } \cdot \vec{v_{20}} \times \vec{v_{20} } \cdot \vec{v_{10}} } \begin{bmatrix} \vec{v_{20} } \cdot \vec{v_{20}} & -\vec{v_{10} } \cdot \vec{v_{20}} \\ -\vec{v_{20} } \cdot \vec{v_{10}} & \vec{v_{10} } \cdot \vec{v_{10}} \\ \end{bmatrix} \begin{bmatrix} \vec{v_{10} } \cdot \vec{hv_0} \\ \vec{v_{20} } \cdot \vec{hv_0} \\ \end{bmatrix} \end{multline}\]이렇게 구한 \(u\), \(v\) 를 가지고 삼각형 내부에 점이 있는지 판단하는 방법을 사용하면 된다.
Box and Ray
Kay-Kajiya test (Slab Test)
코드
설명
RealTime Rending 2ed 에서 소개하는 3가지 방법 중 첫번째로 많이 알려져 있다.
우선 두가지 개념을 정의한다.
- 충돌체크할 박스의 면을 연장시켜서 만든 영역을 Slab 라 하자. (위 그림의 십자가 영역)
- 박스는 서로 평행한 면이 한쌍씩 있는데, 각각에 겹치는 위치를
RayPos
부터의 길이를 기준으로MinValue
,MaxValue
라고 부르자.
전략은 Slab 과 Ray 가 겹치는 구간을 확인하는 것이다. 만약 박스와 충돌한다면 위 그림처럼 MinValue
들은 MaxValue
들보다 작게 된다. 이를 체크하는 것이 요지이다.
Slab
그럼 어떻게 Slab 과 Ray 간의 교점을 구할까? 사실 교점까지 구할 필요는 없고 RayPos
부터 교점까지의 길이만 구하면 된다. 그래서 OBB 처럼 Projection 을 응용하면 된다.
우선 RayPos
부터 Box 의 Center 까지의 벡터를 구하고, 이를 Box 를 이루는 면에 투영한 길이를 구한다(내적으로 간단히 구해진다). 여기서 박스의 Size
를 더하고 빼면 Slab 을 이루는 두 면이 투영된 길이가 된다. (위 그림의 빨간선이 이를 나타내는 보조선이다.)
이 길이는 삼각형의 닮을을 사용해서 RayDir
상의 길이로 바꿀 수 있다. RayDir
의 길이는 1
이므로 RayDir
을 Box 에 면에 투영한 길이를 나누면 된다.
만약 RayDir
과 면이 수직하다면 Box 의 Size
와 Center 까지의 벡터가 투영된 길이를 비교하면 된다. Size
보다 작야아지 박스 안에 있게된다.
댓글남기기