void btPersistentManifold::refreshContactPoints(const btTransform& trA,const btTransform& trB) { int i; #ifdef DEBUG_PERSISTENCY printf("refreshContactPoints posA = (%f,%f,%f) posB = (%f,%f,%f)\n", trA.getOrigin().getX(), trA.getOrigin().getY(), trA.getOrigin().getZ(), trB.getOrigin().getX(), trB.getOrigin().getY(), trB.getOrigin().getZ()); #endif //DEBUG_PERSISTENCY /// first refresh worldspace positions and distance for (i=getNumContacts()-1;i>=0;i--) { btManifoldPoint &manifoldPoint = m_pointCache[i]; manifoldPoint.m_positionWorldOnA = trA( manifoldPoint.m_localPointA ); manifoldPoint.m_positionWorldOnB = trB( manifoldPoint.m_localPointB ); manifoldPoint.m_distance1 = (manifoldPoint.m_positionWorldOnA - manifoldPoint.m_positionWorldOnB).dot(manifoldPoint.m_normalWorldOnB); manifoldPoint.m_lifeTime++; } /// then btScalar distance2d; btVector3 projectedDifference,projectedPoint; for (i=getNumContacts()-1;i>=0;i--) { btManifoldPoint &manifoldPoint = m_pointCache[i]; //contact becomes invalid when signed distance exceeds margin (projected on contactnormal direction) if (!validContactDistance(manifoldPoint)) { removeContactPoint(i); } else { //contact also becomes invalid when relative movement orthogonal to normal exceeds margin projectedPoint = manifoldPoint.m_positionWorldOnA - manifoldPoint.m_normalWorldOnB * manifoldPoint.m_distance1; projectedDifference = manifoldPoint.m_positionWorldOnB - projectedPoint; distance2d = projectedDifference.dot(projectedDifference); if (distance2d > getContactBreakingThreshold()*getContactBreakingThreshold() ) { removeContactPoint(i); } else { //contact point processed callback if (gContactProcessedCallback) (*gContactProcessedCallback)(manifoldPoint,m_body0,m_body1); } } } #ifdef DEBUG_PERSISTENCY DebugPersistency(); #endif // }
void SphereSphereCollisionAlgorithm::doProcessCollisionAlgorithm(const CollisionObjectWrapper &object1, const CollisionObjectWrapper &object2) { const CollisionSphereShape &sphere1 = static_cast<const CollisionSphereShape &>(object1.getShape()); const CollisionSphereShape &sphere2 = static_cast<const CollisionSphereShape &>(object2.getShape()); Vector3<float> diff = object2.getShapeWorldTransform().getPosition().vector(object1.getShapeWorldTransform().getPosition()); float length = diff.length(); float radius1 = sphere1.getRadius(); float radius2 = sphere2.getRadius(); if(length - getContactBreakingThreshold() < (radius1 + radius2)) { //collision detected //compute depth penetration float depth = length - (radius1+radius2); //compute normal (if both spheres have same origin: default normal is (1,0,0)) Vector3<float> normalFromObject2(1.0, 0.0, 0.0); if(length > std::numeric_limits<float>::epsilon()) { //normalize normal (from object2 to object1) normalFromObject2 = diff / length; } //compute intersection point Point3<float> pointOnObject2 = object2.getShapeWorldTransform().getPosition().translate(radius2 * normalFromObject2); addNewContactPoint(normalFromObject2, pointOnObject2, depth); } }
int btPersistentManifold::getCacheEntry(const btManifoldPoint& newPoint) const { btScalar shortestDist = getContactBreakingThreshold() * getContactBreakingThreshold(); int size = getNumContacts(); int nearestPoint = -1; for( int i = 0; i < size; i++ ) { const btManifoldPoint &mp = m_pointCache[i]; btVector3 diffA = mp.m_localPointA- newPoint.m_localPointA; const btScalar distToManiPoint = diffA.dot(diffA); if( distToManiPoint < shortestDist ) { shortestDist = distToManiPoint; nearestPoint = i; } } return nearestPoint; }
void ConvexHullConvexHullCollisionAlgorithm::doProcessCollisionAlgorithm(const CollisionObjectWrapper &object1, const CollisionObjectWrapper &object2) { //transform convex hull shapes std::shared_ptr<CollisionConvexObject3D> convexObject1 = object1.getShape().toConvexObject(object1.getShapeWorldTransform()); std::shared_ptr<CollisionConvexObject3D> convexObject2 = object2.getShape().toConvexObject(object2.getShapeWorldTransform()); //process GJK and EPA hybrid algorithms std::unique_ptr<GJKResult<float>> gjkResultWithoutMargin = gjkAlgorithm.processGJK(*convexObject1.get(), *convexObject2.get(), false); if(gjkResultWithoutMargin->isValidResult()) { if(gjkResultWithoutMargin->isCollide()) { //collision detected on reduced objects (without margins) std::unique_ptr<GJKResult<float>> gjkResultWithMargin = gjkAlgorithm.processGJK(*convexObject1.get(), *convexObject2.get(), true); if(gjkResultWithMargin->isValidResult() && gjkResultWithMargin->isCollide()) { std::unique_ptr<EPAResult<float>> epaResult = epaAlgorithm.processEPA(*convexObject1.get(), *convexObject2.get(), *gjkResultWithMargin.get()); if(epaResult->isValidResult() && epaResult->isCollide()) { //should be always true except for problems due to float imprecision const Vector3<float> &normalFromObject2 = -epaResult->getNormal(); const Point3<float> &pointOnObject2 = epaResult->getContactPointB(); const float penetrationDepth = -epaResult->getPenetrationDepth(); addNewContactPoint(normalFromObject2, pointOnObject2, penetrationDepth); } } }else { //collision detected on enlarged objects (with margins) OR no collision detected const Vector3<float> &vectorBA = gjkResultWithoutMargin->getClosestPointB().vector(gjkResultWithoutMargin->getClosestPointA()); float vectorBALength = vectorBA.length(); float sumMargins = convexObject1->getOuterMargin() + convexObject2->getOuterMargin(); if(sumMargins > vectorBALength - getContactBreakingThreshold()) { //collision detected on enlarged objects const Vector3<float> &normalFromObject2 = vectorBA.normalize(); const Point3<float> &pointOnObject2 = gjkResultWithoutMargin->getClosestPointB().translate(normalFromObject2 * convexObject2->getOuterMargin()); const float penetrationDepth = vectorBALength - sumMargins; addNewContactPoint(normalFromObject2, pointOnObject2, penetrationDepth); } } } }