forked from LeenkxTeam/LNXSDK
		
	
		
			
				
	
	
		
			368 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			368 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
Bullet Continuous Collision Detection and Physics Library
 | 
						|
Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
 | 
						|
 | 
						|
This software is provided 'as-is', without any express or implied warranty.
 | 
						|
In no event will the authors be held liable for any damages arising from the use of this software.
 | 
						|
Permission is granted to anyone to use this software for any purpose, 
 | 
						|
including commercial applications, and to alter it and redistribute it freely, 
 | 
						|
subject to the following restrictions:
 | 
						|
 | 
						|
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.
 | 
						|
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
 | 
						|
3. This notice may not be removed or altered from any source distribution.
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
#include "btSoftMultiBodyDynamicsWorld.h"
 | 
						|
#include "LinearMath/btQuickprof.h"
 | 
						|
 | 
						|
//softbody & helpers
 | 
						|
#include "BulletSoftBody/btSoftBody.h"
 | 
						|
#include "BulletSoftBody/btSoftBodyHelpers.h"
 | 
						|
#include "BulletSoftBody/btSoftBodySolvers.h"
 | 
						|
#include "BulletSoftBody/btDefaultSoftBodySolver.h"
 | 
						|
#include "LinearMath/btSerializer.h"
 | 
						|
 | 
						|
 | 
						|
