1 #include "btInternalEdgeUtility.h" 2 3 #include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" 4 #include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" 5 #include "BulletCollision/CollisionShapes/btTriangleShape.h" 6 #include "BulletCollision/CollisionDispatch/btCollisionObject.h" 7 #include "BulletCollision/NarrowPhaseCollision/btManifoldPoint.h" 8 #include "LinearMath/btIDebugDraw.h" 9 #include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h" 10 11 //#define DEBUG_INTERNAL_EDGE 12 13 #ifdef DEBUG_INTERNAL_EDGE 14 #include <stdio.h> 15 #endif //DEBUG_INTERNAL_EDGE 16 17 18 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 19 static btIDebugDraw* gDebugDrawer = 0; 20 21 void btSetDebugDrawer(btIDebugDraw* debugDrawer) 22 { 23 gDebugDrawer = debugDrawer; 24 } 25 26 static void btDebugDrawLine(const btVector3& from,const btVector3& to, const btVector3& color) 27 { 28 if (gDebugDrawer) 29 gDebugDrawer->drawLine(from,to,color); 30 } 31 #endif //BT_INTERNAL_EDGE_DEBUG_DRAW 32 33 34 static int btGetHash(int partId, int triangleIndex) 35 { 36 int hash = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | triangleIndex; 37 return hash; 38 } 39 40 41 42 static btScalar btGetAngle(const btVector3& edgeA, const btVector3& normalA,const btVector3& normalB) 43 { 44 const btVector3 refAxis0 = edgeA; 45 const btVector3 refAxis1 = normalA; 46 const btVector3 swingAxis = normalB; 47 btScalar angle = btAtan2(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1)); 48 return angle; 49 } 50 51 52 struct btConnectivityProcessor : public btTriangleCallback 53 { 54 int m_partIdA; 55 int m_triangleIndexA; 56 btVector3* m_triangleVerticesA; 57 btTriangleInfoMap* m_triangleInfoMap; 58 59 60 virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) 61 { 62 //skip self-collisions 63 if ((m_partIdA == partId) && (m_triangleIndexA == triangleIndex)) 64 return; 65 66 //skip duplicates (disabled for now) 67 //if ((m_partIdA <= partId) && (m_triangleIndexA <= triangleIndex)) 68 // return; 69 70 //search for shared vertices and edges 71 int numshared = 0; 72 int sharedVertsA[3]={-1,-1,-1}; 73 int sharedVertsB[3]={-1,-1,-1}; 74 75 ///skip degenerate triangles 76 btScalar crossBSqr = ((triangle[1]-triangle[0]).cross(triangle[2]-triangle[0])).length2(); 77 if (crossBSqr < m_triangleInfoMap->m_equalVertexThreshold) 78 return; 79 80 81 btScalar crossASqr = ((m_triangleVerticesA[1]-m_triangleVerticesA[0]).cross(m_triangleVerticesA[2]-m_triangleVerticesA[0])).length2(); 82 ///skip degenerate triangles 83 if (crossASqr< m_triangleInfoMap->m_equalVertexThreshold) 84 return; 85 86 #if 0 87 printf("triangle A[0] = (%f,%f,%f)\ntriangle A[1] = (%f,%f,%f)\ntriangle A[2] = (%f,%f,%f)\n", 88 m_triangleVerticesA[0].getX(),m_triangleVerticesA[0].getY(),m_triangleVerticesA[0].getZ(), 89 m_triangleVerticesA[1].getX(),m_triangleVerticesA[1].getY(),m_triangleVerticesA[1].getZ(), 90 m_triangleVerticesA[2].getX(),m_triangleVerticesA[2].getY(),m_triangleVerticesA[2].getZ()); 91 92 printf("partId=%d, triangleIndex=%d\n",partId,triangleIndex); 93 printf("triangle B[0] = (%f,%f,%f)\ntriangle B[1] = (%f,%f,%f)\ntriangle B[2] = (%f,%f,%f)\n", 94 triangle[0].getX(),triangle[0].getY(),triangle[0].getZ(), 95 triangle[1].getX(),triangle[1].getY(),triangle[1].getZ(), 96 triangle[2].getX(),triangle[2].getY(),triangle[2].getZ()); 97 #endif 98 99 for (int i=0;i<3;i++) 100 { 101 for (int j=0;j<3;j++) 102 { 103 if ( (m_triangleVerticesA[i]-triangle[j]).length2() < m_triangleInfoMap->m_equalVertexThreshold) 104 { 105 sharedVertsA[numshared] = i; 106 sharedVertsB[numshared] = j; 107 numshared++; 108 ///degenerate case 109 if(numshared >= 3) 110 return; 111 } 112 } 113 ///degenerate case 114 if(numshared >= 3) 115 return; 116 } 117 switch (numshared) 118 { 119 case 0: 120 { 121 break; 122 } 123 case 1: 124 { 125 //shared vertex 126 break; 127 } 128 case 2: 129 { 130 //shared edge 131 //we need to make sure the edge is in the order V2V0 and not V0V2 so that the signs are correct 132 if (sharedVertsA[0] == 0 && sharedVertsA[1] == 2) 133 { 134 sharedVertsA[0] = 2; 135 sharedVertsA[1] = 0; 136 int tmp = sharedVertsB[1]; 137 sharedVertsB[1] = sharedVertsB[0]; 138 sharedVertsB[0] = tmp; 139 } 140 141 int hash = btGetHash(m_partIdA,m_triangleIndexA); 142 143 btTriangleInfo* info = m_triangleInfoMap->find(hash); 144 if (!info) 145 { 146 btTriangleInfo tmp; 147 m_triangleInfoMap->insert(hash,tmp); 148 info = m_triangleInfoMap->find(hash); 149 } 150 151 int sumvertsA = sharedVertsA[0]+sharedVertsA[1]; 152 int otherIndexA = 3-sumvertsA; 153 154 155 btVector3 edge(m_triangleVerticesA[sharedVertsA[1]]-m_triangleVerticesA[sharedVertsA[0]]); 156 157 btTriangleShape tA(m_triangleVerticesA[0],m_triangleVerticesA[1],m_triangleVerticesA[2]); 158 int otherIndexB = 3-(sharedVertsB[0]+sharedVertsB[1]); 159 160 btTriangleShape tB(triangle[sharedVertsB[1]],triangle[sharedVertsB[0]],triangle[otherIndexB]); 161 //btTriangleShape tB(triangle[0],triangle[1],triangle[2]); 162 163 btVector3 normalA; 164 btVector3 normalB; 165 tA.calcNormal(normalA); 166 tB.calcNormal(normalB); 167 edge.normalize(); 168 btVector3 edgeCrossA = edge.cross(normalA).normalize(); 169 170 { 171 btVector3 tmp = m_triangleVerticesA[otherIndexA]-m_triangleVerticesA[sharedVertsA[0]]; 172 if (edgeCrossA.dot(tmp) < 0) 173 { 174 edgeCrossA*=-1; 175 } 176 } 177 178 btVector3 edgeCrossB = edge.cross(normalB).normalize(); 179 180 { 181 btVector3 tmp = triangle[otherIndexB]-triangle[sharedVertsB[0]]; 182 if (edgeCrossB.dot(tmp) < 0) 183 { 184 edgeCrossB*=-1; 185 } 186 } 187 188 btScalar angle2 = 0; 189 btScalar ang4 = 0.f; 190 191 192 btVector3 calculatedEdge = edgeCrossA.cross(edgeCrossB); 193 btScalar len2 = calculatedEdge.length2(); 194 195 btScalar correctedAngle(0); 196 btVector3 calculatedNormalB = normalA; 197 bool isConvex = false; 198 199 if (len2<m_triangleInfoMap->m_planarEpsilon) 200 { 201 angle2 = 0.f; 202 ang4 = 0.f; 203 } else 204 { 205 206 calculatedEdge.normalize(); 207 btVector3 calculatedNormalA = calculatedEdge.cross(edgeCrossA); 208 calculatedNormalA.normalize(); 209 angle2 = btGetAngle(calculatedNormalA,edgeCrossA,edgeCrossB); 210 ang4 = SIMD_PI-angle2; 211 btScalar dotA = normalA.dot(edgeCrossB); 212 ///@todo: check if we need some epsilon, due to floating point imprecision 213 isConvex = (dotA<0.); 214 215 correctedAngle = isConvex ? ang4 : -ang4; 216 btQuaternion orn2(calculatedEdge,-correctedAngle); 217 calculatedNormalB = btMatrix3x3(orn2)*normalA; 218 219 220 } 221 222 223 224 225 226 //alternatively use 227 //btVector3 calculatedNormalB2 = quatRotate(orn,normalA); 228 229 230 switch (sumvertsA) 231 { 232 case 1: 233 { 234 btVector3 edge = m_triangleVerticesA[0]-m_triangleVerticesA[1]; 235 btQuaternion orn(edge,-correctedAngle); 236 btVector3 computedNormalB = quatRotate(orn,normalA); 237 btScalar bla = computedNormalB.dot(normalB); 238 if (bla<0) 239 { 240 computedNormalB*=-1; 241 info->m_flags |= TRI_INFO_V0V1_SWAP_NORMALB; 242 } 243 #ifdef DEBUG_INTERNAL_EDGE 244 if ((computedNormalB-normalB).length()>0.0001) 245 { 246 printf("warning: normals not identical\n"); 247 } 248 #endif//DEBUG_INTERNAL_EDGE 249 250 info->m_edgeV0V1Angle = -correctedAngle; 251 252 if (isConvex) 253 info->m_flags |= TRI_INFO_V0V1_CONVEX; 254 break; 255 } 256 case 2: 257 { 258 btVector3 edge = m_triangleVerticesA[2]-m_triangleVerticesA[0]; 259 btQuaternion orn(edge,-correctedAngle); 260 btVector3 computedNormalB = quatRotate(orn,normalA); 261 if (computedNormalB.dot(normalB)<0) 262 { 263 computedNormalB*=-1; 264 info->m_flags |= TRI_INFO_V2V0_SWAP_NORMALB; 265 } 266 267 #ifdef DEBUG_INTERNAL_EDGE 268 if ((computedNormalB-normalB).length()>0.0001) 269 { 270 printf("warning: normals not identical\n"); 271 } 272 #endif //DEBUG_INTERNAL_EDGE 273 info->m_edgeV2V0Angle = -correctedAngle; 274 if (isConvex) 275 info->m_flags |= TRI_INFO_V2V0_CONVEX; 276 break; 277 } 278 case 3: 279 { 280 btVector3 edge = m_triangleVerticesA[1]-m_triangleVerticesA[2]; 281 btQuaternion orn(edge,-correctedAngle); 282 btVector3 computedNormalB = quatRotate(orn,normalA); 283 if (computedNormalB.dot(normalB)<0) 284 { 285 info->m_flags |= TRI_INFO_V1V2_SWAP_NORMALB; 286 computedNormalB*=-1; 287 } 288 #ifdef DEBUG_INTERNAL_EDGE 289 if ((computedNormalB-normalB).length()>0.0001) 290 { 291 printf("warning: normals not identical\n"); 292 } 293 #endif //DEBUG_INTERNAL_EDGE 294 info->m_edgeV1V2Angle = -correctedAngle; 295 296 if (isConvex) 297 info->m_flags |= TRI_INFO_V1V2_CONVEX; 298 break; 299 } 300 } 301 302 break; 303 } 304 default: 305 { 306 // printf("warning: duplicate triangle\n"); 307 } 308 309 } 310 } 311 }; 312 ///////////////////////////////////////////////////////// 313 ///////////////////////////////////////////////////////// 314 315 void btGenerateInternalEdgeInfo (btBvhTriangleMeshShape*trimeshShape, btTriangleInfoMap* triangleInfoMap) 316 { 317 //the user pointer shouldn't already be used for other purposes, we intend to store connectivity info there! 318 if (trimeshShape->getTriangleInfoMap()) 319 return; 320 321 trimeshShape->setTriangleInfoMap(triangleInfoMap); 322 323 btStridingMeshInterface* meshInterface = trimeshShape->getMeshInterface(); 324 const btVector3& meshScaling = meshInterface->getScaling(); 325 326 for (int partId = 0; partId< meshInterface->getNumSubParts();partId++) 327 { 328 const unsigned char *vertexbase = 0; 329 int numverts = 0; 330 PHY_ScalarType type = PHY_INTEGER; 331 int stride = 0; 332 const unsigned char *indexbase = 0; 333 int indexstride = 0; 334 int numfaces = 0; 335 PHY_ScalarType indicestype = PHY_INTEGER; 336 //PHY_ScalarType indexType=0; 337 338 btVector3 triangleVerts[3]; 339 meshInterface->getLockedReadOnlyVertexIndexBase(&vertexbase,numverts, type,stride,&indexbase,indexstride,numfaces,indicestype,partId); 340 btVector3 aabbMin,aabbMax; 341 342 for (int triangleIndex = 0 ; triangleIndex < numfaces;triangleIndex++) 343 { 344 unsigned int* gfxbase = (unsigned int*)(indexbase+triangleIndex*indexstride); 345 346 for (int j=2;j>=0;j--) 347 { 348 349 int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; 350 if (type == PHY_FLOAT) 351 { 352 float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); 353 triangleVerts[j] = btVector3( 354 graphicsbase[0]*meshScaling.getX(), 355 graphicsbase[1]*meshScaling.getY(), 356 graphicsbase[2]*meshScaling.getZ()); 357 } 358 else 359 { 360 double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); 361 triangleVerts[j] = btVector3( btScalar(graphicsbase[0]*meshScaling.getX()), btScalar(graphicsbase[1]*meshScaling.getY()), btScalar(graphicsbase[2]*meshScaling.getZ())); 362 } 363 } 364 aabbMin.setValue(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); 365 aabbMax.setValue(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); 366 aabbMin.setMin(triangleVerts[0]); 367 aabbMax.setMax(triangleVerts[0]); 368 aabbMin.setMin(triangleVerts[1]); 369 aabbMax.setMax(triangleVerts[1]); 370 aabbMin.setMin(triangleVerts[2]); 371 aabbMax.setMax(triangleVerts[2]); 372 373 btConnectivityProcessor connectivityProcessor; 374 connectivityProcessor.m_partIdA = partId; 375 connectivityProcessor.m_triangleIndexA = triangleIndex; 376 connectivityProcessor.m_triangleVerticesA = &triangleVerts[0]; 377 connectivityProcessor.m_triangleInfoMap = triangleInfoMap; 378 379 trimeshShape->processAllTriangles(&connectivityProcessor,aabbMin,aabbMax); 380 } 381 382 } 383 384 } 385 386 387 388 389 // Given a point and a line segment (defined by two points), compute the closest point 390 // in the line. Cap the point at the endpoints of the line segment. 391 void btNearestPointInLineSegment(const btVector3 &point, const btVector3& line0, const btVector3& line1, btVector3& nearestPoint) 392 { 393 btVector3 lineDelta = line1 - line0; 394 395 // Handle degenerate lines 396 if ( lineDelta.fuzzyZero()) 397 { 398 nearestPoint = line0; 399 } 400 else 401 { 402 btScalar delta = (point-line0).dot(lineDelta) / (lineDelta).dot(lineDelta); 403 404 // Clamp the point to conform to the segment's endpoints 405 if ( delta < 0 ) 406 delta = 0; 407 else if ( delta > 1 ) 408 delta = 1; 409 410 nearestPoint = line0 + lineDelta*delta; 411 } 412 } 413 414 415 416 417 bool btClampNormal(const btVector3& edge,const btVector3& tri_normal_org,const btVector3& localContactNormalOnB, btScalar correctedEdgeAngle, btVector3 & clampedLocalNormal) 418 { 419 btVector3 tri_normal = tri_normal_org; 420 //we only have a local triangle normal, not a local contact normal -> only normal in world space... 421 //either compute the current angle all in local space, or all in world space 422 423 btVector3 edgeCross = edge.cross(tri_normal).normalize(); 424 btScalar curAngle = btGetAngle(edgeCross,tri_normal,localContactNormalOnB); 425 426 if (correctedEdgeAngle<0) 427 { 428 if (curAngle < correctedEdgeAngle) 429 { 430 btScalar diffAngle = correctedEdgeAngle-curAngle; 431 btQuaternion rotation(edge,diffAngle ); 432 clampedLocalNormal = btMatrix3x3(rotation)*localContactNormalOnB; 433 return true; 434 } 435 } 436 437 if (correctedEdgeAngle>=0) 438 { 439 if (curAngle > correctedEdgeAngle) 440 { 441 btScalar diffAngle = correctedEdgeAngle-curAngle; 442 btQuaternion rotation(edge,diffAngle ); 443 clampedLocalNormal = btMatrix3x3(rotation)*localContactNormalOnB; 444 return true; 445 } 446 } 447 return false; 448 } 449 450 451 452 /// Changes a btManifoldPoint collision normal to the normal from the mesh. 453 void btAdjustInternalEdgeContacts(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0Wrap,const btCollisionObjectWrapper* colObj1Wrap, int partId0, int index0, int normalAdjustFlags) 454 { 455 //btAssert(colObj0->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE); 456 if (colObj0Wrap->getCollisionShape()->getShapeType() != TRIANGLE_SHAPE_PROXYTYPE) 457 return; 458 459 btBvhTriangleMeshShape* trimesh = 0; 460 461 if( colObj0Wrap->getCollisionObject()->getCollisionShape()->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE ) 462 trimesh = ((btScaledBvhTriangleMeshShape*)colObj0Wrap->getCollisionObject()->getCollisionShape())->getChildShape(); 463 else 464 trimesh = (btBvhTriangleMeshShape*)colObj0Wrap->getCollisionObject()->getCollisionShape(); 465 466 btTriangleInfoMap* triangleInfoMapPtr = (btTriangleInfoMap*) trimesh->getTriangleInfoMap(); 467 if (!triangleInfoMapPtr) 468 return; 469 470 int hash = btGetHash(partId0,index0); 471 472 473 btTriangleInfo* info = triangleInfoMapPtr->find(hash); 474 if (!info) 475 return; 476 477 btScalar frontFacing = (normalAdjustFlags & BT_TRIANGLE_CONVEX_BACKFACE_MODE)==0? 1.f : -1.f; 478 479 const btTriangleShape* tri_shape = static_cast<const btTriangleShape*>(colObj0Wrap->getCollisionShape()); 480 btVector3 v0,v1,v2; 481 tri_shape->getVertex(0,v0); 482 tri_shape->getVertex(1,v1); 483 tri_shape->getVertex(2,v2); 484 485 //btVector3 center = (v0+v1+v2)*btScalar(1./3.); 486 487 btVector3 red(1,0,0), green(0,1,0),blue(0,0,1),white(1,1,1),black(0,0,0); 488 btVector3 tri_normal; 489 tri_shape->calcNormal(tri_normal); 490 491 //btScalar dot = tri_normal.dot(cp.m_normalWorldOnB); 492 btVector3 nearest; 493 btNearestPointInLineSegment(cp.m_localPointB,v0,v1,nearest); 494 495 btVector3 contact = cp.m_localPointB; 496 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 497 const btTransform& tr = colObj0->getWorldTransform(); 498 btDebugDrawLine(tr*nearest,tr*cp.m_localPointB,red); 499 #endif //BT_INTERNAL_EDGE_DEBUG_DRAW 500 501 502 503 bool isNearEdge = false; 504 505 int numConcaveEdgeHits = 0; 506 int numConvexEdgeHits = 0; 507 508 btVector3 localContactNormalOnB = colObj0Wrap->getWorldTransform().getBasis().transpose() * cp.m_normalWorldOnB; 509 localContactNormalOnB.normalize();//is this necessary? 510 511 // Get closest edge 512 int bestedge=-1; 513 btScalar disttobestedge=BT_LARGE_FLOAT; 514 // 515 // Edge 0 -> 1 516 if (btFabs(info->m_edgeV0V1Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) 517 { 518 btVector3 nearest; 519 btNearestPointInLineSegment( cp.m_localPointB, v0, v1, nearest ); 520 btScalar len=(contact-nearest).length(); 521 // 522 if( len < disttobestedge ) 523 { 524 bestedge=0; 525 disttobestedge=len; 526 } 527 } 528 // Edge 1 -> 2 529 if (btFabs(info->m_edgeV1V2Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) 530 { 531 btVector3 nearest; 532 btNearestPointInLineSegment( cp.m_localPointB, v1, v2, nearest ); 533 btScalar len=(contact-nearest).length(); 534 // 535 if( len < disttobestedge ) 536 { 537 bestedge=1; 538 disttobestedge=len; 539 } 540 } 541 // Edge 2 -> 0 542 if (btFabs(info->m_edgeV2V0Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) 543 { 544 btVector3 nearest; 545 btNearestPointInLineSegment( cp.m_localPointB, v2, v0, nearest ); 546 btScalar len=(contact-nearest).length(); 547 // 548 if( len < disttobestedge ) 549 { 550 bestedge=2; 551 disttobestedge=len; 552 } 553 } 554 555 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 556 btVector3 upfix=tri_normal * btVector3(0.1f,0.1f,0.1f); 557 btDebugDrawLine(tr * v0 + upfix, tr * v1 + upfix, red ); 558 #endif 559 if (btFabs(info->m_edgeV0V1Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) 560 { 561 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 562 btDebugDrawLine(tr*contact,tr*(contact+cp.m_normalWorldOnB*10),black); 563 #endif 564 btScalar len = (contact-nearest).length(); 565 if(len<triangleInfoMapPtr->m_edgeDistanceThreshold) 566 if( bestedge==0 ) 567 { 568 btVector3 edge(v0-v1); 569 isNearEdge = true; 570 571 if (info->m_edgeV0V1Angle==btScalar(0)) 572 { 573 numConcaveEdgeHits++; 574 } else 575 { 576 577 bool isEdgeConvex = (info->m_flags & TRI_INFO_V0V1_CONVEX); 578 btScalar swapFactor = isEdgeConvex ? btScalar(1) : btScalar(-1); 579 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 580 btDebugDrawLine(tr*nearest,tr*(nearest+swapFactor*tri_normal*10),white); 581 #endif //BT_INTERNAL_EDGE_DEBUG_DRAW 582 583 btVector3 nA = swapFactor * tri_normal; 584 585 btQuaternion orn(edge,info->m_edgeV0V1Angle); 586 btVector3 computedNormalB = quatRotate(orn,tri_normal); 587 if (info->m_flags & TRI_INFO_V0V1_SWAP_NORMALB) 588 computedNormalB*=-1; 589 btVector3 nB = swapFactor*computedNormalB; 590 591 btScalar NdotA = localContactNormalOnB.dot(nA); 592 btScalar NdotB = localContactNormalOnB.dot(nB); 593 bool backFacingNormal = (NdotA< triangleInfoMapPtr->m_convexEpsilon) && (NdotB<triangleInfoMapPtr->m_convexEpsilon); 594 595 #ifdef DEBUG_INTERNAL_EDGE 596 { 597 598 btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+tr.getBasis()*(nB*20),red); 599 } 600 #endif //DEBUG_INTERNAL_EDGE 601 602 603 if (backFacingNormal) 604 { 605 numConcaveEdgeHits++; 606 } 607 else 608 { 609 numConvexEdgeHits++; 610 btVector3 clampedLocalNormal; 611 bool isClamped = btClampNormal(edge,swapFactor*tri_normal,localContactNormalOnB, info->m_edgeV0V1Angle,clampedLocalNormal); 612 if (isClamped) 613 { 614 if (((normalAdjustFlags & BT_TRIANGLE_CONVEX_DOUBLE_SIDED)!=0) || (clampedLocalNormal.dot(frontFacing*tri_normal)>0)) 615 { 616 btVector3 newNormal = colObj0Wrap->getWorldTransform().getBasis() * clampedLocalNormal; 617 // cp.m_distance1 = cp.m_distance1 * newNormal.dot(cp.m_normalWorldOnB); 618 cp.m_normalWorldOnB = newNormal; 619 // Reproject collision point along normal. (what about cp.m_distance1?) 620 cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; 621 cp.m_localPointB = colObj0Wrap->getWorldTransform().invXform(cp.m_positionWorldOnB); 622 623 } 624 } 625 } 626 } 627 } 628 } 629 630 btNearestPointInLineSegment(contact,v1,v2,nearest); 631 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 632 btDebugDrawLine(tr*nearest,tr*cp.m_localPointB,green); 633 #endif //BT_INTERNAL_EDGE_DEBUG_DRAW 634 635 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 636 btDebugDrawLine(tr * v1 + upfix, tr * v2 + upfix , green ); 637 #endif 638 639 if (btFabs(info->m_edgeV1V2Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) 640 { 641 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 642 btDebugDrawLine(tr*contact,tr*(contact+cp.m_normalWorldOnB*10),black); 643 #endif //BT_INTERNAL_EDGE_DEBUG_DRAW 644 645 646 647 btScalar len = (contact-nearest).length(); 648 if(len<triangleInfoMapPtr->m_edgeDistanceThreshold) 649 if( bestedge==1 ) 650 { 651 isNearEdge = true; 652 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 653 btDebugDrawLine(tr*nearest,tr*(nearest+tri_normal*10),white); 654 #endif //BT_INTERNAL_EDGE_DEBUG_DRAW 655 656 btVector3 edge(v1-v2); 657 658 isNearEdge = true; 659 660 if (info->m_edgeV1V2Angle == btScalar(0)) 661 { 662 numConcaveEdgeHits++; 663 } else 664 { 665 bool isEdgeConvex = (info->m_flags & TRI_INFO_V1V2_CONVEX)!=0; 666 btScalar swapFactor = isEdgeConvex ? btScalar(1) : btScalar(-1); 667 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 668 btDebugDrawLine(tr*nearest,tr*(nearest+swapFactor*tri_normal*10),white); 669 #endif //BT_INTERNAL_EDGE_DEBUG_DRAW 670 671 btVector3 nA = swapFactor * tri_normal; 672 673 btQuaternion orn(edge,info->m_edgeV1V2Angle); 674 btVector3 computedNormalB = quatRotate(orn,tri_normal); 675 if (info->m_flags & TRI_INFO_V1V2_SWAP_NORMALB) 676 computedNormalB*=-1; 677 btVector3 nB = swapFactor*computedNormalB; 678 679 #ifdef DEBUG_INTERNAL_EDGE 680 { 681 btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+tr.getBasis()*(nB*20),red); 682 } 683 #endif //DEBUG_INTERNAL_EDGE 684 685 686 btScalar NdotA = localContactNormalOnB.dot(nA); 687 btScalar NdotB = localContactNormalOnB.dot(nB); 688 bool backFacingNormal = (NdotA< triangleInfoMapPtr->m_convexEpsilon) && (NdotB<triangleInfoMapPtr->m_convexEpsilon); 689 690 if (backFacingNormal) 691 { 692 numConcaveEdgeHits++; 693 } 694 else 695 { 696 numConvexEdgeHits++; 697 btVector3 localContactNormalOnB = colObj0Wrap->getWorldTransform().getBasis().transpose() * cp.m_normalWorldOnB; 698 btVector3 clampedLocalNormal; 699 bool isClamped = btClampNormal(edge,swapFactor*tri_normal,localContactNormalOnB, info->m_edgeV1V2Angle,clampedLocalNormal); 700 if (isClamped) 701 { 702 if (((normalAdjustFlags & BT_TRIANGLE_CONVEX_DOUBLE_SIDED)!=0) || (clampedLocalNormal.dot(frontFacing*tri_normal)>0)) 703 { 704 btVector3 newNormal = colObj0Wrap->getWorldTransform().getBasis() * clampedLocalNormal; 705 // cp.m_distance1 = cp.m_distance1 * newNormal.dot(cp.m_normalWorldOnB); 706 cp.m_normalWorldOnB = newNormal; 707 // Reproject collision point along normal. 708 cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; 709 cp.m_localPointB = colObj0Wrap->getWorldTransform().invXform(cp.m_positionWorldOnB); 710 } 711 } 712 } 713 } 714 } 715 } 716 717 btNearestPointInLineSegment(contact,v2,v0,nearest); 718 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 719 btDebugDrawLine(tr*nearest,tr*cp.m_localPointB,blue); 720 #endif //BT_INTERNAL_EDGE_DEBUG_DRAW 721 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 722 btDebugDrawLine(tr * v2 + upfix, tr * v0 + upfix , blue ); 723 #endif 724 725 if (btFabs(info->m_edgeV2V0Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) 726 { 727 728 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 729 btDebugDrawLine(tr*contact,tr*(contact+cp.m_normalWorldOnB*10),black); 730 #endif //BT_INTERNAL_EDGE_DEBUG_DRAW 731 732 btScalar len = (contact-nearest).length(); 733 if(len<triangleInfoMapPtr->m_edgeDistanceThreshold) 734 if( bestedge==2 ) 735 { 736 isNearEdge = true; 737 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 738 btDebugDrawLine(tr*nearest,tr*(nearest+tri_normal*10),white); 739 #endif //BT_INTERNAL_EDGE_DEBUG_DRAW 740 741 btVector3 edge(v2-v0); 742 743 if (info->m_edgeV2V0Angle==btScalar(0)) 744 { 745 numConcaveEdgeHits++; 746 } else 747 { 748 749 bool isEdgeConvex = (info->m_flags & TRI_INFO_V2V0_CONVEX)!=0; 750 btScalar swapFactor = isEdgeConvex ? btScalar(1) : btScalar(-1); 751 #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW 752 btDebugDrawLine(tr*nearest,tr*(nearest+swapFactor*tri_normal*10),white); 753 #endif //BT_INTERNAL_EDGE_DEBUG_DRAW 754 755 btVector3 nA = swapFactor * tri_normal; 756 btQuaternion orn(edge,info->m_edgeV2V0Angle); 757 btVector3 computedNormalB = quatRotate(orn,tri_normal); 758 if (info->m_flags & TRI_INFO_V2V0_SWAP_NORMALB) 759 computedNormalB*=-1; 760 btVector3 nB = swapFactor*computedNormalB; 761 762 #ifdef DEBUG_INTERNAL_EDGE 763 { 764 btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+tr.getBasis()*(nB*20),red); 765 } 766 #endif //DEBUG_INTERNAL_EDGE 767 768 btScalar NdotA = localContactNormalOnB.dot(nA); 769 btScalar NdotB = localContactNormalOnB.dot(nB); 770 bool backFacingNormal = (NdotA< triangleInfoMapPtr->m_convexEpsilon) && (NdotB<triangleInfoMapPtr->m_convexEpsilon); 771 772 if (backFacingNormal) 773 { 774 numConcaveEdgeHits++; 775 } 776 else 777 { 778 numConvexEdgeHits++; 779 // printf("hitting convex edge\n"); 780 781 782 btVector3 localContactNormalOnB = colObj0Wrap->getWorldTransform().getBasis().transpose() * cp.m_normalWorldOnB; 783 btVector3 clampedLocalNormal; 784 bool isClamped = btClampNormal(edge,swapFactor*tri_normal,localContactNormalOnB,info->m_edgeV2V0Angle,clampedLocalNormal); 785 if (isClamped) 786 { 787 if (((normalAdjustFlags & BT_TRIANGLE_CONVEX_DOUBLE_SIDED)!=0) || (clampedLocalNormal.dot(frontFacing*tri_normal)>0)) 788 { 789 btVector3 newNormal = colObj0Wrap->getWorldTransform().getBasis() * clampedLocalNormal; 790 // cp.m_distance1 = cp.m_distance1 * newNormal.dot(cp.m_normalWorldOnB); 791 cp.m_normalWorldOnB = newNormal; 792 // Reproject collision point along normal. 793 cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; 794 cp.m_localPointB = colObj0Wrap->getWorldTransform().invXform(cp.m_positionWorldOnB); 795 } 796 } 797 } 798 } 799 800 801 } 802 } 803 804 #ifdef DEBUG_INTERNAL_EDGE 805 { 806 btVector3 color(0,1,1); 807 btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+cp.m_normalWorldOnB*10,color); 808 } 809 #endif //DEBUG_INTERNAL_EDGE 810 811 if (isNearEdge) 812 { 813 814 if (numConcaveEdgeHits>0) 815 { 816 if ((normalAdjustFlags & BT_TRIANGLE_CONCAVE_DOUBLE_SIDED)!=0) 817 { 818 //fix tri_normal so it pointing the same direction as the current local contact normal 819 if (tri_normal.dot(localContactNormalOnB) < 0) 820 { 821 tri_normal *= -1; 822 } 823 cp.m_normalWorldOnB = colObj0Wrap->getWorldTransform().getBasis()*tri_normal; 824 } else 825 { 826 btVector3 newNormal = tri_normal *frontFacing; 827 //if the tri_normal is pointing opposite direction as the current local contact normal, skip it 828 btScalar d = newNormal.dot(localContactNormalOnB) ; 829 if (d< 0) 830 { 831 return; 832 } 833 //modify the normal to be the triangle normal (or backfacing normal) 834 cp.m_normalWorldOnB = colObj0Wrap->getWorldTransform().getBasis() *newNormal; 835 } 836 837 // Reproject collision point along normal. 838 cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; 839 cp.m_localPointB = colObj0Wrap->getWorldTransform().invXform(cp.m_positionWorldOnB); 840 } 841 } 842 } 843