Bullet Collision Detection & Physics Library
btConvexConcaveCollisionAlgorithm.cpp
Go to the documentation of this file.
1/*
2Bullet Continuous Collision Detection and Physics Library
3Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
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
30
32 : btActivatingCollisionAlgorithm(ci, body0Wrap, body1Wrap),
33 m_btConvexTriangleCallback(ci.m_dispatcher1, body0Wrap, body1Wrap, isSwapped),
34 m_isSwapped(isSwapped)
35{
36}
37
41
43{
44 if (m_btConvexTriangleCallback.m_manifoldPtr)
45 {
46 manifoldArray.push_back(m_btConvexTriangleCallback.m_manifoldPtr);
47 }
48}
49
50btConvexTriangleCallback::btConvexTriangleCallback(btDispatcher* dispatcher, const btCollisionObjectWrapper* body0Wrap, const btCollisionObjectWrapper* body1Wrap, bool isSwapped) : m_dispatcher(dispatcher),
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 //
59 m_manifoldPtr = m_dispatcher->getNewManifold(m_convexBodyWrap->getCollisionObject(), m_triBodyWrap->getCollisionObject());
60
61 clearCache();
62}
63
69
74
75void 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
93 if (m_dispatchInfoPtr && m_dispatchInfoPtr->m_debugDraw && (m_dispatchInfoPtr->m_debugDraw->getDebugMode() &btIDebugDraw::DBG_DrawWireframe ))
94 {
95 const btCollisionObject* ob = const_cast<btCollisionObject*>(m_triBodyWrap->getCollisionObject());
96 btVector3 color(1,1,0);
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
104 if (m_convexBodyWrap->getCollisionShape()->isConvex())
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
117 btConvexShape* convex = (btConvexShape*)m_convexBodyWrap->getCollisionShape();
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);
124 btScalar contact_threshold = m_manifoldPtr->getContactBreakingThreshold()+ m_resultOut->m_closestPointDistanceThreshold;
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
150 if (m_resultOut->m_closestPointDistanceThreshold > 0)
151 {
153 }
154 else
155 {
157 }
158 const btCollisionObjectWrapper* tmpWrap = 0;
159
160 if (m_resultOut->getBody0Internal() == m_triBodyWrap->getCollisionObject())
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
178 if (m_resultOut->getBody0Internal() == m_triBodyWrap->getCollisionObject())
179 {
180 m_resultOut->setBody0Wrap(tmpWrap);
181 }
182 else
183 {
184 m_resultOut->setBody1Wrap(tmpWrap);
185 }
186
187 colAlgo->~btCollisionAlgorithm();
189 }
190}
191
192void 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;
203 convexInTriangleSpace = m_triBodyWrap->getWorldTransform().inverse() * m_convexBodyWrap->getWorldTransform();
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
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();
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 {
257 resultOut->setPersistentManifold(m_btConvexTriangleCallback.m_manifoldPtr);
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
298 resultOut->setPersistentManifold(m_btConvexTriangleCallback.m_manifoldPtr);
299 m_btConvexTriangleCallback.setTimeStepAndCounters(collisionMarginTriangle, dispatchInfo, convexBodyWrap, triBodyWrap, resultOut);
300
301 m_btConvexTriangleCallback.m_manifoldPtr->setBodies(convexBodyWrap->getCollisionObject(), triBodyWrap->getCollisionObject());
302
304
305 resultOut->refreshContactPoints();
306
307 m_btConvexTriangleCallback.clearWrapperData();
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
btAlignedObjectArray< btPersistentManifold * > btManifoldArray
@ BT_CLOSEST_POINT_ALGORITHMS
@ BT_CONTACT_POINT_ALGORITHMS
#define BT_PROFILE(name)
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
btActivatingCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo &ci)
The btAlignedObjectArray template class uses a subset of the stl::vector interface for its methods It...
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.
btScalar getHitFraction() const
btTransform & getWorldTransform()
const btTransform & getInterpolationWorldTransform() const
const btCollisionShape * getCollisionShape() const
void setHitFraction(btScalar hitFraction)
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...
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 btCollisionObjectWrapper * m_convexBodyWrap
const btCollisionObjectWrapper * m_triBodyWrap
The btDispatcher interface class can be used in combination with broadphase to dispatch calculations ...
virtual void freeCollisionAlgorithm(void *ptr)=0
virtual btCollisionAlgorithm * findAlgorithm(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, btPersistentManifold *sharedManifold, ebtDispatcherQueryType queryType)=0
btManifoldResult is a helper class to manage contact results.
void setPersistentManifold(btPersistentManifold *manifoldPtr)
btScalar m_closestPointDistanceThreshold
virtual void addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorld, btScalar depth)
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.
btScalar getRadius() const
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.
btVector3 invXform(const btVector3 &inVec) const
btMatrix3x3 & getBasis()
Return the basis matrix for the rotation.
void setIdentity()
Set this transformation to the identity.
btVector3 & getOrigin()
Return the origin vector translation.
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
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 & safeNormalize()
Definition btVector3.h:286
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
btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
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 ...