Ogre로 프로젝트를 하면서 가장 시간을 많이 들였던 충돌 처리 부분 입니다.
처음에는 물리 엔진을 써보고자 Physx , bullet, OgreODE 등 많은 물리엔진을 찾아서 사용 해보려 했지만...;;
결국 Ogre로 구현을 하게 되었습니다. ;;
게임 개발에 필요한 수학적 지식이 부족한 상황에서 검색을 하던중 directx 로 구현한 OBB 충돌 소스를 찾게 되어서
그 소스를 이용하여 Ogre에서 구현을 해봤습니다.
dx 소스는 GpgStudy 에서 참고 하였습니다.
Link에 추가 해놓으테니까 참고 하시면 좋을 것 같습니다~~
그리고 이만희님의 OBB 충돌 논문(Fast Overlap Test for OBB)
을 보시면 그래도 이해더 좀더 되 실 겁니다.
첨부 파일로 올려 놓겠습니다.(올려도 되려나??)
-소스 코드-
BOOL PlayState::centerOBB(OBBoxRenderable* OBB1, OBBoxRenderable* OBB2)
{
//box1이 이동하는 OBB / box2는 고정되어 있는 OBB
Vector3 obb1_center, obb2_center, T, LL; //box1,box2 의 각각 센터 좌표,
Real box_len, a1, a2, a3, b1, b2, b3, TL;
Matrix4 obb1_invers_mat, obb2_rotae_mat;
Matrix4 R ;
//OBB 박스의 월드 좌표??
obb1_invers_mat = OBB1->getCharMat.inverse();
obb2_rotae_mat = OBB2->getMonMat();
//box1 의 좌표계를 box2의 좌표계로 회전변환 행렬 R = RA-1 * RB(-1은 iverse)
R = obb1_invers_mat * obb2_rotae_mat;
//box의 좌표축의 normal vector x, y, z 값 (제가 이해한 내용 - 틀린 내용 일 수도 있음 ㅋ)
Vector3 obb1_size = OBB1->getWorldBoundingBox().getSize();
Vector3 obb2_size = OBB2->getWorldBoundingBox().getSize();
a1 = obb1_size.x;
a2 = obb1_size.y ;
a3 = obb1_size.z ;
b1 = obb2_size.x ;
b2 = obb2_size.y ;
b3 = obb2_size.z ;
obb1_center = OBB1->getWorldBoundingBox().getCenter();
obb2_center = OBB2->getWorldBoundingBox().getCenter();
//box1 의좌표계에서 box1 중심에서 box2의 중심으로의 이동을 나타내는 vector3
T = Vector3(obb1_center.x - obb2_center.x, obb1_center.y - obb2_center.y, obb1_center.z - obb2_center.z);
//0. LL = A1
box_len = a1 + b1 * R[0][0] + b2*R[0][1] + b3*R[0][2];
LL =Vector3(1.0f, 0.0f, 0.0f); //분할 축의 벡터
TL = T.absDotProduct(LL); //T 와 L의 내적의 절대값
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/*cout << "충돌되지 않음" << endl;*/
return 0;
}
//1. LL = A2
box_len = a2 + b1 * R[1][0] + b2*R[1][1] + b3*R[1][2];
LL = Vector3(0.0f, 1.0f, 0.0f);
TL = T.absDotProduct(LL);
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/*cout << "충돌되지 않음" << endl;*/
return 0;
}
//2. LL = A3
box_len = a3 + b1 * R[2][0] + b2*R[2][1] + b3*R[2][2];
LL = Vector3(0.0f, 0.0f, 1.0f);
TL = T.absDotProduct(LL);
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/*cout << "충돌되지 않음" << endl;*/
return 0;
}
//3. LL = RB1[R11 R21 R31]
box_len = a1*R[0][0] + a2 * R[1][0] + a3*R[2][0] + b1;
LL = Vector3(R[0][0], R[1][0], R[2][0]);
TL = T.absDotProduct(LL);
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/*cout << "충돌되지 않음" << endl;*/
return 0;
}
//4. LL = RB2[R12 R22 R32]
box_len = a1*R[0][1] + a2 * R[1][1] + a3*R[2][1] + b2;
LL = Vector3(R[0][1], R[1][1], R[2][1]);
TL = T.absDotProduct(LL);
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/*cout << "충돌되지 않음" << endl;*/
return 0;
}
//5. LL = RB3[R13 R23 R33]
box_len = a1*R[0][2] + a2 * R[1][2] + a3*R[2][2] + b3;
LL = Vector3(R[0][2], R[1][2], R[2][2]);
TL = T.absDotProduct(LL);
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/*cout << "충돌되지 않음" << endl;*/
return 0;
}
//6. LL = A1 X RB1 = [1 0 0] X [R13 R23 R33] = [ 0 -R31 R21 ]
box_len = a2*R[2][0] + a3*R[1][0] + b2*R[0][2] + b3*R[0][1];
LL = Vector3(0.0f, R[2][0], R[1][0]);
TL = T.absDotProduct(LL);
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/*cout << "충돌되지 않음" << endl;*/
return 0;
}
//7. LL = A1 X RB2 = [1 0 0] X [R12 R22 R32] = [ 0 -R32 R22 ]
box_len = a2*R[2][1] + a3*R[1][1] + b1*R[0][2] + b3*R[0][0];
LL = Vector3(0.0f, -R[2][1], R[1][1]);
TL = T.absDotProduct(LL);
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/*cout << "충돌되지 않음" << endl;*/
return 0;
}
//8. LL = A1 X RB3 = [1 0 0] X [R13 R23 R33] = [ 0 -R33 R23 ]
box_len = a2*R[2][2] + a3*R[1][2] + b1*R[0][1] + b2*R[0][0];
LL = Vector3(0.0f, -R[2][2], R[1][2]);
TL = T.absDotProduct(LL);
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/*cout << "충돌되지 않음" << endl;*/
return 0;
}
//9. LL = A2 X RB1 = [0 1 0] X [R11 R21 R31] = [R31 0 -R11]
box_len = a1*R[2][0] + a3*R[0][0] + b2*R[1][2] + b3*R[1][1];
LL = Vector3(R[2][0], 0.0f, R[0][0]);
TL = LL.absDotProduct(T);
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/*cout << "충돌되지 않음" << endl;*/
return 0;
}
//10. LL = A2 X RB2 = [0 1 0] X [R12 R22 R32] = [R32 0 -R12]
box_len = a1*R[2][1] + a3*R[0][1] + b1*R[1][2] + b3*R[1][0];
LL = Vector3(R[2][1], 0.0f, -R[0][1]);
TL = T.absDotProduct(LL);
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/*cout << "충돌되지 않음" << endl;*/
return 0;
}
//11. LL = A2 X RB3 = [0 1 0] X [R13 R23 R33] = [R33 0 -R13]
box_len = a1*R[2][2] + a3*R[0][2] + b1*R[1][1] + b2*R[1][0];
LL = Vector3(R[2][2], 0.0f, -R[0][2]);
TL = T.absDotProduct(LL);
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/* cout << "충돌되지 않음" << endl;*/
return 0;
}
//12. LL = A3 X RB1 = [0 0 1] X [R11 R21 R31] = [-R21 R11 0]
box_len = a1*R[1][0] + a2*R[0][0] + b2*R[2][2] + b3*R[2][1];
LL = Vector3(-R[1][0], R[0][0], 0.0f);
TL = T.absDotProduct(LL);
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/*cout << "충돌되지 않음" << endl;*/
return 0;
}
//13. LL = A3 X RB2 = [0 0 1] X [R12 R22 R32] = [-R22 R12 0]
box_len = a1*R[1][1] + a2*R[0][1] + b1*R[2][2] + b3*R[2][0];
LL = Vector3(-R[1][1], R[0][1], 0.0f);
TL = T.absDotProduct(LL);
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/*cout << "충돌되지 않음" << endl;*/
return 0;
}
//14. LL = A3 X RB3 = [0 0 1] X [R13 R23 R33] = [-R23 R13 0]
box_len = a1*R[1][2] + a2*R[0][2] + b1*R[2][1] + b2*R[2][0];
LL = Vector3(-R[1][2], R[0][2], 0.0f);
TL = T.absDotProduct(LL);
box_len = Math::Abs(box_len);
if(TL > box_len)
{
/* cout << "충돌되지 않음" << endl;*/
return 0;
}
//cout << "충돌!!" << endl;
return 1;
}
구현을 해서 실행을 시켜본 결과 충돌 검출은 잘 하는데 살짝 떨어져 있어도 충돌 체크를 하는 경우가 있는데,
이유는 저도 잘...ㅠㅠ 그래도 이렇게해서 충돌 체크를 한다는거에 감사할 따름입니다. ㅋㅋ
혹시 소스 자체에 수정 할 부분이 있다고 생각되시는 분은 가르침 부탁 드리겠습니다^^ㅋ
인증샷!!!!
Ps. box의 Matrix를 받아 오는 함수를 사용해서 Matrix값을 받아오게 했었는데, 값이 이상 했나 보네여 ;; 충돌 처리가 정확히 되지 않았습니다. 그래서 객체의 Entity 의_getBoneMatrices.transpose()를 사용해서 Matrix값을 받아 와서 충돌처리를 했더니 정확하게 OBB의 충돌 위치에서 멈추는 것을 확인 할 수 있었습니다.
아직 정확한 Ogre의 분석이 되지 않은 상태에서 이것 저것 해보다가 얻어 걸린 것이라서 정확하게 어떻다라는 것을 제가 말씀 드릴 수는 없을 것 같습니다. 이해해 주시길..^^;; ㅋㅋ
(소스에서 이상한점을 발견 하시거나 잘못 된 곳을 발견하시면 저에게도 살포시 알려주세요~ㅋㅋㅋ)
출처 : http://eguru.co.kr/986