Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8351 was 8351, checked in by rgrieder, 13 years ago

Merged kicklib2 branch back to trunk (includes former branches ois_update, mac_osx and kicklib).

Notes for updating

Linux:
You don't need an extra package for CEGUILua and Tolua, it's already shipped with CEGUI.
However you do need to make sure that the OgreRenderer is installed too with CEGUI 0.7 (may be a separate package).
Also, Orxonox now recognises if you install the CgProgramManager (a separate package available on newer Ubuntu on Debian systems).

Windows:
Download the new dependency packages versioned 6.0 and use these. If you have problems with that or if you don't like the in game console problem mentioned below, you can download the new 4.3 version of the packages (only available for Visual Studio 2005/2008).

Key new features:

  • *Support for Mac OS X*
  • Visual Studio 2010 support
  • Bullet library update to 2.77
  • OIS library update to 1.3
  • Support for CEGUI 0.7 —> Support for Arch Linux and even SuSE
  • Improved install target
  • Compiles now with GCC 4.6
  • Ogre Cg Shader plugin activated for Linux if available
  • And of course lots of bug fixes

There are also some regressions:

  • No support for CEGUI 0.5, Ogre 1.4 and boost 1.35 - 1.39 any more
  • In game console is not working in main menu for CEGUI 0.7
  • Tolua (just the C lib, not the application) and CEGUILua libraries are no longer in our repository. —> You will need to get these as well when compiling Orxonox
  • And of course lots of new bugs we don't yet know about
  • 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                        m_cachedSeparatingAxis = newCachedSeparatingAxis;
