Bullet Collision Detection & Physics Library

btContinuousConvexCollision.cpp

Go to the documentation of this file.
00001 /*
00002 Bullet Continuous Collision Detection and Physics Library
00003 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
00004 
00005 This software is provided 'as-is', without any express or implied warranty.
00006 In no event will the authors be held liable for any damages arising from the use of this software.
00007 Permission is granted to anyone to use this software for any purpose, 
00008 including commercial applications, and to alter it and redistribute it freely, 
00009 subject to the following restrictions:
00010 
00011 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.
00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
00013 3. This notice may not be removed or altered from any source distribution.
00014 */
00015 
00016 
00017 #include "btContinuousConvexCollision.h"
00018 #include "BulletCollision/CollisionShapes/btConvexShape.h"
00019 #include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h"
00020 #include "LinearMath/btTransformUtil.h"
00021 #include "BulletCollision/CollisionShapes/btSphereShape.h"
00022 
00023 #include "btGjkPairDetector.h"
00024 #include "btPointCollector.h"
00025 #include "BulletCollision/CollisionShapes/btStaticPlaneShape.h"
00026 
00027 
00028 
00029 btContinuousConvexCollision::btContinuousConvexCollision ( const btConvexShape* convexA,const btConvexShape*    convexB,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* penetrationDepthSolver)
00030 :m_simplexSolver(simplexSolver),
00031 m_penetrationDepthSolver(penetrationDepthSolver),
00032 m_convexA(convexA),m_convexB1(convexB),m_planeShape(0)
00033 {
00034 }
00035 
00036 
00037 btContinuousConvexCollision::btContinuousConvexCollision( const btConvexShape*  convexA,const btStaticPlaneShape*       plane)
00038 :m_simplexSolver(0),
00039 m_penetrationDepthSolver(0),
00040 m_convexA(convexA),m_convexB1(0),m_planeShape(plane)
00041 {
00042 }
00043 
00044 
00047 #define MAX_ITERATIONS 64
00048 
00049 void btContinuousConvexCollision::computeClosestPoints( const btTransform& transA, const btTransform& transB,btPointCollector& pointCollector)
00050 {
00051         if (m_convexB1)
00052         {
00053                 m_simplexSolver->reset();
00054                 btGjkPairDetector gjk(m_convexA,m_convexB1,m_convexA->getShapeType(),m_convexB1->getShapeType(),m_convexA->getMargin(),m_convexB1->getMargin(),m_simplexSolver,m_penetrationDepthSolver);               
00055                 btGjkPairDetector::ClosestPointInput input;
00056                 input.m_transformA = transA;
00057                 input.m_transformB = transB;
00058                 gjk.getClosestPoints(input,pointCollector,0);
00059         } else
00060         {
00061                 //convex versus plane
00062                 const btConvexShape* convexShape = m_convexA;
00063                 const btStaticPlaneShape* planeShape = m_planeShape;
00064                 
00065                 bool hasCollision = false;
00066                 const btVector3& planeNormal = planeShape->getPlaneNormal();
00067                 const btScalar& planeConstant = planeShape->getPlaneConstant();
00068                 
00069                 btTransform convexWorldTransform = transA;
00070                 btTransform convexInPlaneTrans;
00071                 convexInPlaneTrans= transB.inverse() * convexWorldTransform;
00072                 btTransform planeInConvex;
00073                 planeInConvex= convexWorldTransform.inverse() * transB;
00074                 
00075                 btVector3 vtx = convexShape->localGetSupportingVertex(planeInConvex.getBasis()*-planeNormal);
00076 
00077                 btVector3 vtxInPlane = convexInPlaneTrans(vtx);
00078                 btScalar distance = (planeNormal.dot(vtxInPlane) - planeConstant);
00079 
00080                 btVector3 vtxInPlaneProjected = vtxInPlane - distance*planeNormal;
00081                 btVector3 vtxInPlaneWorld = transB * vtxInPlaneProjected;
00082                 btVector3 normalOnSurfaceB = transB.getBasis() * planeNormal;
00083 
00084                 pointCollector.addContactPoint(
00085                         normalOnSurfaceB,
00086                         vtxInPlaneWorld,
00087                         distance);
00088         }
00089 }
00090 
00091 bool    btContinuousConvexCollision::calcTimeOfImpact(
00092                                 const btTransform& fromA,
00093                                 const btTransform& toA,
00094                                 const btTransform& fromB,
00095                                 const btTransform& toB,
00096                                 CastResult& result)
00097 {
00098 
00099 
00101         btVector3 linVelA,angVelA,linVelB,angVelB;
00102         btTransformUtil::calculateVelocity(fromA,toA,btScalar(1.),linVelA,angVelA);
00103         btTransformUtil::calculateVelocity(fromB,toB,btScalar(1.),linVelB,angVelB);
00104 
00105 
00106         btScalar boundingRadiusA = m_convexA->getAngularMotionDisc();
00107         btScalar boundingRadiusB = m_convexB1?m_convexB1->getAngularMotionDisc():0.f;
00108 
00109         btScalar maxAngularProjectedVelocity = angVelA.length() * boundingRadiusA + angVelB.length() * boundingRadiusB;
00110         btVector3 relLinVel = (linVelB-linVelA);
00111 
00112         btScalar relLinVelocLength = (linVelB-linVelA).length();
00113         
00114         if ((relLinVelocLength+maxAngularProjectedVelocity) == 0.f)
00115                 return false;
00116 
00117 
00118 
00119         btScalar lambda = btScalar(0.);
00120         btVector3 v(1,0,0);
00121 
00122         int maxIter = MAX_ITERATIONS;
00123 
00124         btVector3 n;
00125         n.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
00126         bool hasResult = false;
00127         btVector3 c;
00128 
00129         btScalar lastLambda = lambda;
00130         //btScalar epsilon = btScalar(0.001);
00131 
00132         int numIter = 0;
00133         //first solution, using GJK
00134 
00135 
00136         btScalar radius = 0.001f;
00137 //      result.drawCoordSystem(sphereTr);
00138 
00139         btPointCollector        pointCollector1;
00140 
00141         {
00142         
00143                 computeClosestPoints(fromA,fromB,pointCollector1);
00144 
00145                 hasResult = pointCollector1.m_hasResult;
00146                 c = pointCollector1.m_pointInWorld;
00147         }
00148 
00149         if (hasResult)
00150         {
00151                 btScalar dist;
00152                 dist = pointCollector1.m_distance + result.m_allowedPenetration;
00153                 n = pointCollector1.m_normalOnBInWorld;
00154                 btScalar projectedLinearVelocity = relLinVel.dot(n);
00155                 if ((projectedLinearVelocity+ maxAngularProjectedVelocity)<=SIMD_EPSILON)
00156                         return false;
00157 
00158                 //not close enough
00159                 while (dist > radius)
00160                 {
00161                         if (result.m_debugDrawer)
00162                         {
00163                                 result.m_debugDrawer->drawSphere(c,0.2f,btVector3(1,1,1));
00164                         }
00165                         btScalar dLambda = btScalar(0.);
00166 
00167                         projectedLinearVelocity = relLinVel.dot(n);
00168 
00169                         
00170                         //don't report time of impact for motion away from the contact normal (or causes minor penetration)
00171                         if ((projectedLinearVelocity+ maxAngularProjectedVelocity)<=SIMD_EPSILON)
00172                                 return false;
00173                         
00174                         dLambda = dist / (projectedLinearVelocity+ maxAngularProjectedVelocity);
00175 
00176                         
00177                         
00178                         lambda = lambda + dLambda;
00179 
00180                         if (lambda > btScalar(1.))
00181                                 return false;
00182 
00183                         if (lambda < btScalar(0.))
00184                                 return false;
00185 
00186 
00187                         //todo: next check with relative epsilon
00188                         if (lambda <= lastLambda)
00189                         {
00190                                 return false;
00191                                 //n.setValue(0,0,0);
00192                                 break;
00193                         }
00194                         lastLambda = lambda;
00195 
00196                         
00197 
00198                         //interpolate to next lambda
00199                         btTransform interpolatedTransA,interpolatedTransB,relativeTrans;
00200 
00201                         btTransformUtil::integrateTransform(fromA,linVelA,angVelA,lambda,interpolatedTransA);
00202                         btTransformUtil::integrateTransform(fromB,linVelB,angVelB,lambda,interpolatedTransB);
00203                         relativeTrans = interpolatedTransB.inverseTimes(interpolatedTransA);
00204 
00205                         if (result.m_debugDrawer)
00206                         {
00207                                 result.m_debugDrawer->drawSphere(interpolatedTransA.getOrigin(),0.2f,btVector3(1,0,0));
00208                         }
00209 
00210                         result.DebugDraw( lambda );
00211 
00212                         btPointCollector        pointCollector;
00213                         computeClosestPoints(interpolatedTransA,interpolatedTransB,pointCollector);
00214 
00215                         if (pointCollector.m_hasResult)
00216                         {
00217                                 dist = pointCollector.m_distance+result.m_allowedPenetration;
00218                                 c = pointCollector.m_pointInWorld;              
00219                                 n = pointCollector.m_normalOnBInWorld;
00220                         } else
00221                         {
00222                                 result.reportFailure(-1, numIter);
00223                                 return false;
00224                         }
00225 
00226                         numIter++;
00227                         if (numIter > maxIter)
00228                         {
00229                                 result.reportFailure(-2, numIter);
00230                                 return false;
00231                         }
00232                 }
00233         
00234                 result.m_fraction = lambda;
00235                 result.m_normal = n;
00236                 result.m_hitPoint = c;
00237                 return true;
00238         }
00239 
00240         return false;
00241 
00242 }
00243