00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "LinearMath/btScalar.h"
00017 #include "SphereTriangleDetector.h"
00018 #include "BulletCollision/CollisionShapes/btTriangleShape.h"
00019 #include "BulletCollision/CollisionShapes/btSphereShape.h"
00020
00021
00022 SphereTriangleDetector::SphereTriangleDetector(btSphereShape* sphere,btTriangleShape* triangle,btScalar contactBreakingThreshold)
00023 :m_sphere(sphere),
00024 m_triangle(triangle),
00025 m_contactBreakingThreshold(contactBreakingThreshold)
00026 {
00027
00028 }
00029
00030 void SphereTriangleDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults)
00031 {
00032
00033 (void)debugDraw;
00034 const btTransform& transformA = input.m_transformA;
00035 const btTransform& transformB = input.m_transformB;
00036
00037 btVector3 point,normal;
00038 btScalar timeOfImpact = btScalar(1.);
00039 btScalar depth = btScalar(0.);
00040
00041
00042 btTransform sphereInTr = transformB.inverseTimes(transformA);
00043
00044 if (collide(sphereInTr.getOrigin(),point,normal,depth,timeOfImpact,m_contactBreakingThreshold))
00045 {
00046 if (swapResults)
00047 {
00048 btVector3 normalOnB = transformB.getBasis()*normal;
00049 btVector3 normalOnA = -normalOnB;
00050 btVector3 pointOnA = transformB*point+normalOnB*depth;
00051 output.addContactPoint(normalOnA,pointOnA,depth);
00052 } else
00053 {
00054 output.addContactPoint(transformB.getBasis()*normal,transformB*point,depth);
00055 }
00056 }
00057
00058 }
00059
00060 #define MAX_OVERLAP btScalar(0.)
00061
00062
00063
00064
00065
00066 btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest);
00067
00068 btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest) {
00069 btVector3 diff = p - from;
00070 btVector3 v = to - from;
00071 btScalar t = v.dot(diff);
00072
00073 if (t > 0) {
00074 btScalar dotVV = v.dot(v);
00075 if (t < dotVV) {
00076 t /= dotVV;
00077 diff -= t*v;
00078 } else {
00079 t = 1;
00080 diff -= v;
00081 }
00082 } else
00083 t = 0;
00084
00085 nearest = from + t*v;
00086 return diff.dot(diff);
00087 }
00088
00089 bool SphereTriangleDetector::facecontains(const btVector3 &p,const btVector3* vertices,btVector3& normal) {
00090 btVector3 lp(p);
00091 btVector3 lnormal(normal);
00092
00093 return pointInTriangle(vertices, lnormal, &lp);
00094 }
00095
00097 bool SphereTriangleDetector::collide(const btVector3& sphereCenter,btVector3 &point, btVector3& resultNormal, btScalar& depth, btScalar &timeOfImpact, btScalar contactBreakingThreshold)
00098 {
00099
00100 const btVector3* vertices = &m_triangle->getVertexPtr(0);
00101 const btVector3& c = sphereCenter;
00102 btScalar r = m_sphere->getRadius();
00103
00104 btVector3 delta (0,0,0);
00105
00106 btVector3 normal = (vertices[1]-vertices[0]).cross(vertices[2]-vertices[0]);
00107 normal.normalize();
00108 btVector3 p1ToCentre = c - vertices[0];
00109 btScalar distanceFromPlane = p1ToCentre.dot(normal);
00110
00111 if (distanceFromPlane < btScalar(0.))
00112 {
00113
00114
00115 distanceFromPlane *= btScalar(-1.);
00116 normal *= btScalar(-1.);
00117 }
00118
00119 btScalar contactMargin = contactBreakingThreshold;
00120 bool isInsideContactPlane = distanceFromPlane < r + contactMargin;
00121 bool isInsideShellPlane = distanceFromPlane < r;
00122
00123 btScalar deltaDotNormal = delta.dot(normal);
00124 if (!isInsideShellPlane && deltaDotNormal >= btScalar(0.0))
00125 return false;
00126
00127
00128 bool hasContact = false;
00129 btVector3 contactPoint;
00130 if (isInsideContactPlane) {
00131 if (facecontains(c,vertices,normal)) {
00132
00133 hasContact = true;
00134 contactPoint = c - normal*distanceFromPlane;
00135 } else {
00136
00137 btScalar contactCapsuleRadiusSqr = (r + contactMargin) * (r + contactMargin);
00138 btVector3 nearestOnEdge;
00139 for (int i = 0; i < m_triangle->getNumEdges(); i++) {
00140
00141 btVector3 pa;
00142 btVector3 pb;
00143
00144 m_triangle->getEdge(i,pa,pb);
00145
00146 btScalar distanceSqr = SegmentSqrDistance(pa,pb,c, nearestOnEdge);
00147 if (distanceSqr < contactCapsuleRadiusSqr) {
00148
00149 hasContact = true;
00150 contactPoint = nearestOnEdge;
00151 }
00152
00153 }
00154 }
00155 }
00156
00157 if (hasContact) {
00158 btVector3 contactToCentre = c - contactPoint;
00159 btScalar distanceSqr = contactToCentre.length2();
00160 if (distanceSqr < (r - MAX_OVERLAP)*(r - MAX_OVERLAP)) {
00161 btScalar distance = btSqrt(distanceSqr);
00162 resultNormal = contactToCentre;
00163 resultNormal.normalize();
00164 point = contactPoint;
00165 depth = -(r-distance);
00166 return true;
00167 }
00168
00169 if (delta.dot(contactToCentre) >= btScalar(0.0))
00170 return false;
00171
00172
00173 point = contactPoint;
00174 timeOfImpact = btScalar(0.0);
00175 return true;
00176 }
00177
00178 return false;
00179 }
00180
00181
00182 bool SphereTriangleDetector::pointInTriangle(const btVector3 vertices[], const btVector3 &normal, btVector3 *p )
00183 {
00184 const btVector3* p1 = &vertices[0];
00185 const btVector3* p2 = &vertices[1];
00186 const btVector3* p3 = &vertices[2];
00187
00188 btVector3 edge1( *p2 - *p1 );
00189 btVector3 edge2( *p3 - *p2 );
00190 btVector3 edge3( *p1 - *p3 );
00191
00192 btVector3 p1_to_p( *p - *p1 );
00193 btVector3 p2_to_p( *p - *p2 );
00194 btVector3 p3_to_p( *p - *p3 );
00195
00196 btVector3 edge1_normal( edge1.cross(normal));
00197 btVector3 edge2_normal( edge2.cross(normal));
00198 btVector3 edge3_normal( edge3.cross(normal));
00199
00200 btScalar r1, r2, r3;
00201 r1 = edge1_normal.dot( p1_to_p );
00202 r2 = edge2_normal.dot( p2_to_p );
00203 r3 = edge3_normal.dot( p3_to_p );
00204 if ( ( r1 > 0 && r2 > 0 && r3 > 0 ) ||
00205 ( r1 <= 0 && r2 <= 0 && r3 <= 0 ) )
00206 return true;
00207 return false;
00208
00209 }