|
Bullet Collision Detection & Physics Library
|
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