Bullet Collision Detection & Physics Library
btGjkPairDetector.cpp
Go to the documentation of this file.
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 #include "btGjkPairDetector.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
38 int gNumGjkChecks = 0;
39 
40 
42 :m_cachedSeparatingAxis(btScalar(0.),btScalar(1.),btScalar(0.)),
43 m_penetrationDepthSolver(penetrationDepthSolver),
44 m_simplexSolver(simplexSolver),
45 m_minkowskiA(objectA),
46 m_minkowskiB(objectB),
47 m_shapeTypeA(objectA->getShapeType()),
48 m_shapeTypeB(objectB->getShapeType()),
49 m_marginA(objectA->getMargin()),
50 m_marginB(objectB->getMargin()),
51 m_ignoreMargin(false),
52 m_lastUsedMethod(-1),
53 m_catchDegeneracies(1),
54 m_fixContactNormalDirection(1)
55 {
56 }
57 btGjkPairDetector::btGjkPairDetector(const btConvexShape* objectA,const btConvexShape* objectB,int shapeTypeA,int shapeTypeB,btScalar marginA, btScalar marginB, btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver* penetrationDepthSolver)
58 :m_cachedSeparatingAxis(btScalar(0.),btScalar(1.),btScalar(0.)),
59 m_penetrationDepthSolver(penetrationDepthSolver),
60 m_simplexSolver(simplexSolver),
61 m_minkowskiA(objectA),
62 m_minkowskiB(objectB),
63 m_shapeTypeA(shapeTypeA),
64 m_shapeTypeB(shapeTypeB),
65 m_marginA(marginA),
66 m_marginB(marginB),
67 m_ignoreMargin(false),
68 m_lastUsedMethod(-1),
69 m_catchDegeneracies(1),
70 m_fixContactNormalDirection(1)
71 {
72 }
73 
74 void btGjkPairDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults)
75 {
76  (void)swapResults;
77 
78  getClosestPointsNonVirtual(input,output,debugDraw);
79 }
80 
81 #ifdef __SPU__
82 void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw)
83 #else
85 #endif
86 {
87  m_cachedSeparatingDistance = 0.f;
88 
89  btScalar distance=btScalar(0.);
90  btVector3 normalInB(btScalar(0.),btScalar(0.),btScalar(0.));
91  btVector3 pointOnA,pointOnB;
92  btTransform localTransA = input.m_transformA;
93  btTransform localTransB = input.m_transformB;
94  btVector3 positionOffset = (localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5);
95  localTransA.getOrigin() -= positionOffset;
96  localTransB.getOrigin() -= positionOffset;
97 
98  bool check2d = m_minkowskiA->isConvex2d() && m_minkowskiB->isConvex2d();
99 
100  btScalar marginA = m_marginA;
101  btScalar marginB = m_marginB;
102 
103  gNumGjkChecks++;
104 
105 #ifdef DEBUG_SPU_COLLISION_DETECTION
106  spu_printf("inside gjk\n");
107 #endif
108  //for CCD we don't use margins
109  if (m_ignoreMargin)
110  {
111  marginA = btScalar(0.);
112  marginB = btScalar(0.);
113 #ifdef DEBUG_SPU_COLLISION_DETECTION
114  spu_printf("ignoring margin\n");
115 #endif
116  }
117 
118  m_curIter = 0;
119  int gGjkMaxIter = 1000;//this is to catch invalid input, perhaps check for #NaN?
120  m_cachedSeparatingAxis.setValue(0,1,0);
121 
122  bool isValid = false;
123  bool checkSimplex = false;
124  bool checkPenetration = true;
125  m_degenerateSimplex = 0;
126 
127  m_lastUsedMethod = -1;
128 
129  {
130  btScalar squaredDistance = BT_LARGE_FLOAT;
131  btScalar delta = btScalar(0.);
132 
133  btScalar margin = marginA + marginB;
134 
135 
136 
137  m_simplexSolver->reset();
138 
139  for ( ; ; )
140  //while (true)
141  {
142 
143  btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* input.m_transformA.getBasis();
144  btVector3 seperatingAxisInB = m_cachedSeparatingAxis* input.m_transformB.getBasis();
145 
146 #if 1
147 
148  btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
149  btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
150 
151 // btVector3 pInA = localGetSupportingVertexWithoutMargin(m_shapeTypeA, m_minkowskiA, seperatingAxisInA,input.m_convexVertexData[0]);//, &featureIndexA);
152 // btVector3 qInB = localGetSupportingVertexWithoutMargin(m_shapeTypeB, m_minkowskiB, seperatingAxisInB,input.m_convexVertexData[1]);//, &featureIndexB);
153 
154 #else
155 #ifdef __SPU__
156  btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
157  btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
158 #else
159  btVector3 pInA = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
160  btVector3 qInB = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
161 #ifdef TEST_NON_VIRTUAL
162  btVector3 pInAv = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
163  btVector3 qInBv = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
164  btAssert((pInAv-pInA).length() < 0.0001);
165  btAssert((qInBv-qInB).length() < 0.0001);
166 #endif //
167 #endif //__SPU__
168 #endif
169 
170 
171  btVector3 pWorld = localTransA(pInA);
172  btVector3 qWorld = localTransB(qInB);
173 
174 #ifdef DEBUG_SPU_COLLISION_DETECTION
175  spu_printf("got local supporting vertices\n");
176 #endif
177 
178  if (check2d)
179  {
180  pWorld[2] = 0.f;
181  qWorld[2] = 0.f;
182  }
183 
184  btVector3 w = pWorld - qWorld;
185  delta = m_cachedSeparatingAxis.dot(w);
186 
187  // potential exit, they don't overlap
188  if ((delta > btScalar(0.0)) && (delta * delta > squaredDistance * input.m_maximumDistanceSquared))
189  {
190  m_degenerateSimplex = 10;
191  checkSimplex=true;
192  //checkPenetration = false;
193  break;
194  }
195 
196  //exit 0: the new point is already in the simplex, or we didn't come any closer
197  if (m_simplexSolver->inSimplex(w))
198  {
199  m_degenerateSimplex = 1;
200  checkSimplex = true;
201  break;
202  }
203  // are we getting any closer ?
204  btScalar f0 = squaredDistance - delta;
205  btScalar f1 = squaredDistance * REL_ERROR2;
206 
207  if (f0 <= f1)
208  {
209  if (f0 <= btScalar(0.))
210  {
211  m_degenerateSimplex = 2;
212  } else
213  {
214  m_degenerateSimplex = 11;
215  }
216  checkSimplex = true;
217  break;
218  }
219 
220 #ifdef DEBUG_SPU_COLLISION_DETECTION
221  spu_printf("addVertex 1\n");
222 #endif
223  //add current vertex to simplex
224  m_simplexSolver->addVertex(w, pWorld, qWorld);
225 #ifdef DEBUG_SPU_COLLISION_DETECTION
226  spu_printf("addVertex 2\n");
227 #endif
228  btVector3 newCachedSeparatingAxis;
229 
230  //calculate the closest point to the origin (update vector v)
231  if (!m_simplexSolver->closest(newCachedSeparatingAxis))
232  {
233  m_degenerateSimplex = 3;
234  checkSimplex = true;
235  break;
236  }
237 
238  if(newCachedSeparatingAxis.length2()<REL_ERROR2)
239  {
240  m_cachedSeparatingAxis = newCachedSeparatingAxis;
241  m_degenerateSimplex = 6;
242  checkSimplex = true;
243  break;
244  }
245 
246  btScalar previousSquaredDistance = squaredDistance;
247  squaredDistance = newCachedSeparatingAxis.length2();
248 #if 0
249  if (squaredDistance>previousSquaredDistance)
251  {
252  m_degenerateSimplex = 7;
253  squaredDistance = previousSquaredDistance;
254  checkSimplex = false;
255  break;
256  }
257 #endif //
258 
259 
260  //redundant m_simplexSolver->compute_points(pointOnA, pointOnB);
261 
262  //are we getting any closer ?
263  if (previousSquaredDistance - squaredDistance <= SIMD_EPSILON * previousSquaredDistance)
264  {
265 // m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
266  checkSimplex = true;
267  m_degenerateSimplex = 12;
268 
269  break;
270  }
271 
272  m_cachedSeparatingAxis = newCachedSeparatingAxis;
273 
274  //degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject
275  if (m_curIter++ > gGjkMaxIter)
276  {
277  #if defined(DEBUG) || defined (_DEBUG) || defined (DEBUG_SPU_COLLISION_DETECTION)
278 
279  printf("btGjkPairDetector maxIter exceeded:%i\n",m_curIter);
280  printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n",
281  m_cachedSeparatingAxis.getX(),
282  m_cachedSeparatingAxis.getY(),
283  m_cachedSeparatingAxis.getZ(),
284  squaredDistance,
285  m_minkowskiA->getShapeType(),
286  m_minkowskiB->getShapeType());
287 
288  #endif
289  break;
290 
291  }
292 
293 
294  bool check = (!m_simplexSolver->fullSimplex());
295  //bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > SIMD_EPSILON * m_simplexSolver->maxVertex());
296 
297  if (!check)
298  {
299  //do we need this backup_closest here ?
300 // m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
301  m_degenerateSimplex = 13;
302  break;
303  }
304  }
305 
306  if (checkSimplex)
307  {
308  m_simplexSolver->compute_points(pointOnA, pointOnB);
309  normalInB = m_cachedSeparatingAxis;
310  btScalar lenSqr =m_cachedSeparatingAxis.length2();
311 
312  //valid normal
313  if (lenSqr < 0.0001)
314  {
315  m_degenerateSimplex = 5;
316  }
317  if (lenSqr > SIMD_EPSILON*SIMD_EPSILON)
318  {
319  btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
320  normalInB *= rlen; //normalize
321  btScalar s = btSqrt(squaredDistance);
322 
323  btAssert(s > btScalar(0.0));
324  pointOnA -= m_cachedSeparatingAxis * (marginA / s);
325  pointOnB += m_cachedSeparatingAxis * (marginB / s);
326  distance = ((btScalar(1.)/rlen) - margin);
327  isValid = true;
328 
329  m_lastUsedMethod = 1;
330  } else
331  {
332  m_lastUsedMethod = 2;
333  }
334  }
335 
336  bool catchDegeneratePenetrationCase =
337  (m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < 0.01));
338 
339  //if (checkPenetration && !isValid)
340  if (checkPenetration && (!isValid || catchDegeneratePenetrationCase ))
341  {
342  //penetration case
343 
344  //if there is no way to handle penetrations, bail out
345  if (m_penetrationDepthSolver)
346  {
347  // Penetration depth case.
348  btVector3 tmpPointOnA,tmpPointOnB;
349 
351  m_cachedSeparatingAxis.setZero();
352 
353  bool isValid2 = m_penetrationDepthSolver->calcPenDepth(
354  *m_simplexSolver,
355  m_minkowskiA,m_minkowskiB,
356  localTransA,localTransB,
357  m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB,
358  debugDraw
359  );
360 
361 
362  if (isValid2)
363  {
364  btVector3 tmpNormalInB = tmpPointOnB-tmpPointOnA;
365  btScalar lenSqr = tmpNormalInB.length2();
366  if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON))
367  {
368  tmpNormalInB = m_cachedSeparatingAxis;
369  lenSqr = m_cachedSeparatingAxis.length2();
370  }
371 
372  if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON))
373  {
374  tmpNormalInB /= btSqrt(lenSqr);
375  btScalar distance2 = -(tmpPointOnA-tmpPointOnB).length();
376  //only replace valid penetrations when the result is deeper (check)
377  if (!isValid || (distance2 < distance))
378  {
379  distance = distance2;
380  pointOnA = tmpPointOnA;
381  pointOnB = tmpPointOnB;
382  normalInB = tmpNormalInB;
383  isValid = true;
384  m_lastUsedMethod = 3;
385  } else
386  {
387  m_lastUsedMethod = 8;
388  }
389  } else
390  {
391  m_lastUsedMethod = 9;
392  }
393  } else
394 
395  {
401 
402 
403  if (m_cachedSeparatingAxis.length2() > btScalar(0.))
404  {
405  btScalar distance2 = (tmpPointOnA-tmpPointOnB).length()-margin;
406  //only replace valid distances when the distance is less
407  if (!isValid || (distance2 < distance))
408  {
409  distance = distance2;
410  pointOnA = tmpPointOnA;
411  pointOnB = tmpPointOnB;
412  pointOnA -= m_cachedSeparatingAxis * marginA ;
413  pointOnB += m_cachedSeparatingAxis * marginB ;
414  normalInB = m_cachedSeparatingAxis;
415  normalInB.normalize();
416  isValid = true;
417  m_lastUsedMethod = 6;
418  } else
419  {
420  m_lastUsedMethod = 5;
421  }
422  }
423  }
424 
425  }
426 
427  }
428  }
429 
430 
431 
432  if (isValid && ((distance < 0) || (distance*distance < input.m_maximumDistanceSquared)))
433  {
434 #if 0
435 // if (check2d)
437  {
438  printf("n = %2.3f,%2.3f,%2.3f. ",normalInB[0],normalInB[1],normalInB[2]);
439  printf("distance = %2.3f exit=%d deg=%d\n",distance,m_lastUsedMethod,m_degenerateSimplex);
440  }
441 #endif
442 
443  if (m_fixContactNormalDirection)
444  {
446  //in some degenerate cases (usually when the use uses very small margins)
447  //the contact normal is pointing the wrong direction
448  //so fix it now (until we can deal with all degenerate cases in GJK and EPA)
449  //contact normals need to point from B to A in all cases, so we can simply check if the contact normal really points from B to A
450  //We like to use a dot product of the normal against the difference of the centroids,
451  //once the centroid is available in the API
452  //until then we use the center of the aabb to approximate the centroid
453  btVector3 aabbMin,aabbMax;
454  m_minkowskiA->getAabb(localTransA,aabbMin,aabbMax);
455  btVector3 posA = (aabbMax+aabbMin)*btScalar(0.5);
456 
457  m_minkowskiB->getAabb(localTransB,aabbMin,aabbMax);
458  btVector3 posB = (aabbMin+aabbMax)*btScalar(0.5);
459 
460  btVector3 diff = posA-posB;
461  if (diff.dot(normalInB) < 0.f)
462  normalInB *= -1.f;
463  }
464  m_cachedSeparatingAxis = normalInB;
465  m_cachedSeparatingDistance = distance;
466 
467  output.addContactPoint(
468  normalInB,
469  pointOnB+positionOffset,
470  distance);
471 
472  }
473 
474 
475 }
476 
477 
478 
479 
480 
btGjkPairDetector(const btConvexShape *objectA, const btConvexShape *objectB, btSimplexSolverInterface *simplexSolver, btConvexPenetrationDepthSolver *penetrationDepthSolver)
#define SIMD_EPSILON
Definition: btScalar.h:448
btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:835
#define BT_LARGE_FLOAT
Definition: btScalar.h:268
ConvexPenetrationDepthSolver provides an interface for penetration depth calculation.
#define spu_printf
btScalar btSqrt(btScalar y)
Definition: btScalar.h:387
#define btAssert(x)
Definition: btScalar.h:101
btScalar dot(const btVector3 &v) const
Return the dot product.
Definition: btVector3.h:235
btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition: btVector3.h:297
The btConvexShape is an abstract shape interface, implemented by all convex shapes such as btBoxShape...
Definition: btConvexShape.h:31
int gNumDeepPenetrationChecks
btVector3 & getOrigin()
Return the origin vector translation.
Definition: btTransform.h:117
#define btSimplexSolverInterface
btMatrix3x3 & getBasis()
Return the basis matrix for the rotation.
Definition: btTransform.h:112
The btIDebugDraw interface class allows hooking up a debug renderer to visually debug simulations...
Definition: btIDebugDraw.h:28
btVector3 can be used to represent 3D points and vectors.
Definition: btVector3.h:83
btScalar length2() const
Return the length of the vector squared.
Definition: btVector3.h:257
#define REL_ERROR2
The btTransform class supports rigid transforms with only translation and rotation and no scaling/she...
Definition: btTransform.h:34
virtual void addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorld, btScalar depth)=0
int gNumGjkChecks
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition: btScalar.h:266
virtual void getClosestPoints(const ClosestPointInput &input, Result &output, class btIDebugDraw *debugDraw, bool swapResults=false)
void getClosestPointsNonVirtual(const ClosestPointInput &input, Result &output, class btIDebugDraw *debugDraw)