|
衝突判定を行う各オブジェクトのOBBをOBB1とOBB2とし、それぞれ次のような構造体で管理することにします。
struct TOBB{
D3DXVECTOR3 m_vec3Center;
D3DXVECTOR3 m_vec3Size;
D3DXQUATERNION m_qPosture;
D3DXVECTOR3 m_vec3WorldCenter;
D3DXQUATERNION m_qWorldPosture;
};
TOBB OBB1;
TOBB OBB2;
まずは、計算しやすいように、OBB2の中心座標をOBB1の座標系へ変換します。
D3DXVECTOR3 vec3OBB2Center;
D3DXQUATERNION qInversePosture;
D3DXMATRIX matPosture;
vec3OBB2Center = (OBB2.m_vec3Center + OBB2.m_vec3WorldCenter)
- (OBB1.m_vec3Center + OBB1.m_vec3WorldCenter);
D3DXQuaternionInverse(&qInversePosture, &(OBB1.m_qPosture * OBB1.m_qWorldPosture));
D3DXMatrixRotationQuaternion(&matPosture, &qInversePosture);
D3DXVec3TransformCoord(&vec3OBB2Center, &vec3OBB2Center, &matPosture);
中心座標の変換ができたら、次はOBB2の各軸もOBB1の座標系に変換します。
D3DXVECTOR3 avec3OBB1Axis[3] = {
D3DXVECTOR3(1.0f, 0.0f, 0.0f),
D3DXVECTOR3(0.0f, 1.0f, 0.0f),
D3DXVECTOR3(0.0f, 0.0f, 1.0f)
};
D3DXVECTOR3 avec3OBB2Axis[3];
D3DXMatrixRotationQuaternion(&matPosture, &(OBB2.m_qPosture * OBB2.m_qWorldPosture * qInversePosture));
D3DXVec3TransformCoord(&avec3OBB2Axis[0], &avec3OBB1Axis[0], &matPosture);
D3DXVec3TransformCoord(&avec3OBB2Axis[1], &avec3OBB1Axis[1], &matPosture);
D3DXVec3TransformCoord(&avec3OBB2Axis[2], &avec3OBB1Axis[2], &matPosture);
OBB2の中心座標と各軸を、OBB1の座標系に変換できたら、いよいよ衝突判定に移ります。
衝突判定は、OBB1とOBB2の各軸を分離軸として、それぞれの分離軸に射影する事で衝突を判定します。
まずは、OBB1の軸を分離軸としてチェックします。
コードを短くするために、ループで処理していますが、実際にはOBB1の座標系で計算してるので、
fProjectOBB1の計算は無駄が多いです。
実際の射影は、OBB1.m_vec3Size.xがOBB1のX軸を分離軸としてみた場合の射影の大きさで、
OBB1.m_vec3Size.yがY軸を分離軸とした場合、OBB1.m_vec3Size.zがZ軸を分離軸とした場合の大きさになります。
float fProjectOBB1;
float fProjectOBB2;
float fProjectOBB1OBB2Center;
for(int i = 0; i <= 2; ++i){
fProjectOBB1 = fabsf(D3DXVec3Dot(&avec3OBB1Axis[i], &(avec3OBB1Axis[0] * OBB1.m_vec3Size.x)))
+ fabsf(D3DXVec3Dot(&avec3OBB1Axis[i], &(avec3OBB1Axis[1] * OBB1.m_vec3Size.y)))
+ fabsf(D3DXVec3Dot(&avec3OBB1Axis[i], &(avec3OBB1Axis[2] * OBB1.m_vec3Size.z)));
fProjectOBB2 = fabsf(D3DXVec3Dot(&avec3OBB1Axis[i], &(avec3OBB2Axis[0] * OBB2.m_vec3Size.x)))
+ fabsf(D3DXVec3Dot(&avec3OBB1Axis[i], &(avec3OBB2Axis[1] * OBB2.m_vec3Size.y)))
+ fabsf(D3DXVec3Dot(&avec3OBB1Axis[i], &(avec3OBB2Axis[2] * OBB2.m_vec3Size.z)));
fProjectOBB1OBB2Center = fabsf(D3DXVec3Dot(&avec3OBB1Axis[i], &vec3OBB2Center));
if(fProjectOBB1OBB2Center > fProjectOBB1 + fProjectOBB2){
break;
}
}
このチェックは具体的には、図3のようにOBB1のある軸に着目すると、
OBB1の対象軸の大きさ(薄い赤の線の射影でProjOBB1とします)と、
OBB2の軸をOBB1の対象軸に射影した大きさ(薄い緑の線の射影でProjOBB2とします)の合計が、
OBB1の中心からOBB2の中心までのベクトルをOBB1の対象軸に射影した大きさ(薄い青の線の射影でProjOBB2Centerとします)以上なら、
OBB同士は衝突している可能性があり、小さければ衝突していない事になります(以下のコード参照)。
if(ProjOBB1 + ProjOBB2 >= ProjOBB2Center){
}
else{
}