btSoftMultiBodyDynamicsWorld::btSoftMultiBodyDynamicsWorld(
 | 
						|
	btDispatcher* dispatcher,
 | 
						|
	btBroadphaseInterface* pairCache,
 | 
						|
	btMultiBodyConstraintSolver* constraintSolver,
 | 
						|
	btCollisionConfiguration* collisionConfiguration,
 | 
						|
	btSoftBodySolver *softBodySolver ) : 
 | 
						|
		btMultiBodyDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration),
 | 
						|
        m_softBodySolver( softBodySolver ),
 | 
						|
        m_ownsSolver(false)
 | 
						|
{
 | 
						|
	if( !m_softBodySolver )
 | 
						|
	{
 | 
						|
		void* ptr = btAlignedAlloc(sizeof(btDefaultSoftBodySolver),16);
 | 
						|
		m_softBodySolver = new(ptr) btDefaultSoftBodySolver();
 | 
						|
		m_ownsSolver = true;
 | 
						|
	}
 | 
						|
 | 
						|
	m_drawFlags			=	fDrawFlags::Std;
 | 
						|
	m_drawNodeTree		=	true;
 | 
						|
	m_drawFaceTree		=	false;
 | 
						|
	m_drawClusterTree	=	false;
 | 
						|
	m_sbi.m_broadphase = pairCache;
 | 
						|
	m_sbi.m_dispatcher = dispatcher;
 | 
						|
	m_sbi.m_sparsesdf.Initialize();
 | 
						|
	m_sbi.m_sparsesdf.Reset();
 | 
						|
 | 
						|
	m_sbi.air_density		=	(btScalar)1.2;
 | 
						|
	m_sbi.water_density	=	0;
 | 
						|
	m_sbi.water_offset		=	0;
 | 
						|
	m_sbi.water_normal		=	btVector3(0,0,0);
 | 
						|
	m_sbi.m_gravity.setValue(0,-10,0);
 | 
						|
 | 
						|
	m_sbi.m_sparsesdf.Initialize();
 | 
						|
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
btSoftMultiBodyDynamicsWorld::~btSoftMultiBodyDynamicsWorld()
 | 
						|
{
 | 
						|
	if (m_ownsSolver)
 | 
						|
	{
 | 
						|
		m_softBodySolver->~btSoftBodySolver();
 | 
						|
		btAlignedFree(m_softBodySolver);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void	btSoftMultiBodyDynamicsWorld::predictUnconstraintMotion(btScalar timeStep)
 | 
						|
{
 | 
						|
	btDiscreteDynamicsWorld::predictUnconstraintMotion( timeStep );
 | 
						|
	{
 | 
						|
		BT_PROFILE("predictUnconstraintMotionSoftBody");
 | 
						|
		m_softBodySolver->predictMotion( float(timeStep) );
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void	btSoftMultiBodyDynamicsWorld::internalSingleStepSimulation( btScalar timeStep )
 | 
						|
{
 | 
						|
 | 
						|
	// Let the solver grab the soft bodies and if necessary optimize for it
 | 
						|
	m_softBodySolver->optimize( getSoftBodyArray() );
 | 
						|
 | 
						|
	if( !m_softBodySolver->checkInitialized() )
 | 
						|
	{
 | 
						|
		btAssert( "Solver initialization failed\n" );
 | 
						|
	}
 | 
						|
 | 
						|
	btDiscreteDynamicsWorld::internalSingleStepSimulation( timeStep );
 | 
						|
 | 
						|
	///solve soft bodies constraints
 | 
						|
	solveSoftBodiesConstraints( timeStep );
 | 
						|
 | 
						|
	//self collisions
 | 
						|
	for ( int i=0;i<m_softBodies.size();i++)
 | 
						|
	{
 | 
						|
		btSoftBody*	psb=(btSoftBody*)m_softBodies[i];
 | 
						|
		psb->defaultCollisionHandler(psb);
 | 
						|
	}
 | 
						|
 | 
						|
	///update soft bodies
 | 
						|
	m_softBodySolver->updateSoftBodies( );
 | 
						|
	
 | 
						|
	// End solver-wise simulation step
 | 
						|
	// ///////////////////////////////
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
void	btSoftMultiBodyDynamicsWorld::solveSoftBodiesConstraints( btScalar timeStep )
 | 
						|
{
 | 
						|
	BT_PROFILE("solveSoftConstraints");
 | 
						|
 | 
						|
	if(m_softBodies.size())
 | 
						|
	{
 | 
						|
		btSoftBody::solveClusters(m_softBodies);
 | 
						|
	}
 | 
						|
 | 
						|
	// Solve constraints solver-wise
 | 
						|
	m_softBodySolver->solveConstraints( timeStep * m_softBodySolver->getTimeScale() );
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
void	btSoftMultiBodyDynamicsWorld::addSoftBody(btSoftBody* body, int collisionFilterGroup, int collisionFilterMask)
 | 
						|
{
 | 
						|
	m_softBodies.push_back(body);
 | 
						|
 | 
						|
	// Set the soft body solver that will deal with this body
 | 
						|
	// to be the world's solver
 | 
						|
	body->setSoftBodySolver( m_softBodySolver );
 | 
						|
 | 
						|
	btCollisionWorld::addCollisionObject(body,
 | 
						|
		collisionFilterGroup,
 | 
						|
		collisionFilterMask);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
void	btSoftMultiBodyDynamicsWorld::removeSoftBody(btSoftBody* body)
 | 
						|
{
 | 
						|
	m_softBodies.remove(body);
 | 
						|
 | 
						|
	btCollisionWorld::removeCollisionObject(body);
 | 
						|
}
 | 
						|
 | 
						|
void	btSoftMultiBodyDynamicsWorld::removeCollisionObject(btCollisionObject* collisionObject)
 | 
						|
{
 | 
						|
	btSoftBody* body = btSoftBody::upcast(collisionObject);
 | 
						|
	if (body)
 | 
						|
		removeSoftBody(body);
 | 
						|
	else
 | 
						|
		btDiscreteDynamicsWorld::removeCollisionObject(collisionObject);
 | 
						|
}
 | 
						|
 | 
						|
void	btSoftMultiBodyDynamicsWorld::debugDrawWorld()
 | 
						|
{
 | 
						|
	btDiscreteDynamicsWorld::debugDrawWorld();
 | 
						|
 | 
						|
	if (getDebugDrawer())
 | 
						|
	{
 | 
						|
		int i;
 | 
						|
		for (  i=0;i<this->m_softBodies.size();i++)
 | 
						|
		{
 | 
						|
			btSoftBody*	psb=(btSoftBody*)this->m_softBodies[i];
 | 
						|
			if (getDebugDrawer() && (getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe)))
 | 
						|
			{
 | 
						|
				btSoftBodyHelpers::DrawFrame(psb,m_debugDrawer);
 | 
						|
				btSoftBodyHelpers::Draw(psb,m_debugDrawer,m_drawFlags);
 | 
						|
			}
 | 
						|
			
 | 
						|
			if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb))
 | 
						|
			{
 | 
						|
				if(m_drawNodeTree)		btSoftBodyHelpers::DrawNodeTree(psb,m_debugDrawer);
 | 
						|
				if(m_drawFaceTree)		btSoftBodyHelpers::DrawFaceTree(psb,m_debugDrawer);
 | 
						|
				if(m_drawClusterTree)	btSoftBodyHelpers::DrawClusterTree(psb,m_debugDrawer);
 | 
						|
			}
 | 
						|
		}		
 | 
						|
	}	
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
struct btSoftSingleRayCallback : public btBroadphaseRayCallback
 | 
						|
{
 | 
						|
	btVector3	m_rayFromWorld;
 | 
						|
	btVector3	m_rayToWorld;
 | 
						|
	btTransform	m_rayFromTrans;
 | 
						|
	btTransform	m_rayToTrans;
 | 
						|
	btVector3	m_hitNormal;
 | 
						|
 | 
						|
	const btSoftMultiBodyDynamicsWorld*	m_world;
 | 
						|
	btCollisionWorld::RayResultCallback&	m_resultCallback;
 | 
						|
 | 
						|
	btSoftSingleRayCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld,const btSoftMultiBodyDynamicsWorld* world,btCollisionWorld::RayResultCallback& resultCallback)
 | 
						|
	:m_rayFromWorld(rayFromWorld),
 | 
						|
	m_rayToWorld(rayToWorld),
 | 
						|
	m_world(world),
 | 
						|
	m_resultCallback(resultCallback)
 | 
						|
	{
 | 
						|
		m_rayFromTrans.setIdentity();
 | 
						|
		m_rayFromTrans.setOrigin(m_rayFromWorld);
 | 
						|
		m_rayToTrans.setIdentity();
 | 
						|
		m_rayToTrans.setOrigin(m_rayToWorld);
 | 
						|
 | 
						|
		btVector3 rayDir = (rayToWorld-rayFromWorld);
 | 
						|
 | 
						|
		rayDir.normalize ();
 | 
						|
		///what about division by zero? --> just set rayDirection[i] to INF/1e30
 | 
						|
		m_rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[0];
 | 
						|
		m_rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[1];
 | 
						|
		m_rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[2];
 | 
						|
		m_signs[0] = m_rayDirectionInverse[0] < 0.0;
 | 
						|
		m_signs[1] = m_rayDirectionInverse[1] < 0.0;
 | 
						|
		m_signs[2] = m_rayDirectionInverse[2] < 0.0;
 | 
						|
 | 
						|
		m_lambda_max = rayDir.dot(m_rayToWorld-m_rayFromWorld);
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
	
 | 
						|
 | 
						|
	virtual bool	process(const btBroadphaseProxy* proxy)
 | 
						|
	{
 | 
						|
		///terminate further ray tests, once the closestHitFraction reached zero
 | 
						|
		if (m_resultCallback.m_closestHitFraction == btScalar(0.f))
 | 
						|
			return false;
 | 
						|
 | 
						|
		btCollisionObject*	collisionObject = (btCollisionObject*)proxy->m_clientObject;
 | 
						|
 | 
						|
		//only perform raycast if filterMask matches
 | 
						|
		if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) 
 | 
						|
		{
 | 
						|
			//RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject();
 | 
						|
			//btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
 | 
						|
#if 0
 | 
						|
#ifdef RECALCULATE_AABB
 | 
						|
			btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
 | 
						|
			collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax);
 | 
						|
#else
 | 
						|
			//getBroadphase()->getAabb(collisionObject->getBroadphaseHandle(),collisionObjectAabbMin,collisionObjectAabbMax);
 | 
						|
			const btVector3& collisionObjectAabbMin = collisionObject->getBroadphaseHandle()->m_aabbMin;
 | 
						|
			const btVector3& collisionObjectAabbMax = collisionObject->getBroadphaseHandle()->m_aabbMax;
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
			//btScalar hitLambda = m_resultCallback.m_closestHitFraction;
 | 
						|
			//culling already done by broadphase
 | 
						|
			//if (btRayAabb(m_rayFromWorld,m_rayToWorld,collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,m_hitNormal))
 | 
						|
			{
 | 
						|
				m_world->rayTestSingle(m_rayFromTrans,m_rayToTrans,
 | 
						|
					collisionObject,
 | 
						|
						collisionObject->getCollisionShape(),
 | 
						|
						collisionObject->getWorldTransform(),
 | 
						|
						m_resultCallback);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
};
 | 
						|
 | 
						|
void	btSoftMultiBodyDynamicsWorld::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const
 | 
						|
{
 | 
						|
	BT_PROFILE("rayTest");
 | 
						|
	/// use the broadphase to accelerate the search for objects, based on their aabb
 | 
						|
	/// and for each object with ray-aabb overlap, perform an exact ray test
 | 
						|
	btSoftSingleRayCallback rayCB(rayFromWorld,rayToWorld,this,resultCallback);
 | 
						|
 | 
						|
#ifndef USE_BRUTEFORCE_RAYBROADPHASE
 | 
						|
	m_broadphasePairCache->rayTest(rayFromWorld,rayToWorld,rayCB);
 | 
						|
#else
 | 
						|
	for (int i=0;i<this->getNumCollisionObjects();i++)
 | 
						|
	{
 | 
						|
		rayCB.process(m_collisionObjects[i]->getBroadphaseHandle());
 | 
						|
	}	
 | 
						|
#endif //USE_BRUTEFORCE_RAYBROADPHASE
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void	btSoftMultiBodyDynamicsWorld::rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans,
 | 
						|
					  btCollisionObject* collisionObject,
 | 
						|
					  const btCollisionShape* collisionShape,
 | 
						|
					  const btTransform& colObjWorldTransform,
 | 
						|
					  RayResultCallback& resultCallback)
 | 
						|
{
 | 
						|
	if (collisionShape->isSoftBody()) {
 | 
						|
		btSoftBody* softBody = btSoftBody::upcast(collisionObject);
 | 
						|
		if (softBody) {
 | 
						|
			btSoftBody::sRayCast softResult;
 | 
						|
			if (softBody->rayTest(rayFromTrans.getOrigin(), rayToTrans.getOrigin(), softResult)) 
 | 
						|
			{
 | 
						|
				
 | 
						|
				if (softResult.fraction<= resultCallback.m_closestHitFraction)
 | 
						|
				{
 | 
						|
 | 
						|
					btCollisionWorld::LocalShapeInfo shapeInfo;
 | 
						|
					shapeInfo.m_shapePart = 0;
 | 
						|
					shapeInfo.m_triangleIndex = softResult.index;
 | 
						|
					// get the normal
 | 
						|
					btVector3 rayDir = rayToTrans.getOrigin() - rayFromTrans.getOrigin();
 | 
						|
					btVector3 normal=-rayDir;
 | 
						|
					normal.normalize();
 | 
						|
 | 
						|
					if (softResult.feature == btSoftBody::eFeature::Face)
 | 
						|
					{
 | 
						|
						normal = softBody->m_faces[softResult.index].m_normal;
 | 
						|
						if (normal.dot(rayDir) > 0) {
 | 
						|
							// normal always point toward origin of the ray
 | 
						|
							normal = -normal;
 | 
						|
						}
 | 
						|
					}
 | 
						|
	
 | 
						|
					btCollisionWorld::LocalRayResult rayResult
 | 
						|
						(collisionObject,
 | 
						|
						 &shapeInfo,
 | 
						|
						 normal,
 | 
						|
						 softResult.fraction);
 | 
						|
					bool	normalInWorldSpace = true;
 | 
						|
					resultCallback.addSingleResult(rayResult,normalInWorldSpace);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	} 
 | 
						|
	else {
 | 
						|
		btCollisionWorld::rayTestSingle(rayFromTrans,rayToTrans,collisionObject,collisionShape,colObjWorldTransform,resultCallback);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void	btSoftMultiBodyDynamicsWorld::serializeSoftBodies(btSerializer* serializer)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	//serialize all collision objects
 | 
						|
	for (i=0;i<m_collisionObjects.size();i++)
 | 
						|
	{
 | 
						|
		btCollisionObject* colObj = m_collisionObjects[i];
 | 
						|
		if (colObj->getInternalType() & btCollisionObject::CO_SOFT_BODY)
 | 
						|
		{
 | 
						|
			int len = colObj->calculateSerializeBufferSize();
 | 
						|
			btChunk* chunk = serializer->allocate(len,1);
 | 
						|
			const char* structType = colObj->serialize(chunk->m_oldPtr, serializer);
 | 
						|
			serializer->finalizeChunk(chunk,structType,BT_SOFTBODY_CODE,colObj);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
void	btSoftMultiBodyDynamicsWorld::serialize(btSerializer* serializer)
 | 
						|
{
 | 
						|
 | 
						|
	serializer->startSerialization();
 | 
						|
 | 
						|
	serializeDynamicsWorldInfo( serializer);
 | 
						|
 | 
						|
	serializeSoftBodies(serializer);
 | 
						|
 | 
						|
	serializeRigidBodies(serializer);
 | 
						|
 | 
						|
	serializeCollisionObjects(serializer);
 | 
						|
 | 
						|
	serializer->finishSerialization();
 | 
						|
}
 | 
						|
 | 
						|
 |