3D有向包围盒与球体碰撞的算法
之前发的小游戏滚蛋躲方块中,用它来判断球体与立方体是否发生了碰撞.
http://www.cnblogs.com/WhyEngine/p/3350012.html
现在发布下该算法:
有向包围盒OBB,是有旋转变化的包围盒,由三种数据组成:
obbCenter表示包围盒的中心位置
obbAxes[3]表示包围盒XYZ三个坐标轴方向上的朝向,应该是正交的,否则意思着立方体有扭曲变形.并且应该是单位向量.
halfExtents表示包围盒三个方向上的长度.
该算法是多年前,已经不记得从什么地方找的了,自己又做了点修改.该代码其实可以更加简化一些,因为原代码中是可以计算球与包围盒的碰撞深度与碰撞的法线方向的.而这里只需要返回TRUE或FALSE即可.
算法的原理比较容易理解:判断球心到包围盒三个坐标轴的投影距离是否小于该轴的长度加上球的半径.如果三个轴都符合,则表示有碰撞.
该算法的基础是判断空间中一点是否在包围盒内部.
1 bool ObbSphereCollisionDetect(const Vector3& obbCenter, 2 const Vector3 obbAxes[3], 3 const Vector3& halfExtents, 4 const Vector3& sphereCenter, 5 float sphereRadius) 6 { 7 Vector3 kDiff = sphereCenter - obbCenter; 8 9 float fSide[3] = { 1.0f, 1.0f, 1.0f }; 10 float fS[3] = { 0.0f, 0.0f, 0.0f }; 11 float fD = 0.0f; 12 13 if (D3DXVec3Dot(&kDiff, &obbAxes[0]) < 0.0f) 14 { 15 fS[0] = D3DXVec3Dot(&( sphereCenter - ( obbCenter - ( obbAxes[0] * halfExtents.x ) ) ), &obbAxes[0]); 16 17 if (fS[0] <= -sphereRadius) 18 return false; 19 20 else if (fS[0] < 0.0f) 21 fD += fS[0] * fS[0]; 22 23 fS[0] += sphereRadius; 24 } 25 else 26 { 27 fS[0] = D3DXVec3Dot(&( ( obbCenter + ( obbAxes[0] * halfExtents.x ) ) - sphereCenter ), &obbAxes[0]); 28 29 if (fS[0] <= -sphereRadius) 30 return false; 31 32 else if (fS[0] < 0.0f) 33 fD += fS[0] * fS[0]; 34 35 fS[0] += sphereRadius; 36 fSide[0] = -1.0f; 37 } 38 39 if (D3DXVec3Dot(&kDiff, &obbAxes[1]) < 0.0f) 40 { 41 fS[1] = D3DXVec3Dot(&( sphereCenter - ( obbCenter - ( obbAxes[1] * halfExtents.y ) ) ), &obbAxes[1]); 42 43 if (fS[1] <= -sphereRadius) 44 return false; 45 46 else if (fS[1] < 0.0f) 47 fD += fS[1] * fS[1]; 48 49 fS[1] += sphereRadius; 50 } 51 else 52 { 53 fS[1] = D3DXVec3Dot(&( ( obbCenter + ( obbAxes[1] * halfExtents.y ) ) - sphereCenter ), &obbAxes[1]); 54 55 if (fS[1] <= -sphereRadius) 56 return false; 57 58 else if (fS[1] < 0.0f) 59 fD += fS[1] * fS[1]; 60 61 fS[1] += sphereRadius; 62 fSide[1] = -1.0f; 63 } 64 65 if (D3DXVec3Dot(&kDiff, &obbAxes[2]) < 0.0f) 66 { 67 fS[2] = D3DXVec3Dot(&( sphereCenter - ( obbCenter - ( obbAxes[2] * halfExtents.z ) ) ), &obbAxes[2]); 68 69 if (fS[2] <= -sphereRadius) 70 return false; 71 72 else if (fS[2] < 0.0f) 73 fD += fS[2] * fS[2]; 74 75 fS[2] += sphereRadius; 76 } 77 else 78 { 79 fS[2] = D3DXVec3Dot(&( ( obbCenter + ( obbAxes[2] * halfExtents.z ) ) - sphereCenter ), &obbAxes[2]); 80 81 if (fS[2] <= -sphereRadius) 82 return false; 83 84 else if (fS[2] < 0.0f) 85 fD += fS[2] * fS[2]; 86 87 fS[2] += sphereRadius; 88 fSide[2] = -1.0f; 89 } 90 91 return (fD <= ( sphereRadius * sphereRadius )); 92 }