(図3)
もちろん、ひとつの軸に対して衝突の可能性がある事がわかっても、完全に衝突しているかどうかわからないので、
これをOBB1とOBB2の各軸を分離軸として全て調べる必要があります。
すべての分離軸に対して、このチェックがパスされれば、OBB同士は衝突している事になります。
同様にして、今度はOBB2の軸を分離軸として調べます。
for(int i = 0; i <= 2; ++i){
fProjectOBB1 = fabsf(D3DXVec3Dot(&avec3OBB2Axis[i], &(avec3OBB1Axis[0] * OBB1.m_vec3Size.x)))
+ fabsf(D3DXVec3Dot(&avec3OBB2Axis[i], &(avec3OBB1Axis[1] * OBB1.m_vec3Size.y)))
+ fabsf(D3DXVec3Dot(&avec3OBB2Axis[i], &(avec3OBB1Axis[2] * OBB1.m_vec3Size.z)));
fProjectOBB2 = fabsf(D3DXVec3Dot(&avec3OBB2Axis[i], &(avec3OBB2Axis[0] * OBB2.m_vec3Size.x)))
+ fabsf(D3DXVec3Dot(&avec3OBB2Axis[i], &(avec3OBB2Axis[1] * OBB2.m_vec3Size.y)))
+ fabsf(D3DXVec3Dot(&avec3OBB2Axis[i], &(avec3OBB2Axis[2] * OBB2.m_vec3Size.z)));
fProjectOBB1OBB2Center = fabsf(D3DXVec3Dot(&avec3OBB2Axis[i], &vec3OBB2Center));
if(fProjectOBB1OBB2Center > fProjectOBB1 + fProjectOBB2){
break;
}
}
最後に、OBB1とOBB2の各軸に直交する軸を分離軸としてチェックします。
D3DXVECTOR3 vec3CrossAxis;
for(int i = 0; i <= 8; ++i){
D3DXVec3Cross(&vec3CrossAxis, &avec3OBB1Axis[i / 3], &avec3OBB2Axis[i % 3]);
D3DXVec3Normalize(&vec3CrossAxis, &vec3CrossAxis);
fProjectOBB1 = fabsf(D3DXVec3Dot(&vec3CrossAxis, &(avec3OBB1Axis[0] * OBB1.m_vec3Size.x))) +
fabsf(D3DXVec3Dot(&vec3CrossAxis, &(avec3OBB1Axis[1] * OBB1.m_vec3Size.y))) +
fabsf(D3DXVec3Dot(&vec3CrossAxis, &(avec3OBB1Axis[2] * OBB1.m_vec3Size.z)));
fProjectOBB2 = fabsf(D3DXVec3Dot(&vec3CrossAxis, &(avec3OBB2Axis[0] * OBB2.m_vec3Size.x))) +
fabsf(D3DXVec3Dot(&vec3CrossAxis, &(avec3OBB2Axis[1] * OBB2.m_vec3Size.y))) +
fabsf(D3DXVec3Dot(&vec3CrossAxis, &(avec3OBB2Axis[2] * OBB2.m_vec3Size.z)));
fProjectOBB1OBB2Center = fabsf(D3DXVec3Dot(&vec3CrossAxis, &vec3OBB2Center));
if(fProjectOBB1OBB2Center > fProjectOBB1 + fProjectOBB2){
break;
}
}
以上全部で15のチェック全てをパスした場合、OBB同士は衝突しているという事になります。
|