Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/kicklib/src/external/bullet/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp @ 8043

Last change on this file since 8043 was 7983, checked in by rgrieder, 14 years ago

Updated Bullet Physics Engine from v2.74 to v2.77

  • Property svn:eol-style set to native
File size: 18.1 KB
Line 
1/*
2Bullet Continuous Collision Detection and Physics Library
3Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
4
5This software is provided 'as-is', without any express or implied warranty.
6In no event will the authors be held liable for any damages arising from the use of this software.
7Permission is granted to anyone to use this software for any purpose,
8including commercial applications, and to alter it and redistribute it freely,
9subject to the following restrictions:
10
111. 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.
122. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
133. This notice may not be removed or altered from any source distribution.
14*/
15
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
20
21#include "btConvexConvexAlgorithm.h"
22
23//#include <stdio.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
30
31#include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h"
32#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
33#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
34#include "BulletCollision/CollisionShapes/btBoxShape.h"
35#include "BulletCollision/CollisionDispatch/btManifoldResult.h"
36
37#include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h"
38#include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h"
39#include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h"
40#include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h"
41
42
43
44#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h"
45#include "BulletCollision/CollisionShapes/btSphereShape.h"
46
47#include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h"
48
49#include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h"
50#include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h"
51
52
53
54///////////
55
56
57
58static SIMD_FORCE_INLINE void segmentsClosestPoints(
59        btVector3& ptsVector,
60        btVector3& offsetA,
61        btVector3& offsetB,
62        btScalar& tA, btScalar& tB,
63        const btVector3& translation,
64        const btVector3& dirA, btScalar hlenA,
65        const btVector3& dirB, btScalar hlenB )
66{
67        // compute the parameters of the closest points on each line segment
68
69        btScalar dirA_dot_dirB = btDot(dirA,dirB);
70        btScalar dirA_dot_trans = btDot(dirA,translation);
71        btScalar dirB_dot_trans = btDot(dirB,translation);
72
73        btScalar denom = 1.0f - dirA_dot_dirB * dirA_dot_dirB;
74
75        if ( denom == 0.0f ) {
76                tA = 0.0f;
77        } else {
78                tA = ( dirA_dot_trans - dirB_dot_trans * dirA_dot_dirB ) / denom;
79                if ( tA < -hlenA )
80                        tA = -hlenA;
81                else if ( tA > hlenA )
82                        tA = hlenA;
83        }
84
85        tB = tA * dirA_dot_dirB - dirB_dot_trans;
86
87        if ( tB < -hlenB ) {
88                tB = -hlenB;
89                tA = tB * dirA_dot_dirB + dirA_dot_trans;
90
91                if ( tA < -hlenA )
92                        tA = -hlenA;
93                else if ( tA > hlenA )
94                        tA = hlenA;
95        } else if ( tB > hlenB ) {
96                tB = hlenB;
97                tA = tB * dirA_dot_dirB + dirA_dot_trans;
98
99                if ( tA < -hlenA )
100                        tA = -hlenA;
101                else if ( tA > hlenA )
102                        tA = hlenA;
103        }
104
105        // compute the closest points relative to segment centers.
106
107        offsetA = dirA * tA;
108        offsetB = dirB * tB;
109
110        ptsVector = translation - offsetA + offsetB;
111}
112
113
114static SIMD_FORCE_INLINE btScalar capsuleCapsuleDistance(
115        btVector3& normalOnB,
116        btVector3& pointOnB,
117        btScalar capsuleLengthA,
118        btScalar        capsuleRadiusA,
119        btScalar capsuleLengthB,
120        btScalar        capsuleRadiusB,
121        int capsuleAxisA,
122        int capsuleAxisB,
123        const btTransform& transformA,
124        const btTransform& transformB,
125        btScalar distanceThreshold )
126{
127        btVector3 directionA = transformA.getBasis().getColumn(capsuleAxisA);
128        btVector3 translationA = transformA.getOrigin();
129        btVector3 directionB = transformB.getBasis().getColumn(capsuleAxisB);
130        btVector3 translationB = transformB.getOrigin();
131
132        // translation between centers
133
134        btVector3 translation = translationB - translationA;
135
136        // compute the closest points of the capsule line segments
137
138        btVector3 ptsVector;           // the vector between the closest points
139       
140        btVector3 offsetA, offsetB;    // offsets from segment centers to their closest points
141        btScalar tA, tB;              // parameters on line segment
142
143        segmentsClosestPoints( ptsVector, offsetA, offsetB, tA, tB, translation,
144                                                   directionA, capsuleLengthA, directionB, capsuleLengthB );
145
146        btScalar distance = ptsVector.length() - capsuleRadiusA - capsuleRadiusB;
147
148        if ( distance > distanceThreshold )
149                return distance;
150
151        btScalar lenSqr = ptsVector.length2();
152        if (lenSqr<= (SIMD_EPSILON*SIMD_EPSILON))
153        {
154                //degenerate case where 2 capsules are likely at the same location: take a vector tangential to 'directionA'
155                btVector3 q;
156                btPlaneSpace1(directionA,normalOnB,q);
157        } else
158        {
159                // compute the contact normal
160                normalOnB = ptsVector*-btRecipSqrt(lenSqr);
161        }
162        pointOnB = transformB.getOrigin()+offsetB + normalOnB * capsuleRadiusB;
163
164        return distance;
165}
166
167
168
169
170
171
172
173//////////
174
175
176
177
178
179btConvexConvexAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface*                       simplexSolver, btConvexPenetrationDepthSolver* pdSolver)
180{
181        m_numPerturbationIterations = 0;
182        m_minimumPointsPerturbationThreshold = 3;
183        m_simplexSolver = simplexSolver;
184        m_pdSolver = pdSolver;
185}
186
187btConvexConvexAlgorithm::CreateFunc::~CreateFunc() 
188{ 
189}
190
191btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold)
192: btActivatingCollisionAlgorithm(ci,body0,body1),
193m_simplexSolver(simplexSolver),
194m_pdSolver(pdSolver),
195m_ownManifold (false),
196m_manifoldPtr(mf),
197m_lowLevelOfDetail(false),
198#ifdef USE_SEPDISTANCE_UTIL2
199m_sepDistance((static_cast<btConvexShape*>(body0->getCollisionShape()))->getAngularMotionDisc(),
200                          (static_cast<btConvexShape*>(body1->getCollisionShape()))->getAngularMotionDisc()),
201#endif
202m_numPerturbationIterations(numPerturbationIterations),
203m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold)
204{
205        (void)body0;
206        (void)body1;
207}
208
209
210
211
212btConvexConvexAlgorithm::~btConvexConvexAlgorithm()
213{
214        if (m_ownManifold)
215        {
216                if (m_manifoldPtr)
217                        m_dispatcher->releaseManifold(m_manifoldPtr);
218        }
219}
220
221void    btConvexConvexAlgorithm ::setLowLevelOfDetail(bool useLowLevel)
222{
223        m_lowLevelOfDetail = useLowLevel;
224}
225
226
227struct btPerturbedContactResult : public btManifoldResult
228{
229        btManifoldResult* m_originalManifoldResult;
230        btTransform m_transformA;
231        btTransform m_transformB;
232        btTransform     m_unPerturbedTransform;
233        bool    m_perturbA;
234        btIDebugDraw*   m_debugDrawer;
235
236
237        btPerturbedContactResult(btManifoldResult* originalResult,const btTransform& transformA,const btTransform& transformB,const btTransform& unPerturbedTransform,bool perturbA,btIDebugDraw* debugDrawer)
238                :m_originalManifoldResult(originalResult),
239                m_transformA(transformA),
240                m_transformB(transformB),
241                m_unPerturbedTransform(unPerturbedTransform),
242                m_perturbA(perturbA),
243                m_debugDrawer(debugDrawer)
244        {
245        }
246        virtual ~ btPerturbedContactResult()
247        {
248        }
249
250        virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar orgDepth)
251        {
252                btVector3 endPt,startPt;
253                btScalar newDepth;
254                btVector3 newNormal;
255
256                if (m_perturbA)
257                {
258                        btVector3 endPtOrg = pointInWorld + normalOnBInWorld*orgDepth;
259                        endPt = (m_unPerturbedTransform*m_transformA.inverse())(endPtOrg);
260                        newDepth = (endPt -  pointInWorld).dot(normalOnBInWorld);
261                        startPt = endPt+normalOnBInWorld*newDepth;
262                } else
263                {
264                        endPt = pointInWorld + normalOnBInWorld*orgDepth;
265                        startPt = (m_unPerturbedTransform*m_transformB.inverse())(pointInWorld);
266                        newDepth = (endPt -  startPt).dot(normalOnBInWorld);
267                       
268                }
269
270//#define DEBUG_CONTACTS 1
271#ifdef DEBUG_CONTACTS
272                m_debugDrawer->drawLine(startPt,endPt,btVector3(1,0,0));
273                m_debugDrawer->drawSphere(startPt,0.05,btVector3(0,1,0));
274                m_debugDrawer->drawSphere(endPt,0.05,btVector3(0,0,1));
275#endif //DEBUG_CONTACTS
276
277               
278                m_originalManifoldResult->addContactPoint(normalOnBInWorld,startPt,newDepth);
279        }
280
281};
282
283extern btScalar gContactBreakingThreshold;
284
285
286//
287// Convex-Convex collision algorithm
288//
289void btConvexConvexAlgorithm ::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
290{
291
292        if (!m_manifoldPtr)
293        {
294                //swapped?
295                m_manifoldPtr = m_dispatcher->getNewManifold(body0,body1);
296                m_ownManifold = true;
297        }
298        resultOut->setPersistentManifold(m_manifoldPtr);
299
300        //comment-out next line to test multi-contact generation
301        //resultOut->getPersistentManifold()->clearManifold();
302       
303
304        btConvexShape* min0 = static_cast<btConvexShape*>(body0->getCollisionShape());
305        btConvexShape* min1 = static_cast<btConvexShape*>(body1->getCollisionShape());
306
307        btVector3  normalOnB;
308                btVector3  pointOnBWorld;
309#ifndef BT_DISABLE_CAPSULE_CAPSULE_COLLIDER
310        if ((min0->getShapeType() == CAPSULE_SHAPE_PROXYTYPE) && (min1->getShapeType() == CAPSULE_SHAPE_PROXYTYPE))
311        {
312                btCapsuleShape* capsuleA = (btCapsuleShape*) min0;
313                btCapsuleShape* capsuleB = (btCapsuleShape*) min1;
314                btVector3 localScalingA = capsuleA->getLocalScaling();
315                btVector3 localScalingB = capsuleB->getLocalScaling();
316               
317                btScalar threshold = m_manifoldPtr->getContactBreakingThreshold();
318
319                btScalar dist = capsuleCapsuleDistance(normalOnB,       pointOnBWorld,capsuleA->getHalfHeight(),capsuleA->getRadius(),
320                        capsuleB->getHalfHeight(),capsuleB->getRadius(),capsuleA->getUpAxis(),capsuleB->getUpAxis(),
321                        body0->getWorldTransform(),body1->getWorldTransform(),threshold);
322
323                if (dist<threshold)
324                {
325                        btAssert(normalOnB.length2()>=(SIMD_EPSILON*SIMD_EPSILON));
326                        resultOut->addContactPoint(normalOnB,pointOnBWorld,dist);       
327                }
328                resultOut->refreshContactPoints();
329                return;
330        }
331#endif //BT_DISABLE_CAPSULE_CAPSULE_COLLIDER
332
333
334#ifdef USE_SEPDISTANCE_UTIL2
335        if (dispatchInfo.m_useConvexConservativeDistanceUtil)
336        {
337                m_sepDistance.updateSeparatingDistance(body0->getWorldTransform(),body1->getWorldTransform());
338        }
339
340        if (!dispatchInfo.m_useConvexConservativeDistanceUtil || m_sepDistance.getConservativeSeparatingDistance()<=0.f)
341#endif //USE_SEPDISTANCE_UTIL2
342
343        {
344
345       
346        btGjkPairDetector::ClosestPointInput input;
347
348        btGjkPairDetector       gjkPairDetector(min0,min1,m_simplexSolver,m_pdSolver);
349        //TODO: if (dispatchInfo.m_useContinuous)
350        gjkPairDetector.setMinkowskiA(min0);
351        gjkPairDetector.setMinkowskiB(min1);
352
353#ifdef USE_SEPDISTANCE_UTIL2
354        if (dispatchInfo.m_useConvexConservativeDistanceUtil)
355        {
356                input.m_maximumDistanceSquared = BT_LARGE_FLOAT;
357        } else
358#endif //USE_SEPDISTANCE_UTIL2
359        {
360                if (dispatchInfo.m_convexMaxDistanceUseCPT)
361                {
362                        input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactProcessingThreshold();
363                } else
364                {
365                        input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold();
366                }
367                input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared;
368        }
369
370        input.m_stackAlloc = dispatchInfo.m_stackAllocator;
371        input.m_transformA = body0->getWorldTransform();
372        input.m_transformB = body1->getWorldTransform();
373
374        gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw);
375
376       
377
378#ifdef USE_SEPDISTANCE_UTIL2
379        btScalar sepDist = 0.f;
380        if (dispatchInfo.m_useConvexConservativeDistanceUtil)
381        {
382                sepDist = gjkPairDetector.getCachedSeparatingDistance();
383                if (sepDist>SIMD_EPSILON)
384                {
385                        sepDist += dispatchInfo.m_convexConservativeDistanceThreshold;
386                        //now perturbe directions to get multiple contact points
387                       
388                }
389        }
390#endif //USE_SEPDISTANCE_UTIL2
391
392        //now perform 'm_numPerturbationIterations' collision queries with the perturbated collision objects
393       
394        //perform perturbation when more then 'm_minimumPointsPerturbationThreshold' points
395        if (m_numPerturbationIterations && resultOut->getPersistentManifold()->getNumContacts() < m_minimumPointsPerturbationThreshold)
396        {
397               
398                int i;
399                btVector3 v0,v1;
400                btVector3 sepNormalWorldSpace;
401       
402                sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis().normalized();
403                btPlaneSpace1(sepNormalWorldSpace,v0,v1);
404
405
406                bool perturbeA = true;
407                const btScalar angleLimit = 0.125f * SIMD_PI;
408                btScalar perturbeAngle;
409                btScalar radiusA = min0->getAngularMotionDisc();
410                btScalar radiusB = min1->getAngularMotionDisc();
411                if (radiusA < radiusB)
412                {
413                        perturbeAngle = gContactBreakingThreshold /radiusA;
414                        perturbeA = true;
415                } else
416                {
417                        perturbeAngle = gContactBreakingThreshold / radiusB;
418                        perturbeA = false;
419                }
420                if ( perturbeAngle > angleLimit ) 
421                                perturbeAngle = angleLimit;
422
423                btTransform unPerturbedTransform;
424                if (perturbeA)
425                {
426                        unPerturbedTransform = input.m_transformA;
427                } else
428                {
429                        unPerturbedTransform = input.m_transformB;
430                }
431               
432                for ( i=0;i<m_numPerturbationIterations;i++)
433                {
434                        if (v0.length2()>SIMD_EPSILON)
435                        {
436                        btQuaternion perturbeRot(v0,perturbeAngle);
437                        btScalar iterationAngle = i*(SIMD_2_PI/btScalar(m_numPerturbationIterations));
438                        btQuaternion rotq(sepNormalWorldSpace,iterationAngle);
439                       
440                       
441                        if (perturbeA)
442                        {
443                                input.m_transformA.setBasis(  btMatrix3x3(rotq.inverse()*perturbeRot*rotq)*body0->getWorldTransform().getBasis());
444                                input.m_transformB = body1->getWorldTransform();
445#ifdef DEBUG_CONTACTS
446                                dispatchInfo.m_debugDraw->drawTransform(input.m_transformA,10.0);
447#endif //DEBUG_CONTACTS
448                        } else
449                        {
450                                input.m_transformA = body0->getWorldTransform();
451                                input.m_transformB.setBasis( btMatrix3x3(rotq.inverse()*perturbeRot*rotq)*body1->getWorldTransform().getBasis());
452#ifdef DEBUG_CONTACTS
453                                dispatchInfo.m_debugDraw->drawTransform(input.m_transformB,10.0);
454#endif
455                        }
456                       
457                        btPerturbedContactResult perturbedResultOut(resultOut,input.m_transformA,input.m_transformB,unPerturbedTransform,perturbeA,dispatchInfo.m_debugDraw);
458                        gjkPairDetector.getClosestPoints(input,perturbedResultOut,dispatchInfo.m_debugDraw);
459                        }
460                       
461                }
462        }
463
464       
465
466#ifdef USE_SEPDISTANCE_UTIL2
467        if (dispatchInfo.m_useConvexConservativeDistanceUtil && (sepDist>SIMD_EPSILON))
468        {
469                m_sepDistance.initSeparatingDistance(gjkPairDetector.getCachedSeparatingAxis(),sepDist,body0->getWorldTransform(),body1->getWorldTransform());
470        }
471#endif //USE_SEPDISTANCE_UTIL2
472
473
474        }
475
476        if (m_ownManifold)
477        {
478                resultOut->refreshContactPoints();
479        }
480
481}
482
483
484
485bool disableCcd = false;
486btScalar        btConvexConvexAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
487{
488        (void)resultOut;
489        (void)dispatchInfo;
490        ///Rather then checking ALL pairs, only calculate TOI when motion exceeds threshold
491   
492        ///Linear motion for one of objects needs to exceed m_ccdSquareMotionThreshold
493        ///col0->m_worldTransform,
494        btScalar resultFraction = btScalar(1.);
495
496
497        btScalar squareMot0 = (col0->getInterpolationWorldTransform().getOrigin() - col0->getWorldTransform().getOrigin()).length2();
498        btScalar squareMot1 = (col1->getInterpolationWorldTransform().getOrigin() - col1->getWorldTransform().getOrigin()).length2();
499   
500        if (squareMot0 < col0->getCcdSquareMotionThreshold() &&
501                squareMot1 < col1->getCcdSquareMotionThreshold())
502                return resultFraction;
503
504        if (disableCcd)
505                return btScalar(1.);
506
507
508        //An adhoc way of testing the Continuous Collision Detection algorithms
509        //One object is approximated as a sphere, to simplify things
510        //Starting in penetration should report no time of impact
511        //For proper CCD, better accuracy and handling of 'allowed' penetration should be added
512        //also the mainloop of the physics should have a kind of toi queue (something like Brian Mirtich's application of Timewarp for Rigidbodies)
513
514               
515        /// Convex0 against sphere for Convex1
516        {
517                btConvexShape* convex0 = static_cast<btConvexShape*>(col0->getCollisionShape());
518
519                btSphereShape   sphere1(col1->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation
520                btConvexCast::CastResult result;
521                btVoronoiSimplexSolver voronoiSimplex;
522                //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex);
523                ///Simplification, one object is simplified as a sphere
524                btGjkConvexCast ccd1( convex0 ,&sphere1,&voronoiSimplex);
525                //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0);
526                if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(),
527                        col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result))
528                {
529               
530                        //store result.m_fraction in both bodies
531               
532                        if (col0->getHitFraction()> result.m_fraction)
533                                col0->setHitFraction( result.m_fraction );
534
535                        if (col1->getHitFraction() > result.m_fraction)
536                                col1->setHitFraction( result.m_fraction);
537
538                        if (resultFraction > result.m_fraction)
539                                resultFraction = result.m_fraction;
540
541                }
542               
543               
544
545
546        }
547
548        /// Sphere (for convex0) against Convex1
549        {
550                btConvexShape* convex1 = static_cast<btConvexShape*>(col1->getCollisionShape());
551
552                btSphereShape   sphere0(col0->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation
553                btConvexCast::CastResult result;
554                btVoronoiSimplexSolver voronoiSimplex;
555                //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex);
556                ///Simplification, one object is simplified as a sphere
557                btGjkConvexCast ccd1(&sphere0,convex1,&voronoiSimplex);
558                //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0);
559                if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(),
560                        col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result))
561                {
562               
563                        //store result.m_fraction in both bodies
564               
565                        if (col0->getHitFraction()      > result.m_fraction)
566                                col0->setHitFraction( result.m_fraction);
567
568                        if (col1->getHitFraction() > result.m_fraction)
569                                col1->setHitFraction( result.m_fraction);
570
571                        if (resultFraction > result.m_fraction)
572                                resultFraction = result.m_fraction;
573
574                }
575        }
576       
577        return resultFraction;
578
579}
580
Note: See TracBrowser for help on using the repository browser.