Bullet Collision Detection & Physics Library
btConvexConcaveCollisionAlgorithm.cpp
Go to the documentation of this file.
1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
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 
17 #include "LinearMath/btQuickprof.h"
30 
32  : btActivatingCollisionAlgorithm(ci, body0Wrap, body1Wrap),
33  m_btConvexTriangleCallback(ci.m_dispatcher1, body0Wrap, body1Wrap, isSwapped),
34  m_isSwapped(isSwapped)
35 {
36 }
37 
39 {
40 }
41 
43 {
45  {
47  }
48 }
49 
50 btConvexTriangleCallback::btConvexTriangleCallback(btDispatcher* dispatcher, const btCollisionObjectWrapper* body0Wrap, const btCollisionObjectWrapper* body1Wrap, bool isSwapped) : m_dispatcher(dispatcher),
51  m_dispatchInfoPtr(0)
52 {
53  m_convexBodyWrap = isSwapped ? body1Wrap : body0Wrap;
54  m_triBodyWrap = isSwapped ? body0Wrap : body1Wrap;
55 
56  //
57  // create the manifold from the dispatcher 'manifold pool'
58  //
60 
61  clearCache();
62 }
63 
65 {
66  clearCache();
68 }
69 
71 {
73 }
74 
75 void btConvexTriangleCallback::processTriangle(btVector3* triangle, int partId, int triangleIndex)
76 {
77  BT_PROFILE("btConvexTriangleCallback::processTriangle");
78 
80  {
81  return;
82  }
83 
84  //just for debugging purposes
85  //printf("triangle %d",m_triangleCount++);
86 
89 
90 #if 0
91 
94  {
96  btVector3 color(1,1,0);
97  btTransform& tr = ob->getWorldTransform();
98  m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[0]),tr(triangle[1]),color);
99  m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[1]),tr(triangle[2]),color);
100  m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[2]),tr(triangle[0]),color);
101  }
102 #endif
103 
105  {
106 #ifndef BT_DISABLE_CONVEX_CONCAVE_EARLY_OUT
107  //an early out optimisation if the object is separated from the triangle
108  //projected on the triangle normal)
109  {
110  const btVector3 v0 = m_triBodyWrap->getWorldTransform()*triangle[0];
111  const btVector3 v1 = m_triBodyWrap->getWorldTransform()*triangle[1];
112  const btVector3 v2 = m_triBodyWrap->getWorldTransform()*triangle[2];
113 
114  btVector3 triangle_normal_world = ( v1 - v0).cross(v2 - v0);
115  triangle_normal_world.normalize();
116 
118 
119  btVector3 localPt = convex->localGetSupportingVertex(m_convexBodyWrap->getWorldTransform().getBasis().inverse()*triangle_normal_world);
120  btVector3 worldPt = m_convexBodyWrap->getWorldTransform()*localPt;
121  //now check if this is fully on one side of the triangle
122  btScalar proj_distPt = triangle_normal_world.dot(worldPt);
123  btScalar proj_distTr = triangle_normal_world.dot(v0);
125  btScalar dist = proj_distTr - proj_distPt;
126  if (dist > contact_threshold)
127  return;
128 
129  //also check the other side of the triangle
130  triangle_normal_world*=-1;
131 
132  localPt = convex->localGetSupportingVertex(m_convexBodyWrap->getWorldTransform().getBasis().inverse()*triangle_normal_world);
133  worldPt = m_convexBodyWrap->getWorldTransform()*localPt;
134  //now check if this is fully on one side of the triangle
135  proj_distPt = triangle_normal_world.dot(worldPt);
136  proj_distTr = triangle_normal_world.dot(v0);
137 
138  dist = proj_distTr - proj_distPt;
139  if (dist > contact_threshold)
140  return;
141  }
142 #endif //BT_DISABLE_CONVEX_CONCAVE_EARLY_OUT
143 
144  btTriangleShape tm(triangle[0], triangle[1], triangle[2]);
146 
147  btCollisionObjectWrapper triObWrap(m_triBodyWrap, &tm, m_triBodyWrap->getCollisionObject(), m_triBodyWrap->getWorldTransform(), partId, triangleIndex); //correct transform?
148  btCollisionAlgorithm* colAlgo = 0;
149 
151  {
153  }
154  else
155  {
157  }
158  const btCollisionObjectWrapper* tmpWrap = 0;
159 
161  {
162  tmpWrap = m_resultOut->getBody0Wrap();
163  m_resultOut->setBody0Wrap(&triObWrap);
164  m_resultOut->setShapeIdentifiersA(partId, triangleIndex);
165  }
166  else
167  {
168  tmpWrap = m_resultOut->getBody1Wrap();
169  m_resultOut->setBody1Wrap(&triObWrap);
170  m_resultOut->setShapeIdentifiersB(partId, triangleIndex);
171  }
172 
173  {
174  BT_PROFILE("processCollision (GJK?)");
176  }
177 
179  {
180  m_resultOut->setBody0Wrap(tmpWrap);
181  }
182  else
183  {
184  m_resultOut->setBody1Wrap(tmpWrap);
185  }
186 
187  colAlgo->~btCollisionAlgorithm();
189  }
190 }
191 
192 void btConvexTriangleCallback::setTimeStepAndCounters(btScalar collisionMarginTriangle, const btDispatcherInfo& dispatchInfo, const btCollisionObjectWrapper* convexBodyWrap, const btCollisionObjectWrapper* triBodyWrap, btManifoldResult* resultOut)
193 {
194  m_convexBodyWrap = convexBodyWrap;
195  m_triBodyWrap = triBodyWrap;
196 
197  m_dispatchInfoPtr = &dispatchInfo;
198  m_collisionMarginTriangle = collisionMarginTriangle;
199  m_resultOut = resultOut;
200 
201  //recalc aabbs
202  btTransform convexInTriangleSpace;
204  const btCollisionShape* convexShape = static_cast<const btCollisionShape*>(m_convexBodyWrap->getCollisionShape());
205  //CollisionShape* triangleShape = static_cast<btCollisionShape*>(triBody->m_collisionShape);
206  convexShape->getAabb(convexInTriangleSpace, m_aabbMin, m_aabbMax);
207  btScalar extraMargin = collisionMarginTriangle + resultOut->m_closestPointDistanceThreshold;
208 
209  btVector3 extra(extraMargin, extraMargin, extraMargin);
210 
211  m_aabbMax += extra;
212  m_aabbMin -= extra;
213 }
214 
216 {
218 }
219 
221 {
222  BT_PROFILE("btConvexConcaveCollisionAlgorithm::processCollision");
223 
224  const btCollisionObjectWrapper* convexBodyWrap = m_isSwapped ? body1Wrap : body0Wrap;
225  const btCollisionObjectWrapper* triBodyWrap = m_isSwapped ? body0Wrap : body1Wrap;
226 
227  if (triBodyWrap->getCollisionShape()->isConcave())
228  {
229  if (triBodyWrap->getCollisionShape()->getShapeType() == SDF_SHAPE_PROXYTYPE)
230  {
231  btSdfCollisionShape* sdfShape = (btSdfCollisionShape*)triBodyWrap->getCollisionShape();
232  if (convexBodyWrap->getCollisionShape()->isConvex())
233  {
234  btConvexShape* convex = (btConvexShape*)convexBodyWrap->getCollisionShape();
235  btAlignedObjectArray<btVector3> queryVertices;
236 
237  if (convex->isPolyhedral())
238  {
240  for (int v = 0; v < poly->getNumVertices(); v++)
241  {
242  btVector3 vtx;
243  poly->getVertex(v, vtx);
244  queryVertices.push_back(vtx);
245  }
246  }
247  btScalar maxDist = SIMD_EPSILON;
248 
249  if (convex->getShapeType() == SPHERE_SHAPE_PROXYTYPE)
250  {
251  queryVertices.push_back(btVector3(0, 0, 0));
252  btSphereShape* sphere = (btSphereShape*)convex;
253  maxDist = sphere->getRadius() + SIMD_EPSILON;
254  }
255  if (queryVertices.size())
256  {
258  //m_btConvexTriangleCallback.m_manifoldPtr->clearManifold();
259 
261  for (int v = 0; v < queryVertices.size(); v++)
262  {
263  const btVector3& vtx = queryVertices[v];
264  btVector3 vtxWorldSpace = convexBodyWrap->getWorldTransform() * vtx;
265  btVector3 vtxInSdf = triBodyWrap->getWorldTransform().invXform(vtxWorldSpace);
266 
267  btVector3 normalLocal;
268  btScalar dist;
269  if (sdfShape->queryPoint(vtxInSdf, dist, normalLocal))
270  {
271  if (dist <= maxDist)
272  {
273  normalLocal.safeNormalize();
274  btVector3 normal = triBodyWrap->getWorldTransform().getBasis() * normalLocal;
275 
276  if (convex->getShapeType() == SPHERE_SHAPE_PROXYTYPE)
277  {
278  btSphereShape* sphere = (btSphereShape*)convex;
279  dist -= sphere->getRadius();
280  vtxWorldSpace -= sphere->getRadius() * normal;
281  }
282  resultOut->addContactPoint(normal, vtxWorldSpace - normal * dist, dist);
283  }
284  }
285  }
286  resultOut->refreshContactPoints();
287  }
288  }
289  }
290  else
291  {
292  const btConcaveShape* concaveShape = static_cast<const btConcaveShape*>(triBodyWrap->getCollisionShape());
293 
294  if (convexBodyWrap->getCollisionShape()->isConvex())
295  {
296  btScalar collisionMarginTriangle = concaveShape->getMargin();
297 
299  m_btConvexTriangleCallback.setTimeStepAndCounters(collisionMarginTriangle, dispatchInfo, convexBodyWrap, triBodyWrap, resultOut);
300 
302 
304 
305  resultOut->refreshContactPoints();
306 
308  }
309  }
310  }
311 }
312 
314 {
315  (void)resultOut;
316  (void)dispatchInfo;
317  btCollisionObject* convexbody = m_isSwapped ? body1 : body0;
318  btCollisionObject* triBody = m_isSwapped ? body0 : body1;
319 
320  //quick approximation using raycast, todo: hook up to the continuous collision detection (one of the btConvexCast)
321 
322  //only perform CCD above a certain threshold, this prevents blocking on the long run
323  //because object in a blocked ccd state (hitfraction<1) get their linear velocity halved each frame...
324  btScalar squareMot0 = (convexbody->getInterpolationWorldTransform().getOrigin() - convexbody->getWorldTransform().getOrigin()).length2();
325  if (squareMot0 < convexbody->getCcdSquareMotionThreshold())
326  {
327  return btScalar(1.);
328  }
329 
330  //const btVector3& from = convexbody->m_worldTransform.getOrigin();
331  //btVector3 to = convexbody->m_interpolationWorldTransform.getOrigin();
332  //todo: only do if the motion exceeds the 'radius'
333 
334  btTransform triInv = triBody->getWorldTransform().inverse();
335  btTransform convexFromLocal = triInv * convexbody->getWorldTransform();
336  btTransform convexToLocal = triInv * convexbody->getInterpolationWorldTransform();
337 
338  struct LocalTriangleSphereCastCallback : public btTriangleCallback
339  {
340  btTransform m_ccdSphereFromTrans;
341  btTransform m_ccdSphereToTrans;
342  btTransform m_meshTransform;
343 
344  btScalar m_ccdSphereRadius;
345  btScalar m_hitFraction;
346 
347  LocalTriangleSphereCastCallback(const btTransform& from, const btTransform& to, btScalar ccdSphereRadius, btScalar hitFraction)
348  : m_ccdSphereFromTrans(from),
349  m_ccdSphereToTrans(to),
350  m_ccdSphereRadius(ccdSphereRadius),
351  m_hitFraction(hitFraction)
352  {
353  }
354 
355  virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex)
356  {
357  BT_PROFILE("processTriangle");
358  (void)partId;
359  (void)triangleIndex;
360  //do a swept sphere for now
361  btTransform ident;
362  ident.setIdentity();
363  btConvexCast::CastResult castResult;
364  castResult.m_fraction = m_hitFraction;
365  btSphereShape pointShape(m_ccdSphereRadius);
366  btTriangleShape triShape(triangle[0], triangle[1], triangle[2]);
367  btVoronoiSimplexSolver simplexSolver;
368  btSubsimplexConvexCast convexCaster(&pointShape, &triShape, &simplexSolver);
369  //GjkConvexCast convexCaster(&pointShape,convexShape,&simplexSolver);
370  //ContinuousConvexCollision convexCaster(&pointShape,convexShape,&simplexSolver,0);
371  //local space?
372 
373  if (convexCaster.calcTimeOfImpact(m_ccdSphereFromTrans, m_ccdSphereToTrans,
374  ident, ident, castResult))
375  {
376  if (m_hitFraction > castResult.m_fraction)
377  m_hitFraction = castResult.m_fraction;
378  }
379  }
380  };
381 
382  if (triBody->getCollisionShape()->isConcave())
383  {
384  btVector3 rayAabbMin = convexFromLocal.getOrigin();
385  rayAabbMin.setMin(convexToLocal.getOrigin());
386  btVector3 rayAabbMax = convexFromLocal.getOrigin();
387  rayAabbMax.setMax(convexToLocal.getOrigin());
388  btScalar ccdRadius0 = convexbody->getCcdSweptSphereRadius();
389  rayAabbMin -= btVector3(ccdRadius0, ccdRadius0, ccdRadius0);
390  rayAabbMax += btVector3(ccdRadius0, ccdRadius0, ccdRadius0);
391 
392  btScalar curHitFraction = btScalar(1.); //is this available?
393  LocalTriangleSphereCastCallback raycastCallback(convexFromLocal, convexToLocal,
394  convexbody->getCcdSweptSphereRadius(), curHitFraction);
395 
396  raycastCallback.m_hitFraction = convexbody->getHitFraction();
397 
398  btCollisionObject* concavebody = triBody;
399 
400  btConcaveShape* triangleMesh = (btConcaveShape*)concavebody->getCollisionShape();
401 
402  if (triangleMesh)
403  {
404  triangleMesh->processAllTriangles(&raycastCallback, rayAabbMin, rayAabbMax);
405  }
406 
407  if (raycastCallback.m_hitFraction < convexbody->getHitFraction())
408  {
409  convexbody->setHitFraction(raycastCallback.m_hitFraction);
410  return raycastCallback.m_hitFraction;
411  }
412  }
413 
414  return btScalar(1.);
415 }
bool TestTriangleAgainstAabb2(const btVector3 *vertices, const btVector3 &aabbMin, const btVector3 &aabbMax)
conservative test for overlap between triangle and aabb
Definition: btAabbUtil2.h:54
@ SDF_SHAPE_PROXYTYPE
@ SPHERE_SHAPE_PROXYTYPE
@ BT_CLOSEST_POINT_ALGORITHMS
Definition: btDispatcher.h:71
@ BT_CONTACT_POINT_ALGORITHMS
Definition: btDispatcher.h:70
#define BT_PROFILE(name)
Definition: btQuickprof.h:198
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition: btScalar.h:314
#define SIMD_EPSILON
Definition: btScalar.h:543
This class is not enabled yet (work-in-progress) to more aggressively activate objects.
int size() const
return the number of elements in the array
void push_back(const T &_Val)
btCollisionAlgorithm is an collision interface that is compatible with the Broadphase and btDispatche...
virtual void processCollision(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut)=0
btCollisionObject can be used to manage collision detection objects.
const btTransform & getInterpolationWorldTransform() const
btScalar getHitFraction() const
btTransform & getWorldTransform()
void setHitFraction(btScalar hitFraction)
const btCollisionShape * getCollisionShape() const
btScalar getCcdSweptSphereRadius() const
Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm::
The btCollisionShape class provides an interface for collision shapes that can be shared among btColl...
int getShapeType() const
bool isConvex() const
virtual void getAabb(const btTransform &t, btVector3 &aabbMin, btVector3 &aabbMax) const =0
getAabb returns the axis aligned bounding box in the coordinate frame of the given transform t.
bool isConcave() const
bool isPolyhedral() const
The btConcaveShape class provides an interface for non-moving (static) concave shapes.
virtual btScalar getMargin() const
virtual void processAllTriangles(btTriangleCallback *callback, const btVector3 &aabbMin, const btVector3 &aabbMax) const =0
btConvexConcaveCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, bool isSwapped)
btScalar calculateTimeOfImpact(btCollisionObject *body0, btCollisionObject *body1, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut)
virtual void getAllContactManifolds(btManifoldArray &manifoldArray)
virtual void processCollision(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut)
virtual void setMargin(btScalar margin)
The btConvexShape is an abstract shape interface, implemented by all convex shapes such as btBoxShape...
Definition: btConvexShape.h:33
virtual btVector3 localGetSupportingVertex(const btVector3 &vec) const =0
btConvexTriangleCallback(btDispatcher *dispatcher, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, bool isSwapped)
virtual void processTriangle(btVector3 *triangle, int partId, int triangleIndex)
void setTimeStepAndCounters(btScalar collisionMarginTriangle, const btDispatcherInfo &dispatchInfo, const btCollisionObjectWrapper *convexBodyWrap, const btCollisionObjectWrapper *triBodyWrap, btManifoldResult *resultOut)
const btDispatcherInfo * m_dispatchInfoPtr
const btCollisionObjectWrapper * m_convexBodyWrap
const btCollisionObjectWrapper * m_triBodyWrap
The btDispatcher interface class can be used in combination with broadphase to dispatch calculations ...
Definition: btDispatcher.h:77
virtual void clearManifold(btPersistentManifold *manifold)=0
virtual void releaseManifold(btPersistentManifold *manifold)=0
virtual void freeCollisionAlgorithm(void *ptr)=0
virtual btPersistentManifold * getNewManifold(const btCollisionObject *b0, const btCollisionObject *b1)=0
virtual btCollisionAlgorithm * findAlgorithm(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, btPersistentManifold *sharedManifold, ebtDispatcherQueryType queryType)=0
virtual void drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color)=0
virtual int getDebugMode() const =0
btManifoldResult is a helper class to manage contact results.
virtual void setShapeIdentifiersA(int partId0, int index0)
setShapeIdentifiersA/B provides experimental support for per-triangle material / custom material comb...
void setBody0Wrap(const btCollisionObjectWrapper *obj0Wrap)
const btCollisionObject * getBody0Internal() const
const btCollisionObjectWrapper * getBody1Wrap() const
const btCollisionObjectWrapper * getBody0Wrap() const
void setBody1Wrap(const btCollisionObjectWrapper *obj1Wrap)
void setPersistentManifold(btPersistentManifold *manifoldPtr)
virtual void setShapeIdentifiersB(int partId1, int index1)
btScalar m_closestPointDistanceThreshold
virtual void addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorld, btScalar depth)
btMatrix3x3 inverse() const
Return the inverse of the matrix.
Definition: btMatrix3x3.h:1093
void setBodies(const btCollisionObject *body0, const btCollisionObject *body1)
btScalar getContactBreakingThreshold() const
The btPolyhedralConvexShape is an internal interface class for polyhedral convex shapes.
virtual void getVertex(int i, btVector3 &vtx) const =0
virtual int getNumVertices() const =0
bool queryPoint(const btVector3 &ptInSDF, btScalar &distOut, btVector3 &normal)
The btSphereShape implements an implicit sphere, centered around a local origin with radius.
Definition: btSphereShape.h:25
btScalar getRadius() const
Definition: btSphereShape.h:48
btSubsimplexConvexCast implements Gino van den Bergens' paper "Ray Casting against bteral Convex Obje...
virtual bool calcTimeOfImpact(const btTransform &fromA, const btTransform &toA, const btTransform &fromB, const btTransform &toB, CastResult &result)
SimsimplexConvexCast calculateTimeOfImpact calculates the time of impact+normal for the linear cast (...
The btTransform class supports rigid transforms with only translation and rotation and no scaling/she...
Definition: btTransform.h:30
btTransform inverse() const
Return the inverse of this transform.
Definition: btTransform.h:183
btMatrix3x3 & getBasis()
Return the basis matrix for the rotation.
Definition: btTransform.h:109
btVector3 invXform(const btVector3 &inVec) const
Definition: btTransform.h:216
btVector3 & getOrigin()
Return the origin vector translation.
Definition: btTransform.h:114
void setIdentity()
Set this transformation to the identity.
Definition: btTransform.h:167
The btTriangleCallback provides a callback for each overlapping triangle when calling processAllTrian...
btVector3 can be used to represent 3D points and vectors.
Definition: btVector3.h:82
btVector3 & safeNormalize()
Definition: btVector3.h:286
void setMax(const btVector3 &other)
Set each element to the max of the current values and the values of another btVector3.
Definition: btVector3.h:609
btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition: btVector3.h:303
btScalar dot(const btVector3 &v) const
Return the dot product.
Definition: btVector3.h:229
void setMin(const btVector3 &other)
Set each element to the min of the current values and the values of another btVector3.
Definition: btVector3.h:626
btVoronoiSimplexSolver is an implementation of the closest point distance algorithm from a 1-4 points...
const btCollisionShape * getCollisionShape() const
const btCollisionObject * getCollisionObject() const
const btTransform & getWorldTransform() const
RayResult stores the closest result alternatively, add a callback method to decide about closest/all ...
Definition: btConvexCast.h:47
class btIDebugDraw * m_debugDraw
Definition: btDispatcher.h:58