Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/external/bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp @ 12207

Last change on this file since 12207 was 8393, checked in by rgrieder, 14 years ago

Updated Bullet from v2.77 to v2.78.
(I'm not going to make a branch for that since the update from 2.74 to 2.77 hasn't been tested that much either).

You will HAVE to do a complete RECOMPILE! I tested with MSVC and MinGW and they both threw linker errors at me.

  • Property svn:eol-style set to native
File size: 13.7 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#include "btGjkPairDetector.h"
17#include "BulletCollision/CollisionShapes/btConvexShape.h"
18#include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h"
19#include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h"
20
21
22
23#if defined(DEBUG) || defined (_DEBUG)
24//#define TEST_NON_VIRTUAL 1
25#include <stdio.h> //for debug printf
26#ifdef __SPU__
27#include <spu_printf.h>
28#define printf spu_printf
29//#define DEBUG_SPU_COLLISION_DETECTION 1
30#endif //__SPU__
31#endif
32
33//must be above the machine epsilon
34#define REL_ERROR2 btScalar(1.0e-6)
35
36//temp globals, to improve GJK/EPA/penetration calculations
37int gNumDeepPenetrationChecks = 0;
38int gNumGjkChecks = 0;
39
40
41btGjkPairDetector::btGjkPairDetector(const btConvexShape* objectA,const btConvexShape* objectB,btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver*  penetrationDepthSolver)
42:m_cachedSeparatingAxis(btScalar(0.),btScalar(1.),btScalar(0.)),
43m_penetrationDepthSolver(penetrationDepthSolver),
44m_simplexSolver(simplexSolver),
45m_minkowskiA(objectA),
46m_minkowskiB(objectB),
47m_shapeTypeA(objectA->getShapeType()),
48m_shapeTypeB(objectB->getShapeType()),
49m_marginA(objectA->getMargin()),
50m_marginB(objectB->getMargin()),
51m_ignoreMargin(false),
52m_lastUsedMethod(-1),
53m_catchDegeneracies(1)
54{
55}
56btGjkPairDetector::btGjkPairDetector(const btConvexShape* objectA,const btConvexShape* objectB,int shapeTypeA,int shapeTypeB,btScalar marginA, btScalar marginB, btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver*        penetrationDepthSolver)
57:m_cachedSeparatingAxis(btScalar(0.),btScalar(1.),btScalar(0.)),
58m_penetrationDepthSolver(penetrationDepthSolver),
59m_simplexSolver(simplexSolver),
60m_minkowskiA(objectA),
61m_minkowskiB(objectB),
62m_shapeTypeA(shapeTypeA),
63m_shapeTypeB(shapeTypeB),
64m_marginA(marginA),
65m_marginB(marginB),
66m_ignoreMargin(false),
67m_lastUsedMethod(-1),
68m_catchDegeneracies(1)
69{
70}
71
72void    btGjkPairDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults)
73{
74        (void)swapResults;
75
76        getClosestPointsNonVirtual(input,output,debugDraw);
77}
78
79#ifdef __SPU__
80void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw)
81#else
82void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw)
83#endif
84{
85        m_cachedSeparatingDistance = 0.f;
86
87        btScalar distance=btScalar(0.);
88        btVector3       normalInB(btScalar(0.),btScalar(0.),btScalar(0.));
89        btVector3 pointOnA,pointOnB;
90        btTransform     localTransA = input.m_transformA;
91        btTransform localTransB = input.m_transformB;
92        btVector3 positionOffset = (localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5);
93        localTransA.getOrigin() -= positionOffset;
94        localTransB.getOrigin() -= positionOffset;
95
96        bool check2d = m_minkowskiA->isConvex2d() && m_minkowskiB->isConvex2d();
97
98        btScalar marginA = m_marginA;
99        btScalar marginB = m_marginB;
100
101        gNumGjkChecks++;
102
103#ifdef DEBUG_SPU_COLLISION_DETECTION
104        spu_printf("inside gjk\n");
105#endif
106        //for CCD we don't use margins
107        if (m_ignoreMargin)
108        {
109                marginA = btScalar(0.);
110                marginB = btScalar(0.);
111#ifdef DEBUG_SPU_COLLISION_DETECTION
112                spu_printf("ignoring margin\n");
113#endif
114        }
115
116        m_curIter = 0;
117        int gGjkMaxIter = 1000;//this is to catch invalid input, perhaps check for #NaN?
118        m_cachedSeparatingAxis.setValue(0,1,0);
119
120        bool isValid = false;
121        bool checkSimplex = false;
122        bool checkPenetration = true;
123        m_degenerateSimplex = 0;
124
125        m_lastUsedMethod = -1;
126
127        {
128                btScalar squaredDistance = BT_LARGE_FLOAT;
129                btScalar delta = btScalar(0.);
130               
131                btScalar margin = marginA + marginB;
132               
133               
134
135                m_simplexSolver->reset();
136               
137                for ( ; ; )
138                //while (true)
139                {
140
141                        btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* input.m_transformA.getBasis();
142                        btVector3 seperatingAxisInB = m_cachedSeparatingAxis* input.m_transformB.getBasis();
143
144#if 1
145
146                        btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
147                        btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
148
149//                      btVector3 pInA  = localGetSupportingVertexWithoutMargin(m_shapeTypeA, m_minkowskiA, seperatingAxisInA,input.m_convexVertexData[0]);//, &featureIndexA);
150//                      btVector3 qInB  = localGetSupportingVertexWithoutMargin(m_shapeTypeB, m_minkowskiB, seperatingAxisInB,input.m_convexVertexData[1]);//, &featureIndexB);
151
152#else
153#ifdef __SPU__
154                        btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
155                        btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
156#else
157                        btVector3 pInA = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
158                        btVector3 qInB = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
159#ifdef TEST_NON_VIRTUAL
160                        btVector3 pInAv = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
161                        btVector3 qInBv = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
162                        btAssert((pInAv-pInA).length() < 0.0001);
163                        btAssert((qInBv-qInB).length() < 0.0001);
164#endif //
165#endif //__SPU__
166#endif
167
168
169                        btVector3  pWorld = localTransA(pInA); 
170                        btVector3  qWorld = localTransB(qInB);
171
172#ifdef DEBUG_SPU_COLLISION_DETECTION
173                spu_printf("got local supporting vertices\n");
174#endif
175
176                        if (check2d)
177                        {
178                                pWorld[2] = 0.f;
179                                qWorld[2] = 0.f;
180                        }
181
182                        btVector3 w     = pWorld - qWorld;
183                        delta = m_cachedSeparatingAxis.dot(w);
184
185                        // potential exit, they don't overlap
186                        if ((delta > btScalar(0.0)) && (delta * delta > squaredDistance * input.m_maximumDistanceSquared)) 
187                        {
188                                m_degenerateSimplex = 10;
189                                checkSimplex=true;
190                                //checkPenetration = false;
191                                break;
192                        }
193
194                        //exit 0: the new point is already in the simplex, or we didn't come any closer
195                        if (m_simplexSolver->inSimplex(w))
196                        {
197                                m_degenerateSimplex = 1;
198                                checkSimplex = true;
199                                break;
200                        }
201                        // are we getting any closer ?
202                        btScalar f0 = squaredDistance - delta;
203                        btScalar f1 = squaredDistance * REL_ERROR2;
204
205                        if (f0 <= f1)
206                        {
207                                if (f0 <= btScalar(0.))
208                                {
209                                        m_degenerateSimplex = 2;
210                                } else
211                                {
212                                        m_degenerateSimplex = 11;
213                                }
214                                checkSimplex = true;
215                                break;
216                        }
217
218#ifdef DEBUG_SPU_COLLISION_DETECTION
219                spu_printf("addVertex 1\n");
220#endif
221                        //add current vertex to simplex
222                        m_simplexSolver->addVertex(w, pWorld, qWorld);
223#ifdef DEBUG_SPU_COLLISION_DETECTION
224                spu_printf("addVertex 2\n");
225#endif
226                        btVector3 newCachedSeparatingAxis;
227
228                        //calculate the closest point to the origin (update vector v)
229                        if (!m_simplexSolver->closest(newCachedSeparatingAxis))
230                        {
231                                m_degenerateSimplex = 3;
232                                checkSimplex = true;
233                                break;
234                        }
235
236                        if(newCachedSeparatingAxis.length2()<REL_ERROR2)
237            {
238                                m_cachedSeparatingAxis = newCachedSeparatingAxis;
239                m_degenerateSimplex = 6;
240                checkSimplex = true;
241                break;
242            }
243
244                        btScalar previousSquaredDistance = squaredDistance;
245                        squaredDistance = newCachedSeparatingAxis.length2();
246#if 0
247///warning: this termination condition leads to some problems in 2d test case see Bullet/Demos/Box2dDemo
248                        if (squaredDistance>previousSquaredDistance)
249                        {
250                                m_degenerateSimplex = 7;
251                                squaredDistance = previousSquaredDistance;
252                checkSimplex = false;
253                break;
254                        }
255#endif //
256                       
257
258                        //redundant m_simplexSolver->compute_points(pointOnA, pointOnB);
259
260                        //are we getting any closer ?
261                        if (previousSquaredDistance - squaredDistance <= SIMD_EPSILON * previousSquaredDistance) 
262                        { 
263//                              m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
264                                checkSimplex = true;
265                                m_degenerateSimplex = 12;
266                               
267                                break;
268                        }
269
270                        m_cachedSeparatingAxis = newCachedSeparatingAxis;
271
272                          //degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject   
273              if (m_curIter++ > gGjkMaxIter)   
274              {   
275                      #if defined(DEBUG) || defined (_DEBUG) || defined (DEBUG_SPU_COLLISION_DETECTION)
276
277                              printf("btGjkPairDetector maxIter exceeded:%i\n",m_curIter);   
278                              printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n",   
279                              m_cachedSeparatingAxis.getX(),   
280                              m_cachedSeparatingAxis.getY(),   
281                              m_cachedSeparatingAxis.getZ(),   
282                              squaredDistance,   
283                              m_minkowskiA->getShapeType(),   
284                              m_minkowskiB->getShapeType());   
285
286                      #endif   
287                      break;   
288
289              } 
290
291
292                        bool check = (!m_simplexSolver->fullSimplex());
293                        //bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > SIMD_EPSILON * m_simplexSolver->maxVertex());
294
295                        if (!check)
296                        {
297                                //do we need this backup_closest here ?
298//                              m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
299                                m_degenerateSimplex = 13;
300                                break;
301                        }
302                }
303
304                if (checkSimplex)
305                {
306                        m_simplexSolver->compute_points(pointOnA, pointOnB);
307                        normalInB = m_cachedSeparatingAxis;
308                        btScalar lenSqr =m_cachedSeparatingAxis.length2();
309                       
310                        //valid normal
311                        if (lenSqr < 0.0001)
312                        {
313                                m_degenerateSimplex = 5;
314                        } 
315                        if (lenSqr > SIMD_EPSILON*SIMD_EPSILON)
316                        {
317                                btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
318                                normalInB *= rlen; //normalize
319                                btScalar s = btSqrt(squaredDistance);
320                       
321                                btAssert(s > btScalar(0.0));
322                                pointOnA -= m_cachedSeparatingAxis * (marginA / s);
323                                pointOnB += m_cachedSeparatingAxis * (marginB / s);
324                                distance = ((btScalar(1.)/rlen) - margin);
325                                isValid = true;
326                               
327                                m_lastUsedMethod = 1;
328                        } else
329                        {
330                                m_lastUsedMethod = 2;
331                        }
332                }
333
334                bool catchDegeneratePenetrationCase = 
335                        (m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < 0.01));
336
337                //if (checkPenetration && !isValid)
338                if (checkPenetration && (!isValid || catchDegeneratePenetrationCase ))
339                {
340                        //penetration case
341
342                        //if there is no way to handle penetrations, bail out
343                        if (m_penetrationDepthSolver)
344                        {
345                                // Penetration depth case.
346                                btVector3 tmpPointOnA,tmpPointOnB;
347                               
348                                gNumDeepPenetrationChecks++;
349                                m_cachedSeparatingAxis.setZero();
350
351                                bool isValid2 = m_penetrationDepthSolver->calcPenDepth( 
352                                        *m_simplexSolver, 
353                                        m_minkowskiA,m_minkowskiB,
354                                        localTransA,localTransB,
355                                        m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB,
356                                        debugDraw,input.m_stackAlloc
357                                        );
358
359
360                                if (isValid2)
361                                {
362                                        btVector3 tmpNormalInB = tmpPointOnB-tmpPointOnA;
363                                        btScalar lenSqr = tmpNormalInB.length2();
364                                        if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON))
365                                        {
366                                                tmpNormalInB = m_cachedSeparatingAxis;
367                                                lenSqr = m_cachedSeparatingAxis.length2();
368                                        }
369
370                                        if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON))
371                                        {
372                                                tmpNormalInB /= btSqrt(lenSqr);
373                                                btScalar distance2 = -(tmpPointOnA-tmpPointOnB).length();
374                                                //only replace valid penetrations when the result is deeper (check)
375                                                if (!isValid || (distance2 < distance))
376                                                {
377                                                        distance = distance2;
378                                                        pointOnA = tmpPointOnA;
379                                                        pointOnB = tmpPointOnB;
380                                                        normalInB = tmpNormalInB;
381                                                        isValid = true;
382                                                        m_lastUsedMethod = 3;
383                                                } else
384                                                {
385                                                        m_lastUsedMethod = 8;
386                                                }
387                                        } else
388                                        {
389                                                m_lastUsedMethod = 9;
390                                        }
391                                } else
392
393                                {
394                                        ///this is another degenerate case, where the initial GJK calculation reports a degenerate case
395                                        ///EPA reports no penetration, and the second GJK (using the supporting vector without margin)
396                                        ///reports a valid positive distance. Use the results of the second GJK instead of failing.
397                                        ///thanks to Jacob.Langford for the reproduction case
398                                        ///http://code.google.com/p/bullet/issues/detail?id=250
399
400                               
401                                        if (m_cachedSeparatingAxis.length2() > btScalar(0.))
402                                        {
403                                                btScalar distance2 = (tmpPointOnA-tmpPointOnB).length()-margin;
404                                                //only replace valid distances when the distance is less
405                                                if (!isValid || (distance2 < distance))
406                                                {
407                                                        distance = distance2;
408                                                        pointOnA = tmpPointOnA;
409                                                        pointOnB = tmpPointOnB;
410                                                        pointOnA -= m_cachedSeparatingAxis * marginA ;
411                                                        pointOnB += m_cachedSeparatingAxis * marginB ;
412                                                        normalInB = m_cachedSeparatingAxis;
413                                                        normalInB.normalize();
414                                                        isValid = true;
415                                                        m_lastUsedMethod = 6;
416                                                } else
417                                                {
418                                                        m_lastUsedMethod = 5;
419                                                }
420                                        }
421                                }
422                               
423                        }
424
425                }
426        }
427
428       
429
430        if (isValid && ((distance < 0) || (distance*distance < input.m_maximumDistanceSquared)))
431        {
432#if 0
433///some debugging
434//              if (check2d)
435                {
436                        printf("n = %2.3f,%2.3f,%2.3f. ",normalInB[0],normalInB[1],normalInB[2]);
437                        printf("distance = %2.3f exit=%d deg=%d\n",distance,m_lastUsedMethod,m_degenerateSimplex);
438                }
439#endif
440
441                m_cachedSeparatingAxis = normalInB;
442                m_cachedSeparatingDistance = distance;
443
444                output.addContactPoint(
445                        normalInB,
446                        pointOnB+positionOffset,
447                        distance);
448
449        }
450
451
452}
453
454
455
456
457
Note: See TracBrowser for help on using the repository browser.