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