258
259                        //redundant m_simplexSolver->compute_points(pointOnA, pointOnB);
260
261                        //are we getting any closer ?
262                        if (previousSquaredDistance - squaredDistance <= SIMD_EPSILON * previousSquaredDistance) 
263                        { 
264                                m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
265                                checkSimplex = true;
266                                m_degenerateSimplex = 12;
267                               
268                                break;
269                        }
270
271                          //degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject   
272              if (m_curIter++ > gGjkMaxIter)   
273              {   
274                      #if defined(DEBUG) || defined (_DEBUG) || defined (DEBUG_SPU_COLLISION_DETECTION)
275
276                              printf("btGjkPairDetector maxIter exceeded:%i\n",m_curIter);   
277                              printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n",   
278                              m_cachedSeparatingAxis.getX(),   
279                              m_cachedSeparatingAxis.getY(),   
280                              m_cachedSeparatingAxis.getZ(),   
281                              squaredDistance,   
282                              m_minkowskiA->getShapeType(),   
283                              m_minkowskiB->getShapeType());   
284
285                      #endif   
286                      break;   
287
288              } 
289
290
291                        bool check = (!m_simplexSolver->fullSimplex());
292                        //bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > SIMD_EPSILON * m_simplexSolver->maxVertex());
293
294                        if (!check)
295                        {
296                                //do we need this backup_closest here ?
297                                m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
298                                m_degenerateSimplex = 13;
299                                break;
300                        }
301                }
302
303                if (checkSimplex)
304                {
305                        m_simplexSolver->compute_points(pointOnA, pointOnB);
306                        normalInB = pointOnA-pointOnB;
307                        btScalar lenSqr =m_cachedSeparatingAxis.length2();
308                       
309                        //valid normal
310                        if (lenSqr < 0.0001)
311                        {
312                                m_degenerateSimplex = 5;
313                        } 
314                        if (lenSqr > SIMD_EPSILON*SIMD_EPSILON)
315                        {
316                                btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
317                                normalInB *= rlen; //normalize
318                                btScalar s = btSqrt(squaredDistance);
319                       
320                                btAssert(s > btScalar(0.0));
321                                pointOnA -= m_cachedSeparatingAxis * (marginA / s);
322                                pointOnB += m_cachedSeparatingAxis * (marginB / s);
323                                distance = ((btScalar(1.)/rlen) - margin);
324                                isValid = true;
325                               
326                                m_lastUsedMethod = 1;
327                        } else
328                        {
329                                m_lastUsedMethod = 2;
330                        }
331                }
332
333                bool catchDegeneratePenetrationCase = 
334                        (m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < 0.01));
335
336                //if (checkPenetration && !isValid)
337                if (checkPenetration && (!isValid || catchDegeneratePenetrationCase ))
338                {
339                        //penetration case
340
341                        //if there is no way to handle penetrations, bail out
342                        if (m_penetrationDepthSolver)
343                        {
344                                // Penetration depth case.
345                                btVector3 tmpPointOnA,tmpPointOnB;
346                               
347                                gNumDeepPenetrationChecks++;
348                                m_cachedSeparatingAxis.setZero();
349
350                                bool isValid2 = m_penetrationDepthSolver->calcPenDepth( 
351                                        *m_simplexSolver, 
352                                        m_minkowskiA,m_minkowskiB,
353                                        localTransA,localTransB,
354                                        m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB,
355                                        debugDraw,input.m_stackAlloc
356                                        );
357
358
359                                if (isValid2)
360                                {
361                                        btVector3 tmpNormalInB = tmpPointOnB-tmpPointOnA;
362                                        btScalar lenSqr = tmpNormalInB.length2();
363                                        if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON))
364                                        {
365                                                tmpNormalInB = m_cachedSeparatingAxis;
366                                                lenSqr = m_cachedSeparatingAxis.length2();
367                                        }
368
369                                        if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON))
370                                        {
371                                                tmpNormalInB /= btSqrt(lenSqr);
372                                                btScalar distance2 = -(tmpPointOnA-tmpPointOnB).length();
373                                                //only replace valid penetrations when the result is deeper (check)
374                                                if (!isValid || (distance2 < distance))
375                                                {
376                                                        distance = distance2;
377                                                        pointOnA = tmpPointOnA;
378                                                        pointOnB = tmpPointOnB;
379                                                        normalInB = tmpNormalInB;
380                                                        isValid = true;
381                                                        m_lastUsedMethod = 3;
382                                                } else
383                                                {
384                                                        m_lastUsedMethod = 8;
385                                                }
386                                        } else
387                                        {
388                                                m_lastUsedMethod = 9;
389                                        }
390                                } else
391
392                                {
393                                        ///this is another degenerate case, where the initial GJK calculation reports a degenerate case
394                                        ///EPA reports no penetration, and the second GJK (using the supporting vector without margin)
395                                        ///reports a valid positive distance. Use the results of the second GJK instead of failing.
396                                        ///thanks to Jacob.Langford for the reproduction case
397                                        ///http://code.google.com/p/bullet/issues/detail?id=250
398
399                               
400                                        if (m_cachedSeparatingAxis.length2() > btScalar(0.))
401                                        {
402                                                btScalar distance2 = (tmpPointOnA-tmpPointOnB).length()-margin;
403                                                //only replace valid distances when the distance is less
404                                                if (!isValid || (distance2 < distance))
405                                                {
406                                                        distance = distance2;
407                                                        pointOnA = tmpPointOnA;
408                                                        pointOnB = tmpPointOnB;
409                                                        pointOnA -= m_cachedSeparatingAxis * marginA ;
410                                                        pointOnB += m_cachedSeparatingAxis * marginB ;
411                                                        normalInB = m_cachedSeparatingAxis;
412                                                        normalInB.normalize();
413                                                        isValid = true;
414                                                        m_lastUsedMethod = 6;
415                                                } else
416                                                {
417                                                        m_lastUsedMethod = 5;
418                                                }
419                                        }
420                                }
421                               
422                        }
423
424                }
425        }
426
427       
428
429        if (isValid && ((distance < 0) || (distance*distance < input.m_maximumDistanceSquared)))
430        {
431#if 0
432///some debugging
433//              if (check2d)
434                {
435                        printf("n = %2.3f,%2.3f,%2.3f. ",normalInB[0],normalInB[1],normalInB[2]);
436                        printf("distance = %2.3f exit=%d deg=%d\n",distance,m_lastUsedMethod,m_degenerateSimplex);
437                }
438#endif
439
440                m_cachedSeparatingAxis = normalInB;
441                m_cachedSeparatingDistance = distance;
442
443                output.addContactPoint(
444                        normalInB,
445                        pointOnB+positionOffset,
446                        distance);
447
448        }
449
450
451}
452
453
454
455
456
Note: See TracBrowser for help on using the repository browser.