@@ -333,6 +333,28 @@ GetAverageSupport(const btConvexShape* shape, const btVector3& localNormal, floa
333333 }
334334}
335335
336+ /* *
337+ * @brief This transversus the parent tree to find the base object and return its world transform
338+ * This should be the links transform and it should only need to transverse twice at max.
339+ * @param cow Bullet collision object wrapper.
340+ * @return Transform of link in world coordinates
341+ */
342+ inline btTransform getLinkTransformFromCOW (const btCollisionObjectWrapper* cow)
343+ {
344+ if (cow->m_parent )
345+ {
346+ if (cow->m_parent ->m_parent )
347+ {
348+ assert (cow->m_parent ->m_parent ->m_parent == nullptr );
349+ return cow->m_parent ->m_parent ->getWorldTransform ();
350+ }
351+
352+ return cow->m_parent ->getWorldTransform ();
353+ }
354+
355+ return cow->getWorldTransform ();
356+ }
357+
336358/* *
337359 * @brief This is used to check if a collision check is required between the provided two collision objects
338360 * @param cow1 The first collision object
@@ -372,38 +394,10 @@ inline btScalar addDiscreteSingleResult(btManifoldPoint& cp,
372394
373395 // }
374396
375- btTransform tf0, tf1, tf0_inv, tf1_inv;
376- tf0 = colObj0Wrap->getWorldTransform ();
377- tf1 = colObj1Wrap->getWorldTransform ();
378-
379- if (colObj0Wrap->m_parent )
380- {
381- if (colObj0Wrap->m_parent ->m_parent )
382- {
383- tf0 = colObj0Wrap->m_parent ->m_parent ->getWorldTransform ();
384- assert (colObj0Wrap->m_parent ->m_parent ->m_parent == nullptr );
385- }
386- else
387- {
388- tf0 = colObj0Wrap->m_parent ->getWorldTransform ();
389- }
390- }
391-
392- if (colObj1Wrap->m_parent )
393- {
394- if (colObj1Wrap->m_parent ->m_parent )
395- {
396- tf1 = colObj1Wrap->m_parent ->m_parent ->getWorldTransform ();
397- assert (colObj1Wrap->m_parent ->m_parent ->m_parent == nullptr );
398- }
399- else
400- {
401- tf1 = colObj1Wrap->m_parent ->getWorldTransform ();
402- }
403- }
404-
405- tf0_inv = tf0.inverse ();
406- tf1_inv = tf1.inverse ();
397+ btTransform tf0 = getLinkTransformFromCOW (colObj0Wrap);
398+ btTransform tf1 = getLinkTransformFromCOW (colObj1Wrap);
399+ btTransform tf0_inv = tf0.inverse ();
400+ btTransform tf1_inv = tf1.inverse ();
407401
408402 ContactResult contact;
409403 contact.link_names [0 ] = cd0->getName ();
@@ -431,6 +425,86 @@ inline btScalar addDiscreteSingleResult(btManifoldPoint& cp,
431425 return 1 ;
432426}
433427
428+ /* *
429+ * @brief Calculate the continuous contact data for casted collision shape
430+ * @param col Contact results
431+ * @param cow Bullet Collision Object Wrapper
432+ * @param pt_world Casted contact point in world coordinates
433+ * @param normal_world Casted normal to move shape out of collision in world coordinates
434+ * @param link_tf_inv The links world transform inverse
435+ * @param link_index The link index in teh ContactResults the shape is associated with
436+ */
437+ inline void calculateContinuousData (ContactResult* col,
438+ const btCollisionObjectWrapper* cow,
439+ const btVector3& pt_world,
440+ const btVector3& normal_world,
441+ const btTransform& link_tf_inv,
442+ size_t link_index)
443+ {
444+ assert (dynamic_cast <const CastHullShape*>(cow->getCollisionShape ()) != nullptr );
445+ const auto * shape = static_cast <const CastHullShape*>(cow->getCollisionShape ());
446+ assert (shape != nullptr );
447+
448+ // Get the start and final location of the shape
449+ btTransform shape_tfWorld0 = cow->getWorldTransform ();
450+ btTransform shape_tfWorld1 = cow->getWorldTransform () * shape->m_t01 ;
451+
452+ // Given the shapes final location calculate the links transform at the final location
453+ Eigen::Isometry3d s = col->transform [link_index].inverse () * convertBtToEigen (shape_tfWorld0);
454+ col->cc_transform [link_index] = convertBtToEigen (shape_tfWorld1) * s.inverse ();
455+
456+ // Get the normal in the local shapes coordinate system at start and final location
457+ btVector3 shape_normalLocal0 = normal_world * shape_tfWorld0.getBasis ();
458+ btVector3 shape_normalLocal1 = normal_world * shape_tfWorld1.getBasis ();
459+
460+ // Calculate the contact point at the start location using the casted normal vector in thapes local coordinate system
461+ btVector3 shape_ptLocal0;
462+ float shape_localsup0;
463+ GetAverageSupport (shape->m_shape , shape_normalLocal0, shape_localsup0, shape_ptLocal0);
464+ btVector3 shape_ptWorld0 = shape_tfWorld0 * shape_ptLocal0;
465+
466+ // Calculate the contact point at the final location using the casted normal vector in thapes local coordinate system
467+ btVector3 shape_ptLocal1;
468+ float shape_localsup1;
469+ GetAverageSupport (shape->m_shape , shape_normalLocal1, shape_localsup1, shape_ptLocal1);
470+ btVector3 shape_ptWorld1 = shape_tfWorld1 * shape_ptLocal1;
471+
472+ float shape_sup0 = normal_world.dot (shape_ptWorld0);
473+ float shape_sup1 = normal_world.dot (shape_ptWorld1);
474+
475+ // TODO: this section is potentially problematic. think hard about the math
476+ if (shape_sup0 - shape_sup1 > BULLET_SUPPORT_FUNC_TOLERANCE)
477+ {
478+ col->cc_time [link_index] = 0 ;
479+ col->cc_type [link_index] = ContinuousCollisionType::CCType_Time0;
480+ }
481+ else if (shape_sup1 - shape_sup0 > BULLET_SUPPORT_FUNC_TOLERANCE)
482+ {
483+ col->cc_time [link_index] = 1 ;
484+ col->cc_type [link_index] = ContinuousCollisionType::CCType_Time1;
485+ }
486+ else
487+ {
488+ // Given the contact point at the start and final location along with the casted contact point
489+ // the time between 0 and 1 can be calculated along the path between the start and final location contact occurs.
490+ float l0c = (pt_world - shape_ptWorld0).length ();
491+ float l1c = (pt_world - shape_ptWorld1).length ();
492+
493+ col->nearest_points_local [link_index] =
494+ convertBtToEigen (link_tf_inv * (shape_tfWorld0 * ((shape_ptLocal0 + shape_ptLocal1) / 2.0 )));
495+ col->cc_type [link_index] = ContinuousCollisionType::CCType_Between;
496+
497+ if (l0c + l1c < BULLET_LENGTH_TOLERANCE)
498+ {
499+ col->cc_time [link_index] = .5 ;
500+ }
501+ else
502+ {
503+ col->cc_time [link_index] = static_cast <double >(l0c / (l0c + l1c));
504+ }
505+ }
506+ }
507+
434508inline btScalar addCastSingleResult (btManifoldPoint& cp,
435509 const btCollisionObjectWrapper* colObj0Wrap,
436510 int /* index0*/ ,
@@ -458,38 +532,10 @@ inline btScalar addCastSingleResult(btManifoldPoint& cp,
458532 // return 0;
459533 // }
460534
461- btTransform tf0, tf1, tf0_inv, tf1_inv;
462- tf0 = colObj0Wrap->getWorldTransform ();
463- tf1 = colObj1Wrap->getWorldTransform ();
464-
465- if (colObj0Wrap->m_parent )
466- {
467- if (colObj0Wrap->m_parent ->m_parent )
468- {
469- tf0 = colObj0Wrap->m_parent ->m_parent ->getWorldTransform ();
470- assert (colObj0Wrap->m_parent ->m_parent ->m_parent == nullptr );
471- }
472- else
473- {
474- tf0 = colObj0Wrap->m_parent ->getWorldTransform ();
475- }
476- }
477-
478- if (colObj1Wrap->m_parent )
479- {
480- if (colObj1Wrap->m_parent ->m_parent )
481- {
482- tf1 = colObj1Wrap->m_parent ->m_parent ->getWorldTransform ();
483- assert (colObj1Wrap->m_parent ->m_parent ->m_parent == nullptr );
484- }
485- else
486- {
487- tf1 = colObj1Wrap->m_parent ->getWorldTransform ();
488- }
489- }
490-
491- tf0_inv = tf0.inverse ();
492- tf1_inv = tf1.inverse ();
535+ btTransform tf0 = getLinkTransformFromCOW (colObj0Wrap);
536+ btTransform tf1 = getLinkTransformFromCOW (colObj1Wrap);
537+ btTransform tf0_inv = tf0.inverse ();
538+ btTransform tf1_inv = tf1.inverse ();
493539
494540 ContactResult contact;
495541 contact.link_names [0 ] = cd0->getName ();
@@ -518,121 +564,16 @@ inline btScalar addCastSingleResult(btManifoldPoint& cp,
518564 if (cd0->m_collisionFilterGroup == btBroadphaseProxy::KinematicFilter &&
519565 cd1->m_collisionFilterGroup == btBroadphaseProxy::KinematicFilter)
520566 {
521- assert (dynamic_cast <const CastHullShape*>(colObj0Wrap->getCollisionShape ()) != nullptr );
522- const auto * shape0 = static_cast <const CastHullShape*>(colObj0Wrap->getCollisionShape ());
523- assert (shape0 != nullptr );
524-
525- assert (dynamic_cast <const CastHullShape*>(colObj1Wrap->getCollisionShape ()) != nullptr );
526- const auto * shape1 = static_cast <const CastHullShape*>(colObj1Wrap->getCollisionShape ());
527- assert (shape1 != nullptr );
528-
529- btVector3 shape0_normalWorld = -1 * cp.m_normalWorldOnB ;
530- btTransform shape0_tfWorld0 = colObj0Wrap->getWorldTransform ();
531- btTransform shape0_tfWorld1 = colObj0Wrap->getWorldTransform () * shape0->m_t01 ;
532- btVector3 shape1_normalWorld = cp.m_normalWorldOnB ;
533- btTransform shape1_tfWorld0 = colObj1Wrap->getWorldTransform ();
534- btTransform shape1_tfWorld1 = colObj1Wrap->getWorldTransform () * shape1->m_t01 ;
535-
536- Eigen::Isometry3d s0 = col->transform [0 ].inverse () * convertBtToEigen (shape0_tfWorld0);
537- Eigen::Isometry3d s1 = col->transform [1 ].inverse () * convertBtToEigen (shape1_tfWorld0);
538- col->cc_transform [0 ] = convertBtToEigen (shape0_tfWorld1) * s0.inverse ();
539- col->cc_transform [1 ] = convertBtToEigen (shape1_tfWorld1) * s1.inverse ();
540-
541- btVector3 shape0_normalLocal0 = shape0_normalWorld * shape0_tfWorld0.getBasis ();
542- btVector3 shape0_normalLocal1 = shape0_normalWorld * shape0_tfWorld1.getBasis ();
543- btVector3 shape1_normalLocal0 = shape1_normalWorld * shape1_tfWorld0.getBasis ();
544- btVector3 shape1_normalLocal1 = shape1_normalWorld * shape1_tfWorld1.getBasis ();
545-
546- btVector3 shape0_ptLocal0;
547- float shape0_localsup0;
548- GetAverageSupport (shape0->m_shape , shape0_normalLocal0, shape0_localsup0, shape0_ptLocal0);
549- btVector3 shape0_ptWorld0 = shape0_tfWorld0 * shape0_ptLocal0;
550- btVector3 shape0_ptLocal1;
551- float shape0_localsup1;
552- GetAverageSupport (shape0->m_shape , shape0_normalLocal1, shape0_localsup1, shape0_ptLocal1);
553- btVector3 shape0_ptWorld1 = shape0_tfWorld1 * shape0_ptLocal1;
554-
555- btVector3 shape1_ptLocal0;
556- float shape1_localsup0;
557- GetAverageSupport (shape1->m_shape , shape1_normalLocal0, shape1_localsup0, shape1_ptLocal0);
558- btVector3 shape1_ptWorld0 = shape1_tfWorld0 * shape1_ptLocal0;
559- btVector3 shape1_ptLocal1;
560- float shape1_localsup1;
561- GetAverageSupport (shape1->m_shape , shape1_normalLocal1, shape1_localsup1, shape1_ptLocal1);
562- btVector3 shape1_ptWorld1 = shape1_tfWorld1 * shape1_ptLocal1;
563-
564- float shape0_sup0 = shape0_normalWorld.dot (shape0_ptWorld0);
565- float shape0_sup1 = shape0_normalWorld.dot (shape0_ptWorld1);
566- float shape1_sup0 = shape1_normalWorld.dot (shape1_ptWorld0);
567- float shape1_sup1 = shape1_normalWorld.dot (shape1_ptWorld1);
568-
569- // TODO: this section is potentially problematic. think hard about the math
570- if (shape0_sup0 - shape0_sup1 > BULLET_SUPPORT_FUNC_TOLERANCE)
571- {
572- col->cc_time [0 ] = 0 ;
573- col->cc_type [0 ] = ContinouseCollisionType::CCType_Time0;
574- }
575- else if (shape0_sup1 - shape0_sup0 > BULLET_SUPPORT_FUNC_TOLERANCE)
576- {
577- col->cc_time [0 ] = 1 ;
578- col->cc_type [0 ] = ContinouseCollisionType::CCType_Time1;
579- }
580- else
581- {
582- float l0c = (cp.m_positionWorldOnA - shape0_ptWorld0).length ();
583- float l1c = (cp.m_positionWorldOnA - shape0_ptWorld1).length ();
584-
585- col->nearest_points_local [0 ] =
586- convertBtToEigen (tf0_inv * (shape0_tfWorld0 * ((shape0_ptLocal0 + shape0_ptLocal1) / 2.0 )));
587- col->cc_type [0 ] = ContinouseCollisionType::CCType_Between;
588-
589- if (l0c + l1c < BULLET_LENGTH_TOLERANCE)
590- {
591- col->cc_time [0 ] = .5 ;
592- }
593- else
594- {
595- col->cc_time [0 ] = static_cast <double >(l0c / (l0c + l1c));
596- }
597- }
598-
599- // TODO: this section is potentially problematic. think hard about the math
600- if (shape1_sup0 - shape1_sup1 > BULLET_SUPPORT_FUNC_TOLERANCE)
601- {
602- col->cc_time [1 ] = 0 ;
603- col->cc_type [1 ] = ContinouseCollisionType::CCType_Time0;
604- }
605- else if (shape1_sup1 - shape1_sup0 > BULLET_SUPPORT_FUNC_TOLERANCE)
606- {
607- col->cc_time [1 ] = 1 ;
608- col->cc_type [1 ] = ContinouseCollisionType::CCType_Time1;
609- }
610- else
611- {
612- float l0c = (cp.m_positionWorldOnB - shape1_ptWorld0).length ();
613- float l1c = (cp.m_positionWorldOnB - shape1_ptWorld1).length ();
614-
615- // Get local in the links frame
616- col->nearest_points_local [1 ] =
617- convertBtToEigen (tf1_inv * (shape1_tfWorld0 * ((shape1_ptLocal0 + shape1_ptLocal1) / 2.0 )));
618- col->cc_type [1 ] = ContinouseCollisionType::CCType_Between;
619-
620- if (l0c + l1c < BULLET_LENGTH_TOLERANCE)
621- {
622- col->cc_time [1 ] = .5 ;
623- }
624- else
625- {
626- col->cc_time [1 ] = static_cast <double >(l0c / (l0c + l1c));
627- }
628- }
567+ calculateContinuousData (col, colObj0Wrap, cp.m_positionWorldOnA , -1 * cp.m_normalWorldOnB , tf0_inv, 0 );
568+ calculateContinuousData (col, colObj1Wrap, cp.m_positionWorldOnB , cp.m_normalWorldOnB , tf1_inv, 1 );
629569 }
630570 else
631571 {
632572 bool castShapeIsFirst = (cd0->m_collisionFilterGroup == btBroadphaseProxy::KinematicFilter) ? true : false ;
633573 btVector3 normalWorldFromCast = -(castShapeIsFirst ? 1 : -1 ) * cp.m_normalWorldOnB ;
634574 const btCollisionObjectWrapper* firstColObjWrap = (castShapeIsFirst ? colObj0Wrap : colObj1Wrap);
635575 const btTransform& first_tf_inv = (castShapeIsFirst ? tf0_inv : tf1_inv);
576+ const btVector3& ptOnCast = castShapeIsFirst ? cp.m_positionWorldOnA : cp.m_positionWorldOnB ;
636577
637578 if (castShapeIsFirst)
638579 {
@@ -646,62 +587,7 @@ inline btScalar addCastSingleResult(btManifoldPoint& cp,
646587 col->normal *= -1 ;
647588 }
648589
649- btTransform tfWorld0, tfWorld1;
650- assert (dynamic_cast <const CastHullShape*>(firstColObjWrap->getCollisionShape ()) != nullptr );
651- const auto * shape = static_cast <const CastHullShape*>(firstColObjWrap->getCollisionShape ());
652- assert (shape != nullptr );
653-
654- tfWorld0 = firstColObjWrap->getWorldTransform ();
655- tfWorld1 = firstColObjWrap->getWorldTransform () * shape->m_t01 ;
656-
657- Eigen::Isometry3d s1 = col->transform [1 ].inverse () * convertBtToEigen (tfWorld0);
658- col->cc_transform [0 ] = col->transform [0 ];
659- col->cc_transform [1 ] = convertBtToEigen (tfWorld1) * s1.inverse ();
660-
661- btVector3 normalLocal0 = normalWorldFromCast * tfWorld0.getBasis ();
662- btVector3 normalLocal1 = normalWorldFromCast * tfWorld1.getBasis ();
663-
664- btVector3 ptLocal0;
665- float localsup0;
666- GetAverageSupport (shape->m_shape , normalLocal0, localsup0, ptLocal0);
667- btVector3 ptWorld0 = tfWorld0 * ptLocal0;
668- btVector3 ptLocal1;
669- float localsup1;
670- GetAverageSupport (shape->m_shape , normalLocal1, localsup1, ptLocal1);
671- btVector3 ptWorld1 = tfWorld1 * ptLocal1;
672-
673- float sup0 = normalWorldFromCast.dot (ptWorld0);
674- float sup1 = normalWorldFromCast.dot (ptWorld1);
675-
676- // TODO: this section is potentially problematic. think hard about the math
677- if (sup0 - sup1 > BULLET_SUPPORT_FUNC_TOLERANCE)
678- {
679- col->cc_time [1 ] = 0 ;
680- col->cc_type [1 ] = ContinouseCollisionType::CCType_Time0;
681- }
682- else if (sup1 - sup0 > BULLET_SUPPORT_FUNC_TOLERANCE)
683- {
684- col->cc_time [1 ] = 1 ;
685- col->cc_type [1 ] = ContinouseCollisionType::CCType_Time1;
686- }
687- else
688- {
689- const btVector3& ptOnCast = castShapeIsFirst ? cp.m_positionWorldOnA : cp.m_positionWorldOnB ;
690- float l0c = (ptOnCast - ptWorld0).length ();
691- float l1c = (ptOnCast - ptWorld1).length ();
692-
693- col->nearest_points_local [1 ] = convertBtToEigen (first_tf_inv * (tfWorld0 * ((ptLocal0 + ptLocal1) / 2.0 )));
694- col->cc_type [1 ] = ContinouseCollisionType::CCType_Between;
695-
696- if (l0c + l1c < BULLET_LENGTH_TOLERANCE)
697- {
698- col->cc_time [1 ] = .5 ;
699- }
700- else
701- {
702- col->cc_time [1 ] = static_cast <double >(l0c / (l0c + l1c));
703- }
704- }
590+ calculateContinuousData (col, firstColObjWrap, ptOnCast, normalWorldFromCast, first_tf_inv, 1 );
705591 }
706592
707593 return 1 ;
0 commit comments