2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
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:
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.
16 ///Specialized capsule-capsule collision algorithm has been added for Bullet 2.75 release to increase ragdoll performance
17 ///If you experience problems with capsule-capsule collision, try to define BT_DISABLE_CAPSULE_CAPSULE_COLLIDER and report it in the Bullet forums
18 ///with reproduction case
19 //#define BT_DISABLE_CAPSULE_CAPSULE_COLLIDER 1
22 #include "btConvexConvexAlgorithm.h"
25 #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h"
26 #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h"
27 #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
28 #include "BulletCollision/CollisionShapes/btConvexShape.h"
29 #include "BulletCollision/CollisionShapes/btCapsuleShape.h"
30 #include "BulletCollision/CollisionShapes/btTriangleShape.h"
31 #include "BulletCollision/CollisionShapes/btConvexPolyhedron.h"
33 #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h"
34 #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
35 #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
36 #include "BulletCollision/CollisionShapes/btBoxShape.h"
37 #include "BulletCollision/CollisionDispatch/btManifoldResult.h"
39 #include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h"
40 #include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h"
41 #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h"
42 #include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h"
44 #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h"
45 #include "BulletCollision/CollisionShapes/btSphereShape.h"
47 #include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h"
49 #include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h"
50 #include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h"
51 #include "BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h"
52 #include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h"
56 static SIMD_FORCE_INLINE void segmentsClosestPoints(
60 btScalar& tA, btScalar& tB,
61 const btVector3& translation,
62 const btVector3& dirA, btScalar hlenA,
63 const btVector3& dirB, btScalar hlenB)
65 // compute the parameters of the closest points on each line segment
67 btScalar dirA_dot_dirB = btDot(dirA, dirB);
68 btScalar dirA_dot_trans = btDot(dirA, translation);
69 btScalar dirB_dot_trans = btDot(dirB, translation);
71 btScalar denom = 1.0f - dirA_dot_dirB * dirA_dot_dirB;
79 tA = (dirA_dot_trans - dirB_dot_trans * dirA_dot_dirB) / denom;
86 tB = tA * dirA_dot_dirB - dirB_dot_trans;
91 tA = tB * dirA_dot_dirB + dirA_dot_trans;
101 tA = tB * dirA_dot_dirB + dirA_dot_trans;
109 // compute the closest points relative to segment centers.
114 ptsVector = translation - offsetA + offsetB;
117 static SIMD_FORCE_INLINE btScalar capsuleCapsuleDistance(
118 btVector3& normalOnB,
120 btScalar capsuleLengthA,
121 btScalar capsuleRadiusA,
122 btScalar capsuleLengthB,
123 btScalar capsuleRadiusB,
126 const btTransform& transformA,
127 const btTransform& transformB,
128 btScalar distanceThreshold)
130 btVector3 directionA = transformA.getBasis().getColumn(capsuleAxisA);
131 btVector3 translationA = transformA.getOrigin();
132 btVector3 directionB = transformB.getBasis().getColumn(capsuleAxisB);
133 btVector3 translationB = transformB.getOrigin();
135 // translation between centers
137 btVector3 translation = translationB - translationA;
139 // compute the closest points of the capsule line segments
141 btVector3 ptsVector; // the vector between the closest points
143 btVector3 offsetA, offsetB; // offsets from segment centers to their closest points
144 btScalar tA, tB; // parameters on line segment
146 segmentsClosestPoints(ptsVector, offsetA, offsetB, tA, tB, translation,
147 directionA, capsuleLengthA, directionB, capsuleLengthB);
149 btScalar distance = ptsVector.length() - capsuleRadiusA - capsuleRadiusB;
151 if (distance > distanceThreshold)
154 btScalar lenSqr = ptsVector.length2();
155 if (lenSqr <= (SIMD_EPSILON * SIMD_EPSILON))
157 //degenerate case where 2 capsules are likely at the same location: take a vector tangential to 'directionA'
159 btPlaneSpace1(directionA, normalOnB, q);
163 // compute the contact normal
164 normalOnB = ptsVector * -btRecipSqrt(lenSqr);
166 pointOnB = transformB.getOrigin() + offsetB + normalOnB * capsuleRadiusB;
173 btConvexConvexAlgorithm::CreateFunc::CreateFunc(btConvexPenetrationDepthSolver* pdSolver)
175 m_numPerturbationIterations = 0;
176 m_minimumPointsPerturbationThreshold = 3;
177 m_pdSolver = pdSolver;
180 btConvexConvexAlgorithm::CreateFunc::~CreateFunc()
184 btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf, const btCollisionAlgorithmConstructionInfo& ci, const btCollisionObjectWrapper* body0Wrap, const btCollisionObjectWrapper* body1Wrap, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold)
185 : btActivatingCollisionAlgorithm(ci, body0Wrap, body1Wrap),
186 m_pdSolver(pdSolver),
187 m_ownManifold(false),
189 m_lowLevelOfDetail(false),
190 #ifdef USE_SEPDISTANCE_UTIL2
191 m_sepDistance((static_cast<btConvexShape*>(body0->getCollisionShape()))->getAngularMotionDisc(),
192 (static_cast<btConvexShape*>(body1->getCollisionShape()))->getAngularMotionDisc()),
194 m_numPerturbationIterations(numPerturbationIterations),
195 m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold)
201 btConvexConvexAlgorithm::~btConvexConvexAlgorithm()
206 m_dispatcher->releaseManifold(m_manifoldPtr);
210 void btConvexConvexAlgorithm ::setLowLevelOfDetail(bool useLowLevel)
212 m_lowLevelOfDetail = useLowLevel;
215 struct btPerturbedContactResult : public btManifoldResult
217 btManifoldResult* m_originalManifoldResult;
218 btTransform m_transformA;
219 btTransform m_transformB;
220 btTransform m_unPerturbedTransform;
222 btIDebugDraw* m_debugDrawer;
224 btPerturbedContactResult(btManifoldResult* originalResult, const btTransform& transformA, const btTransform& transformB, const btTransform& unPerturbedTransform, bool perturbA, btIDebugDraw* debugDrawer)
225 : m_originalManifoldResult(originalResult),
226 m_transformA(transformA),
227 m_transformB(transformB),
228 m_unPerturbedTransform(unPerturbedTransform),
229 m_perturbA(perturbA),
230 m_debugDrawer(debugDrawer)
233 virtual ~btPerturbedContactResult()
237 virtual void addContactPoint(const btVector3& normalOnBInWorld, const btVector3& pointInWorld, btScalar orgDepth)
239 btVector3 endPt, startPt;
245 btVector3 endPtOrg = pointInWorld + normalOnBInWorld * orgDepth;
246 endPt = (m_unPerturbedTransform * m_transformA.inverse())(endPtOrg);
247 newDepth = (endPt - pointInWorld).dot(normalOnBInWorld);
248 startPt = endPt - normalOnBInWorld * newDepth;
252 endPt = pointInWorld + normalOnBInWorld * orgDepth;
253 startPt = (m_unPerturbedTransform * m_transformB.inverse())(pointInWorld);
254 newDepth = (endPt - startPt).dot(normalOnBInWorld);
257 //#define DEBUG_CONTACTS 1
258 #ifdef DEBUG_CONTACTS
259 m_debugDrawer->drawLine(startPt, endPt, btVector3(1, 0, 0));
260 m_debugDrawer->drawSphere(startPt, 0.05, btVector3(0, 1, 0));
261 m_debugDrawer->drawSphere(endPt, 0.05, btVector3(0, 0, 1));
262 #endif //DEBUG_CONTACTS
264 m_originalManifoldResult->addContactPoint(normalOnBInWorld, startPt, newDepth);
268 extern btScalar gContactBreakingThreshold;
271 // Convex-Convex collision algorithm
273 void btConvexConvexAlgorithm ::processCollision(const btCollisionObjectWrapper* body0Wrap, const btCollisionObjectWrapper* body1Wrap, const btDispatcherInfo& dispatchInfo, btManifoldResult* resultOut)
278 m_manifoldPtr = m_dispatcher->getNewManifold(body0Wrap->getCollisionObject(), body1Wrap->getCollisionObject());
279 m_ownManifold = true;
281 resultOut->setPersistentManifold(m_manifoldPtr);
283 //comment-out next line to test multi-contact generation
284 //resultOut->getPersistentManifold()->clearManifold();
286 const btConvexShape* min0 = static_cast<const btConvexShape*>(body0Wrap->getCollisionShape());
287 const btConvexShape* min1 = static_cast<const btConvexShape*>(body1Wrap->getCollisionShape());
290 btVector3 pointOnBWorld;
291 #ifndef BT_DISABLE_CAPSULE_CAPSULE_COLLIDER
292 if ((min0->getShapeType() == CAPSULE_SHAPE_PROXYTYPE) && (min1->getShapeType() == CAPSULE_SHAPE_PROXYTYPE))
294 //m_manifoldPtr->clearManifold();
296 btCapsuleShape* capsuleA = (btCapsuleShape*)min0;
297 btCapsuleShape* capsuleB = (btCapsuleShape*)min1;
299 btScalar threshold = m_manifoldPtr->getContactBreakingThreshold()+ resultOut->m_closestPointDistanceThreshold;
301 btScalar dist = capsuleCapsuleDistance(normalOnB, pointOnBWorld, capsuleA->getHalfHeight(), capsuleA->getRadius(),
302 capsuleB->getHalfHeight(), capsuleB->getRadius(), capsuleA->getUpAxis(), capsuleB->getUpAxis(),
303 body0Wrap->getWorldTransform(), body1Wrap->getWorldTransform(), threshold);
305 if (dist < threshold)
307 btAssert(normalOnB.length2() >= (SIMD_EPSILON * SIMD_EPSILON));
308 resultOut->addContactPoint(normalOnB, pointOnBWorld, dist);
310 resultOut->refreshContactPoints();
314 if ((min0->getShapeType() == CAPSULE_SHAPE_PROXYTYPE) && (min1->getShapeType() == SPHERE_SHAPE_PROXYTYPE))
316 //m_manifoldPtr->clearManifold();
318 btCapsuleShape* capsuleA = (btCapsuleShape*)min0;
319 btSphereShape* capsuleB = (btSphereShape*)min1;
321 btScalar threshold = m_manifoldPtr->getContactBreakingThreshold()+ resultOut->m_closestPointDistanceThreshold;
323 btScalar dist = capsuleCapsuleDistance(normalOnB, pointOnBWorld, capsuleA->getHalfHeight(), capsuleA->getRadius(),
324 0., capsuleB->getRadius(), capsuleA->getUpAxis(), 1,
325 body0Wrap->getWorldTransform(), body1Wrap->getWorldTransform(), threshold);
327 if (dist < threshold)
329 btAssert(normalOnB.length2() >= (SIMD_EPSILON * SIMD_EPSILON));
330 resultOut->addContactPoint(normalOnB, pointOnBWorld, dist);
332 resultOut->refreshContactPoints();
336 if ((min0->getShapeType() == SPHERE_SHAPE_PROXYTYPE) && (min1->getShapeType() == CAPSULE_SHAPE_PROXYTYPE))
338 //m_manifoldPtr->clearManifold();
340 btSphereShape* capsuleA = (btSphereShape*)min0;
341 btCapsuleShape* capsuleB = (btCapsuleShape*)min1;
343 btScalar threshold = m_manifoldPtr->getContactBreakingThreshold()+ resultOut->m_closestPointDistanceThreshold;
345 btScalar dist = capsuleCapsuleDistance(normalOnB, pointOnBWorld, 0., capsuleA->getRadius(),
346 capsuleB->getHalfHeight(), capsuleB->getRadius(), 1, capsuleB->getUpAxis(),
347 body0Wrap->getWorldTransform(), body1Wrap->getWorldTransform(), threshold);
349 if (dist < threshold)
351 btAssert(normalOnB.length2() >= (SIMD_EPSILON * SIMD_EPSILON));
352 resultOut->addContactPoint(normalOnB, pointOnBWorld, dist);
354 resultOut->refreshContactPoints();
357 #endif //BT_DISABLE_CAPSULE_CAPSULE_COLLIDER
359 #ifdef USE_SEPDISTANCE_UTIL2
360 if (dispatchInfo.m_useConvexConservativeDistanceUtil)
362 m_sepDistance.updateSeparatingDistance(body0->getWorldTransform(), body1->getWorldTransform());
365 if (!dispatchInfo.m_useConvexConservativeDistanceUtil || m_sepDistance.getConservativeSeparatingDistance() <= 0.f)
366 #endif //USE_SEPDISTANCE_UTIL2
369 btGjkPairDetector::ClosestPointInput input;
370 btVoronoiSimplexSolver simplexSolver;
371 btGjkPairDetector gjkPairDetector(min0, min1, &simplexSolver, m_pdSolver);
372 //TODO: if (dispatchInfo.m_useContinuous)
373 gjkPairDetector.setMinkowskiA(min0);
374 gjkPairDetector.setMinkowskiB(min1);
376 #ifdef USE_SEPDISTANCE_UTIL2
377 if (dispatchInfo.m_useConvexConservativeDistanceUtil)
379 input.m_maximumDistanceSquared = BT_LARGE_FLOAT;
382 #endif //USE_SEPDISTANCE_UTIL2
384 //if (dispatchInfo.m_convexMaxDistanceUseCPT)
386 // input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactProcessingThreshold();
389 input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold() + resultOut->m_closestPointDistanceThreshold;
392 input.m_maximumDistanceSquared *= input.m_maximumDistanceSquared;
395 input.m_transformA = body0Wrap->getWorldTransform();
396 input.m_transformB = body1Wrap->getWorldTransform();
398 #ifdef USE_SEPDISTANCE_UTIL2
399 btScalar sepDist = 0.f;
400 if (dispatchInfo.m_useConvexConservativeDistanceUtil)
402 sepDist = gjkPairDetector.getCachedSeparatingDistance();
403 if (sepDist > SIMD_EPSILON)
405 sepDist += dispatchInfo.m_convexConservativeDistanceThreshold;
406 //now perturbe directions to get multiple contact points
409 #endif //USE_SEPDISTANCE_UTIL2
411 if (min0->isPolyhedral() && min1->isPolyhedral())
413 struct btDummyResult : public btDiscreteCollisionDetectorInterface::Result
415 btVector3 m_normalOnBInWorld;
416 btVector3 m_pointInWorld;
421 : m_hasContact(false)
425 virtual void setShapeIdentifiersA(int partId0, int index0) {}
426 virtual void setShapeIdentifiersB(int partId1, int index1) {}
427 virtual void addContactPoint(const btVector3& normalOnBInWorld, const btVector3& pointInWorld, btScalar depth)
430 m_normalOnBInWorld = normalOnBInWorld;
431 m_pointInWorld = pointInWorld;
436 struct btWithoutMarginResult : public btDiscreteCollisionDetectorInterface::Result
438 btDiscreteCollisionDetectorInterface::Result* m_originalResult;
439 btVector3 m_reportedNormalOnWorld;
440 btScalar m_marginOnA;
441 btScalar m_marginOnB;
442 btScalar m_reportedDistance;
445 btWithoutMarginResult(btDiscreteCollisionDetectorInterface::Result* result, btScalar marginOnA, btScalar marginOnB)
446 : m_originalResult(result),
447 m_marginOnA(marginOnA),
448 m_marginOnB(marginOnB),
453 virtual void setShapeIdentifiersA(int partId0, int index0) {}
454 virtual void setShapeIdentifiersB(int partId1, int index1) {}
455 virtual void addContactPoint(const btVector3& normalOnBInWorld, const btVector3& pointInWorldOrg, btScalar depthOrg)
457 m_reportedDistance = depthOrg;
458 m_reportedNormalOnWorld = normalOnBInWorld;
460 btVector3 adjustedPointB = pointInWorldOrg - normalOnBInWorld * m_marginOnB;
461 m_reportedDistance = depthOrg + (m_marginOnA + m_marginOnB);
462 if (m_reportedDistance < 0.f)
464 m_foundResult = true;
466 m_originalResult->addContactPoint(normalOnBInWorld, adjustedPointB, m_reportedDistance);
472 ///btBoxShape is an exception: its vertices are created WITH margin so don't subtract it
474 btScalar min0Margin = min0->getShapeType() == BOX_SHAPE_PROXYTYPE ? 0.f : min0->getMargin();
475 btScalar min1Margin = min1->getShapeType() == BOX_SHAPE_PROXYTYPE ? 0.f : min1->getMargin();
477 btWithoutMarginResult withoutMargin(resultOut, min0Margin, min1Margin);
479 btPolyhedralConvexShape* polyhedronA = (btPolyhedralConvexShape*)min0;
480 btPolyhedralConvexShape* polyhedronB = (btPolyhedralConvexShape*)min1;
481 if (polyhedronA->getConvexPolyhedron() && polyhedronB->getConvexPolyhedron())
483 btScalar threshold = m_manifoldPtr->getContactBreakingThreshold()+ resultOut->m_closestPointDistanceThreshold;
485 btScalar minDist = -1e30f;
486 btVector3 sepNormalWorldSpace;
487 bool foundSepAxis = true;
489 if (dispatchInfo.m_enableSatConvex)
491 foundSepAxis = btPolyhedralContactClipping::findSeparatingAxis(
492 *polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(),
493 body0Wrap->getWorldTransform(),
494 body1Wrap->getWorldTransform(),
495 sepNormalWorldSpace, *resultOut);
500 gjkPairDetector.setIgnoreMargin(true);
501 gjkPairDetector.getClosestPoints(input, *resultOut, dispatchInfo.m_debugDraw);
504 gjkPairDetector.getClosestPoints(input, withoutMargin, dispatchInfo.m_debugDraw);
505 //gjkPairDetector.getClosestPoints(input,dummy,dispatchInfo.m_debugDraw);
507 //btScalar l2 = gjkPairDetector.getCachedSeparatingAxis().length2();
508 //if (l2>SIMD_EPSILON)
510 sepNormalWorldSpace = withoutMargin.m_reportedNormalOnWorld; //gjkPairDetector.getCachedSeparatingAxis()*(1.f/l2);
511 //minDist = -1e30f;//gjkPairDetector.getCachedSeparatingDistance();
512 minDist = withoutMargin.m_reportedDistance; //gjkPairDetector.getCachedSeparatingDistance()+min0->getMargin()+min1->getMargin();
515 foundSepAxis = true; //gjkPairDetector.getCachedSeparatingDistance()<0.f;
517 foundSepAxis = withoutMargin.m_foundResult && minDist < 0; //-(min0->getMargin()+min1->getMargin());
523 // printf("sepNormalWorldSpace=%f,%f,%f\n",sepNormalWorldSpace.getX(),sepNormalWorldSpace.getY(),sepNormalWorldSpace.getZ());
525 worldVertsB1.resize(0);
526 btPolyhedralContactClipping::clipHullAgainstHull(sepNormalWorldSpace, *polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(),
527 body0Wrap->getWorldTransform(),
528 body1Wrap->getWorldTransform(), minDist - threshold, threshold, worldVertsB1, worldVertsB2,
533 resultOut->refreshContactPoints();
539 //we can also deal with convex versus triangle (without connectivity data)
540 if (dispatchInfo.m_enableSatConvex && polyhedronA->getConvexPolyhedron() && polyhedronB->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE)
542 btVertexArray worldSpaceVertices;
543 btTriangleShape* tri = (btTriangleShape*)polyhedronB;
544 worldSpaceVertices.push_back(body1Wrap->getWorldTransform() * tri->m_vertices1[0]);
545 worldSpaceVertices.push_back(body1Wrap->getWorldTransform() * tri->m_vertices1[1]);
546 worldSpaceVertices.push_back(body1Wrap->getWorldTransform() * tri->m_vertices1[2]);
548 //tri->initializePolyhedralFeatures();
550 btScalar threshold = m_manifoldPtr->getContactBreakingThreshold()+ resultOut->m_closestPointDistanceThreshold;
552 btVector3 sepNormalWorldSpace;
553 btScalar minDist = -1e30f;
554 btScalar maxDist = threshold;
556 bool foundSepAxis = false;
557 bool useSatSepNormal = true;
564 //initializePolyhedralFeatures performs a convex hull computation, not needed for a single triangle
565 polyhedronB->initializePolyhedralFeatures();
569 btVector3 uniqueEdges[3] = {tri->m_vertices1[1] - tri->m_vertices1[0],
570 tri->m_vertices1[2] - tri->m_vertices1[1],
571 tri->m_vertices1[0] - tri->m_vertices1[2]};
573 uniqueEdges[0].normalize();
574 uniqueEdges[1].normalize();
575 uniqueEdges[2].normalize();
577 btConvexPolyhedron polyhedron;
578 polyhedron.m_vertices.push_back(tri->m_vertices1[2]);
579 polyhedron.m_vertices.push_back(tri->m_vertices1[0]);
580 polyhedron.m_vertices.push_back(tri->m_vertices1[1]);
583 btFace combinedFaceA;
584 combinedFaceA.m_indices.push_back(0);
585 combinedFaceA.m_indices.push_back(1);
586 combinedFaceA.m_indices.push_back(2);
587 btVector3 faceNormal = uniqueEdges[0].cross(uniqueEdges[1]);
588 faceNormal.normalize();
589 btScalar planeEq = 1e30f;
590 for (int v = 0; v < combinedFaceA.m_indices.size(); v++)
592 btScalar eq = tri->m_vertices1[combinedFaceA.m_indices[v]].dot(faceNormal);
598 combinedFaceA.m_plane[0] = faceNormal[0];
599 combinedFaceA.m_plane[1] = faceNormal[1];
600 combinedFaceA.m_plane[2] = faceNormal[2];
601 combinedFaceA.m_plane[3] = -planeEq;
602 polyhedron.m_faces.push_back(combinedFaceA);
605 btFace combinedFaceB;
606 combinedFaceB.m_indices.push_back(0);
607 combinedFaceB.m_indices.push_back(2);
608 combinedFaceB.m_indices.push_back(1);
609 btVector3 faceNormal = -uniqueEdges[0].cross(uniqueEdges[1]);
610 faceNormal.normalize();
611 btScalar planeEq = 1e30f;
612 for (int v = 0; v < combinedFaceB.m_indices.size(); v++)
614 btScalar eq = tri->m_vertices1[combinedFaceB.m_indices[v]].dot(faceNormal);
621 combinedFaceB.m_plane[0] = faceNormal[0];
622 combinedFaceB.m_plane[1] = faceNormal[1];
623 combinedFaceB.m_plane[2] = faceNormal[2];
624 combinedFaceB.m_plane[3] = -planeEq;
625 polyhedron.m_faces.push_back(combinedFaceB);
628 polyhedron.m_uniqueEdges.push_back(uniqueEdges[0]);
629 polyhedron.m_uniqueEdges.push_back(uniqueEdges[1]);
630 polyhedron.m_uniqueEdges.push_back(uniqueEdges[2]);
631 polyhedron.initialize2();
633 polyhedronB->setPolyhedralFeatures(polyhedron);
636 foundSepAxis = btPolyhedralContactClipping::findSeparatingAxis(
637 *polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(),
638 body0Wrap->getWorldTransform(),
639 body1Wrap->getWorldTransform(),
640 sepNormalWorldSpace, *resultOut);
641 // printf("sepNormalWorldSpace=%f,%f,%f\n",sepNormalWorldSpace.getX(),sepNormalWorldSpace.getY(),sepNormalWorldSpace.getZ());
646 gjkPairDetector.setIgnoreMargin(true);
647 gjkPairDetector.getClosestPoints(input, *resultOut, dispatchInfo.m_debugDraw);
649 gjkPairDetector.getClosestPoints(input, dummy, dispatchInfo.m_debugDraw);
652 if (dummy.m_hasContact && dummy.m_depth < 0)
656 if (dummy.m_normalOnBInWorld.dot(sepNormalWorldSpace) < 0.99)
665 sepNormalWorldSpace.setValue(0, 0, 1); // = dummy.m_normalOnBInWorld;
666 //minDist = dummy.m_depth;
670 btScalar l2 = gjkPairDetector.getCachedSeparatingAxis().length2();
673 sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis()*(1.f/l2);
674 //minDist = gjkPairDetector.getCachedSeparatingDistance();
675 //maxDist = threshold;
676 minDist = gjkPairDetector.getCachedSeparatingDistance()-min0->getMargin()-min1->getMargin();
684 worldVertsB2.resize(0);
685 btPolyhedralContactClipping::clipFaceAgainstHull(sepNormalWorldSpace, *polyhedronA->getConvexPolyhedron(),
686 body0Wrap->getWorldTransform(), worldSpaceVertices, worldVertsB2, minDist - threshold, maxDist, *resultOut);
691 resultOut->refreshContactPoints();
699 gjkPairDetector.getClosestPoints(input, *resultOut, dispatchInfo.m_debugDraw);
701 //now perform 'm_numPerturbationIterations' collision queries with the perturbated collision objects
703 //perform perturbation when more then 'm_minimumPointsPerturbationThreshold' points
704 if (m_numPerturbationIterations && resultOut->getPersistentManifold()->getNumContacts() < m_minimumPointsPerturbationThreshold)
708 btVector3 sepNormalWorldSpace;
709 btScalar l2 = gjkPairDetector.getCachedSeparatingAxis().length2();
711 if (l2 > SIMD_EPSILON)
713 sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis() * (1.f / l2);
715 btPlaneSpace1(sepNormalWorldSpace, v0, v1);
717 bool perturbeA = true;
718 const btScalar angleLimit = 0.125f * SIMD_PI;
719 btScalar perturbeAngle;
720 btScalar radiusA = min0->getAngularMotionDisc();
721 btScalar radiusB = min1->getAngularMotionDisc();
722 if (radiusA < radiusB)
724 perturbeAngle = gContactBreakingThreshold / radiusA;
729 perturbeAngle = gContactBreakingThreshold / radiusB;
732 if (perturbeAngle > angleLimit)
733 perturbeAngle = angleLimit;
735 btTransform unPerturbedTransform;
738 unPerturbedTransform = input.m_transformA;
742 unPerturbedTransform = input.m_transformB;
745 for (i = 0; i < m_numPerturbationIterations; i++)
747 if (v0.length2() > SIMD_EPSILON)
749 btQuaternion perturbeRot(v0, perturbeAngle);
750 btScalar iterationAngle = i * (SIMD_2_PI / btScalar(m_numPerturbationIterations));
751 btQuaternion rotq(sepNormalWorldSpace, iterationAngle);
755 input.m_transformA.setBasis(btMatrix3x3(rotq.inverse() * perturbeRot * rotq) * body0Wrap->getWorldTransform().getBasis());
756 input.m_transformB = body1Wrap->getWorldTransform();
757 #ifdef DEBUG_CONTACTS
758 dispatchInfo.m_debugDraw->drawTransform(input.m_transformA, 10.0);
759 #endif //DEBUG_CONTACTS
763 input.m_transformA = body0Wrap->getWorldTransform();
764 input.m_transformB.setBasis(btMatrix3x3(rotq.inverse() * perturbeRot * rotq) * body1Wrap->getWorldTransform().getBasis());
765 #ifdef DEBUG_CONTACTS
766 dispatchInfo.m_debugDraw->drawTransform(input.m_transformB, 10.0);
770 btPerturbedContactResult perturbedResultOut(resultOut, input.m_transformA, input.m_transformB, unPerturbedTransform, perturbeA, dispatchInfo.m_debugDraw);
771 gjkPairDetector.getClosestPoints(input, perturbedResultOut, dispatchInfo.m_debugDraw);
777 #ifdef USE_SEPDISTANCE_UTIL2
778 if (dispatchInfo.m_useConvexConservativeDistanceUtil && (sepDist > SIMD_EPSILON))
780 m_sepDistance.initSeparatingDistance(gjkPairDetector.getCachedSeparatingAxis(), sepDist, body0->getWorldTransform(), body1->getWorldTransform());
782 #endif //USE_SEPDISTANCE_UTIL2
787 resultOut->refreshContactPoints();
791 bool disableCcd = false;
792 btScalar btConvexConvexAlgorithm::calculateTimeOfImpact(btCollisionObject* col0, btCollisionObject* col1, const btDispatcherInfo& dispatchInfo, btManifoldResult* resultOut)
796 ///Rather then checking ALL pairs, only calculate TOI when motion exceeds threshold
798 ///Linear motion for one of objects needs to exceed m_ccdSquareMotionThreshold
799 ///col0->m_worldTransform,
800 btScalar resultFraction = btScalar(1.);
802 btScalar squareMot0 = (col0->getInterpolationWorldTransform().getOrigin() - col0->getWorldTransform().getOrigin()).length2();
803 btScalar squareMot1 = (col1->getInterpolationWorldTransform().getOrigin() - col1->getWorldTransform().getOrigin()).length2();
805 if (squareMot0 < col0->getCcdSquareMotionThreshold() &&
806 squareMot1 < col1->getCcdSquareMotionThreshold())
807 return resultFraction;
812 //An adhoc way of testing the Continuous Collision Detection algorithms
813 //One object is approximated as a sphere, to simplify things
814 //Starting in penetration should report no time of impact
815 //For proper CCD, better accuracy and handling of 'allowed' penetration should be added
816 //also the mainloop of the physics should have a kind of toi queue (something like Brian Mirtich's application of Timewarp for Rigidbodies)
818 /// Convex0 against sphere for Convex1
820 btConvexShape* convex0 = static_cast<btConvexShape*>(col0->getCollisionShape());
822 btSphereShape sphere1(col1->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation
823 btConvexCast::CastResult result;
824 btVoronoiSimplexSolver voronoiSimplex;
825 //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex);
826 ///Simplification, one object is simplified as a sphere
827 btGjkConvexCast ccd1(convex0, &sphere1, &voronoiSimplex);
828 //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0);
829 if (ccd1.calcTimeOfImpact(col0->getWorldTransform(), col0->getInterpolationWorldTransform(),
830 col1->getWorldTransform(), col1->getInterpolationWorldTransform(), result))
832 //store result.m_fraction in both bodies
834 if (col0->getHitFraction() > result.m_fraction)
835 col0->setHitFraction(result.m_fraction);
837 if (col1->getHitFraction() > result.m_fraction)
838 col1->setHitFraction(result.m_fraction);
840 if (resultFraction > result.m_fraction)
841 resultFraction = result.m_fraction;
845 /// Sphere (for convex0) against Convex1
847 btConvexShape* convex1 = static_cast<btConvexShape*>(col1->getCollisionShape());
849 btSphereShape sphere0(col0->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation
850 btConvexCast::CastResult result;
851 btVoronoiSimplexSolver voronoiSimplex;
852 //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex);
853 ///Simplification, one object is simplified as a sphere
854 btGjkConvexCast ccd1(&sphere0, convex1, &voronoiSimplex);
855 //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0);
856 if (ccd1.calcTimeOfImpact(col0->getWorldTransform(), col0->getInterpolationWorldTransform(),
857 col1->getWorldTransform(), col1->getInterpolationWorldTransform(), result))
859 //store result.m_fraction in both bodies
861 if (col0->getHitFraction() > result.m_fraction)
862 col0->setHitFraction(result.m_fraction);
864 if (col1->getHitFraction() > result.m_fraction)
865 col1->setHitFraction(result.m_fraction);
867 if (resultFraction > result.m_fraction)
868 resultFraction = result.m_fraction;
872 return resultFraction;