1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
4 
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:
10 
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.
14 */
15 
16 
17 #include "btSoftMultiBodyDynamicsWorld.h"
18 #include "LinearMath/btQuickprof.h"
19 
20 //softbody & helpers
21 #include "BulletSoftBody/btSoftBody.h"
22 #include "BulletSoftBody/btSoftBodyHelpers.h"
23 #include "BulletSoftBody/btSoftBodySolvers.h"
24 #include "BulletSoftBody/btDefaultSoftBodySolver.h"
25 #include "LinearMath/btSerializer.h"
26 
27 
btSoftMultiBodyDynamicsWorld(btDispatcher * dispatcher,btBroadphaseInterface * pairCache,btMultiBodyConstraintSolver * constraintSolver,btCollisionConfiguration * collisionConfiguration,btSoftBodySolver * softBodySolver)28 btSoftMultiBodyDynamicsWorld::btSoftMultiBodyDynamicsWorld(
29 	btDispatcher* dispatcher,
30 	btBroadphaseInterface* pairCache,
31 	btMultiBodyConstraintSolver* constraintSolver,
32 	btCollisionConfiguration* collisionConfiguration,
33 	btSoftBodySolver *softBodySolver ) :
34 		btMultiBodyDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration),
35         m_softBodySolver( softBodySolver ),
36         m_ownsSolver(false)
37 {
38 	if( !m_softBodySolver )
39 	{
40 		void* ptr = btAlignedAlloc(sizeof(btDefaultSoftBodySolver),16);
41 		m_softBodySolver = new(ptr) btDefaultSoftBodySolver();
42 		m_ownsSolver = true;
43 	}
44 
45 	m_drawFlags			=	fDrawFlags::Std;
46 	m_drawNodeTree		=	true;
47 	m_drawFaceTree		=	false;
48 	m_drawClusterTree	=	false;
49 	m_sbi.m_broadphase = pairCache;
50 	m_sbi.m_dispatcher = dispatcher;
51 	m_sbi.m_sparsesdf.Initialize();
52 	m_sbi.m_sparsesdf.Reset();
53 
54 	m_sbi.air_density		=	(btScalar)1.2;
55 	m_sbi.water_density	=	0;
56 	m_sbi.water_offset		=	0;
57 	m_sbi.water_normal		=	btVector3(0,0,0);
58 	m_sbi.m_gravity.setValue(0,-10,0);
59 
60 	m_sbi.m_sparsesdf.Initialize();
61 
62 
63 }
64 
~btSoftMultiBodyDynamicsWorld()65 btSoftMultiBodyDynamicsWorld::~btSoftMultiBodyDynamicsWorld()
66 {
67 	if (m_ownsSolver)
68 	{
69 		m_softBodySolver->~btSoftBodySolver();
70 		btAlignedFree(m_softBodySolver);
71 	}
72 }
73 
predictUnconstraintMotion(btScalar timeStep)74 void	btSoftMultiBodyDynamicsWorld::predictUnconstraintMotion(btScalar timeStep)
75 {
76 	btDiscreteDynamicsWorld::predictUnconstraintMotion( timeStep );
77 	{
78 		BT_PROFILE("predictUnconstraintMotionSoftBody");
79 		m_softBodySolver->predictMotion( float(timeStep) );
80 	}
81 }
82 
internalSingleStepSimulation(btScalar timeStep)83 void	btSoftMultiBodyDynamicsWorld::internalSingleStepSimulation( btScalar timeStep )
84 {
85 
86 	// Let the solver grab the soft bodies and if necessary optimize for it
87 	m_softBodySolver->optimize( getSoftBodyArray() );
88 
89 	if( !m_softBodySolver->checkInitialized() )
90 	{
91 		btAssert( "Solver initialization failed\n" );
92 	}
93 
94 	btDiscreteDynamicsWorld::internalSingleStepSimulation( timeStep );
95 
96 	///solve soft bodies constraints
97 	solveSoftBodiesConstraints( timeStep );
98 
99 	//self collisions
100 	for ( int i=0;i<m_softBodies.size();i++)
101 	{
102 		btSoftBody*	psb=(btSoftBody*)m_softBodies[i];
103 		psb->defaultCollisionHandler(psb);
104 	}
105 
106 	///update soft bodies
107 	m_softBodySolver->updateSoftBodies( );
108 
109 	// End solver-wise simulation step
110 	// ///////////////////////////////
111 
112 }
113 
solveSoftBodiesConstraints(btScalar timeStep)114 void	btSoftMultiBodyDynamicsWorld::solveSoftBodiesConstraints( btScalar timeStep )
115 {
116 	BT_PROFILE("solveSoftConstraints");
117 
118 	if(m_softBodies.size())
119 	{
120 		btSoftBody::solveClusters(m_softBodies);
121 	}
122 
123 	// Solve constraints solver-wise
124 	m_softBodySolver->solveConstraints( timeStep * m_softBodySolver->getTimeScale() );
125 
126 }
127 
addSoftBody(btSoftBody * body,int collisionFilterGroup,int collisionFilterMask)128 void	btSoftMultiBodyDynamicsWorld::addSoftBody(btSoftBody* body, int collisionFilterGroup, int collisionFilterMask)
129 {
130 	m_softBodies.push_back(body);
131 
132 	// Set the soft body solver that will deal with this body
133 	// to be the world's solver
134 	body->setSoftBodySolver( m_softBodySolver );
135 
136 	btCollisionWorld::addCollisionObject(body,
137 		collisionFilterGroup,
138 		collisionFilterMask);
139 
140 }
141 
removeSoftBody(btSoftBody * body)142 void	btSoftMultiBodyDynamicsWorld::removeSoftBody(btSoftBody* body)
143 {
144 	m_softBodies.remove(body);
145 
146 	btCollisionWorld::removeCollisionObject(body);
147 }
148 
removeCollisionObject(btCollisionObject * collisionObject)149 void	btSoftMultiBodyDynamicsWorld::removeCollisionObject(btCollisionObject* collisionObject)
150 {
151 	btSoftBody* body = btSoftBody::upcast(collisionObject);
152 	if (body)
153 		removeSoftBody(body);
154 	else
155 		btDiscreteDynamicsWorld::removeCollisionObject(collisionObject);
156 }
157 
debugDrawWorld()158 void	btSoftMultiBodyDynamicsWorld::debugDrawWorld()
159 {
160 	btDiscreteDynamicsWorld::debugDrawWorld();
161 
162 	if (getDebugDrawer())
163 	{
164 		int i;
165 		for (  i=0;i<this->m_softBodies.size();i++)
166 		{
167 			btSoftBody*	psb=(btSoftBody*)this->m_softBodies[i];
168 			if (getDebugDrawer() && (getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe)))
169 			{
170 				btSoftBodyHelpers::DrawFrame(psb,m_debugDrawer);
171 				btSoftBodyHelpers::Draw(psb,m_debugDrawer,m_drawFlags);
172 			}
173 
174 			if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb))
175 			{
176 				if(m_drawNodeTree)		btSoftBodyHelpers::DrawNodeTree(psb,m_debugDrawer);
177 				if(m_drawFaceTree)		btSoftBodyHelpers::DrawFaceTree(psb,m_debugDrawer);
178 				if(m_drawClusterTree)	btSoftBodyHelpers::DrawClusterTree(psb,m_debugDrawer);
179 			}
180 		}
181 	}
182 }
183 
184 
185 
186 
187 struct btSoftSingleRayCallback : public btBroadphaseRayCallback
188 {
189 	btVector3	m_rayFromWorld;
190 	btVector3	m_rayToWorld;
191 	btTransform	m_rayFromTrans;
192 	btTransform	m_rayToTrans;
193 	btVector3	m_hitNormal;
194 
195 	const btSoftMultiBodyDynamicsWorld*	m_world;
196 	btCollisionWorld::RayResultCallback&	m_resultCallback;
197 
btSoftSingleRayCallbackbtSoftSingleRayCallback198 	btSoftSingleRayCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld,const btSoftMultiBodyDynamicsWorld* world,btCollisionWorld::RayResultCallback& resultCallback)
199 	:m_rayFromWorld(rayFromWorld),
200 	m_rayToWorld(rayToWorld),
201 	m_world(world),
202 	m_resultCallback(resultCallback)
203 	{
204 		m_rayFromTrans.setIdentity();
205 		m_rayFromTrans.setOrigin(m_rayFromWorld);
206 		m_rayToTrans.setIdentity();
207 		m_rayToTrans.setOrigin(m_rayToWorld);
208 
209 		btVector3 rayDir = (rayToWorld-rayFromWorld);
210 
211 		rayDir.normalize ();
212 		///what about division by zero? --> just set rayDirection[i] to INF/1e30
213 		m_rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[0];
214 		m_rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[1];
215 		m_rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[2];
216 		m_signs[0] = m_rayDirectionInverse[0] < 0.0;
217 		m_signs[1] = m_rayDirectionInverse[1] < 0.0;
218 		m_signs[2] = m_rayDirectionInverse[2] < 0.0;
219 
220 		m_lambda_max = rayDir.dot(m_rayToWorld-m_rayFromWorld);
221 
222 	}
223 
224 
225 
processbtSoftSingleRayCallback226 	virtual bool	process(const btBroadphaseProxy* proxy)
227 	{
228 		///terminate further ray tests, once the closestHitFraction reached zero
229 		if (m_resultCallback.m_closestHitFraction == btScalar(0.f))
230 			return false;
231 
232 		btCollisionObject*	collisionObject = (btCollisionObject*)proxy->m_clientObject;
233 
234 		//only perform raycast if filterMask matches
235 		if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle()))
236 		{
237 			//RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject();
238 			//btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
239 #if 0
240 #ifdef RECALCULATE_AABB
241 			btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
242 			collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax);
243 #else
244 			//getBroadphase()->getAabb(collisionObject->getBroadphaseHandle(),collisionObjectAabbMin,collisionObjectAabbMax);
245 			const btVector3& collisionObjectAabbMin = collisionObject->getBroadphaseHandle()->m_aabbMin;
246 			const btVector3& collisionObjectAabbMax = collisionObject->getBroadphaseHandle()->m_aabbMax;
247 #endif
248 #endif
249 			//btScalar hitLambda = m_resultCallback.m_closestHitFraction;
250 			//culling already done by broadphase
251 			//if (btRayAabb(m_rayFromWorld,m_rayToWorld,collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,m_hitNormal))
252 			{
253 				m_world->rayTestSingle(m_rayFromTrans,m_rayToTrans,
254 					collisionObject,
255 						collisionObject->getCollisionShape(),
256 						collisionObject->getWorldTransform(),
257 						m_resultCallback);
258 			}
259 		}
260 		return true;
261 	}
262 };
263 
rayTest(const btVector3 & rayFromWorld,const btVector3 & rayToWorld,RayResultCallback & resultCallback) const264 void	btSoftMultiBodyDynamicsWorld::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const
265 {
266 	BT_PROFILE("rayTest");
267 	/// use the broadphase to accelerate the search for objects, based on their aabb
268 	/// and for each object with ray-aabb overlap, perform an exact ray test
269 	btSoftSingleRayCallback rayCB(rayFromWorld,rayToWorld,this,resultCallback);
270 
271 #ifndef USE_BRUTEFORCE_RAYBROADPHASE
272 	m_broadphasePairCache->rayTest(rayFromWorld,rayToWorld,rayCB);
273 #else
274 	for (int i=0;i<this->getNumCollisionObjects();i++)
275 	{
276 		rayCB.process(m_collisionObjects[i]->getBroadphaseHandle());
277 	}
278 #endif //USE_BRUTEFORCE_RAYBROADPHASE
279 
280 }
281 
282 
rayTestSingle(const btTransform & rayFromTrans,const btTransform & rayToTrans,btCollisionObject * collisionObject,const btCollisionShape * collisionShape,const btTransform & colObjWorldTransform,RayResultCallback & resultCallback)283 void	btSoftMultiBodyDynamicsWorld::rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans,
284 					  btCollisionObject* collisionObject,
285 					  const btCollisionShape* collisionShape,
286 					  const btTransform& colObjWorldTransform,
287 					  RayResultCallback& resultCallback)
288 {
289 	if (collisionShape->isSoftBody()) {
290 		btSoftBody* softBody = btSoftBody::upcast(collisionObject);
291 		if (softBody) {
292 			btSoftBody::sRayCast softResult;
293 			if (softBody->rayTest(rayFromTrans.getOrigin(), rayToTrans.getOrigin(), softResult))
294 			{
295 
296 				if (softResult.fraction<= resultCallback.m_closestHitFraction)
297 				{
298 
299 					btCollisionWorld::LocalShapeInfo shapeInfo;
300 					shapeInfo.m_shapePart = 0;
301 					shapeInfo.m_triangleIndex = softResult.index;
302 					// get the normal
303 					btVector3 rayDir = rayToTrans.getOrigin() - rayFromTrans.getOrigin();
304 					btVector3 normal=-rayDir;
305 					normal.normalize();
306 
307 					if (softResult.feature == btSoftBody::eFeature::Face)
308 					{
309 						normal = softBody->m_faces[softResult.index].m_normal;
310 						if (normal.dot(rayDir) > 0) {
311 							// normal always point toward origin of the ray
312 							normal = -normal;
313 						}
314 					}
315 
316 					btCollisionWorld::LocalRayResult rayResult
317 						(collisionObject,
318 						 &shapeInfo,
319 						 normal,
320 						 softResult.fraction);
321 					bool	normalInWorldSpace = true;
322 					resultCallback.addSingleResult(rayResult,normalInWorldSpace);
323 				}
324 			}
325 		}
326 	}
327 	else {
328 		btCollisionWorld::rayTestSingle(rayFromTrans,rayToTrans,collisionObject,collisionShape,colObjWorldTransform,resultCallback);
329 	}
330 }
331 
332 
serializeSoftBodies(btSerializer * serializer)333 void	btSoftMultiBodyDynamicsWorld::serializeSoftBodies(btSerializer* serializer)
334 {
335 	int i;
336 	//serialize all collision objects
337 	for (i=0;i<m_collisionObjects.size();i++)
338 	{
339 		btCollisionObject* colObj = m_collisionObjects[i];
340 		if (colObj->getInternalType() & btCollisionObject::CO_SOFT_BODY)
341 		{
342 			int len = colObj->calculateSerializeBufferSize();
343 			btChunk* chunk = serializer->allocate(len,1);
344 			const char* structType = colObj->serialize(chunk->m_oldPtr, serializer);
345 			serializer->finalizeChunk(chunk,structType,BT_SOFTBODY_CODE,colObj);
346 		}
347 	}
348 
349 }
350 
serialize(btSerializer * serializer)351 void	btSoftMultiBodyDynamicsWorld::serialize(btSerializer* serializer)
352 {
353 
354 	serializer->startSerialization();
355 
356 	serializeDynamicsWorldInfo( serializer);
357 
358 	serializeSoftBodies(serializer);
359 
360 	serializeRigidBodies(serializer);
361 
362 	serializeCollisionObjects(serializer);
363 
364 	serializer->finishSerialization();
365 }
366 
367 
368