2
Bullet Continuous Collision Detection and Physics Library
3
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
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:
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.
16
///Specialized capsule-capsule collision algorithm has been added for Bullet 2.75 release to increase ragdoll performance
17
///If you experience problems with capsule-capsule collision, try to define BT_DISABLE_CAPSULE_CAPSULE_COLLIDER and report it in the Bullet forums
18
///with reproduction case
19
//define BT_DISABLE_CAPSULE_CAPSULE_COLLIDER 1
21
#include "btConvexConvexAlgorithm.h"
24
#include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h"
25
#include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h"
26
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
27
#include "BulletCollision/CollisionShapes/btConvexShape.h"
28
#include "BulletCollision/CollisionShapes/btCapsuleShape.h"
29
#include "BulletCollision/CollisionShapes/btTriangleShape.h"
33
#include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h"
34
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
35
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
36
#include "BulletCollision/CollisionShapes/btBoxShape.h"
37
#include "BulletCollision/CollisionDispatch/btManifoldResult.h"
39
#include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h"
40
#include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h"
41
#include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h"
42
#include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h"
46
#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h"
47
#include "BulletCollision/CollisionShapes/btSphereShape.h"
49
#include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h"
51
#include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h"
52
#include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h"
53
#include "BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h"
60
static SIMD_FORCE_INLINE void segmentsClosestPoints(
64
btScalar& tA, btScalar& tB,
65
const btVector3& translation,
66
const btVector3& dirA, btScalar hlenA,
67
const btVector3& dirB, btScalar hlenB )
69
// compute the parameters of the closest points on each line segment
71
btScalar dirA_dot_dirB = btDot(dirA,dirB);
72
btScalar dirA_dot_trans = btDot(dirA,translation);
73
btScalar dirB_dot_trans = btDot(dirB,translation);
75
btScalar denom = 1.0f - dirA_dot_dirB * dirA_dot_dirB;
77
if ( denom == 0.0f ) {
80
tA = ( dirA_dot_trans - dirB_dot_trans * dirA_dot_dirB ) / denom;
83
else if ( tA > hlenA )
87
tB = tA * dirA_dot_dirB - dirB_dot_trans;
91
tA = tB * dirA_dot_dirB + dirA_dot_trans;
95
else if ( tA > hlenA )
97
} else if ( tB > hlenB ) {
99
tA = tB * dirA_dot_dirB + dirA_dot_trans;
103
else if ( tA > hlenA )
107
// compute the closest points relative to segment centers.
112
ptsVector = translation - offsetA + offsetB;
116
static SIMD_FORCE_INLINE btScalar capsuleCapsuleDistance(
117
btVector3& normalOnB,
119
btScalar capsuleLengthA,
120
btScalar capsuleRadiusA,
121
btScalar capsuleLengthB,
122
btScalar capsuleRadiusB,
125
const btTransform& transformA,
126
const btTransform& transformB,
127
btScalar distanceThreshold )
129
btVector3 directionA = transformA.getBasis().getColumn(capsuleAxisA);
130
btVector3 translationA = transformA.getOrigin();
131
btVector3 directionB = transformB.getBasis().getColumn(capsuleAxisB);
132
btVector3 translationB = transformB.getOrigin();
134
// translation between centers
136
btVector3 translation = translationB - translationA;
138
// compute the closest points of the capsule line segments
140
btVector3 ptsVector; // the vector between the closest points
142
btVector3 offsetA, offsetB; // offsets from segment centers to their closest points
143
btScalar tA, tB; // parameters on line segment
145
segmentsClosestPoints( ptsVector, offsetA, offsetB, tA, tB, translation,
146
directionA, capsuleLengthA, directionB, capsuleLengthB );
148
btScalar distance = ptsVector.length() - capsuleRadiusA - capsuleRadiusB;
150
if ( distance > distanceThreshold )
153
btScalar lenSqr = ptsVector.length2();
154
if (lenSqr<= (SIMD_EPSILON*SIMD_EPSILON))
156
//degenerate case where 2 capsules are likely at the same location: take a vector tangential to 'directionA'
158
btPlaneSpace1(directionA,normalOnB,q);
161
// compute the contact normal
162
normalOnB = ptsVector*-btRecipSqrt(lenSqr);
164
pointOnB = transformB.getOrigin()+offsetB + normalOnB * capsuleRadiusB;
181
btConvexConvexAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver)
183
m_numPerturbationIterations = 0;
184
m_minimumPointsPerturbationThreshold = 3;
185
m_simplexSolver = simplexSolver;
186
m_pdSolver = pdSolver;
189
btConvexConvexAlgorithm::CreateFunc::~CreateFunc()
193
btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold)
194
: btActivatingCollisionAlgorithm(ci,body0,body1),
195
m_simplexSolver(simplexSolver),
196
m_pdSolver(pdSolver),
197
m_ownManifold (false),
199
m_lowLevelOfDetail(false),
200
#ifdef USE_SEPDISTANCE_UTIL2
201
m_sepDistance((static_cast<btConvexShape*>(body0->getCollisionShape()))->getAngularMotionDisc(),
202
(static_cast<btConvexShape*>(body1->getCollisionShape()))->getAngularMotionDisc()),
204
m_numPerturbationIterations(numPerturbationIterations),
205
m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold)
214
btConvexConvexAlgorithm::~btConvexConvexAlgorithm()
219
m_dispatcher->releaseManifold(m_manifoldPtr);
223
void btConvexConvexAlgorithm ::setLowLevelOfDetail(bool useLowLevel)
225
m_lowLevelOfDetail = useLowLevel;
229
struct btPerturbedContactResult : public btManifoldResult
231
btManifoldResult* m_originalManifoldResult;
232
btTransform m_transformA;
233
btTransform m_transformB;
234
btTransform m_unPerturbedTransform;
236
btIDebugDraw* m_debugDrawer;
239
btPerturbedContactResult(btManifoldResult* originalResult,const btTransform& transformA,const btTransform& transformB,const btTransform& unPerturbedTransform,bool perturbA,btIDebugDraw* debugDrawer)
240
:m_originalManifoldResult(originalResult),
241
m_transformA(transformA),
242
m_transformB(transformB),
243
m_unPerturbedTransform(unPerturbedTransform),
244
m_perturbA(perturbA),
245
m_debugDrawer(debugDrawer)
248
virtual ~ btPerturbedContactResult()
252
virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar orgDepth)
254
btVector3 endPt,startPt;
260
btVector3 endPtOrg = pointInWorld + normalOnBInWorld*orgDepth;
261
endPt = (m_unPerturbedTransform*m_transformA.inverse())(endPtOrg);
262
newDepth = (endPt - pointInWorld).dot(normalOnBInWorld);
263
startPt = endPt+normalOnBInWorld*newDepth;
266
endPt = pointInWorld + normalOnBInWorld*orgDepth;
267
startPt = (m_unPerturbedTransform*m_transformB.inverse())(pointInWorld);
268
newDepth = (endPt - startPt).dot(normalOnBInWorld);
272
//#define DEBUG_CONTACTS 1
273
#ifdef DEBUG_CONTACTS
274
m_debugDrawer->drawLine(startPt,endPt,btVector3(1,0,0));
275
m_debugDrawer->drawSphere(startPt,0.05,btVector3(0,1,0));
276
m_debugDrawer->drawSphere(endPt,0.05,btVector3(0,0,1));
277
#endif //DEBUG_CONTACTS
280
m_originalManifoldResult->addContactPoint(normalOnBInWorld,startPt,newDepth);
285
extern btScalar gContactBreakingThreshold;
289
// Convex-Convex collision algorithm
291
void btConvexConvexAlgorithm ::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
297
m_manifoldPtr = m_dispatcher->getNewManifold(body0,body1);
298
m_ownManifold = true;
300
resultOut->setPersistentManifold(m_manifoldPtr);
302
//comment-out next line to test multi-contact generation
303
//resultOut->getPersistentManifold()->clearManifold();
306
btConvexShape* min0 = static_cast<btConvexShape*>(body0->getCollisionShape());
307
btConvexShape* min1 = static_cast<btConvexShape*>(body1->getCollisionShape());
310
btVector3 pointOnBWorld;
311
#ifndef BT_DISABLE_CAPSULE_CAPSULE_COLLIDER
312
if ((min0->getShapeType() == CAPSULE_SHAPE_PROXYTYPE) && (min1->getShapeType() == CAPSULE_SHAPE_PROXYTYPE))
314
btCapsuleShape* capsuleA = (btCapsuleShape*) min0;
315
btCapsuleShape* capsuleB = (btCapsuleShape*) min1;
316
btVector3 localScalingA = capsuleA->getLocalScaling();
317
btVector3 localScalingB = capsuleB->getLocalScaling();
319
btScalar threshold = m_manifoldPtr->getContactBreakingThreshold();
321
btScalar dist = capsuleCapsuleDistance(normalOnB, pointOnBWorld,capsuleA->getHalfHeight(),capsuleA->getRadius(),
322
capsuleB->getHalfHeight(),capsuleB->getRadius(),capsuleA->getUpAxis(),capsuleB->getUpAxis(),
323
body0->getWorldTransform(),body1->getWorldTransform(),threshold);
327
btAssert(normalOnB.length2()>=(SIMD_EPSILON*SIMD_EPSILON));
328
resultOut->addContactPoint(normalOnB,pointOnBWorld,dist);
330
resultOut->refreshContactPoints();
333
#endif //BT_DISABLE_CAPSULE_CAPSULE_COLLIDER
338
#ifdef USE_SEPDISTANCE_UTIL2
339
if (dispatchInfo.m_useConvexConservativeDistanceUtil)
341
m_sepDistance.updateSeparatingDistance(body0->getWorldTransform(),body1->getWorldTransform());
344
if (!dispatchInfo.m_useConvexConservativeDistanceUtil || m_sepDistance.getConservativeSeparatingDistance()<=0.f)
345
#endif //USE_SEPDISTANCE_UTIL2
350
btGjkPairDetector::ClosestPointInput input;
352
btGjkPairDetector gjkPairDetector(min0,min1,m_simplexSolver,m_pdSolver);
353
//TODO: if (dispatchInfo.m_useContinuous)
354
gjkPairDetector.setMinkowskiA(min0);
355
gjkPairDetector.setMinkowskiB(min1);
357
#ifdef USE_SEPDISTANCE_UTIL2
358
if (dispatchInfo.m_useConvexConservativeDistanceUtil)
360
input.m_maximumDistanceSquared = BT_LARGE_FLOAT;
362
#endif //USE_SEPDISTANCE_UTIL2
364
//if (dispatchInfo.m_convexMaxDistanceUseCPT)
366
// input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactProcessingThreshold();
369
input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold();
372
input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared;
375
input.m_stackAlloc = dispatchInfo.m_stackAllocator;
376
input.m_transformA = body0->getWorldTransform();
377
input.m_transformB = body1->getWorldTransform();
383
#ifdef USE_SEPDISTANCE_UTIL2
384
btScalar sepDist = 0.f;
385
if (dispatchInfo.m_useConvexConservativeDistanceUtil)
387
sepDist = gjkPairDetector.getCachedSeparatingDistance();
388
if (sepDist>SIMD_EPSILON)
390
sepDist += dispatchInfo.m_convexConservativeDistanceThreshold;
391
//now perturbe directions to get multiple contact points
395
#endif //USE_SEPDISTANCE_UTIL2
397
if (min0->isPolyhedral() && min1->isPolyhedral())
401
struct btDummyResult : public btDiscreteCollisionDetectorInterface::Result
403
virtual void setShapeIdentifiersA(int partId0,int index0){}
404
virtual void setShapeIdentifiersB(int partId1,int index1){}
405
virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth)
413
btPolyhedralConvexShape* polyhedronA = (btPolyhedralConvexShape*) min0;
414
btPolyhedralConvexShape* polyhedronB = (btPolyhedralConvexShape*) min1;
415
if (polyhedronA->getConvexPolyhedron() && polyhedronB->getConvexPolyhedron())
419
gjkPairDetector.getClosestPoints(input,dummy,dispatchInfo.m_debugDraw);
422
btScalar threshold = m_manifoldPtr->getContactBreakingThreshold();
424
btScalar minDist = 0.f;
425
btVector3 sepNormalWorldSpace;
426
bool foundSepAxis = true;
428
if (dispatchInfo.m_enableSatConvex)
430
foundSepAxis = btPolyhedralContactClipping::findSeparatingAxis(
431
*polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(),
432
body0->getWorldTransform(),
433
body1->getWorldTransform(),
434
sepNormalWorldSpace);
437
sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis().normalized();
438
minDist = gjkPairDetector.getCachedSeparatingDistance();
442
// printf("sepNormalWorldSpace=%f,%f,%f\n",sepNormalWorldSpace.getX(),sepNormalWorldSpace.getY(),sepNormalWorldSpace.getZ());
444
btPolyhedralContactClipping::clipHullAgainstHull(sepNormalWorldSpace, *polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(),
445
body0->getWorldTransform(),
446
body1->getWorldTransform(), minDist-threshold, threshold, *resultOut);
451
resultOut->refreshContactPoints();
457
//we can also deal with convex versus triangle (without connectivity data)
458
if (polyhedronA->getConvexPolyhedron() && polyhedronB->getShapeType()==TRIANGLE_SHAPE_PROXYTYPE)
460
gjkPairDetector.getClosestPoints(input,dummy,dispatchInfo.m_debugDraw);
462
btVector3 sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis().normalized();
464
btVertexArray vertices;
465
btTriangleShape* tri = (btTriangleShape*)polyhedronB;
466
vertices.push_back( body1->getWorldTransform()*tri->m_vertices1[0]);
467
vertices.push_back( body1->getWorldTransform()*tri->m_vertices1[1]);
468
vertices.push_back( body1->getWorldTransform()*tri->m_vertices1[2]);
470
btScalar threshold = m_manifoldPtr->getContactBreakingThreshold();
471
btScalar minDist = gjkPairDetector.getCachedSeparatingDistance();
472
btPolyhedralContactClipping::clipFaceAgainstHull(sepNormalWorldSpace, *polyhedronA->getConvexPolyhedron(),
473
body0->getWorldTransform(), vertices, minDist-threshold, threshold, *resultOut);
478
resultOut->refreshContactPoints();
489
gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw);
491
//now perform 'm_numPerturbationIterations' collision queries with the perturbated collision objects
493
//perform perturbation when more then 'm_minimumPointsPerturbationThreshold' points
494
if (m_numPerturbationIterations && resultOut->getPersistentManifold()->getNumContacts() < m_minimumPointsPerturbationThreshold)
499
btVector3 sepNormalWorldSpace;
501
sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis().normalized();
502
btPlaneSpace1(sepNormalWorldSpace,v0,v1);
505
bool perturbeA = true;
506
const btScalar angleLimit = 0.125f * SIMD_PI;
507
btScalar perturbeAngle;
508
btScalar radiusA = min0->getAngularMotionDisc();
509
btScalar radiusB = min1->getAngularMotionDisc();
510
if (radiusA < radiusB)
512
perturbeAngle = gContactBreakingThreshold /radiusA;
516
perturbeAngle = gContactBreakingThreshold / radiusB;
519
if ( perturbeAngle > angleLimit )
520
perturbeAngle = angleLimit;
522
btTransform unPerturbedTransform;
525
unPerturbedTransform = input.m_transformA;
528
unPerturbedTransform = input.m_transformB;
531
for ( i=0;i<m_numPerturbationIterations;i++)
533
if (v0.length2()>SIMD_EPSILON)
535
btQuaternion perturbeRot(v0,perturbeAngle);
536
btScalar iterationAngle = i*(SIMD_2_PI/btScalar(m_numPerturbationIterations));
537
btQuaternion rotq(sepNormalWorldSpace,iterationAngle);
542
input.m_transformA.setBasis( btMatrix3x3(rotq.inverse()*perturbeRot*rotq)*body0->getWorldTransform().getBasis());
543
input.m_transformB = body1->getWorldTransform();
544
#ifdef DEBUG_CONTACTS
545
dispatchInfo.m_debugDraw->drawTransform(input.m_transformA,10.0);
546
#endif //DEBUG_CONTACTS
549
input.m_transformA = body0->getWorldTransform();
550
input.m_transformB.setBasis( btMatrix3x3(rotq.inverse()*perturbeRot*rotq)*body1->getWorldTransform().getBasis());
551
#ifdef DEBUG_CONTACTS
552
dispatchInfo.m_debugDraw->drawTransform(input.m_transformB,10.0);
556
btPerturbedContactResult perturbedResultOut(resultOut,input.m_transformA,input.m_transformB,unPerturbedTransform,perturbeA,dispatchInfo.m_debugDraw);
557
gjkPairDetector.getClosestPoints(input,perturbedResultOut,dispatchInfo.m_debugDraw);
565
#ifdef USE_SEPDISTANCE_UTIL2
566
if (dispatchInfo.m_useConvexConservativeDistanceUtil && (sepDist>SIMD_EPSILON))
568
m_sepDistance.initSeparatingDistance(gjkPairDetector.getCachedSeparatingAxis(),sepDist,body0->getWorldTransform(),body1->getWorldTransform());
570
#endif //USE_SEPDISTANCE_UTIL2
577
resultOut->refreshContactPoints();
584
bool disableCcd = false;
585
btScalar btConvexConvexAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
589
///Rather then checking ALL pairs, only calculate TOI when motion exceeds threshold
591
///Linear motion for one of objects needs to exceed m_ccdSquareMotionThreshold
592
///col0->m_worldTransform,
593
btScalar resultFraction = btScalar(1.);
596
btScalar squareMot0 = (col0->getInterpolationWorldTransform().getOrigin() - col0->getWorldTransform().getOrigin()).length2();
597
btScalar squareMot1 = (col1->getInterpolationWorldTransform().getOrigin() - col1->getWorldTransform().getOrigin()).length2();
599
if (squareMot0 < col0->getCcdSquareMotionThreshold() &&
600
squareMot1 < col1->getCcdSquareMotionThreshold())
601
return resultFraction;
607
//An adhoc way of testing the Continuous Collision Detection algorithms
608
//One object is approximated as a sphere, to simplify things
609
//Starting in penetration should report no time of impact
610
//For proper CCD, better accuracy and handling of 'allowed' penetration should be added
611
//also the mainloop of the physics should have a kind of toi queue (something like Brian Mirtich's application of Timewarp for Rigidbodies)
614
/// Convex0 against sphere for Convex1
616
btConvexShape* convex0 = static_cast<btConvexShape*>(col0->getCollisionShape());
618
btSphereShape sphere1(col1->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation
619
btConvexCast::CastResult result;
620
btVoronoiSimplexSolver voronoiSimplex;
621
//SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex);
622
///Simplification, one object is simplified as a sphere
623
btGjkConvexCast ccd1( convex0 ,&sphere1,&voronoiSimplex);
624
//ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0);
625
if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(),
626
col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result))
629
//store result.m_fraction in both bodies
631
if (col0->getHitFraction()> result.m_fraction)
632
col0->setHitFraction( result.m_fraction );
634
if (col1->getHitFraction() > result.m_fraction)
635
col1->setHitFraction( result.m_fraction);
637
if (resultFraction > result.m_fraction)
638
resultFraction = result.m_fraction;
647
/// Sphere (for convex0) against Convex1
649
btConvexShape* convex1 = static_cast<btConvexShape*>(col1->getCollisionShape());
651
btSphereShape sphere0(col0->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation
652
btConvexCast::CastResult result;
653
btVoronoiSimplexSolver voronoiSimplex;
654
//SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex);
655
///Simplification, one object is simplified as a sphere
656
btGjkConvexCast ccd1(&sphere0,convex1,&voronoiSimplex);
657
//ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0);
658
if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(),
659
col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result))
662
//store result.m_fraction in both bodies
664
if (col0->getHitFraction() > result.m_fraction)
665
col0->setHitFraction( result.m_fraction);
667
if (col1->getHitFraction() > result.m_fraction)
668
col1->setHitFraction( result.m_fraction);
670
if (resultFraction > result.m_fraction)
671
resultFraction = result.m_fraction;
676
return resultFraction;