2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
17 #include "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h"
18 #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
19 #include "BulletCollision/CollisionShapes/btCompoundShape.h"
20 #include "BulletCollision/BroadphaseCollision/btDbvt.h"
21 #include "LinearMath/btIDebugDraw.h"
22 #include "LinearMath/btAabbUtil2.h"
23 #include "btManifoldResult.h"
24 #include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h"
26 btShapePairCallback gCompoundChildShapePairCallback = 0;
28 btCompoundCollisionAlgorithm::btCompoundCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci, const btCollisionObjectWrapper* body0Wrap, const btCollisionObjectWrapper* body1Wrap, bool isSwapped)
29 : btActivatingCollisionAlgorithm(ci, body0Wrap, body1Wrap),
30 m_isSwapped(isSwapped),
31 m_sharedManifold(ci.m_manifold)
33 m_ownsManifold = false;
35 const btCollisionObjectWrapper* colObjWrap = m_isSwapped ? body1Wrap : body0Wrap;
36 btAssert(colObjWrap->getCollisionShape()->isCompound());
38 const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(colObjWrap->getCollisionShape());
39 m_compoundShapeRevision = compoundShape->getUpdateRevision();
41 preallocateChildAlgorithms(body0Wrap, body1Wrap);
44 void btCompoundCollisionAlgorithm::preallocateChildAlgorithms(const btCollisionObjectWrapper* body0Wrap, const btCollisionObjectWrapper* body1Wrap)
46 const btCollisionObjectWrapper* colObjWrap = m_isSwapped ? body1Wrap : body0Wrap;
47 const btCollisionObjectWrapper* otherObjWrap = m_isSwapped ? body0Wrap : body1Wrap;
48 btAssert(colObjWrap->getCollisionShape()->isCompound());
50 const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(colObjWrap->getCollisionShape());
52 int numChildren = compoundShape->getNumChildShapes();
55 m_childCollisionAlgorithms.resize(numChildren);
56 for (i = 0; i < numChildren; i++)
58 if (compoundShape->getDynamicAabbTree())
60 m_childCollisionAlgorithms[i] = 0;
64 const btCollisionShape* childShape = compoundShape->getChildShape(i);
66 btCollisionObjectWrapper childWrap(colObjWrap, childShape, colObjWrap->getCollisionObject(), colObjWrap->getWorldTransform(), -1, i); //wrong child trans, but unused (hopefully)
67 m_childCollisionAlgorithms[i] = m_dispatcher->findAlgorithm(&childWrap, otherObjWrap, m_sharedManifold, BT_CONTACT_POINT_ALGORITHMS);
69 btAlignedObjectArray<btCollisionAlgorithm*> m_childCollisionAlgorithmsContact;
70 btAlignedObjectArray<btCollisionAlgorithm*> m_childCollisionAlgorithmsClosestPoints;
75 void btCompoundCollisionAlgorithm::removeChildAlgorithms()
77 int numChildren = m_childCollisionAlgorithms.size();
79 for (i = 0; i < numChildren; i++)
81 if (m_childCollisionAlgorithms[i])
83 m_childCollisionAlgorithms[i]->~btCollisionAlgorithm();
84 m_dispatcher->freeCollisionAlgorithm(m_childCollisionAlgorithms[i]);
89 btCompoundCollisionAlgorithm::~btCompoundCollisionAlgorithm()
91 removeChildAlgorithms();
94 struct btCompoundLeafCallback : btDbvt::ICollide
97 const btCollisionObjectWrapper* m_compoundColObjWrap;
98 const btCollisionObjectWrapper* m_otherObjWrap;
99 btDispatcher* m_dispatcher;
100 const btDispatcherInfo& m_dispatchInfo;
101 btManifoldResult* m_resultOut;
102 btCollisionAlgorithm** m_childCollisionAlgorithms;
103 btPersistentManifold* m_sharedManifold;
105 btCompoundLeafCallback(const btCollisionObjectWrapper* compoundObjWrap, const btCollisionObjectWrapper* otherObjWrap, btDispatcher* dispatcher, const btDispatcherInfo& dispatchInfo, btManifoldResult* resultOut, btCollisionAlgorithm** childCollisionAlgorithms, btPersistentManifold* sharedManifold)
106 : m_compoundColObjWrap(compoundObjWrap), m_otherObjWrap(otherObjWrap), m_dispatcher(dispatcher), m_dispatchInfo(dispatchInfo), m_resultOut(resultOut), m_childCollisionAlgorithms(childCollisionAlgorithms), m_sharedManifold(sharedManifold)
110 void ProcessChildShape(const btCollisionShape* childShape, int index)
112 btAssert(index >= 0);
113 const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(m_compoundColObjWrap->getCollisionShape());
114 btAssert(index < compoundShape->getNumChildShapes());
116 if (gCompoundChildShapePairCallback)
118 if (!gCompoundChildShapePairCallback(m_otherObjWrap->getCollisionShape(), childShape))
123 btTransform orgTrans = m_compoundColObjWrap->getWorldTransform();
125 const btTransform& childTrans = compoundShape->getChildTransform(index);
126 btTransform newChildWorldTrans = orgTrans * childTrans;
128 //perform an AABB check first
129 btVector3 aabbMin0, aabbMax0;
130 childShape->getAabb(newChildWorldTrans, aabbMin0, aabbMax0);
132 btVector3 extendAabb(m_resultOut->m_closestPointDistanceThreshold, m_resultOut->m_closestPointDistanceThreshold, m_resultOut->m_closestPointDistanceThreshold);
133 aabbMin0 -= extendAabb;
134 aabbMax0 += extendAabb;
136 btVector3 aabbMin1, aabbMax1;
137 m_otherObjWrap->getCollisionShape()->getAabb(m_otherObjWrap->getWorldTransform(), aabbMin1, aabbMax1);
140 if (TestAabbAgainstAabb2(aabbMin0, aabbMax0, aabbMin1, aabbMax1))
142 btTransform preTransform = childTrans;
143 if (this->m_compoundColObjWrap->m_preTransform)
145 preTransform = preTransform *(*(this->m_compoundColObjWrap->m_preTransform));
147 btCollisionObjectWrapper compoundWrap(this->m_compoundColObjWrap, childShape, m_compoundColObjWrap->getCollisionObject(), newChildWorldTrans, preTransform, -1, index);
149 btCollisionAlgorithm* algo = 0;
150 bool allocatedAlgorithm = false;
152 if (m_resultOut->m_closestPointDistanceThreshold > 0)
154 algo = m_dispatcher->findAlgorithm(&compoundWrap, m_otherObjWrap, 0, BT_CLOSEST_POINT_ALGORITHMS);
155 allocatedAlgorithm = true;
159 //the contactpoint is still projected back using the original inverted worldtrans
160 if (!m_childCollisionAlgorithms[index])
162 m_childCollisionAlgorithms[index] = m_dispatcher->findAlgorithm(&compoundWrap, m_otherObjWrap, m_sharedManifold, BT_CONTACT_POINT_ALGORITHMS);
164 algo = m_childCollisionAlgorithms[index];
167 const btCollisionObjectWrapper* tmpWrap = 0;
169 ///detect swapping case
170 if (m_resultOut->getBody0Internal() == m_compoundColObjWrap->getCollisionObject())
172 tmpWrap = m_resultOut->getBody0Wrap();
173 m_resultOut->setBody0Wrap(&compoundWrap);
174 m_resultOut->setShapeIdentifiersA(-1, index);
178 tmpWrap = m_resultOut->getBody1Wrap();
179 m_resultOut->setBody1Wrap(&compoundWrap);
180 m_resultOut->setShapeIdentifiersB(-1, index);
183 algo->processCollision(&compoundWrap, m_otherObjWrap, m_dispatchInfo, m_resultOut);
186 if (m_dispatchInfo.m_debugDraw && (m_dispatchInfo.m_debugDraw->getDebugMode() & btIDebugDraw::DBG_DrawAabb))
188 btVector3 worldAabbMin,worldAabbMax;
189 m_dispatchInfo.m_debugDraw->drawAabb(aabbMin0,aabbMax0,btVector3(1,1,1));
190 m_dispatchInfo.m_debugDraw->drawAabb(aabbMin1,aabbMax1,btVector3(1,1,1));
194 if (m_resultOut->getBody0Internal() == m_compoundColObjWrap->getCollisionObject())
196 m_resultOut->setBody0Wrap(tmpWrap);
200 m_resultOut->setBody1Wrap(tmpWrap);
202 if (allocatedAlgorithm)
204 algo->~btCollisionAlgorithm();
205 m_dispatcher->freeCollisionAlgorithm(algo);
209 void Process(const btDbvtNode* leaf)
211 int index = leaf->dataAsInt;
213 const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(m_compoundColObjWrap->getCollisionShape());
214 const btCollisionShape* childShape = compoundShape->getChildShape(index);
217 if (m_dispatchInfo.m_debugDraw && (m_dispatchInfo.m_debugDraw->getDebugMode() & btIDebugDraw::DBG_DrawAabb))
219 btVector3 worldAabbMin,worldAabbMax;
220 btTransform orgTrans = m_compoundColObjWrap->getWorldTransform();
221 btTransformAabb(leaf->volume.Mins(),leaf->volume.Maxs(),0.,orgTrans,worldAabbMin,worldAabbMax);
222 m_dispatchInfo.m_debugDraw->drawAabb(worldAabbMin,worldAabbMax,btVector3(1,0,0));
226 ProcessChildShape(childShape, index);
230 void btCompoundCollisionAlgorithm::processCollision(const btCollisionObjectWrapper* body0Wrap, const btCollisionObjectWrapper* body1Wrap, const btDispatcherInfo& dispatchInfo, btManifoldResult* resultOut)
232 const btCollisionObjectWrapper* colObjWrap = m_isSwapped ? body1Wrap : body0Wrap;
233 const btCollisionObjectWrapper* otherObjWrap = m_isSwapped ? body0Wrap : body1Wrap;
235 btAssert(colObjWrap->getCollisionShape()->isCompound());
236 const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(colObjWrap->getCollisionShape());
238 ///btCompoundShape might have changed:
239 ////make sure the internal child collision algorithm caches are still valid
240 if (compoundShape->getUpdateRevision() != m_compoundShapeRevision)
242 ///clear and update all
243 removeChildAlgorithms();
245 preallocateChildAlgorithms(body0Wrap, body1Wrap);
246 m_compoundShapeRevision = compoundShape->getUpdateRevision();
249 if (m_childCollisionAlgorithms.size() == 0)
252 const btDbvt* tree = compoundShape->getDynamicAabbTree();
253 //use a dynamic aabb tree to cull potential child-overlaps
254 btCompoundLeafCallback callback(colObjWrap, otherObjWrap, m_dispatcher, dispatchInfo, resultOut, &m_childCollisionAlgorithms[0], m_sharedManifold);
256 ///we need to refresh all contact manifolds
257 ///note that we should actually recursively traverse all children, btCompoundShape can nested more then 1 level deep
258 ///so we should add a 'refreshManifolds' in the btCollisionAlgorithm
261 manifoldArray.resize(0);
262 for (i = 0; i < m_childCollisionAlgorithms.size(); i++)
264 if (m_childCollisionAlgorithms[i])
266 m_childCollisionAlgorithms[i]->getAllContactManifolds(manifoldArray);
267 for (int m = 0; m < manifoldArray.size(); m++)
269 if (manifoldArray[m]->getNumContacts())
271 resultOut->setPersistentManifold(manifoldArray[m]);
272 resultOut->refreshContactPoints();
273 resultOut->setPersistentManifold(0); //??necessary?
276 manifoldArray.resize(0);
283 btVector3 localAabbMin, localAabbMax;
284 btTransform otherInCompoundSpace;
285 otherInCompoundSpace = colObjWrap->getWorldTransform().inverse() * otherObjWrap->getWorldTransform();
286 otherObjWrap->getCollisionShape()->getAabb(otherInCompoundSpace, localAabbMin, localAabbMax);
287 btVector3 extraExtends(resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold);
288 localAabbMin -= extraExtends;
289 localAabbMax += extraExtends;
291 const ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds = btDbvtVolume::FromMM(localAabbMin, localAabbMax);
292 //process all children, that overlap with the given AABB bounds
293 tree->collideTVNoStackAlloc(tree->m_root, bounds, stack2, callback);
297 //iterate over all children, perform an AABB check inside ProcessChildShape
298 int numChildren = m_childCollisionAlgorithms.size();
300 for (i = 0; i < numChildren; i++)
302 callback.ProcessChildShape(compoundShape->getChildShape(i), i);
307 //iterate over all children, perform an AABB check inside ProcessChildShape
308 int numChildren = m_childCollisionAlgorithms.size();
310 manifoldArray.resize(0);
311 const btCollisionShape* childShape = 0;
312 btTransform orgTrans;
314 btTransform newChildWorldTrans;
315 btVector3 aabbMin0, aabbMax0, aabbMin1, aabbMax1;
317 for (i = 0; i < numChildren; i++)
319 if (m_childCollisionAlgorithms[i])
321 childShape = compoundShape->getChildShape(i);
322 //if not longer overlapping, remove the algorithm
323 orgTrans = colObjWrap->getWorldTransform();
325 const btTransform& childTrans = compoundShape->getChildTransform(i);
326 newChildWorldTrans = orgTrans * childTrans;
328 //perform an AABB check first
329 childShape->getAabb(newChildWorldTrans, aabbMin0, aabbMax0);
330 otherObjWrap->getCollisionShape()->getAabb(otherObjWrap->getWorldTransform(), aabbMin1, aabbMax1);
332 if (!TestAabbAgainstAabb2(aabbMin0, aabbMax0, aabbMin1, aabbMax1))
334 m_childCollisionAlgorithms[i]->~btCollisionAlgorithm();
335 m_dispatcher->freeCollisionAlgorithm(m_childCollisionAlgorithms[i]);
336 m_childCollisionAlgorithms[i] = 0;
343 btScalar btCompoundCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0, btCollisionObject* body1, const btDispatcherInfo& dispatchInfo, btManifoldResult* resultOut)
346 //needs to be fixed, using btCollisionObjectWrapper and NOT modifying internal data structures
347 btCollisionObject* colObj = m_isSwapped ? body1 : body0;
348 btCollisionObject* otherObj = m_isSwapped ? body0 : body1;
350 btAssert(colObj->getCollisionShape()->isCompound());
352 btCompoundShape* compoundShape = static_cast<btCompoundShape*>(colObj->getCollisionShape());
354 //We will use the OptimizedBVH, AABB tree to cull potential child-overlaps
355 //If both proxies are Compound, we will deal with that directly, by performing sequential/parallel tree traversals
356 //given Proxy0 and Proxy1, if both have a tree, Tree0 and Tree1, this means:
357 //determine overlapping nodes of Proxy1 using Proxy0 AABB against Tree1
358 //then use each overlapping node AABB against Tree0
361 btScalar hitFraction = btScalar(1.);
363 int numChildren = m_childCollisionAlgorithms.size();
365 btTransform orgTrans;
367 for (i = 0; i < numChildren; i++)
369 //btCollisionShape* childShape = compoundShape->getChildShape(i);
372 orgTrans = colObj->getWorldTransform();
374 const btTransform& childTrans = compoundShape->getChildTransform(i);
375 //btTransform newChildWorldTrans = orgTrans*childTrans ;
376 colObj->setWorldTransform(orgTrans * childTrans);
378 //btCollisionShape* tmpShape = colObj->getCollisionShape();
379 //colObj->internalSetTemporaryCollisionShape( childShape );
380 frac = m_childCollisionAlgorithms[i]->calculateTimeOfImpact(colObj, otherObj, dispatchInfo, resultOut);
381 if (frac < hitFraction)
386 //colObj->internalSetTemporaryCollisionShape( tmpShape);
387 colObj->setWorldTransform(orgTrans);