00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "btSphereBoxCollisionAlgorithm.h"
00017 #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
00018 #include "BulletCollision/CollisionShapes/btSphereShape.h"
00019 #include "BulletCollision/CollisionShapes/btBoxShape.h"
00020 #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
00021
00022
00023 btSphereBoxCollisionAlgorithm::btSphereBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped)
00024 : btActivatingCollisionAlgorithm(ci,col0,col1),
00025 m_ownManifold(false),
00026 m_manifoldPtr(mf),
00027 m_isSwapped(isSwapped)
00028 {
00029 btCollisionObject* sphereObj = m_isSwapped? col1 : col0;
00030 btCollisionObject* boxObj = m_isSwapped? col0 : col1;
00031
00032 if (!m_manifoldPtr && m_dispatcher->needsCollision(sphereObj,boxObj))
00033 {
00034 m_manifoldPtr = m_dispatcher->getNewManifold(sphereObj,boxObj);
00035 m_ownManifold = true;
00036 }
00037 }
00038
00039
00040 btSphereBoxCollisionAlgorithm::~btSphereBoxCollisionAlgorithm()
00041 {
00042 if (m_ownManifold)
00043 {
00044 if (m_manifoldPtr)
00045 m_dispatcher->releaseManifold(m_manifoldPtr);
00046 }
00047 }
00048
00049
00050
00051 void btSphereBoxCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
00052 {
00053 (void)dispatchInfo;
00054 (void)resultOut;
00055 if (!m_manifoldPtr)
00056 return;
00057
00058 btCollisionObject* sphereObj = m_isSwapped? body1 : body0;
00059 btCollisionObject* boxObj = m_isSwapped? body0 : body1;
00060
00061
00062 btSphereShape* sphere0 = (btSphereShape*)sphereObj->getCollisionShape();
00063
00064 btVector3 normalOnSurfaceB;
00065 btVector3 pOnBox,pOnSphere;
00066 btVector3 sphereCenter = sphereObj->getWorldTransform().getOrigin();
00067 btScalar radius = sphere0->getRadius();
00068
00069 btScalar dist = getSphereDistance(boxObj,pOnBox,pOnSphere,sphereCenter,radius);
00070
00071 resultOut->setPersistentManifold(m_manifoldPtr);
00072
00073 if (dist < SIMD_EPSILON)
00074 {
00075 btVector3 normalOnSurfaceB = (pOnBox- pOnSphere).normalize();
00076
00078
00079 resultOut->addContactPoint(normalOnSurfaceB,pOnBox,dist);
00080
00081 }
00082
00083 if (m_ownManifold)
00084 {
00085 if (m_manifoldPtr->getNumContacts())
00086 {
00087 resultOut->refreshContactPoints();
00088 }
00089 }
00090
00091 }
00092
00093 btScalar btSphereBoxCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
00094 {
00095 (void)resultOut;
00096 (void)dispatchInfo;
00097 (void)col0;
00098 (void)col1;
00099
00100
00101 return btScalar(1.);
00102 }
00103
00104
00105 btScalar btSphereBoxCollisionAlgorithm::getSphereDistance(btCollisionObject* boxObj, btVector3& pointOnBox, btVector3& v3PointOnSphere, const btVector3& sphereCenter, btScalar fRadius )
00106 {
00107
00108 btScalar margins;
00109 btVector3 bounds[2];
00110 btBoxShape* boxShape= (btBoxShape*)boxObj->getCollisionShape();
00111
00112 bounds[0] = -boxShape->getHalfExtentsWithoutMargin();
00113 bounds[1] = boxShape->getHalfExtentsWithoutMargin();
00114
00115 margins = boxShape->getMargin();
00116
00117 const btTransform& m44T = boxObj->getWorldTransform();
00118
00119 btVector3 boundsVec[2];
00120 btScalar fPenetration;
00121
00122 boundsVec[0] = bounds[0];
00123 boundsVec[1] = bounds[1];
00124
00125 btVector3 marginsVec( margins, margins, margins );
00126
00127
00128 bounds[0] += marginsVec;
00129 bounds[1] -= marginsVec;
00130
00132
00133 btVector3 tmp, prel, n[6], normal, v3P;
00134 btScalar fSep = btScalar(10000000.0), fSepThis;
00135
00136 n[0].setValue( btScalar(-1.0), btScalar(0.0), btScalar(0.0) );
00137 n[1].setValue( btScalar(0.0), btScalar(-1.0), btScalar(0.0) );
00138 n[2].setValue( btScalar(0.0), btScalar(0.0), btScalar(-1.0) );
00139 n[3].setValue( btScalar(1.0), btScalar(0.0), btScalar(0.0) );
00140 n[4].setValue( btScalar(0.0), btScalar(1.0), btScalar(0.0) );
00141 n[5].setValue( btScalar(0.0), btScalar(0.0), btScalar(1.0) );
00142
00143
00144 prel = m44T.invXform( sphereCenter);
00145
00146 bool bFound = false;
00147
00148 v3P = prel;
00149
00150 for (int i=0;i<6;i++)
00151 {
00152 int j = i<3? 0:1;
00153 if ( (fSepThis = ((v3P-bounds[j]) .dot(n[i]))) > btScalar(0.0) )
00154 {
00155 v3P = v3P - n[i]*fSepThis;
00156 bFound = true;
00157 }
00158 }
00159
00160
00161
00162 if ( bFound )
00163 {
00164 bounds[0] = boundsVec[0];
00165 bounds[1] = boundsVec[1];
00166
00167 normal = (prel - v3P).normalize();
00168 pointOnBox = v3P + normal*margins;
00169 v3PointOnSphere = prel - normal*fRadius;
00170
00171 if ( ((v3PointOnSphere - pointOnBox) .dot (normal)) > btScalar(0.0) )
00172 {
00173 return btScalar(1.0);
00174 }
00175
00176
00177 tmp = m44T( pointOnBox);
00178 pointOnBox = tmp;
00179 tmp = m44T( v3PointOnSphere);
00180 v3PointOnSphere = tmp;
00181 btScalar fSeps2 = (pointOnBox-v3PointOnSphere).length2();
00182
00183
00184 if (fSeps2 > SIMD_EPSILON)
00185 {
00186 fSep = - btSqrt(fSeps2);
00187 normal = (pointOnBox-v3PointOnSphere);
00188 normal *= btScalar(1.)/fSep;
00189 }
00190
00191 return fSep;
00192 }
00193
00195
00196
00197 fPenetration = getSpherePenetration( boxObj,pointOnBox, v3PointOnSphere, sphereCenter, fRadius,bounds[0],bounds[1] );
00198
00199 bounds[0] = boundsVec[0];
00200 bounds[1] = boundsVec[1];
00201
00202 if ( fPenetration <= btScalar(0.0) )
00203 return (fPenetration-margins);
00204 else
00205 return btScalar(1.0);
00206 }
00207
00208 btScalar btSphereBoxCollisionAlgorithm::getSpherePenetration( btCollisionObject* boxObj,btVector3& pointOnBox, btVector3& v3PointOnSphere, const btVector3& sphereCenter, btScalar fRadius, const btVector3& aabbMin, const btVector3& aabbMax)
00209 {
00210
00211 btVector3 bounds[2];
00212
00213 bounds[0] = aabbMin;
00214 bounds[1] = aabbMax;
00215
00216 btVector3 p0, tmp, prel, n[6], normal;
00217 btScalar fSep = btScalar(-10000000.0), fSepThis;
00218
00219
00220 p0.setValue(btScalar(0.), btScalar(0.), btScalar(0.));
00221 normal.setValue(btScalar(0.), btScalar(0.), btScalar(0.));
00222
00223 n[0].setValue( btScalar(-1.0), btScalar(0.0), btScalar(0.0) );
00224 n[1].setValue( btScalar(0.0), btScalar(-1.0), btScalar(0.0) );
00225 n[2].setValue( btScalar(0.0), btScalar(0.0), btScalar(-1.0) );
00226 n[3].setValue( btScalar(1.0), btScalar(0.0), btScalar(0.0) );
00227 n[4].setValue( btScalar(0.0), btScalar(1.0), btScalar(0.0) );
00228 n[5].setValue( btScalar(0.0), btScalar(0.0), btScalar(1.0) );
00229
00230 const btTransform& m44T = boxObj->getWorldTransform();
00231
00232
00233 prel = m44T.invXform( sphereCenter);
00234
00236
00237 for (int i=0;i<6;i++)
00238 {
00239 int j = i<3 ? 0:1;
00240 if ( (fSepThis = ((prel-bounds[j]) .dot( n[i]))-fRadius) > btScalar(0.0) ) return btScalar(1.0);
00241 if ( fSepThis > fSep )
00242 {
00243 p0 = bounds[j]; normal = (btVector3&)n[i];
00244 fSep = fSepThis;
00245 }
00246 }
00247
00248 pointOnBox = prel - normal*(normal.dot((prel-p0)));
00249 v3PointOnSphere = pointOnBox + normal*fSep;
00250
00251
00252 tmp = m44T( pointOnBox);
00253 pointOnBox = tmp;
00254 tmp = m44T( v3PointOnSphere); v3PointOnSphere = tmp;
00255 normal = (pointOnBox-v3PointOnSphere).normalize();
00256
00257 return fSep;
00258
00259 }
00260