1 /*
2  * Copyright (c) 2011-2021, The DART development contributors
3  * All rights reserved.
4  *
5  * The list of contributors can be found at:
6  *   https://github.com/dartsim/dart/blob/master/LICENSE
7  *
8  * This file is provided under the following "BSD-style" License:
9  *   Redistribution and use in source and binary forms, with or
10  *   without modification, are permitted provided that the following
11  *   conditions are met:
12  *   * Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *   * Redistributions in binary form must reproduce the above
15  *     copyright notice, this list of conditions and the following
16  *     disclaimer in the documentation and/or other materials provided
17  *     with the distribution.
18  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26  *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  *   POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 // Must be included before any Bullet headers.
34 #include "dart/config.hpp"
35 
36 #include <algorithm>
37 
38 #include "dart/collision/bullet/BulletCollisionDetector.hpp"
39 
40 #include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
41 #include <BulletCollision/Gimpact/btGImpactShape.h>
42 
43 #include "dart/collision/CollisionFilter.hpp"
44 #include "dart/collision/CollisionObject.hpp"
45 #include "dart/collision/bullet/BulletCollisionGroup.hpp"
46 #include "dart/collision/bullet/BulletCollisionObject.hpp"
47 #include "dart/collision/bullet/BulletTypes.hpp"
48 #include "dart/collision/bullet/detail/BulletCollisionDispatcher.hpp"
49 #include "dart/collision/bullet/detail/BulletOverlapFilterCallback.hpp"
50 #include "dart/common/Console.hpp"
51 #include "dart/dynamics/BoxShape.hpp"
52 #include "dart/dynamics/CapsuleShape.hpp"
53 #include "dart/dynamics/ConeShape.hpp"
54 #include "dart/dynamics/CylinderShape.hpp"
55 #include "dart/dynamics/EllipsoidShape.hpp"
56 #include "dart/dynamics/HeightmapShape.hpp"
57 #include "dart/dynamics/MeshShape.hpp"
58 #include "dart/dynamics/MultiSphereConvexHullShape.hpp"
59 #include "dart/dynamics/PlaneShape.hpp"
60 #include "dart/dynamics/Shape.hpp"
61 #include "dart/dynamics/ShapeFrame.hpp"
62 #include "dart/dynamics/SoftMeshShape.hpp"
63 #include "dart/dynamics/SphereShape.hpp"
64 
65 namespace dart {
66 namespace collision {
67 
68 namespace {
69 
70 Contact convertContact(
71     const btManifoldPoint& bulletManifoldPoint,
72     BulletCollisionObject* collObj1,
73     BulletCollisionObject* collObj2);
74 
75 void reportContacts(
76     btCollisionWorld* collWorld,
77     const CollisionOption& option,
78     CollisionResult& result);
79 
80 void reportRayHits(
81     const btCollisionWorld::ClosestRayResultCallback callback,
82     const RaycastOption& option,
83     RaycastResult& result);
84 
85 void reportRayHits(
86     const btCollisionWorld::AllHitsRayResultCallback callback,
87     const RaycastOption& option,
88     RaycastResult& result);
89 
90 std::unique_ptr<btCollisionShape> createBulletEllipsoidMesh(
91     float sizeX, float sizeY, float sizeZ);
92 
93 std::unique_ptr<btCollisionShape> createBulletCollisionShapeFromAssimpScene(
94     const Eigen::Vector3d& scale, const aiScene* scene);
95 
96 std::unique_ptr<btCollisionShape> createBulletCollisionShapeFromAssimpMesh(
97     const aiMesh* mesh);
98 
99 template <typename HeightmapShapeT>
100 std::unique_ptr<BulletCollisionShape> createBulletCollisionShapeFromHeightmap(
101     const HeightmapShapeT* heightMap);
102 
103 } // anonymous namespace
104 
105 //==============================================================================
106 BulletCollisionDetector::Registrar<BulletCollisionDetector>
107     BulletCollisionDetector::mRegistrar{
108         BulletCollisionDetector::getStaticType(),
__anon0b06599f0202() 109         []() -> std::shared_ptr<dart::collision::BulletCollisionDetector> {
110           return dart::collision::BulletCollisionDetector::create();
111         }};
112 
113 //==============================================================================
create()114 std::shared_ptr<BulletCollisionDetector> BulletCollisionDetector::create()
115 {
116   return std::shared_ptr<BulletCollisionDetector>(
117       new BulletCollisionDetector());
118 }
119 
120 //==============================================================================
~BulletCollisionDetector()121 BulletCollisionDetector::~BulletCollisionDetector()
122 {
123   assert(mShapeMap.empty());
124 }
125 
126 //==============================================================================
127 std::shared_ptr<CollisionDetector>
cloneWithoutCollisionObjects() const128 BulletCollisionDetector::cloneWithoutCollisionObjects() const
129 {
130   return BulletCollisionDetector::create();
131 }
132 
133 //==============================================================================
getType() const134 const std::string& BulletCollisionDetector::getType() const
135 {
136   return getStaticType();
137 }
138 
139 //==============================================================================
getStaticType()140 const std::string& BulletCollisionDetector::getStaticType()
141 {
142   static const std::string type = "bullet";
143   return type;
144 }
145 
146 //==============================================================================
createCollisionGroup()147 std::unique_ptr<CollisionGroup> BulletCollisionDetector::createCollisionGroup()
148 {
149   return std::make_unique<BulletCollisionGroup>(shared_from_this());
150 }
151 
152 //==============================================================================
checkGroupValidity(BulletCollisionDetector * cd,CollisionGroup * group)153 static bool checkGroupValidity(
154     BulletCollisionDetector* cd, CollisionGroup* group)
155 {
156   if (cd != group->getCollisionDetector().get())
157   {
158     dterr << "[BulletCollisionDetector::collide] Attempting to check collision "
159           << "for a collision group that is created from a different collision "
160           << "detector instance.\n";
161 
162     return false;
163   }
164 
165   return true;
166 }
167 
168 //==============================================================================
isCollision(btCollisionWorld * world)169 static bool isCollision(btCollisionWorld* world)
170 {
171   assert(world);
172 
173   auto dispatcher = world->getDispatcher();
174   assert(dispatcher);
175 
176   const auto numManifolds = dispatcher->getNumManifolds();
177 
178   for (auto i = 0; i < numManifolds; ++i)
179   {
180     const auto* contactManifold = dispatcher->getManifoldByIndexInternal(i);
181 
182     if (contactManifold->getNumContacts() > 0)
183       return true;
184   }
185 
186   return false;
187 }
188 
189 //==============================================================================
filterOutCollisions(btCollisionWorld * world)190 void filterOutCollisions(btCollisionWorld* world)
191 {
192   assert(world);
193 
194   auto dispatcher
195       = static_cast<detail::BulletCollisionDispatcher*>(world->getDispatcher());
196   assert(dispatcher);
197 
198   const auto filter = dispatcher->getFilter();
199   if (!filter)
200     return;
201 
202   const auto numManifolds = dispatcher->getNumManifolds();
203 
204   std::vector<btPersistentManifold*> manifoldsToRelease;
205 
206   for (auto i = 0; i < numManifolds; ++i)
207   {
208     const auto contactManifold = dispatcher->getManifoldByIndexInternal(i);
209 
210     const auto body0 = contactManifold->getBody0();
211     const auto body1 = contactManifold->getBody1();
212 
213     const auto userPtr0 = body0->getUserPointer();
214     const auto userPtr1 = body1->getUserPointer();
215 
216     const auto collObj0 = static_cast<BulletCollisionObject*>(userPtr0);
217     const auto collObj1 = static_cast<BulletCollisionObject*>(userPtr1);
218 
219     if (filter->ignoresCollision(collObj0, collObj1))
220       manifoldsToRelease.push_back(contactManifold);
221   }
222 
223   for (const auto& manifold : manifoldsToRelease)
224     dispatcher->clearManifold(manifold);
225 }
226 
227 //==============================================================================
collide(CollisionGroup * group,const CollisionOption & option,CollisionResult * result)228 bool BulletCollisionDetector::collide(
229     CollisionGroup* group,
230     const CollisionOption& option,
231     CollisionResult* result)
232 {
233   if (result)
234     result->clear();
235 
236   if (0u == option.maxNumContacts)
237     return false;
238 
239   // Check if 'this' is the collision engine of 'group'.
240   if (!checkGroupValidity(this, group))
241     return false;
242 
243   auto castedGroup = static_cast<BulletCollisionGroup*>(group);
244   auto collisionWorld = castedGroup->getBulletCollisionWorld();
245 
246   auto dispatcher = static_cast<detail::BulletCollisionDispatcher*>(
247       collisionWorld->getDispatcher());
248   dispatcher->setFilter(option.collisionFilter);
249 
250   // Filter out persistent contact pairs already existing in the world
251   filterOutCollisions(collisionWorld);
252 
253   castedGroup->updateEngineData();
254   collisionWorld->performDiscreteCollisionDetection();
255 
256   if (result)
257   {
258     reportContacts(collisionWorld, option, *result);
259 
260     return result->isCollision();
261   }
262   else
263   {
264     return isCollision(collisionWorld);
265   }
266 }
267 
268 //==============================================================================
collide(CollisionGroup * group1,CollisionGroup * group2,const CollisionOption & option,CollisionResult * result)269 bool BulletCollisionDetector::collide(
270     CollisionGroup* group1,
271     CollisionGroup* group2,
272     const CollisionOption& option,
273     CollisionResult* result)
274 {
275   if (result)
276     result->clear();
277 
278   if (0u == option.maxNumContacts)
279     return false;
280 
281   if (!checkGroupValidity(this, group1))
282     return false;
283 
284   if (!checkGroupValidity(this, group2))
285     return false;
286 
287   // Create a new collision group, merging the two groups into
288   mGroupForFiltering.reset(new BulletCollisionGroup(shared_from_this()));
289   auto bulletCollisionWorld = mGroupForFiltering->getBulletCollisionWorld();
290   auto bulletPairCache = bulletCollisionWorld->getPairCache();
291   auto filterCallback = new detail::BulletOverlapFilterCallback(
292       option.collisionFilter, group1, group2);
293   bulletPairCache->setOverlapFilterCallback(filterCallback);
294 
295   mGroupForFiltering->addShapeFramesOf(group1, group2);
296   mGroupForFiltering->updateEngineData();
297 
298   bulletCollisionWorld->performDiscreteCollisionDetection();
299 
300   if (result)
301   {
302     reportContacts(bulletCollisionWorld, option, *result);
303 
304     return result->isCollision();
305   }
306   else
307   {
308     return isCollision(bulletCollisionWorld);
309   }
310 }
311 
312 //==============================================================================
distance(CollisionGroup *,const DistanceOption &,DistanceResult *)313 double BulletCollisionDetector::distance(
314     CollisionGroup* /*group*/,
315     const DistanceOption& /*option*/,
316     DistanceResult* /*result*/)
317 {
318   static bool warned = false;
319   if (!warned)
320   {
321     dtwarn
322         << "[BulletCollisionDetector::distance] This collision detector does "
323         << "not support (signed) distance queries. Returning 0.0.\n";
324     warned = true;
325   }
326 
327   return 0.0;
328 }
329 
330 //==============================================================================
distance(CollisionGroup *,CollisionGroup *,const DistanceOption &,DistanceResult *)331 double BulletCollisionDetector::distance(
332     CollisionGroup* /*group1*/,
333     CollisionGroup* /*group2*/,
334     const DistanceOption& /*option*/,
335     DistanceResult* /*result*/)
336 {
337   static bool warned = false;
338   if (!warned)
339   {
340     dtwarn
341         << "[BulletCollisionDetector::distance] This collision detector does "
342         << "not support (signed) distance queries. Returning.\n";
343     warned = true;
344   }
345 
346   return 0.0;
347 }
348 
349 //==============================================================================
raycast(CollisionGroup * group,const Eigen::Vector3d & from,const Eigen::Vector3d & to,const RaycastOption & option,RaycastResult * result)350 bool BulletCollisionDetector::raycast(
351     CollisionGroup* group,
352     const Eigen::Vector3d& from,
353     const Eigen::Vector3d& to,
354     const RaycastOption& option,
355     RaycastResult* result)
356 {
357   if (result)
358     result->clear();
359 
360   // Check if 'this' is the collision engine of 'group'.
361   if (!checkGroupValidity(this, group))
362     return false;
363 
364   auto castedGroup = static_cast<BulletCollisionGroup*>(group);
365   auto collisionWorld = castedGroup->getBulletCollisionWorld();
366 
367   const auto btFrom = convertVector3(from);
368   const auto btTo = convertVector3(to);
369 
370   if (option.mEnableAllHits)
371   {
372     auto callback = btCollisionWorld::AllHitsRayResultCallback(btFrom, btTo);
373     castedGroup->updateEngineData();
374     collisionWorld->rayTest(btFrom, btTo, callback);
375 
376     if (result == nullptr)
377       return callback.hasHit();
378 
379     if (callback.hasHit())
380     {
381       reportRayHits(callback, option, *result);
382       return result->hasHit();
383     }
384     else
385     {
386       return false;
387     }
388   }
389   else
390   {
391     auto callback = btCollisionWorld::ClosestRayResultCallback(btFrom, btTo);
392     castedGroup->updateEngineData();
393     collisionWorld->rayTest(btFrom, btTo, callback);
394 
395     if (result == nullptr)
396       return callback.hasHit();
397 
398     if (callback.hasHit())
399     {
400       reportRayHits(callback, option, *result);
401       return result->hasHit();
402     }
403     else
404     {
405       return false;
406     }
407   }
408 }
409 
410 //==============================================================================
BulletCollisionDetector()411 BulletCollisionDetector::BulletCollisionDetector() : CollisionDetector()
412 {
413   mCollisionObjectManager.reset(new ManagerForUnsharableCollisionObjects(this));
414 }
415 
416 //==============================================================================
createCollisionObject(const dynamics::ShapeFrame * shapeFrame)417 std::unique_ptr<CollisionObject> BulletCollisionDetector::createCollisionObject(
418     const dynamics::ShapeFrame* shapeFrame)
419 {
420   auto bulletCollShape = claimBulletCollisionShape(shapeFrame->getShape());
421 
422   return std::unique_ptr<BulletCollisionObject>(
423       new BulletCollisionObject(this, shapeFrame, bulletCollShape));
424 }
425 
426 //==============================================================================
refreshCollisionObject(CollisionObject * object)427 void BulletCollisionDetector::refreshCollisionObject(CollisionObject* object)
428 {
429   BulletCollisionObject* bullet = static_cast<BulletCollisionObject*>(object);
430 
431   bullet->mBulletCollisionShape = claimBulletCollisionShape(bullet->getShape());
432   bullet->mBulletCollisionObject->setCollisionShape(
433       bullet->mBulletCollisionShape->mCollisionShape.get());
434 }
435 
436 //==============================================================================
notifyCollisionObjectDestroying(CollisionObject * object)437 void BulletCollisionDetector::notifyCollisionObjectDestroying(
438     CollisionObject* object)
439 {
440   reclaimBulletCollisionShape(object->getShape());
441 }
442 
443 //==============================================================================
444 std::shared_ptr<BulletCollisionShape>
claimBulletCollisionShape(const dynamics::ConstShapePtr & shape)445 BulletCollisionDetector::claimBulletCollisionShape(
446     const dynamics::ConstShapePtr& shape)
447 {
448   const std::size_t currentVersion = shape->getVersion();
449 
450   const auto search = mShapeMap.insert(std::make_pair(shape, ShapeInfo()));
451   const bool inserted = search.second;
452   ShapeInfo& info = search.first->second;
453 
454   if (!inserted && currentVersion == info.mLastKnownVersion)
455   {
456     const auto& bulletCollShape = info.mShape.lock();
457     assert(bulletCollShape);
458 
459     return bulletCollShape;
460   }
461 
462   auto newBulletCollisionShape = std::shared_ptr<BulletCollisionShape>(
463       createBulletCollisionShape(shape).release(),
464       BulletCollisionShapeDeleter(this, shape));
465   info.mShape = newBulletCollisionShape;
466   info.mLastKnownVersion = currentVersion;
467 
468   return newBulletCollisionShape;
469 }
470 
471 //==============================================================================
reclaimBulletCollisionShape(const dynamics::ConstShapePtr & shape)472 void BulletCollisionDetector::reclaimBulletCollisionShape(
473     const dynamics::ConstShapePtr& shape)
474 {
475   const auto& search = mShapeMap.find(shape);
476   if (search == mShapeMap.end())
477     return;
478 
479   const auto& bulletShape = search->second.mShape.lock();
480   if (!bulletShape || bulletShape.use_count() <= 2)
481     mShapeMap.erase(search);
482 }
483 
484 //==============================================================================
485 std::unique_ptr<BulletCollisionShape>
createBulletCollisionShape(const dynamics::ConstShapePtr & shape)486 BulletCollisionDetector::createBulletCollisionShape(
487     const dynamics::ConstShapePtr& shape)
488 {
489   using dynamics::BoxShape;
490   using dynamics::CapsuleShape;
491   using dynamics::ConeShape;
492   using dynamics::CylinderShape;
493   using dynamics::EllipsoidShape;
494   using dynamics::HeightmapShaped;
495   using dynamics::HeightmapShapef;
496   using dynamics::MeshShape;
497   using dynamics::MultiSphereConvexHullShape;
498   using dynamics::PlaneShape;
499   using dynamics::Shape;
500   using dynamics::SoftMeshShape;
501   using dynamics::SphereShape;
502 
503   if (shape->is<SphereShape>())
504   {
505     assert(dynamic_cast<const SphereShape*>(shape.get()));
506 
507     const auto sphere = static_cast<const SphereShape*>(shape.get());
508     const auto radius = sphere->getRadius();
509 
510     auto bulletCollisionShape = std::make_unique<btSphereShape>(radius);
511 
512     return std::make_unique<BulletCollisionShape>(
513         std::move(bulletCollisionShape));
514   }
515   else if (shape->is<BoxShape>())
516   {
517     assert(dynamic_cast<const BoxShape*>(shape.get()));
518 
519     const auto box = static_cast<const BoxShape*>(shape.get());
520     const Eigen::Vector3d& size = box->getSize();
521 
522     auto bulletCollisionShape
523         = std::make_unique<btBoxShape>(convertVector3(size * 0.5));
524 
525     return std::make_unique<BulletCollisionShape>(
526         std::move(bulletCollisionShape));
527   }
528   else if (shape->is<EllipsoidShape>())
529   {
530     assert(dynamic_cast<const EllipsoidShape*>(shape.get()));
531 
532     const auto ellipsoid = static_cast<const EllipsoidShape*>(shape.get());
533     const Eigen::Vector3d& radii = ellipsoid->getRadii();
534 
535     auto bulletCollisionShape = createBulletEllipsoidMesh(
536         radii[0] * 2.0, radii[1] * 2.0, radii[2] * 2.0);
537 
538     return std::make_unique<BulletCollisionShape>(
539         std::move(bulletCollisionShape));
540   }
541   else if (shape->is<CylinderShape>())
542   {
543     assert(dynamic_cast<const CylinderShape*>(shape.get()));
544 
545     const auto cylinder = static_cast<const CylinderShape*>(shape.get());
546     const auto radius = cylinder->getRadius();
547     const auto height = cylinder->getHeight();
548     const auto size = btVector3(radius, radius, height * 0.5);
549 
550     auto bulletCollisionShape = std::make_unique<btCylinderShapeZ>(size);
551 
552     return std::make_unique<BulletCollisionShape>(
553         std::move(bulletCollisionShape));
554   }
555   else if (shape->is<CapsuleShape>())
556   {
557     assert(dynamic_cast<const CapsuleShape*>(shape.get()));
558 
559     const auto capsule = static_cast<const CapsuleShape*>(shape.get());
560     const auto radius = capsule->getRadius();
561     const auto height = capsule->getHeight();
562 
563     auto bulletCollisionShape
564         = std::make_unique<btCapsuleShapeZ>(radius, height);
565 
566     return std::make_unique<BulletCollisionShape>(
567         std::move(bulletCollisionShape));
568   }
569   else if (shape->is<ConeShape>())
570   {
571     assert(dynamic_cast<const ConeShape*>(shape.get()));
572 
573     const auto cone = static_cast<const ConeShape*>(shape.get());
574     const auto radius = cone->getRadius();
575     const auto height = cone->getHeight();
576 
577     auto bulletCollisionShape = std::make_unique<btConeShapeZ>(radius, height);
578     bulletCollisionShape->setMargin(0.0);
579     // TODO(JS): Bullet seems to use constant margin 0.4, however this could be
580     // dangerous when the cone is sufficiently small. We use zero margin here
581     // until find better solution even using zero margin is not recommended:
582     // https://www.sjbaker.org/wiki/index.php?title=Physics_-_Bullet_Collected_random_advice#Minimum_object_sizes_-_by_Erwin
583 
584     return std::make_unique<BulletCollisionShape>(
585         std::move(bulletCollisionShape));
586   }
587   else if (shape->is<PlaneShape>())
588   {
589     assert(dynamic_cast<const PlaneShape*>(shape.get()));
590 
591     const auto plane = static_cast<const PlaneShape*>(shape.get());
592     const Eigen::Vector3d normal = plane->getNormal();
593     const double offset = plane->getOffset();
594 
595     auto bulletCollisionShape
596         = std::make_unique<btStaticPlaneShape>(convertVector3(normal), offset);
597 
598     return std::make_unique<BulletCollisionShape>(
599         std::move(bulletCollisionShape));
600   }
601   else if (shape->is<MultiSphereConvexHullShape>())
602   {
603     assert(dynamic_cast<const MultiSphereConvexHullShape*>(shape.get()));
604 
605     const auto multiSphere
606         = static_cast<const MultiSphereConvexHullShape*>(shape.get());
607     const auto numSpheres = multiSphere->getNumSpheres();
608     const auto& spheres = multiSphere->getSpheres();
609 
610     std::vector<btVector3> bulletPositions(numSpheres);
611     std::vector<btScalar> bulletRadii(numSpheres);
612 
613     for (auto i = 0u; i < numSpheres; ++i)
614     {
615       bulletRadii[i] = static_cast<btScalar>(spheres[i].first);
616       bulletPositions[i] = convertVector3(spheres[i].second);
617     }
618 
619     auto bulletCollisionShape = std::make_unique<btMultiSphereShape>(
620         bulletPositions.data(), bulletRadii.data(), numSpheres);
621 
622     return std::make_unique<BulletCollisionShape>(
623         std::move(bulletCollisionShape));
624   }
625   else if (shape->is<MeshShape>())
626   {
627     assert(dynamic_cast<const MeshShape*>(shape.get()));
628 
629     const auto shapeMesh = static_cast<const MeshShape*>(shape.get());
630     const auto scale = shapeMesh->getScale();
631     const auto mesh = shapeMesh->getMesh();
632 
633     auto bulletCollisionShape
634         = createBulletCollisionShapeFromAssimpScene(scale, mesh);
635 
636     return std::make_unique<BulletCollisionShape>(
637         std::move(bulletCollisionShape));
638   }
639   else if (shape->is<SoftMeshShape>())
640   {
641     assert(dynamic_cast<const SoftMeshShape*>(shape.get()));
642 
643     const auto softMeshShape = static_cast<const SoftMeshShape*>(shape.get());
644     const auto mesh = softMeshShape->getAssimpMesh();
645 
646     auto bulletCollisionShape = createBulletCollisionShapeFromAssimpMesh(mesh);
647 
648     return std::make_unique<BulletCollisionShape>(
649         std::move(bulletCollisionShape));
650   }
651   else if (shape->is<HeightmapShapef>())
652   {
653     assert(dynamic_cast<const HeightmapShapef*>(shape.get()));
654 
655     const auto heightMap = static_cast<const HeightmapShapef*>(shape.get());
656 
657     return createBulletCollisionShapeFromHeightmap(heightMap);
658   }
659   else if (shape->is<HeightmapShaped>())
660   {
661     assert(dynamic_cast<const HeightmapShaped*>(shape.get()));
662 
663     dterr << "[BulletCollisionDetector::createBulletCollisionShape] "
664           << "Bullet does not support double height fields (shape type ["
665           << shape->getType() << "]). Creating a sphere with 0.1 radius "
666           << "instead.\n";
667 
668     return std::make_unique<BulletCollisionShape>(
669         std::make_unique<btSphereShape>(0.1));
670 
671     // take this back in as soon as bullet supports double in heightmaps
672     // const auto heightMap = static_cast<const HeightmapShaped*>(shape.get());
673     // return createBulletCollisionShapeFromHeightmap(heightMap);
674   }
675   else
676   {
677     dterr << "[BulletCollisionDetector::createBulletCollisionShape] "
678           << "Attempting to create an unsupported shape type ["
679           << shape->getType() << "] Creating a sphere with 0.1 radius "
680           << "instead.\n";
681 
682     return std::make_unique<BulletCollisionShape>(
683         std::make_unique<btSphereShape>(0.1));
684   }
685 }
686 
687 //==============================================================================
688 BulletCollisionDetector::BulletCollisionShapeDeleter ::
BulletCollisionShapeDeleter(BulletCollisionDetector * cd,const dynamics::ConstShapePtr & shape)689     BulletCollisionShapeDeleter(
690         BulletCollisionDetector* cd, const dynamics::ConstShapePtr& shape)
691   : mBulletCollisionDetector(cd), mShape(shape)
692 {
693   // Do nothing
694 }
695 
696 //==============================================================================
operator ()(BulletCollisionShape * shape) const697 void BulletCollisionDetector::BulletCollisionShapeDeleter ::operator()(
698     BulletCollisionShape* shape) const
699 {
700   mBulletCollisionDetector->reclaimBulletCollisionShape(mShape);
701 
702   delete shape;
703 }
704 
705 namespace {
706 
707 //==============================================================================
convertContact(const btManifoldPoint & bulletManifoldPoint,BulletCollisionObject * collObj1,BulletCollisionObject * collObj2)708 Contact convertContact(
709     const btManifoldPoint& bulletManifoldPoint,
710     BulletCollisionObject* collObj1,
711     BulletCollisionObject* collObj2)
712 {
713   assert(collObj1);
714   assert(collObj2);
715 
716   Contact contact;
717 
718   contact.point = convertVector3(bulletManifoldPoint.getPositionWorldOnA());
719   contact.normal = convertVector3(bulletManifoldPoint.m_normalWorldOnB);
720   contact.penetrationDepth = -bulletManifoldPoint.m_distance1;
721   contact.collisionObject1 = collObj1;
722   contact.collisionObject2 = collObj2;
723 
724   return contact;
725 }
726 
727 //==============================================================================
reportContacts(btCollisionWorld * world,const CollisionOption & option,CollisionResult & result)728 void reportContacts(
729     btCollisionWorld* world,
730     const CollisionOption& option,
731     CollisionResult& result)
732 {
733   assert(world);
734 
735   auto dispatcher
736       = static_cast<detail::BulletCollisionDispatcher*>(world->getDispatcher());
737   assert(dispatcher);
738 
739   const auto numManifolds = dispatcher->getNumManifolds();
740 
741   for (auto i = 0; i < numManifolds; ++i)
742   {
743     const auto contactManifold = dispatcher->getManifoldByIndexInternal(i);
744 
745     const auto body0 = contactManifold->getBody0();
746     const auto body1 = contactManifold->getBody1();
747 
748     const auto userPointer0 = body0->getUserPointer();
749     const auto userPointer1 = body1->getUserPointer();
750 
751     const auto collObj0 = static_cast<BulletCollisionObject*>(userPointer0);
752     const auto collObj1 = static_cast<BulletCollisionObject*>(userPointer1);
753 
754     const auto numContacts = contactManifold->getNumContacts();
755 
756     for (auto j = 0; j < numContacts; ++j)
757     {
758       const auto& cp = contactManifold->getContactPoint(j);
759 
760       if (cp.m_normalWorldOnB.length2() < Contact::getNormalEpsilonSquared())
761       {
762         // Skip this contact. This is because we assume that a contact with
763         // zero-length normal is invalid.
764         continue;
765       }
766 
767       result.addContact(convertContact(cp, collObj0, collObj1));
768 
769       // No need to check further collisions
770       if (result.getNumContacts() >= option.maxNumContacts)
771       {
772         dispatcher->setDone(true);
773         return;
774       }
775     }
776   }
777 }
778 
779 //==============================================================================
convertRayHit(const btCollisionObject * btCollObj,btVector3 hitPointWorld,btVector3 hitNormalWorld,btScalar closestHitFraction)780 RayHit convertRayHit(
781     const btCollisionObject* btCollObj,
782     btVector3 hitPointWorld,
783     btVector3 hitNormalWorld,
784     btScalar closestHitFraction)
785 {
786   RayHit rayHit;
787   assert(btCollObj);
788   const auto* userPointer = btCollObj->getUserPointer();
789   assert(userPointer);
790   const auto* collObj = static_cast<const BulletCollisionObject*>(userPointer);
791   assert(collObj);
792   rayHit.mCollisionObject = collObj;
793   rayHit.mPoint = convertVector3(hitPointWorld);
794   rayHit.mNormal = convertVector3(hitNormalWorld);
795   rayHit.mFraction = static_cast<double>(closestHitFraction);
796 
797   return rayHit;
798 }
799 
800 //==============================================================================
reportRayHits(const btCollisionWorld::ClosestRayResultCallback callback,const RaycastOption &,RaycastResult & result)801 void reportRayHits(
802     const btCollisionWorld::ClosestRayResultCallback callback,
803     const RaycastOption& /*option*/,
804     RaycastResult& result)
805 {
806   // This function shouldn't be called if callback has not ray hit.
807   assert(callback.hasHit());
808 
809   const auto rayHit = convertRayHit(
810       callback.m_collisionObject,
811       callback.m_hitPointWorld,
812       callback.m_hitNormalWorld,
813       callback.m_closestHitFraction);
814 
815   result.mRayHits.clear();
816   result.mRayHits.reserve(1);
817   result.mRayHits.emplace_back(rayHit);
818 }
819 
820 //==============================================================================
821 struct FractionLess
822 {
operator ()dart::collision::__anon0b06599f0311::FractionLess823   bool operator()(const RayHit& a, const RayHit& b)
824   {
825     return a.mFraction < b.mFraction;
826   }
827 };
828 
829 //==============================================================================
reportRayHits(const btCollisionWorld::AllHitsRayResultCallback callback,const RaycastOption & option,RaycastResult & result)830 void reportRayHits(
831     const btCollisionWorld::AllHitsRayResultCallback callback,
832     const RaycastOption& option,
833     RaycastResult& result)
834 {
835   result.mRayHits.clear();
836   result.mRayHits.reserve(
837       static_cast<std::size_t>(callback.m_hitPointWorld.size()));
838 
839   for (auto i = 0; i < callback.m_hitPointWorld.size(); ++i)
840   {
841     const auto rayHit = convertRayHit(
842         callback.m_collisionObjects[i],
843         callback.m_hitPointWorld[i],
844         callback.m_hitNormalWorld[i],
845         callback.m_hitFractions[i]);
846     result.mRayHits.emplace_back(rayHit);
847   }
848 
849   if (option.mSortByClosest)
850     std::sort(result.mRayHits.begin(), result.mRayHits.end(), FractionLess());
851 }
852 
853 //==============================================================================
createBulletEllipsoidMesh(float sizeX,float sizeY,float sizeZ)854 std::unique_ptr<btCollisionShape> createBulletEllipsoidMesh(
855     float sizeX, float sizeY, float sizeZ)
856 {
857   float v[59][3] = {{0, 0, 0},
858                     {0.135299, -0.461940, -0.135299},
859                     {0.000000, -0.461940, -0.191342},
860                     {-0.135299, -0.461940, -0.135299},
861                     {-0.191342, -0.461940, 0.000000},
862                     {-0.135299, -0.461940, 0.135299},
863                     {0.000000, -0.461940, 0.191342},
864                     {0.135299, -0.461940, 0.135299},
865                     {0.191342, -0.461940, 0.000000},
866                     {0.250000, -0.353553, -0.250000},
867                     {0.000000, -0.353553, -0.353553},
868                     {-0.250000, -0.353553, -0.250000},
869                     {-0.353553, -0.353553, 0.000000},
870                     {-0.250000, -0.353553, 0.250000},
871                     {0.000000, -0.353553, 0.353553},
872                     {0.250000, -0.353553, 0.250000},
873                     {0.353553, -0.353553, 0.000000},
874                     {0.326641, -0.191342, -0.326641},
875                     {0.000000, -0.191342, -0.461940},
876                     {-0.326641, -0.191342, -0.326641},
877                     {-0.461940, -0.191342, 0.000000},
878                     {-0.326641, -0.191342, 0.326641},
879                     {0.000000, -0.191342, 0.461940},
880                     {0.326641, -0.191342, 0.326641},
881                     {0.461940, -0.191342, 0.000000},
882                     {0.353553, 0.000000, -0.353553},
883                     {0.000000, 0.000000, -0.500000},
884                     {-0.353553, 0.000000, -0.353553},
885                     {-0.500000, 0.000000, 0.000000},
886                     {-0.353553, 0.000000, 0.353553},
887                     {0.000000, 0.000000, 0.500000},
888                     {0.353553, 0.000000, 0.353553},
889                     {0.500000, 0.000000, 0.000000},
890                     {0.326641, 0.191342, -0.326641},
891                     {0.000000, 0.191342, -0.461940},
892                     {-0.326641, 0.191342, -0.326641},
893                     {-0.461940, 0.191342, 0.000000},
894                     {-0.326641, 0.191342, 0.326641},
895                     {0.000000, 0.191342, 0.461940},
896                     {0.326641, 0.191342, 0.326641},
897                     {0.461940, 0.191342, 0.000000},
898                     {0.250000, 0.353553, -0.250000},
899                     {0.000000, 0.353553, -0.353553},
900                     {-0.250000, 0.353553, -0.250000},
901                     {-0.353553, 0.353553, 0.000000},
902                     {-0.250000, 0.353553, 0.250000},
903                     {0.000000, 0.353553, 0.353553},
904                     {0.250000, 0.353553, 0.250000},
905                     {0.353553, 0.353553, 0.000000},
906                     {0.135299, 0.461940, -0.135299},
907                     {0.000000, 0.461940, -0.191342},
908                     {-0.135299, 0.461940, -0.135299},
909                     {-0.191342, 0.461940, 0.000000},
910                     {-0.135299, 0.461940, 0.135299},
911                     {0.000000, 0.461940, 0.191342},
912                     {0.135299, 0.461940, 0.135299},
913                     {0.191342, 0.461940, 0.000000},
914                     {0.000000, -0.500000, 0.000000},
915                     {0.000000, 0.500000, 0.000000}};
916 
917   int f[112][3]
918       = {{1, 2, 9},    {9, 2, 10},   {2, 3, 10},   {10, 3, 11},  {3, 4, 11},
919          {11, 4, 12},  {4, 5, 12},   {12, 5, 13},  {5, 6, 13},   {13, 6, 14},
920          {6, 7, 14},   {14, 7, 15},  {7, 8, 15},   {15, 8, 16},  {8, 1, 16},
921          {16, 1, 9},   {9, 10, 17},  {17, 10, 18}, {10, 11, 18}, {18, 11, 19},
922          {11, 12, 19}, {19, 12, 20}, {12, 13, 20}, {20, 13, 21}, {13, 14, 21},
923          {21, 14, 22}, {14, 15, 22}, {22, 15, 23}, {15, 16, 23}, {23, 16, 24},
924          {16, 9, 24},  {24, 9, 17},  {17, 18, 25}, {25, 18, 26}, {18, 19, 26},
925          {26, 19, 27}, {19, 20, 27}, {27, 20, 28}, {20, 21, 28}, {28, 21, 29},
926          {21, 22, 29}, {29, 22, 30}, {22, 23, 30}, {30, 23, 31}, {23, 24, 31},
927          {31, 24, 32}, {24, 17, 32}, {32, 17, 25}, {25, 26, 33}, {33, 26, 34},
928          {26, 27, 34}, {34, 27, 35}, {27, 28, 35}, {35, 28, 36}, {28, 29, 36},
929          {36, 29, 37}, {29, 30, 37}, {37, 30, 38}, {30, 31, 38}, {38, 31, 39},
930          {31, 32, 39}, {39, 32, 40}, {32, 25, 40}, {40, 25, 33}, {33, 34, 41},
931          {41, 34, 42}, {34, 35, 42}, {42, 35, 43}, {35, 36, 43}, {43, 36, 44},
932          {36, 37, 44}, {44, 37, 45}, {37, 38, 45}, {45, 38, 46}, {38, 39, 46},
933          {46, 39, 47}, {39, 40, 47}, {47, 40, 48}, {40, 33, 48}, {48, 33, 41},
934          {41, 42, 49}, {49, 42, 50}, {42, 43, 50}, {50, 43, 51}, {43, 44, 51},
935          {51, 44, 52}, {44, 45, 52}, {52, 45, 53}, {45, 46, 53}, {53, 46, 54},
936          {46, 47, 54}, {54, 47, 55}, {47, 48, 55}, {55, 48, 56}, {48, 41, 56},
937          {56, 41, 49}, {2, 1, 57},   {3, 2, 57},   {4, 3, 57},   {5, 4, 57},
938          {6, 5, 57},   {7, 6, 57},   {8, 7, 57},   {1, 8, 57},   {49, 50, 58},
939          {50, 51, 58}, {51, 52, 58}, {52, 53, 58}, {53, 54, 58}, {54, 55, 58},
940          {55, 56, 58}, {56, 49, 58}};
941 
942   auto triMesh = new btTriangleMesh();
943 
944   for (auto i = 0u; i < 112; ++i)
945   {
946     btVector3 vertices[3];
947 
948     const auto& index0 = f[i][0];
949     const auto& index1 = f[i][1];
950     const auto& index2 = f[i][2];
951 
952     const auto& p0 = v[index0];
953     const auto& p1 = v[index1];
954     const auto& p2 = v[index2];
955 
956     vertices[0] = btVector3(p0[0] * sizeX, p0[1] * sizeY, p0[2] * sizeZ);
957     vertices[1] = btVector3(p1[0] * sizeX, p1[1] * sizeY, p1[2] * sizeZ);
958     vertices[2] = btVector3(p2[0] * sizeX, p2[1] * sizeY, p2[2] * sizeZ);
959 
960     triMesh->addTriangle(vertices[0], vertices[1], vertices[2]);
961   }
962 
963   auto gimpactMeshShape = std::make_unique<btGImpactMeshShape>(triMesh);
964   gimpactMeshShape->updateBound();
965 
966   return gimpactMeshShape;
967 }
968 
969 //==============================================================================
createBulletCollisionShapeFromAssimpScene(const Eigen::Vector3d & scale,const aiScene * scene)970 std::unique_ptr<btCollisionShape> createBulletCollisionShapeFromAssimpScene(
971     const Eigen::Vector3d& scale, const aiScene* scene)
972 {
973   auto triMesh = new btTriangleMesh();
974 
975   for (auto i = 0u; i < scene->mNumMeshes; ++i)
976   {
977     for (auto j = 0u; j < scene->mMeshes[i]->mNumFaces; ++j)
978     {
979       btVector3 vertices[3];
980       for (auto k = 0u; k < 3; ++k)
981       {
982         const aiVector3D& vertex
983             = scene->mMeshes[i]
984                   ->mVertices[scene->mMeshes[i]->mFaces[j].mIndices[k]];
985         vertices[k] = btVector3(
986             vertex.x * scale[0], vertex.y * scale[1], vertex.z * scale[2]);
987       }
988       triMesh->addTriangle(vertices[0], vertices[1], vertices[2]);
989     }
990   }
991 
992   auto gimpactMeshShape = std::make_unique<btGImpactMeshShape>(triMesh);
993   gimpactMeshShape->updateBound();
994   gimpactMeshShape->setUserPointer(triMesh);
995 
996   return gimpactMeshShape;
997 }
998 
999 //==============================================================================
createBulletCollisionShapeFromAssimpMesh(const aiMesh * mesh)1000 std::unique_ptr<btCollisionShape> createBulletCollisionShapeFromAssimpMesh(
1001     const aiMesh* mesh)
1002 {
1003   auto triMesh = new btTriangleMesh();
1004 
1005   for (auto i = 0u; i < mesh->mNumFaces; ++i)
1006   {
1007     btVector3 vertices[3];
1008     for (auto j = 0u; j < 3; ++j)
1009     {
1010       const aiVector3D& vertex = mesh->mVertices[mesh->mFaces[i].mIndices[j]];
1011       vertices[j] = btVector3(vertex.x, vertex.y, vertex.z);
1012     }
1013     triMesh->addTriangle(vertices[0], vertices[1], vertices[2]);
1014   }
1015 
1016   auto gimpactMeshShape = std::make_unique<btGImpactMeshShape>(triMesh);
1017   gimpactMeshShape->updateBound();
1018 
1019   return gimpactMeshShape;
1020 }
1021 
1022 //==============================================================================
1023 template <typename HeightmapShapeT>
createBulletCollisionShapeFromHeightmap(const HeightmapShapeT * heightMap)1024 std::unique_ptr<BulletCollisionShape> createBulletCollisionShapeFromHeightmap(
1025     const HeightmapShapeT* heightMap)
1026 {
1027   // get the heightmap parameters
1028   const auto& scale = heightMap->getScale();
1029   const auto minHeight = heightMap->getMinHeight();
1030   const auto maxHeight = heightMap->getMaxHeight();
1031 
1032   // determine which data type (float or double) is to be used for the field
1033   PHY_ScalarType scalarType = PHY_FLOAT;
1034   if (std::is_same<typename HeightmapShapeT::S, double>::value)
1035   {
1036     dterr << "Bullet does not support DOUBLE as heightmap field yet.\n";
1037     return nullptr;
1038     // take this back in as soon as it is supported
1039     // scalarType = PHY_DOUBLE;
1040   }
1041 
1042   // the y-values in the height field need to be flipped
1043   heightMap->flipY();
1044 
1045   const auto& heights = heightMap->getHeightField();
1046 
1047   // create the height field
1048   const btVector3 localScaling(scale.x(), scale.y(), scale.z());
1049   const bool flipQuadEdges = false;
1050   auto heightFieldShape = std::make_unique<btHeightfieldTerrainShape>(
1051       heightMap->getWidth(), // Width of height field
1052       heightMap->getDepth(), // Depth of height field
1053       heights.data(),        // Height values
1054       1,                     // Height scaling
1055       minHeight,             // Min height
1056       maxHeight,             // Max height
1057       2,                     // Up axis
1058       scalarType,            // Float or double field
1059       flipQuadEdges);        // Flip quad edges
1060   heightFieldShape->setLocalScaling(localScaling);
1061   heightFieldShape->setUseZigzagSubdivision(true);
1062 
1063   // change the relative transform of the height field so that the minimum
1064   // height is at the same z coordinate. Bullet shifts the height map such
1065   // that its center is the AABB center.
1066   const btVector3 trans(
1067       0, 0, ((maxHeight - minHeight) * 0.5 + minHeight) * scale.z());
1068   btTransform relativeShapeTransform(btMatrix3x3::getIdentity(), trans);
1069 
1070   // bullet places the heightfield such that the origin is in the
1071   // middle of the AABB. We want however that the minimum height value
1072   // is on x/y plane.
1073   btVector3 min;
1074   btVector3 max;
1075   heightFieldShape->getAabb(btTransform::getIdentity(), min, max);
1076   dtdbg << "DART Bullet heightfield AABB: min = {" << min.x() << ", " << min.y()
1077         << ", " << min.z() << "}, max = {" << max.x() << ", " << max.y() << ", "
1078         << max.z() << "}"
1079         << " (will be translated by z=" << trans.z() << ")" << std::endl;
1080 
1081   return std::make_unique<BulletCollisionShape>(
1082       std::move(heightFieldShape), relativeShapeTransform);
1083 }
1084 
1085 } // anonymous namespace
1086 
1087 } // namespace collision
1088 } // namespace dart
1089