1 /* 2 Bullet Continuous Collision Detection and Physics Library 3 Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 4 5 This software is provided 'as-is', without any express or implied warranty. 6 In no event will the authors be held liable for any damages arising from the use of this software. 7 Permission is granted to anyone to use this software for any purpose, 8 including commercial applications, and to alter it and redistribute it freely, 9 subject to the following restrictions: 10 11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 13 3. This notice may not be removed or altered from any source distribution. 14 */ 15 16 17 #include "btConvexConcaveCollisionAlgorithm.h" 18 #include "BulletCollision/CollisionDispatch/btCollisionObject.h" 19 #include "BulletCollision/CollisionShapes/btMultiSphereShape.h" 20 #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" 21 #include "BulletCollision/CollisionShapes/btConcaveShape.h" 22 #include "BulletCollision/CollisionDispatch/btManifoldResult.h" 23 #include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" 24 #include "BulletCollision/CollisionShapes/btTriangleShape.h" 25 #include "BulletCollision/CollisionShapes/btSphereShape.h" 26 #include "LinearMath/btIDebugDraw.h" 27 #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" 28 #include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h" 29 30 btConvexConcaveCollisionAlgorithm::btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci, const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,bool isSwapped) 31 : btActivatingCollisionAlgorithm(ci,body0Wrap,body1Wrap), 32 m_isSwapped(isSwapped), 33 m_btConvexTriangleCallback(ci.m_dispatcher1,body0Wrap,body1Wrap,isSwapped) 34 { 35 } 36 37 btConvexConcaveCollisionAlgorithm::~btConvexConcaveCollisionAlgorithm() 38 { 39 } 40 41 void btConvexConcaveCollisionAlgorithm::getAllContactManifolds(btManifoldArray& manifoldArray) 42 { 43 if (m_btConvexTriangleCallback.m_manifoldPtr) 44 { 45 manifoldArray.push_back(m_btConvexTriangleCallback.m_manifoldPtr); 46 } 47 } 48 49 50 btConvexTriangleCallback::btConvexTriangleCallback(btDispatcher* dispatcher,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,bool isSwapped): 51 m_dispatcher(dispatcher), 52 m_dispatchInfoPtr(0) 53 { 54 m_convexBodyWrap = isSwapped? body1Wrap:body0Wrap; 55 m_triBodyWrap = isSwapped? body0Wrap:body1Wrap; 56 57 // 58 // create the manifold from the dispatcher 'manifold pool' 59 // 60 m_manifoldPtr = m_dispatcher->getNewManifold(m_convexBodyWrap->getCollisionObject(),m_triBodyWrap->getCollisionObject()); 61 62 clearCache(); 63 } 64 65 btConvexTriangleCallback::~btConvexTriangleCallback() 66 { 67 clearCache(); 68 m_dispatcher->releaseManifold( m_manifoldPtr ); 69 70 } 71 72 73 void btConvexTriangleCallback::clearCache() 74 { 75 m_dispatcher->clearManifold(m_manifoldPtr); 76 } 77 78 79 void btConvexTriangleCallback::processTriangle(btVector3* triangle,int 80 partId, int triangleIndex) 81 { 82 83 if (!TestTriangleAgainstAabb2(triangle, m_aabbMin, m_aabbMax)) 84 { 85 return; 86 } 87 88 //just for debugging purposes 89 //printf("triangle %d",m_triangleCount++); 90 91 92 93 btCollisionAlgorithmConstructionInfo ci; 94 ci.m_dispatcher1 = m_dispatcher; 95 96 97 98 #if 0 99 100 ///debug drawing of the overlapping triangles 101 if (m_dispatchInfoPtr && m_dispatchInfoPtr->m_debugDraw && (m_dispatchInfoPtr->m_debugDraw->getDebugMode() &btIDebugDraw::DBG_DrawWireframe )) 102 { 103 const btCollisionObject* ob = const_cast<btCollisionObject*>(m_triBodyWrap->getCollisionObject()); 104 btVector3 color(1,1,0); 105 btTransform& tr = ob->getWorldTransform(); 106 m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[0]),tr(triangle[1]),color); 107 m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[1]),tr(triangle[2]),color); 108 m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[2]),tr(triangle[0]),color); 109 } 110 #endif 111 112 if (m_convexBodyWrap->getCollisionShape()->isConvex()) 113 { 114 btTriangleShape tm(triangle[0],triangle[1],triangle[2]); 115 tm.setMargin(m_collisionMarginTriangle); 116 117 118 btCollisionObjectWrapper triObWrap(m_triBodyWrap,&tm,m_triBodyWrap->getCollisionObject(),m_triBodyWrap->getWorldTransform(),partId,triangleIndex);//correct transform? 119 btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(m_convexBodyWrap,&triObWrap,m_manifoldPtr); 120 121 const btCollisionObjectWrapper* tmpWrap = 0; 122 123 if (m_resultOut->getBody0Internal() == m_triBodyWrap->getCollisionObject()) 124 { 125 tmpWrap = m_resultOut->getBody0Wrap(); 126 m_resultOut->setBody0Wrap(&triObWrap); 127 m_resultOut->setShapeIdentifiersA(partId,triangleIndex); 128 } 129 else 130 { 131 tmpWrap = m_resultOut->getBody1Wrap(); 132 m_resultOut->setBody1Wrap(&triObWrap); 133 m_resultOut->setShapeIdentifiersB(partId,triangleIndex); 134 } 135 136 colAlgo->processCollision(m_convexBodyWrap,&triObWrap,*m_dispatchInfoPtr,m_resultOut); 137 138 if (m_resultOut->getBody0Internal() == m_triBodyWrap->getCollisionObject()) 139 { 140 m_resultOut->setBody0Wrap(tmpWrap); 141 } else 142 { 143 m_resultOut->setBody1Wrap(tmpWrap); 144 } 145 146 147 148 colAlgo->~btCollisionAlgorithm(); 149 ci.m_dispatcher1->freeCollisionAlgorithm(colAlgo); 150 } 151 152 } 153 154 155 156 void btConvexTriangleCallback::setTimeStepAndCounters(btScalar collisionMarginTriangle,const btDispatcherInfo& dispatchInfo,const btCollisionObjectWrapper* convexBodyWrap, const btCollisionObjectWrapper* triBodyWrap, btManifoldResult* resultOut) 157 { 158 m_convexBodyWrap = convexBodyWrap; 159 m_triBodyWrap = triBodyWrap; 160 161 m_dispatchInfoPtr = &dispatchInfo; 162 m_collisionMarginTriangle = collisionMarginTriangle; 163 m_resultOut = resultOut; 164 165 //recalc aabbs 166 btTransform convexInTriangleSpace; 167 convexInTriangleSpace = m_triBodyWrap->getWorldTransform().inverse() * m_convexBodyWrap->getWorldTransform(); 168 const btCollisionShape* convexShape = static_cast<const btCollisionShape*>(m_convexBodyWrap->getCollisionShape()); 169 //CollisionShape* triangleShape = static_cast<btCollisionShape*>(triBody->m_collisionShape); 170 convexShape->getAabb(convexInTriangleSpace,m_aabbMin,m_aabbMax); 171 btScalar extraMargin = collisionMarginTriangle; 172 btVector3 extra(extraMargin,extraMargin,extraMargin); 173 174 m_aabbMax += extra; 175 m_aabbMin -= extra; 176 177 } 178 179 void btConvexConcaveCollisionAlgorithm::clearCache() 180 { 181 m_btConvexTriangleCallback.clearCache(); 182 183 } 184 185 void btConvexConcaveCollisionAlgorithm::processCollision (const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) 186 { 187 188 189 const btCollisionObjectWrapper* convexBodyWrap = m_isSwapped ? body1Wrap : body0Wrap; 190 const btCollisionObjectWrapper* triBodyWrap = m_isSwapped ? body0Wrap : body1Wrap; 191 192 if (triBodyWrap->getCollisionShape()->isConcave()) 193 { 194 195 196 197 const btConcaveShape* concaveShape = static_cast<const btConcaveShape*>( triBodyWrap->getCollisionShape()); 198 199 if (convexBodyWrap->getCollisionShape()->isConvex()) 200 { 201 btScalar collisionMarginTriangle = concaveShape->getMargin(); 202 203 resultOut->setPersistentManifold(m_btConvexTriangleCallback.m_manifoldPtr); 204 m_btConvexTriangleCallback.setTimeStepAndCounters(collisionMarginTriangle,dispatchInfo,convexBodyWrap,triBodyWrap,resultOut); 205 206 m_btConvexTriangleCallback.m_manifoldPtr->setBodies(convexBodyWrap->getCollisionObject(),triBodyWrap->getCollisionObject()); 207 208 concaveShape->processAllTriangles( &m_btConvexTriangleCallback,m_btConvexTriangleCallback.getAabbMin(),m_btConvexTriangleCallback.getAabbMax()); 209 210 resultOut->refreshContactPoints(); 211 212 m_btConvexTriangleCallback.clearWrapperData(); 213 214 } 215 216 } 217 218 } 219 220 221 btScalar btConvexConcaveCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) 222 { 223 (void)resultOut; 224 (void)dispatchInfo; 225 btCollisionObject* convexbody = m_isSwapped ? body1 : body0; 226 btCollisionObject* triBody = m_isSwapped ? body0 : body1; 227 228 229 //quick approximation using raycast, todo: hook up to the continuous collision detection (one of the btConvexCast) 230 231 //only perform CCD above a certain threshold, this prevents blocking on the long run 232 //because object in a blocked ccd state (hitfraction<1) get their linear velocity halved each frame... 233 btScalar squareMot0 = (convexbody->getInterpolationWorldTransform().getOrigin() - convexbody->getWorldTransform().getOrigin()).length2(); 234 if (squareMot0 < convexbody->getCcdSquareMotionThreshold()) 235 { 236 return btScalar(1.); 237 } 238 239 //const btVector3& from = convexbody->m_worldTransform.getOrigin(); 240 //btVector3 to = convexbody->m_interpolationWorldTransform.getOrigin(); 241 //todo: only do if the motion exceeds the 'radius' 242 243 btTransform triInv = triBody->getWorldTransform().inverse(); 244 btTransform convexFromLocal = triInv * convexbody->getWorldTransform(); 245 btTransform convexToLocal = triInv * convexbody->getInterpolationWorldTransform(); 246 247 struct LocalTriangleSphereCastCallback : public btTriangleCallback 248 { 249 btTransform m_ccdSphereFromTrans; 250 btTransform m_ccdSphereToTrans; 251 btTransform m_meshTransform; 252 253 btScalar m_ccdSphereRadius; 254 btScalar m_hitFraction; 255 256 257 LocalTriangleSphereCastCallback(const btTransform& from,const btTransform& to,btScalar ccdSphereRadius,btScalar hitFraction) 258 :m_ccdSphereFromTrans(from), 259 m_ccdSphereToTrans(to), 260 m_ccdSphereRadius(ccdSphereRadius), 261 m_hitFraction(hitFraction) 262 { 263 } 264 265 266 virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) 267 { 268 (void)partId; 269 (void)triangleIndex; 270 //do a swept sphere for now 271 btTransform ident; 272 ident.setIdentity(); 273 btConvexCast::CastResult castResult; 274 castResult.m_fraction = m_hitFraction; 275 btSphereShape pointShape(m_ccdSphereRadius); 276 btTriangleShape triShape(triangle[0],triangle[1],triangle[2]); 277 btVoronoiSimplexSolver simplexSolver; 278 btSubsimplexConvexCast convexCaster(&pointShape,&triShape,&simplexSolver); 279 //GjkConvexCast convexCaster(&pointShape,convexShape,&simplexSolver); 280 //ContinuousConvexCollision convexCaster(&pointShape,convexShape,&simplexSolver,0); 281 //local space? 282 283 if (convexCaster.calcTimeOfImpact(m_ccdSphereFromTrans,m_ccdSphereToTrans, 284 ident,ident,castResult)) 285 { 286 if (m_hitFraction > castResult.m_fraction) 287 m_hitFraction = castResult.m_fraction; 288 } 289 290 } 291 292 }; 293 294 295 296 297 298 if (triBody->getCollisionShape()->isConcave()) 299 { 300 btVector3 rayAabbMin = convexFromLocal.getOrigin(); 301 rayAabbMin.setMin(convexToLocal.getOrigin()); 302 btVector3 rayAabbMax = convexFromLocal.getOrigin(); 303 rayAabbMax.setMax(convexToLocal.getOrigin()); 304 btScalar ccdRadius0 = convexbody->getCcdSweptSphereRadius(); 305 rayAabbMin -= btVector3(ccdRadius0,ccdRadius0,ccdRadius0); 306 rayAabbMax += btVector3(ccdRadius0,ccdRadius0,ccdRadius0); 307 308 btScalar curHitFraction = btScalar(1.); //is this available? 309 LocalTriangleSphereCastCallback raycastCallback(convexFromLocal,convexToLocal, 310 convexbody->getCcdSweptSphereRadius(),curHitFraction); 311 312 raycastCallback.m_hitFraction = convexbody->getHitFraction(); 313 314 btCollisionObject* concavebody = triBody; 315 316 btConcaveShape* triangleMesh = (btConcaveShape*) concavebody->getCollisionShape(); 317 318 if (triangleMesh) 319 { 320 triangleMesh->processAllTriangles(&raycastCallback,rayAabbMin,rayAabbMax); 321 } 322 323 324 325 if (raycastCallback.m_hitFraction < convexbody->getHitFraction()) 326 { 327 convexbody->setHitFraction( raycastCallback.m_hitFraction); 328 return raycastCallback.m_hitFraction; 329 } 330 } 331 332 return btScalar(1.); 333 334 } 335