충돌
* Bounding Box
* 충돌을 검사하기 위해 단순한 박스 모양으로 충돌을 검사하는 것.
- 메쉬의 폴리곤 하나하나 검사하기엔 연산이 너무 많아 단순한 박스 모양이나 구, 캡슐 형태를 주로 사용한다.
AABB와 OBB의 차이
* AABB (Axis Aligned Bounding Box) : 정렬된 축의 박스끼리의 충돌이다.
* OBB (Oriented Bounding Box) : 박스와 함께 축 같이 회전한다.
AABB (Axis Aligned Bounding Box)
* 2D AABB 충돌은 두 가지를 체크하여 두 가지 모두 true여야 충돌이다.
1. 가로 체크 : 두 사각형의 중점 가로 사이의 거리 < 두 사각형의 밑변 절반의 크기 합
2. 세로 체크 : 두 사각형의 중점 세로 사이의 거리 < 두 사각형의 높이 절반의 크기 합
// vPos : 위치
// vRect : 바운딩 박스 크기
float fDistanceX = fabs( Src.vPos.x - Dst.vPos.x ); // 오브젝트 가로 거리 (절대 값)
float fRadCX = Dst.vRect.fWidth * 0.5f + Src.vRect.fWidth * 0.5f; // 밑변 절반 합
if ( fDistanceX > fRadCX) // 거리가 더 크면 충돌 안 됨
return false;
float fDistanceY = fabs( Src.vPos.y - Dst.vPos.y ); // 오브젝트 세로 거리 (절대 값)
float fRadCY = Dst.vRect.fHeight * 0.5f + Src.vRect.fHeight * 0.5f; // 높이 절반 합
if ( fDistanceY > fRadCY) // 거리가 더 크면 충돌 안 됨
return false;
// 충돌된 부분의 크기
*pCollCX = fRadCX - fDistanceX;
*pCollCY = fRadCY - fDistanceY;
return true;
OBB (Oriented Bounding Box)
* 2D OBB 충돌은 내적을 이용한 투영으로 4가지를 체크한다. 4가지 모두 true여야 충돌이다.
1. 오브젝트1 Right축 기준 투영
2. 오브젝트1 Up축 기준 투영
3. 오브젝트2 Right축 기준 투영
4. 오브젝트2 Up축 기준 투영
OBB충돌 체크를 위해 위자드오브레전드를 모작해보았다. 공격 이펙트의 충돌박스와 축이 회전하고 있다.
< 오브젝트1 Right축 투영을 기준으로 설명 >
OBB를 체크를 하기위해 총 4번의 체크를 하는데, 1번의 체크마다 4번의 내적으로 값을 구해야한다.
3번의 내적 값은 AABB에서 했던 것처럼 밑변 절받의 합을 구하기 위해 내적한다.
나머지 하나는 두 오브젝트 사이의 거리를 내적한다.
그림만 보기엔 무척 복잡하다. 하나하나 풀어서 보면
1) 첫 번째로 오브젝트1의 Right 벡터를 기준으로 잡고 이 축에 내적으로 투영을 시킬 것이다. 이 때, 기준 축 벡터는 단위벡터 (크기가 1인 벡터)여야만 한다. // Normalize
미리 Right벡터 변수를 만들어 두었다. 사람마다 다르게 구하겠지만 2번점 위치에서 1번점 위치를 빼서 Right 벡터를 구하는 방법도 있다.
2) 오브젝트1의 충돌박스 점 중 하나를 잡고 중심에서 그 점을 바라보는 벡터를 구한다. (네 점들 중 아무 점이나 상관없다. 중심에서 각 점까지의 크기가 같기때문.)
해당 점 위치벡터 - 중심 점 위치벡터를 하면 중심에서 점을 바라보는 벡터가 나온다.
3) 2번에서 구한 벡터를 Right벡터에 투영 시킨다. (내적이기 때문에 벡터 순서는 상관없다.) 내적을 하게되면 노란색부분의 크기가 나오게된다. 4번의 내적 중 1개의 값을 구했다.
4) 이제 구해야 할 것은 오브젝트2의 크기를 오브젝트1 Right축 기준으로 구해야한다.
이 노란색 크기를 구해야하는데, 그럼 점 하나 잡고 그냥 투영 시키면 내적 3번만에 OBB 체크가 끝나지않나? 라는 궁금증이 생기는데 다른 점을 기준으로 잡아보면 각 점마다 노란색의 크기가 다르게 나온다..
어느 점을 잡아야할지 모르게 때문에 오브젝트2의 Up벡터와 Right벡터를 이용한 내적을 두 번해서 아무 점이라도 같은 값이 나오게 구할 것이다.
5) 아무 점을 잡고 오브젝트 2의 Up 벡터에 투영을 시킨다. (이펙트의 축이 이상하다고 생각될 텐데 Offset을 적용시켜놔서 그러므로 신경쓰지 않아도 된다.)
그럼 이런 모양이 나온다. 이 노란색 부분을 오브젝트1 Right벡터(보라선)에 투영시켜야 하는데, 저 벡터를 구할려면 내적(투영)해서 나온 스칼라 값을 오브젝트2의 Up벡터에 곱해주면된다. (단위벡터기 때문)
6) 5에서 구한 노란 벡터를 오브젝트1 Right벡터(보라선)에 투영시켜준다.
그럼 저 노란색 크기가 나오게된다. 이로써 두 번째 값을 구했다.
7) 같은 방법으로 오브젝트 2의 Right벡터에 투영한 후 오브젝트 1의 Right벡터에 투영시킨다.
다른 점에 대해서도 같은 값이 나온다.
이제 하나의 값이 남았는데, 이 값은 AABB에서 했었던 두 중점 사이의 거리를 투영시킨 값이다.
8) 간단하다. 오브젝트 1에서 오브젝트 2를 바라보는 벡터를 구한 뒤 투영시킨다.
9) 3번, 6번, 7번에서 구한 값을들 합한 값과 8번에서 구한 값을 비교해본다. 이건 AABB와 같다. 8번 값(거리) < 3번+6번+7번 일 경우 해당 축에 대해 충돌이 true이다.
아래 스샷은 거리가 더 크므로 Right축 충돌이 false인 상태 이로써 한 축에 대한 체크를 해보았다. 나머지 세 축도 같은 방법으로 진행하면 된다.
'그래픽스 > 수학 물리' 카테고리의 다른 글
지수의 밑변환 공식, 로그의 밑변환 공식 - 개념, 유도, 적용 (0) | 2024.04.24 |
---|---|
로그(log) 계산 공식 (상용로그, 자연로그) 총정리 (0) | 2024.04.24 |
두 점 사이의 거리 구하기 (0) | 2023.09.03 |
선형 보간법 (linear, bilinear, trilinear interpolation) (0) | 2022.07.25 |
아핀 변환 Affine Transformation (0) | 2022.06.20 |