mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 13:41:03 +00:00 
			
		
		
		
	Update to bullet master (2.90)
This commit is contained in:
		
							parent
							
								
									43f0767390
								
							
						
					
					
						commit
						3e7db60d56
					
				
					 56 changed files with 4403 additions and 858 deletions
				
			
		|  | @ -175,6 +175,7 @@ if env["builtin_bullet"]: | ||||||
|         "BulletSoftBody/btDeformableContactProjection.cpp", |         "BulletSoftBody/btDeformableContactProjection.cpp", | ||||||
|         "BulletSoftBody/btDeformableMultiBodyDynamicsWorld.cpp", |         "BulletSoftBody/btDeformableMultiBodyDynamicsWorld.cpp", | ||||||
|         "BulletSoftBody/btDeformableContactConstraint.cpp", |         "BulletSoftBody/btDeformableContactConstraint.cpp", | ||||||
|  |         "BulletSoftBody/poly34.cpp", | ||||||
|         # clew |         # clew | ||||||
|         "clew/clew.c", |         "clew/clew.c", | ||||||
|         # LinearMath |         # LinearMath | ||||||
|  |  | ||||||
|  | @ -217,15 +217,17 @@ def configure(env): | ||||||
|         env.ParseConfig("pkg-config libpng16 --cflags --libs") |         env.ParseConfig("pkg-config libpng16 --cflags --libs") | ||||||
| 
 | 
 | ||||||
|     if not env["builtin_bullet"]: |     if not env["builtin_bullet"]: | ||||||
|         # We need at least version 2.89 |         # We need at least version 2.90 | ||||||
|  |         min_bullet_version = "2.90" | ||||||
|  | 
 | ||||||
|         import subprocess |         import subprocess | ||||||
| 
 | 
 | ||||||
|         bullet_version = subprocess.check_output(["pkg-config", "bullet", "--modversion"]).strip() |         bullet_version = subprocess.check_output(["pkg-config", "bullet", "--modversion"]).strip() | ||||||
|         if str(bullet_version) < "2.89": |         if str(bullet_version) < min_bullet_version: | ||||||
|             # Abort as system bullet was requested but too old |             # Abort as system bullet was requested but too old | ||||||
|             print( |             print( | ||||||
|                 "Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format( |                 "Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format( | ||||||
|                     bullet_version, "2.89" |                     bullet_version, min_bullet_version | ||||||
|                 ) |                 ) | ||||||
|             ) |             ) | ||||||
|             sys.exit(255) |             sys.exit(255) | ||||||
|  |  | ||||||
							
								
								
									
										5
									
								
								thirdparty/README.md
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								thirdparty/README.md
									
										
									
									
										vendored
									
									
								
							|  | @ -40,9 +40,12 @@ Files extracted from upstream source: | ||||||
| ## bullet | ## bullet | ||||||
| 
 | 
 | ||||||
| - Upstream: https://github.com/bulletphysics/bullet3 | - Upstream: https://github.com/bulletphysics/bullet3 | ||||||
| - Version: 2.89 | - Version: 2.90 (master cd8cf7521cbb8b7808126a6adebd47bb83ea166a) | ||||||
| - License: zlib | - License: zlib | ||||||
| 
 | 
 | ||||||
|  | Important: Synced with a pre-release version of bullet 2.90 from the master branch. | ||||||
|  | Commit hash: cd8cf7521cbb8b7808126a6adebd47bb83ea166a | ||||||
|  | 
 | ||||||
| Files extracted from upstream source: | Files extracted from upstream source: | ||||||
| 
 | 
 | ||||||
| - src/* apart from CMakeLists.txt and premake4.lua files | - src/* apart from CMakeLists.txt and premake4.lua files | ||||||
|  |  | ||||||
|  | @ -203,8 +203,8 @@ struct btDbvntNode | ||||||
| 
 | 
 | ||||||
|     btDbvntNode(const btDbvtNode* n) |     btDbvntNode(const btDbvtNode* n) | ||||||
|     : volume(n->volume) |     : volume(n->volume) | ||||||
|     , angle(0) |  | ||||||
|     , normal(0,0,0) |     , normal(0,0,0) | ||||||
|  |     , angle(0) | ||||||
|     , data(n->data) |     , data(n->data) | ||||||
|     { |     { | ||||||
|         childs[0] = 0; |         childs[0] = 0; | ||||||
|  |  | ||||||
|  | @ -61,7 +61,8 @@ public: | ||||||
| 	virtual void cleanOverlappingPair(btBroadphasePair& pair, btDispatcher* dispatcher) = 0; | 	virtual void cleanOverlappingPair(btBroadphasePair& pair, btDispatcher* dispatcher) = 0; | ||||||
| 
 | 
 | ||||||
| 	virtual int getNumOverlappingPairs() const = 0; | 	virtual int getNumOverlappingPairs() const = 0; | ||||||
| 
 | 	virtual bool needsBroadphaseCollision(btBroadphaseProxy * proxy0, btBroadphaseProxy * proxy1) const = 0; | ||||||
|  | 	virtual btOverlapFilterCallback* getOverlapFilterCallback() = 0; | ||||||
| 	virtual void cleanProxyFromPairs(btBroadphaseProxy* proxy, btDispatcher* dispatcher) = 0; | 	virtual void cleanProxyFromPairs(btBroadphaseProxy* proxy, btDispatcher* dispatcher) = 0; | ||||||
| 
 | 
 | ||||||
| 	virtual void setOverlapFilterCallback(btOverlapFilterCallback* callback) = 0; | 	virtual void setOverlapFilterCallback(btOverlapFilterCallback* callback) = 0; | ||||||
|  | @ -380,6 +381,14 @@ public: | ||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	bool needsBroadphaseCollision(btBroadphaseProxy*, btBroadphaseProxy*) const | ||||||
|  | 	{ | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 	btOverlapFilterCallback* getOverlapFilterCallback() | ||||||
|  | 	{ | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
| 	virtual void setOverlapFilterCallback(btOverlapFilterCallback* /*callback*/) | 	virtual void setOverlapFilterCallback(btOverlapFilterCallback* /*callback*/) | ||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -468,7 +468,7 @@ void btQuantizedBvh::walkStacklessTreeAgainstRay(btNodeOverlapCallback* nodeCall | ||||||
| 
 | 
 | ||||||
| #ifdef RAYAABB2 | #ifdef RAYAABB2 | ||||||
| 	btVector3 rayDir = (rayTarget - raySource); | 	btVector3 rayDir = (rayTarget - raySource); | ||||||
| 	rayDir.normalize(); | 	rayDir.safeNormalize();// stephengold changed normalize to safeNormalize 2020-02-17
 | ||||||
| 	lambda_max = rayDir.dot(rayTarget - raySource); | 	lambda_max = rayDir.dot(rayTarget - raySource); | ||||||
| 	///what about division by zero? --> just set rayDirection[i] to 1.0
 | 	///what about division by zero? --> just set rayDirection[i] to 1.0
 | ||||||
| 	btVector3 rayDirectionInverse; | 	btVector3 rayDirectionInverse; | ||||||
|  | @ -554,7 +554,7 @@ void btQuantizedBvh::walkStacklessQuantizedTreeAgainstRay(btNodeOverlapCallback* | ||||||
| 
 | 
 | ||||||
| #ifdef RAYAABB2 | #ifdef RAYAABB2 | ||||||
| 	btVector3 rayDirection = (rayTarget - raySource); | 	btVector3 rayDirection = (rayTarget - raySource); | ||||||
| 	rayDirection.normalize(); | 	rayDirection.safeNormalize();// stephengold changed normalize to safeNormalize 2020-02-17
 | ||||||
| 	lambda_max = rayDirection.dot(rayTarget - raySource); | 	lambda_max = rayDirection.dot(rayTarget - raySource); | ||||||
| 	///what about division by zero? --> just set rayDirection[i] to 1.0
 | 	///what about division by zero? --> just set rayDirection[i] to 1.0
 | ||||||
| 	rayDirection[0] = rayDirection[0] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDirection[0]; | 	rayDirection[0] = rayDirection[0] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDirection[0]; | ||||||
|  |  | ||||||
|  | @ -46,8 +46,6 @@ protected: | ||||||
| 
 | 
 | ||||||
| 	btAlignedObjectArray<btPersistentManifold*> m_manifoldsPtr; | 	btAlignedObjectArray<btPersistentManifold*> m_manifoldsPtr; | ||||||
| 
 | 
 | ||||||
| 	btManifoldResult m_defaultManifoldResult; |  | ||||||
| 
 |  | ||||||
| 	btNearCallback m_nearCallback; | 	btNearCallback m_nearCallback; | ||||||
| 
 | 
 | ||||||
| 	btPoolAllocator* m_collisionAlgorithmPoolAllocator; | 	btPoolAllocator* m_collisionAlgorithmPoolAllocator; | ||||||
|  | @ -95,11 +93,15 @@ public: | ||||||
| 
 | 
 | ||||||
| 	btPersistentManifold* getManifoldByIndexInternal(int index) | 	btPersistentManifold* getManifoldByIndexInternal(int index) | ||||||
| 	{ | 	{ | ||||||
|  | 		btAssert(index>=0); | ||||||
|  | 		btAssert(index<m_manifoldsPtr.size()); | ||||||
| 		return m_manifoldsPtr[index]; | 		return m_manifoldsPtr[index]; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	const btPersistentManifold* getManifoldByIndexInternal(int index) const | 	const btPersistentManifold* getManifoldByIndexInternal(int index) const | ||||||
| 	{ | 	{ | ||||||
|  | 		btAssert(index>=0); | ||||||
|  | 		btAssert(index<m_manifoldsPtr.size()); | ||||||
| 		return m_manifoldsPtr[index]; | 		return m_manifoldsPtr[index]; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ subject to the following restrictions: | ||||||
| btCollisionDispatcherMt::btCollisionDispatcherMt(btCollisionConfiguration* config, int grainSize) | btCollisionDispatcherMt::btCollisionDispatcherMt(btCollisionConfiguration* config, int grainSize) | ||||||
| 	: btCollisionDispatcher(config) | 	: btCollisionDispatcher(config) | ||||||
| { | { | ||||||
|  | 	m_batchManifoldsPtr.resize(btGetTaskScheduler()->getNumThreads()); | ||||||
| 	m_batchUpdating = false; | 	m_batchUpdating = false; | ||||||
| 	m_grainSize = grainSize;  // iterations per task
 | 	m_grainSize = grainSize;  // iterations per task
 | ||||||
| } | } | ||||||
|  | @ -65,6 +66,10 @@ btPersistentManifold* btCollisionDispatcherMt::getNewManifold(const btCollisionO | ||||||
| 		manifold->m_index1a = m_manifoldsPtr.size(); | 		manifold->m_index1a = m_manifoldsPtr.size(); | ||||||
| 		m_manifoldsPtr.push_back(manifold); | 		m_manifoldsPtr.push_back(manifold); | ||||||
| 	} | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		m_batchManifoldsPtr[btGetCurrentThreadIndex()].push_back(manifold); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return manifold; | 	return manifold; | ||||||
| } | } | ||||||
|  | @ -121,7 +126,7 @@ struct CollisionDispatcherUpdater : public btIParallelForBody | ||||||
| 
 | 
 | ||||||
| void btCollisionDispatcherMt::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache, const btDispatcherInfo& info, btDispatcher* dispatcher) | void btCollisionDispatcherMt::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache, const btDispatcherInfo& info, btDispatcher* dispatcher) | ||||||
| { | { | ||||||
| 	int pairCount = pairCache->getNumOverlappingPairs(); | 	const int pairCount = pairCache->getNumOverlappingPairs(); | ||||||
| 	if (pairCount == 0) | 	if (pairCount == 0) | ||||||
| 	{ | 	{ | ||||||
| 		return; | 		return; | ||||||
|  | @ -136,16 +141,17 @@ void btCollisionDispatcherMt::dispatchAllCollisionPairs(btOverlappingPairCache* | ||||||
| 	btParallelFor(0, pairCount, m_grainSize, updater); | 	btParallelFor(0, pairCount, m_grainSize, updater); | ||||||
| 	m_batchUpdating = false; | 	m_batchUpdating = false; | ||||||
| 
 | 
 | ||||||
| 	// reconstruct the manifolds array to ensure determinism
 | 	// merge new manifolds, if any
 | ||||||
| 	m_manifoldsPtr.resizeNoInitialize(0); | 	for (int i = 0; i < m_batchManifoldsPtr.size(); ++i) | ||||||
| 
 |  | ||||||
| 	btBroadphasePair* pairs = pairCache->getOverlappingPairArrayPtr(); |  | ||||||
| 	for (int i = 0; i < pairCount; ++i) |  | ||||||
| 	{ | 	{ | ||||||
| 		if (btCollisionAlgorithm* algo = pairs[i].m_algorithm) | 		btAlignedObjectArray<btPersistentManifold*>& batchManifoldsPtr = m_batchManifoldsPtr[i]; | ||||||
|  | 
 | ||||||
|  | 		for (int j = 0; j < batchManifoldsPtr.size(); ++j) | ||||||
| 		{ | 		{ | ||||||
| 			algo->getAllContactManifolds(m_manifoldsPtr); | 			m_manifoldsPtr.push_back(batchManifoldsPtr[j]); | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		batchManifoldsPtr.resizeNoInitialize(0); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// update the indices (used when releasing manifolds)
 | 	// update the indices (used when releasing manifolds)
 | ||||||
|  |  | ||||||
|  | @ -30,6 +30,7 @@ public: | ||||||
| 	virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache, const btDispatcherInfo& info, btDispatcher* dispatcher) BT_OVERRIDE; | 	virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache, const btDispatcherInfo& info, btDispatcher* dispatcher) BT_OVERRIDE; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
|  | 	btAlignedObjectArray<btAlignedObjectArray<btPersistentManifold*> > m_batchManifoldsPtr; | ||||||
| 	bool m_batchUpdating; | 	bool m_batchUpdating; | ||||||
| 	int m_grainSize; | 	int m_grainSize; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -139,7 +139,12 @@ public: | ||||||
| 
 | 
 | ||||||
| 		if (TestAabbAgainstAabb2(aabbMin0, aabbMax0, aabbMin1, aabbMax1)) | 		if (TestAabbAgainstAabb2(aabbMin0, aabbMax0, aabbMin1, aabbMax1)) | ||||||
| 		{ | 		{ | ||||||
| 			btCollisionObjectWrapper compoundWrap(this->m_compoundColObjWrap, childShape, m_compoundColObjWrap->getCollisionObject(), newChildWorldTrans, childTrans, -1, index); | 			btTransform preTransform = childTrans; | ||||||
|  | 			if (this->m_compoundColObjWrap->m_preTransform) | ||||||
|  | 			{ | ||||||
|  | 				preTransform = preTransform *(*(this->m_compoundColObjWrap->m_preTransform)); | ||||||
|  | 			} | ||||||
|  | 			btCollisionObjectWrapper compoundWrap(this->m_compoundColObjWrap, childShape, m_compoundColObjWrap->getCollisionObject(), newChildWorldTrans, preTransform, -1, index); | ||||||
| 
 | 
 | ||||||
| 			btCollisionAlgorithm* algo = 0; | 			btCollisionAlgorithm* algo = 0; | ||||||
| 			bool allocatedAlgorithm = false; | 			bool allocatedAlgorithm = false; | ||||||
|  |  | ||||||
|  | @ -46,7 +46,7 @@ struct btContactSolverInfoData | ||||||
| 	btScalar m_sor;          //successive over-relaxation term
 | 	btScalar m_sor;          //successive over-relaxation term
 | ||||||
| 	btScalar m_erp;          //error reduction for non-contact constraints
 | 	btScalar m_erp;          //error reduction for non-contact constraints
 | ||||||
| 	btScalar m_erp2;         //error reduction for contact constraints
 | 	btScalar m_erp2;         //error reduction for contact constraints
 | ||||||
|     btScalar m_deformable_erp;          //error reduction for deformable constraints
 | 	btScalar m_deformable_erp;          //error reduction for deformable constraints
 | ||||||
| 	btScalar m_globalCfm;    //constraint force mixing for contacts and non-contacts
 | 	btScalar m_globalCfm;    //constraint force mixing for contacts and non-contacts
 | ||||||
| 	btScalar m_frictionERP;  //error reduction for friction constraints
 | 	btScalar m_frictionERP;  //error reduction for friction constraints
 | ||||||
| 	btScalar m_frictionCFM;  //constraint force mixing for friction constraints
 | 	btScalar m_frictionCFM;  //constraint force mixing for friction constraints
 | ||||||
|  | @ -67,6 +67,7 @@ struct btContactSolverInfoData | ||||||
| 	bool m_jointFeedbackInWorldSpace; | 	bool m_jointFeedbackInWorldSpace; | ||||||
| 	bool m_jointFeedbackInJointFrame; | 	bool m_jointFeedbackInJointFrame; | ||||||
| 	int m_reportSolverAnalytics; | 	int m_reportSolverAnalytics; | ||||||
|  | 	int m_numNonContactInnerIterations; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct btContactSolverInfo : public btContactSolverInfoData | struct btContactSolverInfo : public btContactSolverInfoData | ||||||
|  | @ -82,7 +83,7 @@ struct btContactSolverInfo : public btContactSolverInfoData | ||||||
| 		m_numIterations = 10; | 		m_numIterations = 10; | ||||||
| 		m_erp = btScalar(0.2); | 		m_erp = btScalar(0.2); | ||||||
| 		m_erp2 = btScalar(0.2); | 		m_erp2 = btScalar(0.2); | ||||||
|         m_deformable_erp = btScalar(0.); | 		m_deformable_erp = btScalar(0.1); | ||||||
| 		m_globalCfm = btScalar(0.); | 		m_globalCfm = btScalar(0.); | ||||||
| 		m_frictionERP = btScalar(0.2);  //positional friction 'anchors' are disabled by default
 | 		m_frictionERP = btScalar(0.2);  //positional friction 'anchors' are disabled by default
 | ||||||
| 		m_frictionCFM = btScalar(0.); | 		m_frictionCFM = btScalar(0.); | ||||||
|  | @ -104,6 +105,7 @@ struct btContactSolverInfo : public btContactSolverInfoData | ||||||
| 		m_jointFeedbackInWorldSpace = false; | 		m_jointFeedbackInWorldSpace = false; | ||||||
| 		m_jointFeedbackInJointFrame = false; | 		m_jointFeedbackInJointFrame = false; | ||||||
| 		m_reportSolverAnalytics = 0; | 		m_reportSolverAnalytics = 0; | ||||||
|  | 		m_numNonContactInnerIterations = 1;   // the number of inner iterations for solving motor constraint in a single iteration of the constraint solve
 | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -876,7 +876,10 @@ int btGeneric6DofSpring2Constraint::get_limit_motor_info2( | ||||||
| 		// will we not request a velocity with the wrong direction ?
 | 		// will we not request a velocity with the wrong direction ?
 | ||||||
| 		// and the answer is not, because in practice during the solving the current velocity is subtracted from the m_constraintError
 | 		// and the answer is not, because in practice during the solving the current velocity is subtracted from the m_constraintError
 | ||||||
| 		// so the sign of the force that is really matters
 | 		// so the sign of the force that is really matters
 | ||||||
| 		info->m_constraintError[srow] = (rotational ? -1 : 1) * (f < 0 ? -SIMD_INFINITY : SIMD_INFINITY); | 		if (m_flags & BT_6DOF_FLAGS_USE_INFINITE_ERROR) | ||||||
|  | 			info->m_constraintError[srow] = (rotational ? -1 : 1) * (f < 0 ? -SIMD_INFINITY : SIMD_INFINITY); | ||||||
|  | 		else | ||||||
|  | 			info->m_constraintError[srow] = vel + f / m * (rotational ? -1 : 1); | ||||||
| 
 | 
 | ||||||
| 		btScalar minf = f < fd ? f : fd; | 		btScalar minf = f < fd ? f : fd; | ||||||
| 		btScalar maxf = f < fd ? fd : f; | 		btScalar maxf = f < fd ? fd : f; | ||||||
|  |  | ||||||
|  | @ -265,6 +265,7 @@ enum bt6DofFlags2 | ||||||
| 	BT_6DOF_FLAGS_ERP_STOP2 = 2, | 	BT_6DOF_FLAGS_ERP_STOP2 = 2, | ||||||
| 	BT_6DOF_FLAGS_CFM_MOTO2 = 4, | 	BT_6DOF_FLAGS_CFM_MOTO2 = 4, | ||||||
| 	BT_6DOF_FLAGS_ERP_MOTO2 = 8, | 	BT_6DOF_FLAGS_ERP_MOTO2 = 8, | ||||||
|  | 	BT_6DOF_FLAGS_USE_INFINITE_ERROR = (1<<16) | ||||||
| }; | }; | ||||||
| #define BT_6DOF_FLAGS_AXIS_SHIFT2 4  // bits per axis
 | #define BT_6DOF_FLAGS_AXIS_SHIFT2 4  // bits per axis
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -14,7 +14,9 @@ subject to the following restrictions: | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| //#define COMPUTE_IMPULSE_DENOM 1
 | //#define COMPUTE_IMPULSE_DENOM 1
 | ||||||
| //#define BT_ADDITIONAL_DEBUG
 | #ifdef BT_DEBUG | ||||||
|  | #	define BT_ADDITIONAL_DEBUG | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| //It is not necessary (redundant) to refresh contact manifolds, this refresh has been moved to the collision algorithms.
 | //It is not necessary (redundant) to refresh contact manifolds, this refresh has been moved to the collision algorithms.
 | ||||||
| 
 | 
 | ||||||
|  | @ -690,8 +692,10 @@ int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject& | ||||||
| { | { | ||||||
| #if BT_THREADSAFE | #if BT_THREADSAFE | ||||||
| 	int solverBodyId = -1; | 	int solverBodyId = -1; | ||||||
| 	bool isRigidBodyType = btRigidBody::upcast(&body) != NULL; | 	const bool isRigidBodyType = btRigidBody::upcast(&body) != NULL; | ||||||
| 	if (isRigidBodyType && !body.isStaticOrKinematicObject()) | 	const bool isStaticOrKinematic = body.isStaticOrKinematicObject(); | ||||||
|  | 	const bool isKinematic = body.isKinematicObject(); | ||||||
|  | 	if (isRigidBodyType && !isStaticOrKinematic) | ||||||
| 	{ | 	{ | ||||||
| 		// dynamic body
 | 		// dynamic body
 | ||||||
| 		// Dynamic bodies can only be in one island, so it's safe to write to the companionId
 | 		// Dynamic bodies can only be in one island, so it's safe to write to the companionId
 | ||||||
|  | @ -704,7 +708,7 @@ int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject& | ||||||
| 			body.setCompanionId(solverBodyId); | 			body.setCompanionId(solverBodyId); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	else if (isRigidBodyType && body.isKinematicObject()) | 	else if (isRigidBodyType && isKinematic) | ||||||
| 	{ | 	{ | ||||||
| 		//
 | 		//
 | ||||||
| 		// NOTE: must test for kinematic before static because some kinematic objects also
 | 		// NOTE: must test for kinematic before static because some kinematic objects also
 | ||||||
|  |  | ||||||
|  | @ -800,6 +800,14 @@ public: | ||||||
| 		///don't do CCD when the collision filters are not matching
 | 		///don't do CCD when the collision filters are not matching
 | ||||||
| 		if (!ClosestConvexResultCallback::needsCollision(proxy0)) | 		if (!ClosestConvexResultCallback::needsCollision(proxy0)) | ||||||
| 			return false; | 			return false; | ||||||
|  | 		if (m_pairCache->getOverlapFilterCallback()) { | ||||||
|  | 			btBroadphaseProxy* proxy1 = m_me->getBroadphaseHandle(); | ||||||
|  | 			bool collides = m_pairCache->needsBroadphaseCollision(proxy0, proxy1); | ||||||
|  | 			if (!collides) | ||||||
|  | 			{ | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		btCollisionObject* otherObj = (btCollisionObject*)proxy0->m_clientObject; | 		btCollisionObject* otherObj = (btCollisionObject*)proxy0->m_clientObject; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -136,8 +136,13 @@ void btRigidBody::setGravity(const btVector3& acceleration) | ||||||
| 
 | 
 | ||||||
| void btRigidBody::setDamping(btScalar lin_damping, btScalar ang_damping) | void btRigidBody::setDamping(btScalar lin_damping, btScalar ang_damping) | ||||||
| { | { | ||||||
| 	m_linearDamping = btClamped(lin_damping, (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); | #ifdef BT_USE_OLD_DAMPING_METHOD | ||||||
| 	m_angularDamping = btClamped(ang_damping, (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); | 	m_linearDamping = btMax(lin_damping, btScalar(0.0)); | ||||||
|  | 	m_angularDamping = btMax(ang_damping, btScalar(0.0)); | ||||||
|  | #else | ||||||
|  | 	m_linearDamping = btClamped(lin_damping, btScalar(0.0), btScalar(1.0)); | ||||||
|  | 	m_angularDamping = btClamped(ang_damping, btScalar(0.0), btScalar(1.0)); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ///applyDamping damps the velocity, using the given m_linearDamping and m_angularDamping
 | ///applyDamping damps the velocity, using the given m_linearDamping and m_angularDamping
 | ||||||
|  | @ -146,10 +151,9 @@ void btRigidBody::applyDamping(btScalar timeStep) | ||||||
| 	//On new damping: see discussion/issue report here: http://code.google.com/p/bullet/issues/detail?id=74
 | 	//On new damping: see discussion/issue report here: http://code.google.com/p/bullet/issues/detail?id=74
 | ||||||
| 	//todo: do some performance comparisons (but other parts of the engine are probably bottleneck anyway
 | 	//todo: do some performance comparisons (but other parts of the engine are probably bottleneck anyway
 | ||||||
| 
 | 
 | ||||||
| //#define USE_OLD_DAMPING_METHOD 1
 | #ifdef BT_USE_OLD_DAMPING_METHOD | ||||||
| #ifdef USE_OLD_DAMPING_METHOD | 	m_linearVelocity *= btMax((btScalar(1.0) - timeStep * m_linearDamping), btScalar(0.0)); | ||||||
| 	m_linearVelocity *= GEN_clamped((btScalar(1.) - timeStep * m_linearDamping), (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); | 	m_angularVelocity *= btMax((btScalar(1.0) - timeStep * m_angularDamping), btScalar(0.0)); | ||||||
| 	m_angularVelocity *= GEN_clamped((btScalar(1.) - timeStep * m_angularDamping), (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); |  | ||||||
| #else | #else | ||||||
| 	m_linearVelocity *= btPow(btScalar(1) - m_linearDamping, timeStep); | 	m_linearVelocity *= btPow(btScalar(1) - m_linearDamping, timeStep); | ||||||
| 	m_angularVelocity *= btPow(btScalar(1) - m_angularDamping, timeStep); | 	m_angularVelocity *= btPow(btScalar(1) - m_angularDamping, timeStep); | ||||||
|  | @ -380,6 +384,9 @@ void btRigidBody::integrateVelocities(btScalar step) | ||||||
| 	{ | 	{ | ||||||
| 		m_angularVelocity *= (MAX_ANGVEL / step) / angvel; | 		m_angularVelocity *= (MAX_ANGVEL / step) / angvel; | ||||||
| 	} | 	} | ||||||
|  | 	#if defined(BT_CLAMP_VELOCITY_TO) && BT_CLAMP_VELOCITY_TO > 0 | ||||||
|  | 	clampVelocity(m_angularVelocity); | ||||||
|  | 	#endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| btQuaternion btRigidBody::getOrientation() const | btQuaternion btRigidBody::getOrientation() const | ||||||
|  |  | ||||||
|  | @ -305,6 +305,9 @@ public: | ||||||
| 	void applyTorque(const btVector3& torque) | 	void applyTorque(const btVector3& torque) | ||||||
| 	{ | 	{ | ||||||
| 		m_totalTorque += torque * m_angularFactor; | 		m_totalTorque += torque * m_angularFactor; | ||||||
|  | 		#if defined(BT_CLAMP_VELOCITY_TO) && BT_CLAMP_VELOCITY_TO > 0 | ||||||
|  | 		clampVelocity(m_totalTorque); | ||||||
|  | 		#endif | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void applyForce(const btVector3& force, const btVector3& rel_pos) | 	void applyForce(const btVector3& force, const btVector3& rel_pos) | ||||||
|  | @ -316,11 +319,17 @@ public: | ||||||
| 	void applyCentralImpulse(const btVector3& impulse) | 	void applyCentralImpulse(const btVector3& impulse) | ||||||
| 	{ | 	{ | ||||||
| 		m_linearVelocity += impulse * m_linearFactor * m_inverseMass; | 		m_linearVelocity += impulse * m_linearFactor * m_inverseMass; | ||||||
|  | 		#if defined(BT_CLAMP_VELOCITY_TO) && BT_CLAMP_VELOCITY_TO > 0 | ||||||
|  | 		clampVelocity(m_linearVelocity); | ||||||
|  | 		#endif | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void applyTorqueImpulse(const btVector3& torque) | 	void applyTorqueImpulse(const btVector3& torque) | ||||||
| 	{ | 	{ | ||||||
| 		m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor; | 		m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor; | ||||||
|  | 		#if defined(BT_CLAMP_VELOCITY_TO) && BT_CLAMP_VELOCITY_TO > 0 | ||||||
|  | 		clampVelocity(m_angularVelocity); | ||||||
|  | 		#endif | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void applyImpulse(const btVector3& impulse, const btVector3& rel_pos) | 	void applyImpulse(const btVector3& impulse, const btVector3& rel_pos) | ||||||
|  | @ -362,19 +371,45 @@ public: | ||||||
|         m_pushVelocity = v; |         m_pushVelocity = v; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     #if defined(BT_CLAMP_VELOCITY_TO) && BT_CLAMP_VELOCITY_TO > 0 | ||||||
|  |     void clampVelocity(btVector3& v) const { | ||||||
|  |         v.setX( | ||||||
|  |             fmax(-BT_CLAMP_VELOCITY_TO, | ||||||
|  |                  fmin(BT_CLAMP_VELOCITY_TO, v.getX())) | ||||||
|  |         ); | ||||||
|  |         v.setY( | ||||||
|  |             fmax(-BT_CLAMP_VELOCITY_TO, | ||||||
|  |                  fmin(BT_CLAMP_VELOCITY_TO, v.getY())) | ||||||
|  |         ); | ||||||
|  |         v.setZ( | ||||||
|  |             fmax(-BT_CLAMP_VELOCITY_TO, | ||||||
|  |                  fmin(BT_CLAMP_VELOCITY_TO, v.getZ())) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     #endif | ||||||
|  | 
 | ||||||
|     void setTurnVelocity(const btVector3& v) |     void setTurnVelocity(const btVector3& v) | ||||||
|     { |     { | ||||||
|         m_turnVelocity = v; |         m_turnVelocity = v; | ||||||
|  |         #if defined(BT_CLAMP_VELOCITY_TO) && BT_CLAMP_VELOCITY_TO > 0 | ||||||
|  |         clampVelocity(m_turnVelocity); | ||||||
|  |         #endif | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     void applyCentralPushImpulse(const btVector3& impulse) |     void applyCentralPushImpulse(const btVector3& impulse) | ||||||
|     { |     { | ||||||
|         m_pushVelocity += impulse * m_linearFactor * m_inverseMass; |         m_pushVelocity += impulse * m_linearFactor * m_inverseMass; | ||||||
|  |         #if defined(BT_CLAMP_VELOCITY_TO) && BT_CLAMP_VELOCITY_TO > 0 | ||||||
|  |         clampVelocity(m_pushVelocity); | ||||||
|  |         #endif | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     void applyTorqueTurnImpulse(const btVector3& torque) |     void applyTorqueTurnImpulse(const btVector3& torque) | ||||||
|     { |     { | ||||||
|         m_turnVelocity += m_invInertiaTensorWorld * torque * m_angularFactor; |         m_turnVelocity += m_invInertiaTensorWorld * torque * m_angularFactor; | ||||||
|  |         #if defined(BT_CLAMP_VELOCITY_TO) && BT_CLAMP_VELOCITY_TO > 0 | ||||||
|  |         clampVelocity(m_turnVelocity); | ||||||
|  |         #endif | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 	void clearForces() | 	void clearForces() | ||||||
|  | @ -408,12 +443,18 @@ public: | ||||||
| 	{ | 	{ | ||||||
| 		m_updateRevision++; | 		m_updateRevision++; | ||||||
| 		m_linearVelocity = lin_vel; | 		m_linearVelocity = lin_vel; | ||||||
|  | 		#if defined(BT_CLAMP_VELOCITY_TO) && BT_CLAMP_VELOCITY_TO > 0 | ||||||
|  | 		clampVelocity(m_linearVelocity); | ||||||
|  | 		#endif | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	inline void setAngularVelocity(const btVector3& ang_vel) | 	inline void setAngularVelocity(const btVector3& ang_vel) | ||||||
| 	{ | 	{ | ||||||
| 		m_updateRevision++; | 		m_updateRevision++; | ||||||
| 		m_angularVelocity = ang_vel; | 		m_angularVelocity = ang_vel; | ||||||
|  | 		#if defined(BT_CLAMP_VELOCITY_TO) && BT_CLAMP_VELOCITY_TO > 0 | ||||||
|  | 		clampVelocity(m_angularVelocity); | ||||||
|  | 		#endif | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	btVector3 getVelocityInLocalPoint(const btVector3& rel_pos) const | 	btVector3 getVelocityInLocalPoint(const btVector3& rel_pos) const | ||||||
|  |  | ||||||
|  | @ -171,6 +171,8 @@ void btSimulationIslandManagerMt::initIslandPools() | ||||||
| 
 | 
 | ||||||
| btSimulationIslandManagerMt::Island* btSimulationIslandManagerMt::getIsland(int id) | btSimulationIslandManagerMt::Island* btSimulationIslandManagerMt::getIsland(int id) | ||||||
| { | { | ||||||
|  | 	btAssert(id >= 0); | ||||||
|  | 	btAssert(id < m_lookupIslandFromId.size()); | ||||||
| 	Island* island = m_lookupIslandFromId[id]; | 	Island* island = m_lookupIslandFromId[id]; | ||||||
| 	if (island == NULL) | 	if (island == NULL) | ||||||
| 	{ | 	{ | ||||||
|  |  | ||||||
|  | @ -583,52 +583,6 @@ void btMultiBody::compTreeLinkVelocities(btVector3 *omega, btVector3 *vel) const | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| btScalar btMultiBody::getKineticEnergy() const |  | ||||||
| { |  | ||||||
| 	int num_links = getNumLinks(); |  | ||||||
| 	// TODO: would be better not to allocate memory here
 |  | ||||||
| 	btAlignedObjectArray<btVector3> omega; |  | ||||||
| 	omega.resize(num_links + 1); |  | ||||||
| 	btAlignedObjectArray<btVector3> vel; |  | ||||||
| 	vel.resize(num_links + 1); |  | ||||||
| 	compTreeLinkVelocities(&omega[0], &vel[0]); |  | ||||||
| 
 |  | ||||||
| 	// we will do the factor of 0.5 at the end
 |  | ||||||
| 	btScalar result = m_baseMass * vel[0].dot(vel[0]); |  | ||||||
| 	result += omega[0].dot(m_baseInertia * omega[0]); |  | ||||||
| 
 |  | ||||||
| 	for (int i = 0; i < num_links; ++i) |  | ||||||
| 	{ |  | ||||||
| 		result += m_links[i].m_mass * vel[i + 1].dot(vel[i + 1]); |  | ||||||
| 		result += omega[i + 1].dot(m_links[i].m_inertiaLocal * omega[i + 1]); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return 0.5f * result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| btVector3 btMultiBody::getAngularMomentum() const |  | ||||||
| { |  | ||||||
| 	int num_links = getNumLinks(); |  | ||||||
| 	// TODO: would be better not to allocate memory here
 |  | ||||||
| 	btAlignedObjectArray<btVector3> omega; |  | ||||||
| 	omega.resize(num_links + 1); |  | ||||||
| 	btAlignedObjectArray<btVector3> vel; |  | ||||||
| 	vel.resize(num_links + 1); |  | ||||||
| 	btAlignedObjectArray<btQuaternion> rot_from_world; |  | ||||||
| 	rot_from_world.resize(num_links + 1); |  | ||||||
| 	compTreeLinkVelocities(&omega[0], &vel[0]); |  | ||||||
| 
 |  | ||||||
| 	rot_from_world[0] = m_baseQuat; |  | ||||||
| 	btVector3 result = quatRotate(rot_from_world[0].inverse(), (m_baseInertia * omega[0])); |  | ||||||
| 
 |  | ||||||
| 	for (int i = 0; i < num_links; ++i) |  | ||||||
| 	{ |  | ||||||
| 		rot_from_world[i + 1] = m_links[i].m_cachedRotParentToThis * rot_from_world[m_links[i].m_parent + 1]; |  | ||||||
| 		result += (quatRotate(rot_from_world[i + 1].inverse(), (m_links[i].m_inertiaLocal * omega[i + 1]))); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return result; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| void btMultiBody::clearConstraintForces() | void btMultiBody::clearConstraintForces() | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -307,13 +307,6 @@ public: | ||||||
| 	//
 | 	//
 | ||||||
| 	btMatrix3x3 localFrameToWorld(int i, const btMatrix3x3 &local_frame) const; | 	btMatrix3x3 localFrameToWorld(int i, const btMatrix3x3 &local_frame) const; | ||||||
| 
 | 
 | ||||||
| 	//
 |  | ||||||
| 	// calculate kinetic energy and angular momentum
 |  | ||||||
| 	// useful for debugging.
 |  | ||||||
| 	//
 |  | ||||||
| 
 |  | ||||||
| 	btScalar getKineticEnergy() const; |  | ||||||
| 	btVector3 getAngularMomentum() const; |  | ||||||
| 
 | 
 | ||||||
| 	//
 | 	//
 | ||||||
| 	// set external forces and torques. Note all external forces/torques are given in the WORLD frame.
 | 	// set external forces and torques. Note all external forces/torques are given in the WORLD frame.
 | ||||||
|  |  | ||||||
|  | @ -30,23 +30,28 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl | ||||||
| 	btScalar leastSquaredResidual = btSequentialImpulseConstraintSolver::solveSingleIteration(iteration, bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer); | 	btScalar leastSquaredResidual = btSequentialImpulseConstraintSolver::solveSingleIteration(iteration, bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer); | ||||||
| 
 | 
 | ||||||
| 	//solve featherstone non-contact constraints
 | 	//solve featherstone non-contact constraints
 | ||||||
| 
 | 	btScalar nonContactResidual = 0; | ||||||
| 	//printf("m_multiBodyNonContactConstraints = %d\n",m_multiBodyNonContactConstraints.size());
 | 	//printf("m_multiBodyNonContactConstraints = %d\n",m_multiBodyNonContactConstraints.size());
 | ||||||
| 
 | 	for (int i = 0; i < infoGlobal.m_numNonContactInnerIterations; ++i) | ||||||
| 	for (int j = 0; j < m_multiBodyNonContactConstraints.size(); j++) |  | ||||||
| 	{ | 	{ | ||||||
| 		int index = iteration & 1 ? j : m_multiBodyNonContactConstraints.size() - 1 - j; | 		// reset the nonContactResdual to 0 at start of each inner iteration
 | ||||||
|  | 		nonContactResidual = 0; | ||||||
|  | 		for (int j = 0; j < m_multiBodyNonContactConstraints.size(); j++) | ||||||
|  | 		{ | ||||||
|  | 			int index = iteration & 1 ? j : m_multiBodyNonContactConstraints.size() - 1 - j; | ||||||
| 
 | 
 | ||||||
| 		btMultiBodySolverConstraint& constraint = m_multiBodyNonContactConstraints[index]; | 			btMultiBodySolverConstraint& constraint = m_multiBodyNonContactConstraints[index]; | ||||||
| 
 | 
 | ||||||
| 		btScalar residual = resolveSingleConstraintRowGeneric(constraint); | 			btScalar residual = resolveSingleConstraintRowGeneric(constraint); | ||||||
| 		leastSquaredResidual = btMax(leastSquaredResidual, residual * residual); | 			nonContactResidual = btMax(nonContactResidual, residual * residual); | ||||||
| 
 | 
 | ||||||
| 		if (constraint.m_multiBodyA) | 			if (constraint.m_multiBodyA) | ||||||
| 			constraint.m_multiBodyA->setPosUpdated(false); | 				constraint.m_multiBodyA->setPosUpdated(false); | ||||||
| 		if (constraint.m_multiBodyB) | 			if (constraint.m_multiBodyB) | ||||||
| 			constraint.m_multiBodyB->setPosUpdated(false); | 				constraint.m_multiBodyB->setPosUpdated(false); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  | 	leastSquaredResidual = btMax(leastSquaredResidual, nonContactResidual); | ||||||
| 
 | 
 | ||||||
| 	//solve featherstone normal contact
 | 	//solve featherstone normal contact
 | ||||||
| 	for (int j0 = 0; j0 < m_multiBodyNormalContactConstraints.size(); j0++) | 	for (int j0 = 0; j0 < m_multiBodyNormalContactConstraints.size(); j0++) | ||||||
|  | @ -1270,7 +1275,7 @@ void btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold* | ||||||
| 	//	return;
 | 	//	return;
 | ||||||
| 
 | 
 | ||||||
| 	//only a single rollingFriction per manifold
 | 	//only a single rollingFriction per manifold
 | ||||||
| 	int rollingFriction = 1; | 	int rollingFriction = 4; | ||||||
| 
 | 
 | ||||||
| 	for (int j = 0; j < manifold->getNumContacts(); j++) | 	for (int j = 0; j < manifold->getNumContacts(); j++) | ||||||
| 	{ | 	{ | ||||||
|  |  | ||||||
							
								
								
									
										188
									
								
								thirdparty/bullet/BulletSoftBody/btConjugateResidual.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								thirdparty/bullet/BulletSoftBody/btConjugateResidual.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,188 @@ | ||||||
|  | /*
 | ||||||
|  |  Written by Xuchen Han <xuchenhan2015@u.northwestern.edu> | ||||||
|  |   | ||||||
|  |  Bullet Continuous Collision Detection and Physics Library | ||||||
|  |  Copyright (c) 2019 Google Inc. http://bulletphysics.org
 | ||||||
|  |  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. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef BT_CONJUGATE_RESIDUAL_H | ||||||
|  | #define BT_CONJUGATE_RESIDUAL_H | ||||||
|  | #include <iostream> | ||||||
|  | #include <cmath> | ||||||
|  | #include <limits> | ||||||
|  | #include <LinearMath/btAlignedObjectArray.h> | ||||||
|  | #include <LinearMath/btVector3.h> | ||||||
|  | #include <LinearMath/btScalar.h> | ||||||
|  | #include "LinearMath/btQuickprof.h" | ||||||
|  | template <class MatrixX> | ||||||
|  | class btConjugateResidual | ||||||
|  | { | ||||||
|  |     typedef btAlignedObjectArray<btVector3> TVStack; | ||||||
|  |     TVStack r,p,z,temp_p, temp_r, best_x; | ||||||
|  |     // temp_r = A*r
 | ||||||
|  |     // temp_p = A*p
 | ||||||
|  |     // z = M^(-1) * temp_p = M^(-1) * A * p
 | ||||||
|  |     int max_iterations; | ||||||
|  |     btScalar tolerance_squared, best_r; | ||||||
|  | public: | ||||||
|  |     btConjugateResidual(const int max_it_in) | ||||||
|  |     : max_iterations(max_it_in) | ||||||
|  |     { | ||||||
|  |         tolerance_squared = 1e-2; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     virtual ~btConjugateResidual(){} | ||||||
|  |      | ||||||
|  |     // return the number of iterations taken
 | ||||||
|  |     int solve(MatrixX& A, TVStack& x, const TVStack& b, bool verbose = false) | ||||||
|  |     { | ||||||
|  |         BT_PROFILE("CRSolve"); | ||||||
|  |         btAssert(x.size() == b.size()); | ||||||
|  |         reinitialize(b); | ||||||
|  |         // r = b - A * x --with assigned dof zeroed out
 | ||||||
|  |         A.multiply(x, temp_r); // borrow temp_r here to store A*x
 | ||||||
|  |         r = sub(b, temp_r); | ||||||
|  |         // z = M^(-1) * r
 | ||||||
|  |         A.precondition(r, z);  // borrow z to store preconditioned r
 | ||||||
|  |         r = z; | ||||||
|  |         btScalar residual_norm = norm(r); | ||||||
|  |         if (residual_norm <= tolerance_squared) { | ||||||
|  |             if (verbose) | ||||||
|  |             { | ||||||
|  |                 std::cout << "Iteration = 0" << std::endl; | ||||||
|  |                 std::cout << "Two norm of the residual = " << residual_norm << std::endl; | ||||||
|  |             } | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |         p = r; | ||||||
|  |         btScalar r_dot_Ar, r_dot_Ar_new; | ||||||
|  |         // temp_p = A*p
 | ||||||
|  |         A.multiply(p, temp_p); | ||||||
|  |         // temp_r = A*r
 | ||||||
|  |         temp_r = temp_p; | ||||||
|  |         r_dot_Ar = dot(r, temp_r); | ||||||
|  |         for (int k = 1; k <= max_iterations; k++) { | ||||||
|  |             // z = M^(-1) * Ap
 | ||||||
|  |             A.precondition(temp_p, z); | ||||||
|  |             // alpha = r^T * A * r / (Ap)^T * M^-1 * Ap)
 | ||||||
|  |             btScalar alpha = r_dot_Ar / dot(temp_p, z); | ||||||
|  |             //  x += alpha * p;
 | ||||||
|  |             multAndAddTo(alpha, p, x); | ||||||
|  |             //  r -= alpha * z;
 | ||||||
|  |             multAndAddTo(-alpha, z, r); | ||||||
|  |             btScalar norm_r = norm(r); | ||||||
|  |             if (norm_r < best_r) | ||||||
|  |             { | ||||||
|  |                 best_x = x; | ||||||
|  |                 best_r = norm_r; | ||||||
|  |                 if (norm_r < tolerance_squared) { | ||||||
|  |                     if (verbose) | ||||||
|  |                     { | ||||||
|  |                         std::cout << "ConjugateResidual iterations " << k << std::endl; | ||||||
|  |                     } | ||||||
|  |                     return k; | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                 { | ||||||
|  |                     if (verbose) | ||||||
|  |                     { | ||||||
|  |                         std::cout << "ConjugateResidual iterations " << k << " has residual "<< norm_r << std::endl; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             // temp_r = A * r;
 | ||||||
|  |             A.multiply(r, temp_r); | ||||||
|  |             r_dot_Ar_new = dot(r, temp_r); | ||||||
|  |             btScalar beta = r_dot_Ar_new/r_dot_Ar; | ||||||
|  |             r_dot_Ar = r_dot_Ar_new; | ||||||
|  |             // p = beta*p + r;
 | ||||||
|  |             p = multAndAdd(beta, p, r); | ||||||
|  |             // temp_p = beta*temp_p + temp_r;
 | ||||||
|  |             temp_p = multAndAdd(beta, temp_p, temp_r); | ||||||
|  |         } | ||||||
|  |         if (verbose) | ||||||
|  |         { | ||||||
|  |             std::cout << "ConjugateResidual max iterations reached " << max_iterations << std::endl; | ||||||
|  |         } | ||||||
|  |         x = best_x; | ||||||
|  |         return max_iterations; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     void reinitialize(const TVStack& b) | ||||||
|  |     { | ||||||
|  |         r.resize(b.size()); | ||||||
|  |         p.resize(b.size()); | ||||||
|  |         z.resize(b.size()); | ||||||
|  |         temp_p.resize(b.size()); | ||||||
|  |         temp_r.resize(b.size()); | ||||||
|  |         best_x.resize(b.size()); | ||||||
|  |         best_r = SIMD_INFINITY; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     TVStack sub(const TVStack& a, const TVStack& b) | ||||||
|  |     { | ||||||
|  |         // c = a-b
 | ||||||
|  |         btAssert(a.size() == b.size()); | ||||||
|  |         TVStack c; | ||||||
|  |         c.resize(a.size()); | ||||||
|  |         for (int i = 0; i < a.size(); ++i) | ||||||
|  |         { | ||||||
|  |             c[i] = a[i] - b[i]; | ||||||
|  |         } | ||||||
|  |         return c; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     btScalar squaredNorm(const TVStack& a) | ||||||
|  |     { | ||||||
|  |         return dot(a,a); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     btScalar norm(const TVStack& a) | ||||||
|  |     { | ||||||
|  |         btScalar ret = 0; | ||||||
|  |         for (int i = 0; i < a.size(); ++i) | ||||||
|  |         { | ||||||
|  |             for (int d = 0; d < 3; ++d) | ||||||
|  |             { | ||||||
|  |                 ret = btMax(ret, btFabs(a[i][d])); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     btScalar dot(const TVStack& a, const TVStack& b) | ||||||
|  |     { | ||||||
|  |         btScalar ans(0); | ||||||
|  |         for (int i = 0; i < a.size(); ++i) | ||||||
|  |             ans += a[i].dot(b[i]); | ||||||
|  |         return ans; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     void multAndAddTo(btScalar s, const TVStack& a, TVStack& result) | ||||||
|  |     { | ||||||
|  |         //        result += s*a
 | ||||||
|  |         btAssert(a.size() == result.size()); | ||||||
|  |         for (int i = 0; i < a.size(); ++i) | ||||||
|  |             result[i] += s * a[i]; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     TVStack multAndAdd(btScalar s, const TVStack& a, const TVStack& b) | ||||||
|  |     { | ||||||
|  |         // result = a*s + b
 | ||||||
|  |         TVStack result; | ||||||
|  |         result.resize(a.size()); | ||||||
|  |         for (int i = 0; i < a.size(); ++i) | ||||||
|  |             result[i] = s * a[i] + b[i]; | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | #endif /* btConjugateResidual_h */ | ||||||
|  | 
 | ||||||
|  | @ -23,12 +23,15 @@ btDeformableBackwardEulerObjective::btDeformableBackwardEulerObjective(btAligned | ||||||
| , m_backupVelocity(backup_v) | , m_backupVelocity(backup_v) | ||||||
| , m_implicit(false) | , m_implicit(false) | ||||||
| { | { | ||||||
|     m_preconditioner = new MassPreconditioner(m_softBodies); |     m_massPreconditioner = new MassPreconditioner(m_softBodies); | ||||||
|  |     m_KKTPreconditioner = new KKTPreconditioner(m_softBodies, m_projection, m_lf, m_dt, m_implicit); | ||||||
|  |     m_preconditioner = m_KKTPreconditioner; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| btDeformableBackwardEulerObjective::~btDeformableBackwardEulerObjective() | btDeformableBackwardEulerObjective::~btDeformableBackwardEulerObjective() | ||||||
| { | { | ||||||
|     delete m_preconditioner; |     delete m_KKTPreconditioner; | ||||||
|  |     delete m_massPreconditioner; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void btDeformableBackwardEulerObjective::reinitialize(bool nodeUpdated, btScalar dt) | void btDeformableBackwardEulerObjective::reinitialize(bool nodeUpdated, btScalar dt) | ||||||
|  | @ -47,7 +50,7 @@ void btDeformableBackwardEulerObjective::reinitialize(bool nodeUpdated, btScalar | ||||||
|         m_lf[i]->reinitialize(nodeUpdated); |         m_lf[i]->reinitialize(nodeUpdated); | ||||||
|     } |     } | ||||||
|     m_projection.reinitialize(nodeUpdated); |     m_projection.reinitialize(nodeUpdated); | ||||||
|     m_preconditioner->reinitialize(nodeUpdated); | //    m_preconditioner->reinitialize(nodeUpdated);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void btDeformableBackwardEulerObjective::setDt(btScalar dt) | void btDeformableBackwardEulerObjective::setDt(btScalar dt) | ||||||
|  | @ -80,6 +83,33 @@ void btDeformableBackwardEulerObjective::multiply(const TVStack& x, TVStack& b) | ||||||
|              m_lf[i]->addScaledElasticForceDifferential(-m_dt*m_dt, x, b); |              m_lf[i]->addScaledElasticForceDifferential(-m_dt*m_dt, x, b); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     int offset = m_nodes.size(); | ||||||
|  |     for (int i = offset; i < b.size(); ++i) | ||||||
|  |     { | ||||||
|  |         b[i].setZero(); | ||||||
|  |     } | ||||||
|  |     // add in the lagrange multiplier terms
 | ||||||
|  |      | ||||||
|  |     for (int c = 0; c < m_projection.m_lagrangeMultipliers.size(); ++c) | ||||||
|  |     { | ||||||
|  |         // C^T * lambda
 | ||||||
|  |         const LagrangeMultiplier& lm = m_projection.m_lagrangeMultipliers[c]; | ||||||
|  |         for (int i = 0; i < lm.m_num_nodes; ++i) | ||||||
|  |         { | ||||||
|  |             for (int j = 0; j < lm.m_num_constraints; ++j) | ||||||
|  |             { | ||||||
|  |                 b[lm.m_indices[i]] += x[offset+c][j] * lm.m_weights[i] * lm.m_dirs[j]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         // C * x
 | ||||||
|  |         for (int d = 0; d < lm.m_num_constraints; ++d) | ||||||
|  |         { | ||||||
|  |             for (int i = 0; i < lm.m_num_nodes; ++i) | ||||||
|  |             { | ||||||
|  |                 b[offset+c][d] += lm.m_weights[i] * x[lm.m_indices[i]].dot(lm.m_dirs[d]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void btDeformableBackwardEulerObjective::updateVelocity(const TVStack& dv) | void btDeformableBackwardEulerObjective::updateVelocity(const TVStack& dv) | ||||||
|  | @ -134,7 +164,7 @@ void btDeformableBackwardEulerObjective::computeResidual(btScalar dt, TVStack &r | ||||||
|             m_lf[i]->addScaledDampingForce(dt, residual); |             m_lf[i]->addScaledDampingForce(dt, residual); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     m_projection.project(residual); | //    m_projection.project(residual);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| btScalar btDeformableBackwardEulerObjective::computeNorm(const TVStack& residual) const | btScalar btDeformableBackwardEulerObjective::computeNorm(const TVStack& residual) const | ||||||
|  | @ -186,9 +216,9 @@ void btDeformableBackwardEulerObjective::initialGuess(TVStack& dv, const TVStack | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //set constraints as projections
 | //set constraints as projections
 | ||||||
| void btDeformableBackwardEulerObjective::setConstraints() | void btDeformableBackwardEulerObjective::setConstraints(const btContactSolverInfo& infoGlobal) | ||||||
| { | { | ||||||
|     m_projection.setConstraints(); |     m_projection.setConstraints(infoGlobal); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void btDeformableBackwardEulerObjective::applyDynamicFriction(TVStack& r) | void btDeformableBackwardEulerObjective::applyDynamicFriction(TVStack& r) | ||||||
|  |  | ||||||
|  | @ -15,11 +15,12 @@ | ||||||
| 
 | 
 | ||||||
| #ifndef BT_BACKWARD_EULER_OBJECTIVE_H | #ifndef BT_BACKWARD_EULER_OBJECTIVE_H | ||||||
| #define BT_BACKWARD_EULER_OBJECTIVE_H | #define BT_BACKWARD_EULER_OBJECTIVE_H | ||||||
| #include "btConjugateGradient.h" | //#include "btConjugateGradient.h"
 | ||||||
| #include "btDeformableLagrangianForce.h" | #include "btDeformableLagrangianForce.h" | ||||||
| #include "btDeformableMassSpringForce.h" | #include "btDeformableMassSpringForce.h" | ||||||
| #include "btDeformableGravityForce.h" | #include "btDeformableGravityForce.h" | ||||||
| #include "btDeformableCorotatedForce.h" | #include "btDeformableCorotatedForce.h" | ||||||
|  | #include "btDeformableMousePickingForce.h" | ||||||
| #include "btDeformableLinearElasticityForce.h" | #include "btDeformableLinearElasticityForce.h" | ||||||
| #include "btDeformableNeoHookeanForce.h" | #include "btDeformableNeoHookeanForce.h" | ||||||
| #include "btDeformableContactProjection.h" | #include "btDeformableContactProjection.h" | ||||||
|  | @ -39,6 +40,8 @@ public: | ||||||
|     const TVStack& m_backupVelocity; |     const TVStack& m_backupVelocity; | ||||||
|     btAlignedObjectArray<btSoftBody::Node* > m_nodes; |     btAlignedObjectArray<btSoftBody::Node* > m_nodes; | ||||||
|     bool m_implicit; |     bool m_implicit; | ||||||
|  |     MassPreconditioner* m_massPreconditioner; | ||||||
|  |     KKTPreconditioner* m_KKTPreconditioner; | ||||||
| 
 | 
 | ||||||
|     btDeformableBackwardEulerObjective(btAlignedObjectArray<btSoftBody *>& softBodies, const TVStack& backup_v); |     btDeformableBackwardEulerObjective(btAlignedObjectArray<btSoftBody *>& softBodies, const TVStack& backup_v); | ||||||
|      |      | ||||||
|  | @ -79,7 +82,7 @@ public: | ||||||
|     void updateVelocity(const TVStack& dv); |     void updateVelocity(const TVStack& dv); | ||||||
|      |      | ||||||
|     //set constraints as projections
 |     //set constraints as projections
 | ||||||
|     void setConstraints(); |     void setConstraints(const btContactSolverInfo& infoGlobal); | ||||||
|      |      | ||||||
|     // update the projections and project the residual
 |     // update the projections and project the residual
 | ||||||
|     void project(TVStack& r) |     void project(TVStack& r) | ||||||
|  | @ -129,6 +132,42 @@ public: | ||||||
| 
 | 
 | ||||||
|     // Calculate the total potential energy in the system
 |     // Calculate the total potential energy in the system
 | ||||||
|     btScalar totalEnergy(btScalar dt); |     btScalar totalEnergy(btScalar dt); | ||||||
|  |      | ||||||
|  |     void addLagrangeMultiplier(const TVStack& vec, TVStack& extended_vec) | ||||||
|  |     { | ||||||
|  |         extended_vec.resize(vec.size() + m_projection.m_lagrangeMultipliers.size()); | ||||||
|  |         for (int i = 0; i < vec.size(); ++i) | ||||||
|  |         { | ||||||
|  |             extended_vec[i] = vec[i]; | ||||||
|  |         } | ||||||
|  |         int offset = vec.size(); | ||||||
|  |         for (int i = 0; i < m_projection.m_lagrangeMultipliers.size(); ++i) | ||||||
|  |         { | ||||||
|  |             extended_vec[offset + i].setZero(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     void addLagrangeMultiplierRHS(const TVStack& residual, const TVStack& m_dv, TVStack& extended_residual) | ||||||
|  |     { | ||||||
|  |         extended_residual.resize(residual.size() + m_projection.m_lagrangeMultipliers.size()); | ||||||
|  |         for (int i = 0; i < residual.size(); ++i) | ||||||
|  |         { | ||||||
|  |             extended_residual[i] = residual[i]; | ||||||
|  |         } | ||||||
|  |         int offset = residual.size(); | ||||||
|  |         for (int i = 0; i < m_projection.m_lagrangeMultipliers.size(); ++i) | ||||||
|  |         { | ||||||
|  |             const LagrangeMultiplier& lm = m_projection.m_lagrangeMultipliers[i]; | ||||||
|  |             extended_residual[offset + i].setZero(); | ||||||
|  |             for (int d = 0; d < lm.m_num_constraints; ++d) | ||||||
|  |             { | ||||||
|  |                 for (int n = 0; n < lm.m_num_nodes; ++n) | ||||||
|  |                 { | ||||||
|  |                     extended_residual[offset + i][d] += lm.m_weights[n] * m_dv[lm.m_indices[n]].dot(lm.m_dirs[d]); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #endif /* btBackwardEulerObjective_h */ | #endif /* btBackwardEulerObjective_h */ | ||||||
|  |  | ||||||
|  | @ -18,13 +18,15 @@ | ||||||
| #include "btDeformableBodySolver.h" | #include "btDeformableBodySolver.h" | ||||||
| #include "btSoftBodyInternals.h" | #include "btSoftBodyInternals.h" | ||||||
| #include "LinearMath/btQuickprof.h" | #include "LinearMath/btQuickprof.h" | ||||||
| static const int kMaxConjugateGradientIterations  = 50; | static const int kMaxConjugateGradientIterations = 50; | ||||||
| btDeformableBodySolver::btDeformableBodySolver() | btDeformableBodySolver::btDeformableBodySolver() | ||||||
| : m_numNodes(0) | : m_numNodes(0) | ||||||
| , m_cg(kMaxConjugateGradientIterations) | , m_cg(kMaxConjugateGradientIterations) | ||||||
|  | , m_cr(kMaxConjugateGradientIterations) | ||||||
| , m_maxNewtonIterations(5) | , m_maxNewtonIterations(5) | ||||||
| , m_newtonTolerance(1e-4) | , m_newtonTolerance(1e-4) | ||||||
| , m_lineSearch(false) | , m_lineSearch(false) | ||||||
|  | , m_useProjection(false) | ||||||
| { | { | ||||||
|     m_objective = new btDeformableBackwardEulerObjective(m_softBodies, m_backupVelocity); |     m_objective = new btDeformableBackwardEulerObjective(m_softBodies, m_backupVelocity); | ||||||
| } | } | ||||||
|  | @ -41,7 +43,22 @@ void btDeformableBodySolver::solveDeformableConstraints(btScalar solverdt) | ||||||
|     { |     { | ||||||
|         m_objective->computeResidual(solverdt, m_residual); |         m_objective->computeResidual(solverdt, m_residual); | ||||||
|         m_objective->applyDynamicFriction(m_residual); |         m_objective->applyDynamicFriction(m_residual); | ||||||
|         computeStep(m_dv, m_residual); |         if (m_useProjection) | ||||||
|  |         { | ||||||
|  |             computeStep(m_dv, m_residual); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             TVStack rhs, x; | ||||||
|  |             m_objective->addLagrangeMultiplierRHS(m_residual, m_dv, rhs); | ||||||
|  |             m_objective->addLagrangeMultiplier(m_dv, x); | ||||||
|  |             m_objective->m_preconditioner->reinitialize(true); | ||||||
|  |             computeStep(x, rhs); | ||||||
|  |             for (int i = 0; i<m_dv.size(); ++i) | ||||||
|  |             { | ||||||
|  |                     m_dv[i] = x[i]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|         updateVelocity(); |         updateVelocity(); | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
|  | @ -200,7 +217,10 @@ void btDeformableBodySolver::updateDv(btScalar scale) | ||||||
| 
 | 
 | ||||||
| void btDeformableBodySolver::computeStep(TVStack& ddv, const TVStack& residual) | void btDeformableBodySolver::computeStep(TVStack& ddv, const TVStack& residual) | ||||||
| { | { | ||||||
|     m_cg.solve(*m_objective, ddv, residual); |     if (m_useProjection) | ||||||
|  |         m_cg.solve(*m_objective, ddv, residual, false); | ||||||
|  |     else | ||||||
|  |         m_cr.solve(*m_objective, ddv, residual, false); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void btDeformableBodySolver::reinitialize(const btAlignedObjectArray<btSoftBody *>& softBodies, btScalar dt) | void btDeformableBodySolver::reinitialize(const btAlignedObjectArray<btSoftBody *>& softBodies, btScalar dt) | ||||||
|  | @ -226,27 +246,22 @@ void btDeformableBodySolver::reinitialize(const btAlignedObjectArray<btSoftBody | ||||||
|      |      | ||||||
|     m_dt = dt; |     m_dt = dt; | ||||||
|     m_objective->reinitialize(nodeUpdated, dt); |     m_objective->reinitialize(nodeUpdated, dt); | ||||||
|  |     updateSoftBodies(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void btDeformableBodySolver::setConstraints() | void btDeformableBodySolver::setConstraints(const btContactSolverInfo& infoGlobal) | ||||||
| { | { | ||||||
|     BT_PROFILE("setConstraint"); |     BT_PROFILE("setConstraint"); | ||||||
|     m_objective->setConstraints(); |     m_objective->setConstraints(infoGlobal); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| btScalar btDeformableBodySolver::solveContactConstraints(btCollisionObject** deformableBodies,int numDeformableBodies) | btScalar btDeformableBodySolver::solveContactConstraints(btCollisionObject** deformableBodies,int numDeformableBodies, const btContactSolverInfo& infoGlobal) | ||||||
| { | { | ||||||
|     BT_PROFILE("solveContactConstraints"); |     BT_PROFILE("solveContactConstraints"); | ||||||
|     btScalar maxSquaredResidual = m_objective->m_projection.update(deformableBodies,numDeformableBodies); |     btScalar maxSquaredResidual = m_objective->m_projection.update(deformableBodies,numDeformableBodies, infoGlobal); | ||||||
|     return maxSquaredResidual; |     return maxSquaredResidual; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| btScalar btDeformableBodySolver::solveSplitImpulse(const btContactSolverInfo& infoGlobal) |  | ||||||
| { |  | ||||||
|     BT_PROFILE("solveSplitImpulse"); |  | ||||||
|     return m_objective->m_projection.solveSplitImpulse(infoGlobal); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void btDeformableBodySolver::splitImpulseSetup(const btContactSolverInfo& infoGlobal) | void btDeformableBodySolver::splitImpulseSetup(const btContactSolverInfo& infoGlobal) | ||||||
| { | { | ||||||
|      m_objective->m_projection.splitImpulseSetup(infoGlobal); |      m_objective->m_projection.splitImpulseSetup(infoGlobal); | ||||||
|  | @ -333,8 +348,10 @@ void btDeformableBodySolver::setupDeformableSolve(bool implicit) | ||||||
|                 m_backupVelocity[counter] = psb->m_nodes[j].m_vn; |                 m_backupVelocity[counter] = psb->m_nodes[j].m_vn; | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|  |             { | ||||||
|                 m_dv[counter] =  psb->m_nodes[j].m_v - m_backupVelocity[counter]; |                 m_dv[counter] =  psb->m_nodes[j].m_v - m_backupVelocity[counter]; | ||||||
|             psb->m_nodes[j].m_v = m_backupVelocity[counter] + psb->m_nodes[j].m_vsplit; |             } | ||||||
|  |             psb->m_nodes[j].m_v = m_backupVelocity[counter]; | ||||||
|             ++counter; |             ++counter; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -385,6 +402,7 @@ void btDeformableBodySolver::predictMotion(btScalar solverdt) | ||||||
| 
 | 
 | ||||||
| void btDeformableBodySolver::predictDeformableMotion(btSoftBody* psb, btScalar dt) | void btDeformableBodySolver::predictDeformableMotion(btSoftBody* psb, btScalar dt) | ||||||
| { | { | ||||||
|  |     BT_PROFILE("btDeformableBodySolver::predictDeformableMotion"); | ||||||
|     int i, ni; |     int i, ni; | ||||||
|      |      | ||||||
|     /* Update                */ |     /* Update                */ | ||||||
|  | @ -423,40 +441,22 @@ void btDeformableBodySolver::predictDeformableMotion(btSoftBody* psb, btScalar d | ||||||
|             n.m_v *= max_v; |             n.m_v *= max_v; | ||||||
|         } |         } | ||||||
|         n.m_q = n.m_x + n.m_v * dt; |         n.m_q = n.m_x + n.m_v * dt; | ||||||
|  |         n.m_penetration = 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Nodes                */ |     /* Nodes                */ | ||||||
|     ATTRIBUTE_ALIGNED16(btDbvtVolume) |     psb->updateNodeTree(true, true); | ||||||
|     vol; |  | ||||||
|     for (i = 0, ni = psb->m_nodes.size(); i < ni; ++i) |  | ||||||
|     { |  | ||||||
|         btSoftBody::Node& n = psb->m_nodes[i]; |  | ||||||
|         btVector3 points[2] = {n.m_x, n.m_q}; |  | ||||||
|         vol = btDbvtVolume::FromPoints(points, 2); |  | ||||||
|         vol.Expand(btVector3(psb->m_sst.radmrg, psb->m_sst.radmrg, psb->m_sst.radmrg)); |  | ||||||
|         psb->m_ndbvt.update(n.m_leaf, vol); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (!psb->m_fdbvt.empty()) |     if (!psb->m_fdbvt.empty()) | ||||||
|     { |     { | ||||||
|         for (int i = 0; i < psb->m_faces.size(); ++i) |         psb->updateFaceTree(true, true); | ||||||
|         { |  | ||||||
|             btSoftBody::Face& f = psb->m_faces[i]; |  | ||||||
|             btVector3 points[6] = {f.m_n[0]->m_x, f.m_n[0]->m_q, |  | ||||||
|                                    f.m_n[1]->m_x, f.m_n[1]->m_q, |  | ||||||
|                                    f.m_n[2]->m_x, f.m_n[2]->m_q}; |  | ||||||
|             vol = btDbvtVolume::FromPoints(points, 6); |  | ||||||
|             vol.Expand(btVector3(psb->m_sst.radmrg, psb->m_sst.radmrg, psb->m_sst.radmrg)); |  | ||||||
|             psb->m_fdbvt.update(f.m_leaf, vol); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     /* Clear contacts        */ |     /* Clear contacts */ | ||||||
|     psb->m_nodeRigidContacts.resize(0); |     psb->m_nodeRigidContacts.resize(0); | ||||||
|     psb->m_faceRigidContacts.resize(0); |     psb->m_faceRigidContacts.resize(0); | ||||||
|     psb->m_faceNodeContacts.resize(0); |     psb->m_faceNodeContacts.resize(0); | ||||||
|     /* Optimize dbvt's        */ |     /* Optimize dbvt's        */ | ||||||
|     psb->m_ndbvt.optimizeIncremental(1); | //    psb->m_ndbvt.optimizeIncremental(1);
 | ||||||
|     psb->m_fdbvt.optimizeIncremental(1); | //    psb->m_fdbvt.optimizeIncremental(1);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -22,7 +22,8 @@ | ||||||
| #include "btDeformableMultiBodyDynamicsWorld.h" | #include "btDeformableMultiBodyDynamicsWorld.h" | ||||||
| #include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h" | #include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h" | ||||||
| #include "BulletDynamics/Featherstone/btMultiBodyConstraint.h" | #include "BulletDynamics/Featherstone/btMultiBodyConstraint.h" | ||||||
| 
 | #include "btConjugateResidual.h" | ||||||
|  | #include "btConjugateGradient.h" | ||||||
| struct btCollisionObjectWrapper; | struct btCollisionObjectWrapper; | ||||||
| class btDeformableBackwardEulerObjective; | class btDeformableBackwardEulerObjective; | ||||||
| class btDeformableMultiBodyDynamicsWorld; | class btDeformableMultiBodyDynamicsWorld; | ||||||
|  | @ -40,14 +41,15 @@ protected: | ||||||
|     TVStack m_backupVelocity;       // backed up v, equals v_n for implicit, equals v_{n+1}^* for explicit
 |     TVStack m_backupVelocity;       // backed up v, equals v_n for implicit, equals v_{n+1}^* for explicit
 | ||||||
|     btScalar m_dt;                  // dt
 |     btScalar m_dt;                  // dt
 | ||||||
|     btConjugateGradient<btDeformableBackwardEulerObjective> m_cg;  // CG solver
 |     btConjugateGradient<btDeformableBackwardEulerObjective> m_cg;  // CG solver
 | ||||||
|  |     btConjugateResidual<btDeformableBackwardEulerObjective> m_cr;  // CR solver
 | ||||||
|     bool m_implicit;                // use implicit scheme if true, explicit scheme if false
 |     bool m_implicit;                // use implicit scheme if true, explicit scheme if false
 | ||||||
|     int m_maxNewtonIterations;      // max number of newton iterations
 |     int m_maxNewtonIterations;      // max number of newton iterations
 | ||||||
|     btScalar m_newtonTolerance;     // stop newton iterations if f(x) < m_newtonTolerance
 |     btScalar m_newtonTolerance;     // stop newton iterations if f(x) < m_newtonTolerance
 | ||||||
|     bool m_lineSearch;              // If true, use newton's method with line search under implicit scheme
 |     bool m_lineSearch;              // If true, use newton's method with line search under implicit scheme
 | ||||||
|      |  | ||||||
| public: | public: | ||||||
|     // handles data related to objective function
 |     // handles data related to objective function
 | ||||||
|     btDeformableBackwardEulerObjective* m_objective; |     btDeformableBackwardEulerObjective* m_objective; | ||||||
|  |     bool m_useProjection; | ||||||
|      |      | ||||||
|     btDeformableBodySolver(); |     btDeformableBodySolver(); | ||||||
|      |      | ||||||
|  | @ -61,15 +63,11 @@ public: | ||||||
|     // update soft body normals
 |     // update soft body normals
 | ||||||
|     virtual void updateSoftBodies(); |     virtual void updateSoftBodies(); | ||||||
|      |      | ||||||
|  |     virtual btScalar solveContactConstraints(btCollisionObject** deformableBodies,int numDeformableBodies, const btContactSolverInfo& infoGlobal); | ||||||
|  |      | ||||||
|     // solve the momentum equation
 |     // solve the momentum equation
 | ||||||
|     virtual void solveDeformableConstraints(btScalar solverdt); |     virtual void solveDeformableConstraints(btScalar solverdt); | ||||||
|      |      | ||||||
|     // solve the contact between deformable and rigid as well as among deformables
 |  | ||||||
|     btScalar solveContactConstraints(btCollisionObject** deformableBodies,int numDeformableBodies); |  | ||||||
|      |  | ||||||
|     // solve the position error  between deformable and rigid as well as among deformables;
 |  | ||||||
|     btScalar solveSplitImpulse(const btContactSolverInfo& infoGlobal); |  | ||||||
|      |  | ||||||
|     // set up the position error in split impulse
 |     // set up the position error in split impulse
 | ||||||
|     void splitImpulseSetup(const btContactSolverInfo& infoGlobal); |     void splitImpulseSetup(const btContactSolverInfo& infoGlobal); | ||||||
| 
 | 
 | ||||||
|  | @ -77,7 +75,7 @@ public: | ||||||
|     void reinitialize(const btAlignedObjectArray<btSoftBody *>& softBodies, btScalar dt); |     void reinitialize(const btAlignedObjectArray<btSoftBody *>& softBodies, btScalar dt); | ||||||
|      |      | ||||||
|     // set up contact constraints
 |     // set up contact constraints
 | ||||||
|     void setConstraints(); |     void setConstraints(const btContactSolverInfo& infoGlobal); | ||||||
|      |      | ||||||
|     // add in elastic forces and gravity to obtain v_{n+1}^* and calls predictDeformableMotion
 |     // add in elastic forces and gravity to obtain v_{n+1}^* and calls predictDeformableMotion
 | ||||||
|     virtual void predictMotion(btScalar solverdt); |     virtual void predictMotion(btScalar solverdt); | ||||||
|  |  | ||||||
|  | @ -15,9 +15,9 @@ | ||||||
| 
 | 
 | ||||||
| #include "btDeformableContactConstraint.h" | #include "btDeformableContactConstraint.h" | ||||||
| /* ================   Deformable Node Anchor   =================== */ | /* ================   Deformable Node Anchor   =================== */ | ||||||
| btDeformableNodeAnchorConstraint::btDeformableNodeAnchorConstraint(const btSoftBody::DeformableNodeRigidAnchor& a) | btDeformableNodeAnchorConstraint::btDeformableNodeAnchorConstraint(const btSoftBody::DeformableNodeRigidAnchor& a, const btContactSolverInfo& infoGlobal) | ||||||
| : m_anchor(&a) | : m_anchor(&a) | ||||||
| , btDeformableContactConstraint(a.m_cti.m_normal) | , btDeformableContactConstraint(a.m_cti.m_normal, infoGlobal) | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -79,14 +79,14 @@ btVector3 btDeformableNodeAnchorConstraint::getVa() const | ||||||
|     return va; |     return va; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| btScalar btDeformableNodeAnchorConstraint::solveConstraint() | btScalar btDeformableNodeAnchorConstraint::solveConstraint(const btContactSolverInfo& infoGlobal) | ||||||
| { | { | ||||||
|     const btSoftBody::sCti& cti = m_anchor->m_cti; |     const btSoftBody::sCti& cti = m_anchor->m_cti; | ||||||
|     btVector3 va = getVa(); |     btVector3 va = getVa(); | ||||||
|     btVector3 vb = getVb(); |     btVector3 vb = getVb(); | ||||||
|     btVector3 vr = (vb - va); |     btVector3 vr = (vb - va); | ||||||
|     // + (m_anchor->m_node->m_x - cti.m_colObj->getWorldTransform() * m_anchor->m_local) * 10.0
 |     // + (m_anchor->m_node->m_x - cti.m_colObj->getWorldTransform() * m_anchor->m_local) * 10.0
 | ||||||
|     const btScalar dn = btDot(vr, cti.m_normal); |     const btScalar dn = btDot(vr, vr); | ||||||
|     // dn is the normal component of velocity diffrerence. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt
 |     // dn is the normal component of velocity diffrerence. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt
 | ||||||
|     btScalar residualSquare = dn*dn; |     btScalar residualSquare = dn*dn; | ||||||
|     btVector3 impulse = m_anchor->m_c0 * vr; |     btVector3 impulse = m_anchor->m_c0 * vr; | ||||||
|  | @ -134,14 +134,15 @@ void btDeformableNodeAnchorConstraint::applyImpulse(const btVector3& impulse) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* ================   Deformable vs. Rigid   =================== */ | /* ================   Deformable vs. Rigid   =================== */ | ||||||
| btDeformableRigidContactConstraint::btDeformableRigidContactConstraint(const btSoftBody::DeformableRigidContact& c) | btDeformableRigidContactConstraint::btDeformableRigidContactConstraint(const btSoftBody::DeformableRigidContact& c, const btContactSolverInfo& infoGlobal) | ||||||
| : m_contact(&c) | : m_contact(&c) | ||||||
| , btDeformableContactConstraint(c.m_cti.m_normal) | , btDeformableContactConstraint(c.m_cti.m_normal, infoGlobal) | ||||||
| { | { | ||||||
|     m_total_normal_dv.setZero(); |     m_total_normal_dv.setZero(); | ||||||
|     m_total_tangent_dv.setZero(); |     m_total_tangent_dv.setZero(); | ||||||
|     // penetration is non-positive. The magnitude of penetration is the depth of penetration.
 |     // The magnitude of penetration is the depth of penetration.
 | ||||||
|     m_penetration = btMin(btScalar(0), c.m_cti.m_offset); |     m_penetration = c.m_cti.m_offset; | ||||||
|  | //	m_penetration = btMin(btScalar(0),c.m_cti.m_offset);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| btDeformableRigidContactConstraint::btDeformableRigidContactConstraint(const btDeformableRigidContactConstraint& other) | btDeformableRigidContactConstraint::btDeformableRigidContactConstraint(const btDeformableRigidContactConstraint& other) | ||||||
|  | @ -206,16 +207,16 @@ btVector3 btDeformableRigidContactConstraint::getVa() const | ||||||
|     return va; |     return va; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| btScalar btDeformableRigidContactConstraint::solveConstraint() | btScalar btDeformableRigidContactConstraint::solveConstraint(const btContactSolverInfo& infoGlobal) | ||||||
| { | { | ||||||
|     const btSoftBody::sCti& cti = m_contact->m_cti; |     const btSoftBody::sCti& cti = m_contact->m_cti; | ||||||
|     btVector3 va = getVa(); |     btVector3 va = getVa(); | ||||||
|     btVector3 vb = getVb(); |     btVector3 vb = getVb(); | ||||||
|     btVector3 vr = vb - va; |     btVector3 vr = vb - va; | ||||||
|     const btScalar dn = btDot(vr, cti.m_normal); |     btScalar dn = btDot(vr, cti.m_normal) + m_penetration * infoGlobal.m_deformable_erp / infoGlobal.m_timeStep; | ||||||
|     // dn is the normal component of velocity diffrerence. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt
 |     // dn is the normal component of velocity diffrerence. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt
 | ||||||
|     btScalar residualSquare = dn*dn; |     btScalar residualSquare = dn*dn; | ||||||
|     btVector3 impulse = m_contact->m_c0 * vr; |     btVector3 impulse = m_contact->m_c0 * (vr + m_penetration * infoGlobal.m_deformable_erp / infoGlobal.m_timeStep * cti.m_normal) ; | ||||||
|     const btVector3 impulse_normal = m_contact->m_c0 * (cti.m_normal * dn); |     const btVector3 impulse_normal = m_contact->m_c0 * (cti.m_normal * dn); | ||||||
|     btVector3 impulse_tangent = impulse - impulse_normal; |     btVector3 impulse_tangent = impulse - impulse_normal; | ||||||
|     btVector3 old_total_tangent_dv = m_total_tangent_dv; |     btVector3 old_total_tangent_dv = m_total_tangent_dv; | ||||||
|  | @ -256,6 +257,8 @@ btScalar btDeformableRigidContactConstraint::solveConstraint() | ||||||
|     impulse = impulse_normal + impulse_tangent; |     impulse = impulse_normal + impulse_tangent; | ||||||
|     // apply impulse to deformable nodes involved and change their velocities
 |     // apply impulse to deformable nodes involved and change their velocities
 | ||||||
|     applyImpulse(impulse); |     applyImpulse(impulse); | ||||||
|  | 	if (residualSquare < 1e-7) | ||||||
|  | 		return residualSquare; | ||||||
|     // apply impulse to the rigid/multibodies involved and change their velocities
 |     // apply impulse to the rigid/multibodies involved and change their velocities
 | ||||||
|     if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY) |     if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY) | ||||||
|     { |     { | ||||||
|  | @ -285,43 +288,17 @@ btScalar btDeformableRigidContactConstraint::solveConstraint() | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | //    va = getVa();
 | ||||||
|  | //    vb = getVb();
 | ||||||
|  | //    vr = vb - va;
 | ||||||
|  | //    btScalar dn1 = btDot(vr, cti.m_normal) / 150;
 | ||||||
|  | //    m_penetration += dn1;
 | ||||||
|     return residualSquare; |     return residualSquare; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| btScalar btDeformableRigidContactConstraint::solveSplitImpulse(const btContactSolverInfo& infoGlobal) |  | ||||||
| { |  | ||||||
|     const btSoftBody::sCti& cti = m_contact->m_cti; |  | ||||||
|     const btScalar dn = m_penetration; |  | ||||||
|     if (dn != 0) |  | ||||||
|     { |  | ||||||
|         const btVector3 impulse = (m_contact->m_c0 * (cti.m_normal * dn / infoGlobal.m_timeStep)); |  | ||||||
|         // one iteration of the position impulse corrects all the position error at this timestep
 |  | ||||||
|         m_penetration -= dn; |  | ||||||
|         // apply impulse to deformable nodes involved and change their position
 |  | ||||||
|         applySplitImpulse(impulse); |  | ||||||
|         // apply impulse to the rigid/multibodies involved and change their position
 |  | ||||||
|         if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY) |  | ||||||
|         { |  | ||||||
|             btRigidBody* rigidCol = 0; |  | ||||||
|             rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj); |  | ||||||
|             if (rigidCol) |  | ||||||
|             { |  | ||||||
|                 rigidCol->applyPushImpulse(impulse, m_contact->m_c1); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK) |  | ||||||
|         { |  | ||||||
|             // todo xuchenhan@
 |  | ||||||
|         } |  | ||||||
|         return (m_penetration/infoGlobal.m_timeStep) * (m_penetration/infoGlobal.m_timeStep); |  | ||||||
|     } |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* ================   Node vs. Rigid   =================== */ | /* ================   Node vs. Rigid   =================== */ | ||||||
| btDeformableNodeRigidContactConstraint::btDeformableNodeRigidContactConstraint(const btSoftBody::DeformableNodeRigidContact& contact) | btDeformableNodeRigidContactConstraint::btDeformableNodeRigidContactConstraint(const btSoftBody::DeformableNodeRigidContact& contact, const btContactSolverInfo& infoGlobal) | ||||||
|     : m_node(contact.m_node) |     : m_node(contact.m_node) | ||||||
|     , btDeformableRigidContactConstraint(contact) |     , btDeformableRigidContactConstraint(contact, infoGlobal) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -349,22 +326,17 @@ void btDeformableNodeRigidContactConstraint::applyImpulse(const btVector3& impul | ||||||
|     contact->m_node->m_v -= dv; |     contact->m_node->m_v -= dv; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void btDeformableNodeRigidContactConstraint::applySplitImpulse(const btVector3& impulse) |  | ||||||
| { |  | ||||||
|     const btSoftBody::DeformableNodeRigidContact* contact = getContact(); |  | ||||||
|     btVector3 dv = impulse * contact->m_c2; |  | ||||||
|     contact->m_node->m_vsplit -= dv; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /* ================   Face vs. Rigid   =================== */ | /* ================   Face vs. Rigid   =================== */ | ||||||
| btDeformableFaceRigidContactConstraint::btDeformableFaceRigidContactConstraint(const btSoftBody::DeformableFaceRigidContact& contact) | btDeformableFaceRigidContactConstraint::btDeformableFaceRigidContactConstraint(const btSoftBody::DeformableFaceRigidContact& contact, const btContactSolverInfo& infoGlobal, bool useStrainLimiting) | ||||||
| : m_face(contact.m_face) | : m_face(contact.m_face) | ||||||
| , btDeformableRigidContactConstraint(contact) | , m_useStrainLimiting(useStrainLimiting) | ||||||
|  | , btDeformableRigidContactConstraint(contact, infoGlobal) | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| btDeformableFaceRigidContactConstraint::btDeformableFaceRigidContactConstraint(const btDeformableFaceRigidContactConstraint& other) | btDeformableFaceRigidContactConstraint::btDeformableFaceRigidContactConstraint(const btDeformableFaceRigidContactConstraint& other) | ||||||
| : m_face(other.m_face) | : m_face(other.m_face) | ||||||
|  | , m_useStrainLimiting(other.m_useStrainLimiting) | ||||||
| , btDeformableRigidContactConstraint(other) | , btDeformableRigidContactConstraint(other) | ||||||
| { | { | ||||||
| } | } | ||||||
|  | @ -411,47 +383,70 @@ void btDeformableFaceRigidContactConstraint::applyImpulse(const btVector3& impul | ||||||
|         v1 -= dv * contact->m_weights[1]; |         v1 -= dv * contact->m_weights[1]; | ||||||
|     if (im2 > 0) |     if (im2 > 0) | ||||||
|         v2 -= dv * contact->m_weights[2]; |         v2 -= dv * contact->m_weights[2]; | ||||||
|      | 	if (m_useStrainLimiting) | ||||||
|     // apply strain limiting to prevent undamped modes
 | 	{ | ||||||
|     btScalar m01 = (btScalar(1)/(im0 + im1)); | 		btScalar relaxation = 1./btScalar(m_infoGlobal->m_numIterations); | ||||||
|     btScalar m02 = (btScalar(1)/(im0 + im2)); | 		btScalar m01 = (relaxation/(im0 + im1)); | ||||||
|     btScalar m12 = (btScalar(1)/(im1 + im2)); | 		btScalar m02 = (relaxation/(im0 + im2)); | ||||||
|      | 		btScalar m12 = (relaxation/(im1 + im2)); | ||||||
|     btVector3 dv0 = im0 * (m01 * (v1-v0) + m02 * (v2-v0)); | 		#ifdef USE_STRAIN_RATE_LIMITING | ||||||
|     btVector3 dv1 = im1 * (m01 * (v0-v1) + m12 * (v2-v1)); | 		// apply strain limiting to prevent the new velocity to change the current length of the edge by more than 1%.
 | ||||||
|     btVector3 dv2 = im2 * (m12 * (v1-v2) + m02 * (v0-v2)); | 		btScalar p = 0.01; | ||||||
|      | 		btVector3& x0 = face->m_n[0]->m_x; | ||||||
|     v0 += dv0; | 		btVector3& x1 = face->m_n[1]->m_x; | ||||||
|     v1 += dv1; | 		btVector3& x2 = face->m_n[2]->m_x; | ||||||
|     v2 += dv2; | 		const btVector3 x_diff[3] = {x1-x0, x2-x0, x2-x1}; | ||||||
| } | 		const btVector3 v_diff[3] = {v1-v0, v2-v0, v2-v1}; | ||||||
| 
 | 		btVector3 u[3]; | ||||||
| void btDeformableFaceRigidContactConstraint::applySplitImpulse(const btVector3& impulse) | 		btScalar x_diff_dot_u, dn[3]; | ||||||
| { | 		btScalar dt = m_infoGlobal->m_timeStep; | ||||||
|     const btSoftBody::DeformableFaceRigidContact* contact = getContact(); | 		for (int i = 0; i < 3; ++i) | ||||||
|     btVector3 dv = impulse * contact->m_c2; | 		{ | ||||||
|     btSoftBody::Face* face = contact->m_face; | 			btScalar x_diff_norm = x_diff[i].safeNorm(); | ||||||
| 
 | 			btScalar x_diff_norm_new = (x_diff[i] + v_diff[i] * dt).safeNorm(); | ||||||
|     btVector3& v0 = face->m_n[0]->m_vsplit; | 			btScalar strainRate = x_diff_norm_new/x_diff_norm; | ||||||
|     btVector3& v1 = face->m_n[1]->m_vsplit; | 			u[i] = v_diff[i]; | ||||||
|     btVector3& v2 = face->m_n[2]->m_vsplit; | 			u[i].safeNormalize(); | ||||||
|     const btScalar& im0 = face->m_n[0]->m_im; | 			if (x_diff_norm == 0 || (1-p <= strainRate && strainRate <= 1+p)) | ||||||
|     const btScalar& im1 = face->m_n[1]->m_im; | 			{ | ||||||
|     const btScalar& im2 = face->m_n[2]->m_im; | 				dn[i] = 0; | ||||||
|     if (im0 > 0) | 				continue; | ||||||
|         v0 -= dv * contact->m_weights[0]; | 			} | ||||||
|     if (im1 > 0) | 			x_diff_dot_u = btDot(x_diff[i], u[i]); | ||||||
|         v1 -= dv * contact->m_weights[1]; | 			btScalar s; | ||||||
|     if (im2 > 0) | 			if (1-p > strainRate) | ||||||
|         v2 -= dv * contact->m_weights[2]; | 			{ | ||||||
|  | 				s = 1/dt * (-x_diff_dot_u - btSqrt(x_diff_dot_u*x_diff_dot_u + (p*p-2*p) * x_diff_norm * x_diff_norm)); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				s = 1/dt * (-x_diff_dot_u + btSqrt(x_diff_dot_u*x_diff_dot_u + (p*p+2*p) * x_diff_norm * x_diff_norm)); | ||||||
|  | 			} | ||||||
|  | 			//		x_diff_norm_new = (x_diff[i] + s * u[i] * dt).safeNorm();
 | ||||||
|  | 			//		strainRate = x_diff_norm_new/x_diff_norm;
 | ||||||
|  | 			dn[i] = s - v_diff[i].safeNorm(); | ||||||
|  | 		} | ||||||
|  | 		btVector3 dv0 = im0 * (m01 * u[0]*(-dn[0]) + m02 * u[1]*-(dn[1])); | ||||||
|  | 		btVector3 dv1 = im1 * (m01 * u[0]*(dn[0]) + m12 * u[2]*(-dn[2])); | ||||||
|  | 		btVector3 dv2 = im2 * (m12 * u[2]*(dn[2]) + m02 * u[1]*(dn[1])); | ||||||
|  | 	#else | ||||||
|  | 		// apply strain limiting to prevent undamped modes
 | ||||||
|  | 		btVector3 dv0 = im0 * (m01 * (v1-v0) + m02 * (v2-v0)); | ||||||
|  | 		btVector3 dv1 = im1 * (m01 * (v0-v1) + m12 * (v2-v1)); | ||||||
|  | 		btVector3 dv2 = im2 * (m12 * (v1-v2) + m02 * (v0-v2)); | ||||||
|  | 	#endif | ||||||
|  | 		v0 += dv0; | ||||||
|  | 		v1 += dv1; | ||||||
|  | 		v2 += dv2; | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* ================   Face vs. Node   =================== */ | /* ================   Face vs. Node   =================== */ | ||||||
| btDeformableFaceNodeContactConstraint::btDeformableFaceNodeContactConstraint(const btSoftBody::DeformableFaceNodeContact& contact) | btDeformableFaceNodeContactConstraint::btDeformableFaceNodeContactConstraint(const btSoftBody::DeformableFaceNodeContact& contact, const btContactSolverInfo& infoGlobal) | ||||||
| : m_node(contact.m_node) | : m_node(contact.m_node) | ||||||
| , m_face(contact.m_face) | , m_face(contact.m_face) | ||||||
| , m_contact(&contact) | , m_contact(&contact) | ||||||
| , btDeformableContactConstraint(contact.m_normal) | , btDeformableContactConstraint(contact.m_normal, infoGlobal) | ||||||
| { | { | ||||||
|     m_total_normal_dv.setZero(); |     m_total_normal_dv.setZero(); | ||||||
|     m_total_tangent_dv.setZero(); |     m_total_tangent_dv.setZero(); | ||||||
|  | @ -487,7 +482,7 @@ btVector3 btDeformableFaceNodeContactConstraint::getDv(const btSoftBody::Node* n | ||||||
|     return dv * contact->m_weights[2]; |     return dv * contact->m_weights[2]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| btScalar btDeformableFaceNodeContactConstraint::solveConstraint() | btScalar btDeformableFaceNodeContactConstraint::solveConstraint(const btContactSolverInfo& infoGlobal) | ||||||
| { | { | ||||||
|     btVector3 va = getVa(); |     btVector3 va = getVa(); | ||||||
|     btVector3 vb = getVb(); |     btVector3 vb = getVb(); | ||||||
|  | @ -577,15 +572,4 @@ void btDeformableFaceNodeContactConstraint::applyImpulse(const btVector3& impuls | ||||||
|     { |     { | ||||||
|         v2 -= dvb * contact->m_weights[2]; |         v2 -= dvb * contact->m_weights[2]; | ||||||
|     } |     } | ||||||
|     // todo: Face node constraints needs more work
 |  | ||||||
| //    btScalar m01 = (btScalar(1)/(im0 + im1));
 |  | ||||||
| //    btScalar m02 = (btScalar(1)/(im0 + im2));
 |  | ||||||
| //    btScalar m12 = (btScalar(1)/(im1 + im2));
 |  | ||||||
| //
 |  | ||||||
| //    btVector3 dv0 = im0 * (m01 * (v1-v0) + m02 * (v2-v0));
 |  | ||||||
| //    btVector3 dv1 = im1 * (m01 * (v0-v1) + m12 * (v2-v1));
 |  | ||||||
| //    btVector3 dv2 = im2 * (m12 * (v1-v2) + m02 * (v0-v2));
 |  | ||||||
| //    v0 += dv0;
 |  | ||||||
| //    v1 += dv1;
 |  | ||||||
| //    v2 += dv2;
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -24,34 +24,33 @@ public: | ||||||
|     // True if the friction is static
 |     // True if the friction is static
 | ||||||
|     // False if the friction is dynamic
 |     // False if the friction is dynamic
 | ||||||
|     bool m_static; |     bool m_static; | ||||||
|  | 	const btContactSolverInfo* m_infoGlobal; | ||||||
| 
 | 
 | ||||||
|     // normal of the contact
 | 	// normal of the contact
 | ||||||
|     btVector3 m_normal; | 	btVector3 m_normal; | ||||||
| 
 | 
 | ||||||
|     btDeformableContactConstraint(const btVector3& normal): m_static(false), m_normal(normal) | 	btDeformableContactConstraint(const btVector3& normal, const btContactSolverInfo& infoGlobal): m_static(false), m_normal(normal), m_infoGlobal(&infoGlobal) | ||||||
|     { | 	{ | ||||||
|     } | 	} | ||||||
| 
 | 
 | ||||||
|     btDeformableContactConstraint(bool isStatic, const btVector3& normal): m_static(isStatic), m_normal(normal) | 	btDeformableContactConstraint(bool isStatic, const btVector3& normal, const btContactSolverInfo& infoGlobal): m_static(isStatic), m_normal(normal), m_infoGlobal(&infoGlobal) | ||||||
|     { | 	{ | ||||||
|     } | 	} | ||||||
| 	 | 	 | ||||||
|     btDeformableContactConstraint(const btDeformableContactConstraint& other) | 	btDeformableContactConstraint(){} | ||||||
|     : m_static(other.m_static) |  | ||||||
|     , m_normal(other.m_normal) |  | ||||||
|     { |  | ||||||
| 
 | 
 | ||||||
|     } | 	btDeformableContactConstraint(const btDeformableContactConstraint& other) | ||||||
|     btDeformableContactConstraint(){} | 	: m_static(other.m_static) | ||||||
|  | 	, m_normal(other.m_normal) | ||||||
|  | 	, m_infoGlobal(other.m_infoGlobal) | ||||||
|  | 	{ | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
|     virtual ~btDeformableContactConstraint(){} |     virtual ~btDeformableContactConstraint(){} | ||||||
|      |      | ||||||
|     // solve the constraint with inelastic impulse and return the error, which is the square of normal component of velocity diffrerence
 |     // solve the constraint with inelastic impulse and return the error, which is the square of normal component of velocity diffrerence
 | ||||||
|     // the constraint is solved by calculating the impulse between object A and B in the contact and apply the impulse to both objects involved in the contact
 |     // the constraint is solved by calculating the impulse between object A and B in the contact and apply the impulse to both objects involved in the contact
 | ||||||
|     virtual btScalar solveConstraint() = 0; |     virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal) = 0; | ||||||
|      |  | ||||||
|     // solve the position error by applying an inelastic impulse that changes only the position (not velocity)
 |  | ||||||
|     virtual btScalar solveSplitImpulse(const btContactSolverInfo& infoGlobal) = 0; |  | ||||||
|      |      | ||||||
|     // get the velocity of the object A in the contact
 |     // get the velocity of the object A in the contact
 | ||||||
|     virtual btVector3 getVa() const = 0; |     virtual btVector3 getVa() const = 0; | ||||||
|  | @ -65,9 +64,6 @@ public: | ||||||
|     // apply impulse to the soft body node and/or face involved
 |     // apply impulse to the soft body node and/or face involved
 | ||||||
|     virtual void applyImpulse(const btVector3& impulse) = 0; |     virtual void applyImpulse(const btVector3& impulse) = 0; | ||||||
|      |      | ||||||
|     // apply position based impulse to the soft body node and/or face involved
 |  | ||||||
|     virtual void applySplitImpulse(const btVector3& impulse) = 0; |  | ||||||
|      |  | ||||||
|     // scale the penetration depth by erp
 |     // scale the penetration depth by erp
 | ||||||
|     virtual void setPenetrationScale(btScalar scale) = 0; |     virtual void setPenetrationScale(btScalar scale) = 0; | ||||||
| }; | }; | ||||||
|  | @ -77,29 +73,21 @@ public: | ||||||
| class btDeformableStaticConstraint : public btDeformableContactConstraint | class btDeformableStaticConstraint : public btDeformableContactConstraint | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     const btSoftBody::Node* m_node; |     btSoftBody::Node* m_node; | ||||||
|      |      | ||||||
|     btDeformableStaticConstraint(){} |     btDeformableStaticConstraint(btSoftBody::Node* node, const btContactSolverInfo& infoGlobal): m_node(node), btDeformableContactConstraint(false, btVector3(0,0,0), infoGlobal) | ||||||
|      |  | ||||||
|     btDeformableStaticConstraint(const btSoftBody::Node* node): m_node(node), btDeformableContactConstraint(false, btVector3(0,0,0)) |  | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|      | 	btDeformableStaticConstraint(){} | ||||||
|     btDeformableStaticConstraint(const btDeformableStaticConstraint& other) |     btDeformableStaticConstraint(const btDeformableStaticConstraint& other) | ||||||
|     : m_node(other.m_node) |     : m_node(other.m_node) | ||||||
|     , btDeformableContactConstraint(other) |     , btDeformableContactConstraint(other) | ||||||
|     { |     { | ||||||
|          |  | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     virtual ~btDeformableStaticConstraint(){} |     virtual ~btDeformableStaticConstraint(){} | ||||||
|      |      | ||||||
|     virtual btScalar solveConstraint() |     virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal) | ||||||
|     { |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     virtual btScalar solveSplitImpulse(const btContactSolverInfo& infoGlobal) |  | ||||||
|     { |     { | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  | @ -120,7 +108,6 @@ public: | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     virtual void applyImpulse(const btVector3& impulse){} |     virtual void applyImpulse(const btVector3& impulse){} | ||||||
|     virtual void applySplitImpulse(const btVector3& impulse){} |  | ||||||
|     virtual void setPenetrationScale(btScalar scale){} |     virtual void setPenetrationScale(btScalar scale){} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -131,18 +118,14 @@ class btDeformableNodeAnchorConstraint : public btDeformableContactConstraint | ||||||
| public: | public: | ||||||
|     const btSoftBody::DeformableNodeRigidAnchor* m_anchor; |     const btSoftBody::DeformableNodeRigidAnchor* m_anchor; | ||||||
| 	 | 	 | ||||||
|     btDeformableNodeAnchorConstraint(){} |     btDeformableNodeAnchorConstraint(const btSoftBody::DeformableNodeRigidAnchor& c, const btContactSolverInfo& infoGlobal); | ||||||
|     btDeformableNodeAnchorConstraint(const btSoftBody::DeformableNodeRigidAnchor& c); |  | ||||||
|     btDeformableNodeAnchorConstraint(const btDeformableNodeAnchorConstraint& other); |     btDeformableNodeAnchorConstraint(const btDeformableNodeAnchorConstraint& other); | ||||||
|  | 	btDeformableNodeAnchorConstraint(){} | ||||||
|     virtual ~btDeformableNodeAnchorConstraint() |     virtual ~btDeformableNodeAnchorConstraint() | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|     virtual btScalar solveConstraint(); |     virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal); | ||||||
|     virtual btScalar solveSplitImpulse(const btContactSolverInfo& infoGlobal) | 
 | ||||||
|     { |  | ||||||
|         // todo xuchenhan@
 |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
|     // object A is the rigid/multi body, and object B is the deformable node/face
 |     // object A is the rigid/multi body, and object B is the deformable node/face
 | ||||||
|     virtual btVector3 getVa() const; |     virtual btVector3 getVa() const; | ||||||
|     // get the velocity of the deformable node in contact
 |     // get the velocity of the deformable node in contact
 | ||||||
|  | @ -152,10 +135,7 @@ public: | ||||||
|         return btVector3(0,0,0); |         return btVector3(0,0,0); | ||||||
|     } |     } | ||||||
|     virtual void applyImpulse(const btVector3& impulse); |     virtual void applyImpulse(const btVector3& impulse); | ||||||
|     virtual void applySplitImpulse(const btVector3& impulse) | 
 | ||||||
|     { |  | ||||||
|         // todo xuchenhan@
 |  | ||||||
|     }; |  | ||||||
|     virtual void setPenetrationScale(btScalar scale){} |     virtual void setPenetrationScale(btScalar scale){} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -170,9 +150,9 @@ public: | ||||||
|     btScalar m_penetration; |     btScalar m_penetration; | ||||||
|     const btSoftBody::DeformableRigidContact* m_contact; |     const btSoftBody::DeformableRigidContact* m_contact; | ||||||
| 	 | 	 | ||||||
|     btDeformableRigidContactConstraint(){} |     btDeformableRigidContactConstraint(const btSoftBody::DeformableRigidContact& c, const btContactSolverInfo& infoGlobal); | ||||||
|     btDeformableRigidContactConstraint(const btSoftBody::DeformableRigidContact& c); |  | ||||||
|     btDeformableRigidContactConstraint(const btDeformableRigidContactConstraint& other); |     btDeformableRigidContactConstraint(const btDeformableRigidContactConstraint& other); | ||||||
|  | 	btDeformableRigidContactConstraint(){} | ||||||
|     virtual ~btDeformableRigidContactConstraint() |     virtual ~btDeformableRigidContactConstraint() | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  | @ -180,9 +160,7 @@ public: | ||||||
|     // object A is the rigid/multi body, and object B is the deformable node/face
 |     // object A is the rigid/multi body, and object B is the deformable node/face
 | ||||||
|     virtual btVector3 getVa() const; |     virtual btVector3 getVa() const; | ||||||
|      |      | ||||||
|     virtual btScalar solveConstraint(); |     virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal); | ||||||
|      |  | ||||||
|     virtual btScalar solveSplitImpulse(const btContactSolverInfo& infoGlobal); |  | ||||||
|      |      | ||||||
|     virtual void setPenetrationScale(btScalar scale) |     virtual void setPenetrationScale(btScalar scale) | ||||||
|     { |     { | ||||||
|  | @ -196,12 +174,11 @@ class btDeformableNodeRigidContactConstraint : public btDeformableRigidContactCo | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     // the deformable node in contact
 |     // the deformable node in contact
 | ||||||
|     const btSoftBody::Node* m_node; |     btSoftBody::Node* m_node; | ||||||
| 	 | 	 | ||||||
|     btDeformableNodeRigidContactConstraint(){} |     btDeformableNodeRigidContactConstraint(const btSoftBody::DeformableNodeRigidContact& contact, const btContactSolverInfo& infoGlobal); | ||||||
|     btDeformableNodeRigidContactConstraint(const btSoftBody::DeformableNodeRigidContact& contact); |  | ||||||
|     btDeformableNodeRigidContactConstraint(const btDeformableNodeRigidContactConstraint& other); |     btDeformableNodeRigidContactConstraint(const btDeformableNodeRigidContactConstraint& other); | ||||||
|      | 	btDeformableNodeRigidContactConstraint(){} | ||||||
|     virtual ~btDeformableNodeRigidContactConstraint() |     virtual ~btDeformableNodeRigidContactConstraint() | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  | @ -219,7 +196,6 @@ public: | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     virtual void applyImpulse(const btVector3& impulse); |     virtual void applyImpulse(const btVector3& impulse); | ||||||
|     virtual void applySplitImpulse(const btVector3& impulse); |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| //
 | //
 | ||||||
|  | @ -228,10 +204,10 @@ class btDeformableFaceRigidContactConstraint : public btDeformableRigidContactCo | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     const btSoftBody::Face* m_face; |     const btSoftBody::Face* m_face; | ||||||
|     btDeformableFaceRigidContactConstraint(){} |     bool m_useStrainLimiting; | ||||||
|     btDeformableFaceRigidContactConstraint(const btSoftBody::DeformableFaceRigidContact& contact); |     btDeformableFaceRigidContactConstraint(const btSoftBody::DeformableFaceRigidContact& contact, const btContactSolverInfo& infoGlobal, bool useStrainLimiting); | ||||||
|     btDeformableFaceRigidContactConstraint(const btDeformableFaceRigidContactConstraint& other); |     btDeformableFaceRigidContactConstraint(const btDeformableFaceRigidContactConstraint& other); | ||||||
|      |     btDeformableFaceRigidContactConstraint(): m_useStrainLimiting(false) {} | ||||||
|     virtual ~btDeformableFaceRigidContactConstraint() |     virtual ~btDeformableFaceRigidContactConstraint() | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  | @ -249,7 +225,6 @@ public: | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     virtual void applyImpulse(const btVector3& impulse); |     virtual void applyImpulse(const btVector3& impulse); | ||||||
|     virtual void applySplitImpulse(const btVector3& impulse); |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| //
 | //
 | ||||||
|  | @ -263,19 +238,11 @@ public: | ||||||
|     btVector3 m_total_normal_dv; |     btVector3 m_total_normal_dv; | ||||||
|     btVector3 m_total_tangent_dv; |     btVector3 m_total_tangent_dv; | ||||||
|      |      | ||||||
|     btDeformableFaceNodeContactConstraint(){} |     btDeformableFaceNodeContactConstraint(const btSoftBody::DeformableFaceNodeContact& contact, const btContactSolverInfo& infoGlobal); | ||||||
|      | 	btDeformableFaceNodeContactConstraint(){} | ||||||
|     btDeformableFaceNodeContactConstraint(const btSoftBody::DeformableFaceNodeContact& contact); |  | ||||||
|      |  | ||||||
|     virtual ~btDeformableFaceNodeContactConstraint(){} |     virtual ~btDeformableFaceNodeContactConstraint(){} | ||||||
|      |      | ||||||
|     virtual btScalar solveConstraint(); |     virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal); | ||||||
|      |  | ||||||
|     virtual btScalar solveSplitImpulse(const btContactSolverInfo& infoGlobal) |  | ||||||
|     { |  | ||||||
|         // todo: xuchenhan@
 |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
|      |      | ||||||
|     // get the velocity of the object A in the contact
 |     // get the velocity of the object A in the contact
 | ||||||
|     virtual btVector3 getVa() const; |     virtual btVector3 getVa() const; | ||||||
|  | @ -293,10 +260,7 @@ public: | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     virtual void applyImpulse(const btVector3& impulse); |     virtual void applyImpulse(const btVector3& impulse); | ||||||
|     virtual void applySplitImpulse(const btVector3& impulse) | 
 | ||||||
|     { |  | ||||||
|         // todo xuchenhan@
 |  | ||||||
|     } |  | ||||||
|     virtual void setPenetrationScale(btScalar scale){} |     virtual void setPenetrationScale(btScalar scale){} | ||||||
| }; | }; | ||||||
| #endif /* BT_DEFORMABLE_CONTACT_CONSTRAINT_H */ | #endif /* BT_DEFORMABLE_CONTACT_CONSTRAINT_H */ | ||||||
|  |  | ||||||
|  | @ -17,7 +17,7 @@ | ||||||
| #include "btDeformableMultiBodyDynamicsWorld.h" | #include "btDeformableMultiBodyDynamicsWorld.h" | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <cmath> | #include <cmath> | ||||||
| btScalar btDeformableContactProjection::update(btCollisionObject** deformableBodies,int numDeformableBodies) | btScalar btDeformableContactProjection::update(btCollisionObject** deformableBodies,int numDeformableBodies, const btContactSolverInfo& infoGlobal) | ||||||
| { | { | ||||||
| 	btScalar residualSquare = 0; | 	btScalar residualSquare = 0; | ||||||
| 	for (int i = 0; i < numDeformableBodies; ++i) | 	for (int i = 0; i < numDeformableBodies; ++i) | ||||||
|  | @ -32,25 +32,25 @@ btScalar btDeformableContactProjection::update(btCollisionObject** deformableBod | ||||||
| 			for (int k = 0; k < m_nodeRigidConstraints[j].size(); ++k) | 			for (int k = 0; k < m_nodeRigidConstraints[j].size(); ++k) | ||||||
| 			{ | 			{ | ||||||
| 				btDeformableNodeRigidContactConstraint& constraint = m_nodeRigidConstraints[j][k]; | 				btDeformableNodeRigidContactConstraint& constraint = m_nodeRigidConstraints[j][k]; | ||||||
| 				btScalar localResidualSquare = constraint.solveConstraint(); | 				btScalar localResidualSquare = constraint.solveConstraint(infoGlobal); | ||||||
| 				residualSquare = btMax(residualSquare, localResidualSquare); | 				residualSquare = btMax(residualSquare, localResidualSquare); | ||||||
| 			} | 			} | ||||||
| 			for (int k = 0; k < m_nodeAnchorConstraints[j].size(); ++k) | 			for (int k = 0; k < m_nodeAnchorConstraints[j].size(); ++k) | ||||||
| 			{ | 			{ | ||||||
| 				btDeformableNodeAnchorConstraint& constraint = m_nodeAnchorConstraints[j][k]; | 				btDeformableNodeAnchorConstraint& constraint = m_nodeAnchorConstraints[j][k]; | ||||||
| 				btScalar localResidualSquare = constraint.solveConstraint(); | 				btScalar localResidualSquare = constraint.solveConstraint(infoGlobal); | ||||||
| 				residualSquare = btMax(residualSquare, localResidualSquare); | 				residualSquare = btMax(residualSquare, localResidualSquare); | ||||||
| 			} | 			} | ||||||
| 			for (int k = 0; k < m_faceRigidConstraints[j].size(); ++k) | 			for (int k = 0; k < m_faceRigidConstraints[j].size(); ++k) | ||||||
| 			{ | 			{ | ||||||
| 				btDeformableFaceRigidContactConstraint& constraint = m_faceRigidConstraints[j][k]; | 				btDeformableFaceRigidContactConstraint& constraint = m_faceRigidConstraints[j][k]; | ||||||
| 				btScalar localResidualSquare = constraint.solveConstraint(); | 				btScalar localResidualSquare = constraint.solveConstraint(infoGlobal); | ||||||
| 				residualSquare = btMax(residualSquare, localResidualSquare); | 				residualSquare = btMax(residualSquare, localResidualSquare); | ||||||
| 			} | 			} | ||||||
| 			for (int k = 0; k < m_deformableConstraints[j].size(); ++k) | 			for (int k = 0; k < m_deformableConstraints[j].size(); ++k) | ||||||
| 			{ | 			{ | ||||||
| 				btDeformableFaceNodeContactConstraint& constraint = m_deformableConstraints[j][k]; | 				btDeformableFaceNodeContactConstraint& constraint = m_deformableConstraints[j][k]; | ||||||
| 				btScalar localResidualSquare = constraint.solveConstraint(); | 				btScalar localResidualSquare = constraint.solveConstraint(infoGlobal); | ||||||
| 				residualSquare = btMax(residualSquare, localResidualSquare); | 				residualSquare = btMax(residualSquare, localResidualSquare); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | @ -77,38 +77,7 @@ void btDeformableContactProjection::splitImpulseSetup(const btContactSolverInfo& | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| btScalar btDeformableContactProjection::solveSplitImpulse(const btContactSolverInfo& infoGlobal) | void btDeformableContactProjection::setConstraints(const btContactSolverInfo& infoGlobal) | ||||||
| { |  | ||||||
| 	btScalar residualSquare = 0; |  | ||||||
| 	for (int i = 0; i < m_softBodies.size(); ++i) |  | ||||||
| 	{ |  | ||||||
| 		// node constraints
 |  | ||||||
| 		for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j) |  | ||||||
| 		{ |  | ||||||
| 			btDeformableNodeRigidContactConstraint& constraint = m_nodeRigidConstraints[i][j]; |  | ||||||
| 			btScalar localResidualSquare = constraint.solveSplitImpulse(infoGlobal); |  | ||||||
| 			residualSquare = btMax(residualSquare, localResidualSquare); |  | ||||||
| 		} |  | ||||||
| 		// anchor constraints
 |  | ||||||
| 		for (int j = 0; j < m_nodeAnchorConstraints[i].size(); ++j) |  | ||||||
| 		{ |  | ||||||
| 			btDeformableNodeAnchorConstraint& constraint = m_nodeAnchorConstraints[i][j]; |  | ||||||
| 			btScalar localResidualSquare = constraint.solveSplitImpulse(infoGlobal); |  | ||||||
| 			residualSquare = btMax(residualSquare, localResidualSquare); |  | ||||||
| 		} |  | ||||||
| 		// face constraints
 |  | ||||||
| 		for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j) |  | ||||||
| 		{ |  | ||||||
| 			btDeformableFaceRigidContactConstraint& constraint = m_faceRigidConstraints[i][j]; |  | ||||||
| 			btScalar localResidualSquare = constraint.solveSplitImpulse(infoGlobal); |  | ||||||
| 			residualSquare = btMax(residualSquare, localResidualSquare); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 	} |  | ||||||
| 	return residualSquare; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void btDeformableContactProjection::setConstraints() |  | ||||||
| {   | {   | ||||||
| 	BT_PROFILE("setConstraints"); | 	BT_PROFILE("setConstraints"); | ||||||
| 	for (int i = 0; i < m_softBodies.size(); ++i) | 	for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
|  | @ -124,7 +93,7 @@ void btDeformableContactProjection::setConstraints() | ||||||
| 		{ | 		{ | ||||||
| 			if (psb->m_nodes[j].m_im == 0) | 			if (psb->m_nodes[j].m_im == 0) | ||||||
| 			{ | 			{ | ||||||
| 				btDeformableStaticConstraint static_constraint(&psb->m_nodes[j]); | 				btDeformableStaticConstraint static_constraint(&psb->m_nodes[j], infoGlobal); | ||||||
| 				m_staticConstraints[i].push_back(static_constraint); | 				m_staticConstraints[i].push_back(static_constraint); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | @ -139,7 +108,7 @@ void btDeformableContactProjection::setConstraints() | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			anchor.m_c1 = anchor.m_cti.m_colObj->getWorldTransform().getBasis() * anchor.m_local; | 			anchor.m_c1 = anchor.m_cti.m_colObj->getWorldTransform().getBasis() * anchor.m_local; | ||||||
| 			btDeformableNodeAnchorConstraint constraint(anchor); | 			btDeformableNodeAnchorConstraint constraint(anchor, infoGlobal); | ||||||
| 			m_nodeAnchorConstraints[i].push_back(constraint); | 			m_nodeAnchorConstraints[i].push_back(constraint); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
|  | @ -152,7 +121,7 @@ void btDeformableContactProjection::setConstraints() | ||||||
| 			{ | 			{ | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			btDeformableNodeRigidContactConstraint constraint(contact); | 			btDeformableNodeRigidContactConstraint constraint(contact, infoGlobal); | ||||||
| 			btVector3 va = constraint.getVa(); | 			btVector3 va = constraint.getVa(); | ||||||
| 			btVector3 vb = constraint.getVb(); | 			btVector3 vb = constraint.getVb(); | ||||||
| 			const btVector3 vr = vb - va; | 			const btVector3 vr = vb - va; | ||||||
|  | @ -173,7 +142,7 @@ void btDeformableContactProjection::setConstraints() | ||||||
| 			{ | 			{ | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			btDeformableFaceRigidContactConstraint constraint(contact); | 			btDeformableFaceRigidContactConstraint constraint(contact, infoGlobal, m_useStrainLimiting); | ||||||
| 			btVector3 va = constraint.getVa(); | 			btVector3 va = constraint.getVa(); | ||||||
| 			btVector3 vb = constraint.getVb(); | 			btVector3 vb = constraint.getVb(); | ||||||
| 			const btVector3 vr = vb - va; | 			const btVector3 vr = vb - va; | ||||||
|  | @ -184,253 +153,404 @@ void btDeformableContactProjection::setConstraints() | ||||||
| 				m_faceRigidConstraints[i].push_back(constraint); | 				m_faceRigidConstraints[i].push_back(constraint); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		 |  | ||||||
| 		// set Deformable Face vs. Deformable Node constraint
 |  | ||||||
| 		for (int j = 0; j < psb->m_faceNodeContacts.size(); ++j) |  | ||||||
| 		{ |  | ||||||
| 			const btSoftBody::DeformableFaceNodeContact& contact = psb->m_faceNodeContacts[j]; |  | ||||||
| 
 |  | ||||||
| 			btDeformableFaceNodeContactConstraint constraint(contact); |  | ||||||
| 			btVector3 va = constraint.getVa(); |  | ||||||
| 			btVector3 vb = constraint.getVb(); |  | ||||||
| 			const btVector3 vr = vb - va; |  | ||||||
| 			const btScalar dn = btDot(vr, contact.m_normal); |  | ||||||
| 			if (dn > -SIMD_EPSILON) |  | ||||||
| 			{ |  | ||||||
| 				m_deformableConstraints[i].push_back(constraint); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void btDeformableContactProjection::project(TVStack& x) | void btDeformableContactProjection::project(TVStack& x) | ||||||
| { | { | ||||||
| 	const int dim = 3; | #ifndef USE_MGS | ||||||
| 	for (int index = 0; index < m_projectionsDict.size(); ++index) |     const int dim = 3; | ||||||
| 	{ |     for (int index = 0; index < m_projectionsDict.size(); ++index) | ||||||
| 		btAlignedObjectArray<btVector3>& projectionDirs = *m_projectionsDict.getAtIndex(index); |     { | ||||||
| 		size_t i = m_projectionsDict.getKeyAtIndex(index).getUid1(); |         btAlignedObjectArray<btVector3>& projectionDirs = *m_projectionsDict.getAtIndex(index); | ||||||
| 		if (projectionDirs.size() >= dim) |         size_t i = m_projectionsDict.getKeyAtIndex(index).getUid1(); | ||||||
| 		{ |         if (projectionDirs.size() >= dim) | ||||||
| 			// static node
 |         { | ||||||
| 			x[i].setZero(); |             // static node
 | ||||||
| 			continue; |             x[i].setZero(); | ||||||
| 		} |             continue; | ||||||
| 		else if (projectionDirs.size() == 2) |         } | ||||||
| 		{ |         else if (projectionDirs.size() == 2) | ||||||
| 			btVector3 dir0 = projectionDirs[0]; |         { | ||||||
| 			btVector3 dir1 = projectionDirs[1]; |             btVector3 dir0 = projectionDirs[0]; | ||||||
| 			btVector3 free_dir = btCross(dir0, dir1); |             btVector3 dir1 = projectionDirs[1]; | ||||||
| 			if (free_dir.safeNorm() < SIMD_EPSILON) |             btVector3 free_dir = btCross(dir0, dir1); | ||||||
| 			{ |             if (free_dir.safeNorm() < SIMD_EPSILON) | ||||||
| 				x[i] -= x[i].dot(dir0) * dir0; |             { | ||||||
| 				x[i] -= x[i].dot(dir1) * dir1; |                 x[i] -= x[i].dot(dir0) * dir0; | ||||||
| 			} |                 x[i] -= x[i].dot(dir1) * dir1; | ||||||
| 			else |             } | ||||||
| 			{ |             else | ||||||
| 				free_dir.normalize(); |             { | ||||||
| 				x[i] = x[i].dot(free_dir) * free_dir; |                 free_dir.normalize(); | ||||||
| 			} |                 x[i] = x[i].dot(free_dir) * free_dir; | ||||||
| 		} |             } | ||||||
| 		else |         } | ||||||
| 		{ |         else | ||||||
| 			btAssert(projectionDirs.size() == 1); |         { | ||||||
| 			btVector3 dir0 = projectionDirs[0]; |             btAssert(projectionDirs.size() == 1); | ||||||
| 			x[i] -= x[i].dot(dir0) * dir0; |             btVector3 dir0 = projectionDirs[0]; | ||||||
| 		} |             x[i] -= x[i].dot(dir0) * dir0; | ||||||
| 	} |         } | ||||||
|  |     } | ||||||
|  | #else | ||||||
|  |     btReducedVector p(x.size()); | ||||||
|  |     for (int i = 0; i < m_projections.size(); ++i) | ||||||
|  |     { | ||||||
|  |         p += (m_projections[i].dot(x) * m_projections[i]); | ||||||
|  |     } | ||||||
|  |     for (int i = 0; i < p.m_indices.size(); ++i) | ||||||
|  |     { | ||||||
|  |         x[p.m_indices[i]] -= p.m_vecs[i]; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void btDeformableContactProjection::setProjection() | void btDeformableContactProjection::setProjection() | ||||||
| { | { | ||||||
| 	btAlignedObjectArray<btVector3> units; | #ifndef USE_MGS | ||||||
| 	units.push_back(btVector3(1,0,0)); |     BT_PROFILE("btDeformableContactProjection::setProjection"); | ||||||
| 	units.push_back(btVector3(0,1,0)); |     btAlignedObjectArray<btVector3> units; | ||||||
| 	units.push_back(btVector3(0,0,1)); |     units.push_back(btVector3(1,0,0)); | ||||||
| 	for (int i = 0; i < m_softBodies.size(); ++i) |     units.push_back(btVector3(0,1,0)); | ||||||
| 	{ |     units.push_back(btVector3(0,0,1)); | ||||||
| 		btSoftBody* psb = m_softBodies[i]; |     for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
| 		if (!psb->isActive()) |     { | ||||||
| 		{ |         btSoftBody* psb = m_softBodies[i]; | ||||||
| 			continue; |         if (!psb->isActive()) | ||||||
| 		} |         { | ||||||
| 		for (int j = 0; j < m_staticConstraints[i].size(); ++j) |             continue; | ||||||
| 		{ |         } | ||||||
| 			int index = m_staticConstraints[i][j].m_node->index; |         for (int j = 0; j < m_staticConstraints[i].size(); ++j) | ||||||
| 			if (m_projectionsDict.find(index) == NULL) |         { | ||||||
| 			{ |             int index = m_staticConstraints[i][j].m_node->index; | ||||||
| 				m_projectionsDict.insert(index, units); |             m_staticConstraints[i][j].m_node->m_penetration = SIMD_INFINITY; | ||||||
| 			} |             if (m_projectionsDict.find(index) == NULL) | ||||||
| 			else |             { | ||||||
| 			{ |                 m_projectionsDict.insert(index, units); | ||||||
| 				btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; |             } | ||||||
| 				for (int k = 0; k < 3; ++k) |             else | ||||||
| 				{ |             { | ||||||
| 					projections.push_back(units[k]); |                 btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; | ||||||
| 				} |                 for (int k = 0; k < 3; ++k) | ||||||
| 			} |                 { | ||||||
| 		} |                     projections.push_back(units[k]); | ||||||
| 		for (int j = 0; j < m_nodeAnchorConstraints[i].size(); ++j) |                 } | ||||||
| 		{ |             } | ||||||
| 			int index = m_nodeAnchorConstraints[i][j].m_anchor->m_node->index; |         } | ||||||
| 			if (m_projectionsDict.find(index) == NULL) |         for (int j = 0; j < m_nodeAnchorConstraints[i].size(); ++j) | ||||||
| 			{ |         { | ||||||
| 				m_projectionsDict.insert(index, units); |             int index = m_nodeAnchorConstraints[i][j].m_anchor->m_node->index; | ||||||
| 			} |             m_nodeAnchorConstraints[i][j].m_anchor->m_node->m_penetration = SIMD_INFINITY; | ||||||
| 			else |             if (m_projectionsDict.find(index) == NULL) | ||||||
| 			{ |             { | ||||||
| 				btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; |                 m_projectionsDict.insert(index, units); | ||||||
| 				for (int k = 0; k < 3; ++k) |             } | ||||||
| 				{ |             else | ||||||
| 					projections.push_back(units[k]); |             { | ||||||
| 				} |                 btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; | ||||||
| 			} |                 for (int k = 0; k < 3; ++k) | ||||||
| 		} |                 { | ||||||
| 		for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j) |                     projections.push_back(units[k]); | ||||||
| 		{ |                 } | ||||||
| 			int index = m_nodeRigidConstraints[i][j].m_node->index; |             } | ||||||
| 			if (m_nodeRigidConstraints[i][j].m_static) |         } | ||||||
| 			{ |         for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j) | ||||||
| 				if (m_projectionsDict.find(index) == NULL) |         { | ||||||
| 				{ |             int index = m_nodeRigidConstraints[i][j].m_node->index; | ||||||
| 					m_projectionsDict.insert(index, units); |             m_nodeRigidConstraints[i][j].m_node->m_penetration = -m_nodeRigidConstraints[i][j].getContact()->m_cti.m_offset; | ||||||
| 				} |             if (m_nodeRigidConstraints[i][j].m_static) | ||||||
| 				else |             { | ||||||
| 				{ |                 if (m_projectionsDict.find(index) == NULL) | ||||||
| 					btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; |                 { | ||||||
| 					for (int k = 0; k < 3; ++k) |                     m_projectionsDict.insert(index, units); | ||||||
| 					{ |                 } | ||||||
| 						projections.push_back(units[k]); |                 else | ||||||
| 					} |                 { | ||||||
| 				} |                     btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; | ||||||
| 			} |                     for (int k = 0; k < 3; ++k) | ||||||
| 			else |                     { | ||||||
| 			{ |                         projections.push_back(units[k]); | ||||||
| 				if (m_projectionsDict.find(index) == NULL) |                     } | ||||||
| 				{ |                 } | ||||||
| 					btAlignedObjectArray<btVector3> projections; |             } | ||||||
| 					projections.push_back(m_nodeRigidConstraints[i][j].m_normal); |             else | ||||||
| 					m_projectionsDict.insert(index, projections); |             { | ||||||
| 				} |                 if (m_projectionsDict.find(index) == NULL) | ||||||
| 				else |                 { | ||||||
| 				{ |                     btAlignedObjectArray<btVector3> projections; | ||||||
| 					btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; |                     projections.push_back(m_nodeRigidConstraints[i][j].m_normal); | ||||||
| 					projections.push_back(m_nodeRigidConstraints[i][j].m_normal); |                     m_projectionsDict.insert(index, projections); | ||||||
| 				} |                 } | ||||||
| 			} |                 else | ||||||
| 		} |                 { | ||||||
| 		for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j) |                     btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; | ||||||
| 		{ |                     projections.push_back(m_nodeRigidConstraints[i][j].m_normal); | ||||||
| 			const btSoftBody::Face* face = m_faceRigidConstraints[i][j].m_face; |                 } | ||||||
| 			for (int k = 0; k < 3; ++k) |             } | ||||||
| 			{ |         } | ||||||
| 				const btSoftBody::Node* node = face->m_n[k]; |         for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j) | ||||||
| 				int index = node->index; |         { | ||||||
| 				if (m_faceRigidConstraints[i][j].m_static) |             const btSoftBody::Face* face = m_faceRigidConstraints[i][j].m_face; | ||||||
| 				{ |             btScalar penetration = -m_faceRigidConstraints[i][j].getContact()->m_cti.m_offset; | ||||||
| 					if (m_projectionsDict.find(index) == NULL) |             for (int k = 0; k < 3; ++k) | ||||||
| 					{ |             { | ||||||
| 						m_projectionsDict.insert(index, units); |                 face->m_n[k]->m_penetration = btMax(face->m_n[k]->m_penetration, penetration); | ||||||
| 					} |             } | ||||||
| 					else |             for (int k = 0; k < 3; ++k) | ||||||
| 					{ |             { | ||||||
| 						btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; |                 btSoftBody::Node* node = face->m_n[k]; | ||||||
| 						for (int k = 0; k < 3; ++k) |                 node->m_penetration = true; | ||||||
| 						{ |                 int index = node->index; | ||||||
| 							projections.push_back(units[k]); |                 if (m_faceRigidConstraints[i][j].m_static) | ||||||
| 						} |                 { | ||||||
| 					} |                     if (m_projectionsDict.find(index) == NULL) | ||||||
| 				} |                     { | ||||||
| 				else |                         m_projectionsDict.insert(index, units); | ||||||
| 				{ |                     } | ||||||
| 					if (m_projectionsDict.find(index) == NULL) |                     else | ||||||
| 					{ |                     { | ||||||
| 						btAlignedObjectArray<btVector3> projections; |                         btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; | ||||||
| 						projections.push_back(m_faceRigidConstraints[i][j].m_normal); |                         for (int k = 0; k < 3; ++k) | ||||||
| 						m_projectionsDict.insert(index, projections); |                         { | ||||||
| 					} |                             projections.push_back(units[k]); | ||||||
| 					else |                         } | ||||||
| 					{ |                     } | ||||||
| 						btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; |                 } | ||||||
| 						projections.push_back(m_faceRigidConstraints[i][j].m_normal); |                 else | ||||||
| 					} |                 { | ||||||
| 				} |                     if (m_projectionsDict.find(index) == NULL) | ||||||
| 			} |                     { | ||||||
| 		} |                         btAlignedObjectArray<btVector3> projections; | ||||||
| 		for (int j = 0; j < m_deformableConstraints[i].size(); ++j) |                         projections.push_back(m_faceRigidConstraints[i][j].m_normal); | ||||||
| 		{ |                         m_projectionsDict.insert(index, projections); | ||||||
| 			const btSoftBody::Face* face = m_deformableConstraints[i][j].m_face; |                     } | ||||||
| 			for (int k = 0; k < 3; ++k) |                     else | ||||||
| 			{ |                     { | ||||||
| 				const btSoftBody::Node* node = face->m_n[k]; |                         btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; | ||||||
| 				int index = node->index; |                         projections.push_back(m_faceRigidConstraints[i][j].m_normal); | ||||||
| 				if (m_deformableConstraints[i][j].m_static) |                     } | ||||||
| 				{ |                 } | ||||||
| 					if (m_projectionsDict.find(index) == NULL) |             } | ||||||
| 					{ |         } | ||||||
| 						m_projectionsDict.insert(index, units); |     } | ||||||
| 					} | #else | ||||||
| 					else |     int dof = 0; | ||||||
| 					{ |     for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
| 						btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; |     { | ||||||
| 						for (int k = 0; k < 3; ++k) |         dof += m_softBodies[i]->m_nodes.size(); | ||||||
| 						{ |     } | ||||||
| 							projections.push_back(units[k]); |     for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
| 						} |     { | ||||||
| 					} |         btSoftBody* psb = m_softBodies[i]; | ||||||
| 				} |         if (!psb->isActive()) | ||||||
| 				else |         { | ||||||
| 				{ |             continue; | ||||||
| 					if (m_projectionsDict.find(index) == NULL) |         } | ||||||
| 					{ |         for (int j = 0; j < m_staticConstraints[i].size(); ++j) | ||||||
| 						btAlignedObjectArray<btVector3> projections; |         { | ||||||
| 						projections.push_back(m_deformableConstraints[i][j].m_normal); |             int index = m_staticConstraints[i][j].m_node->index; | ||||||
| 						m_projectionsDict.insert(index, projections); |             m_staticConstraints[i][j].m_node->m_penetration = SIMD_INFINITY; | ||||||
| 					} |             btAlignedObjectArray<int> indices; | ||||||
| 					else |             btAlignedObjectArray<btVector3> vecs1,vecs2,vecs3; | ||||||
| 					{ |             indices.push_back(index); | ||||||
| 						btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; |             vecs1.push_back(btVector3(1,0,0)); | ||||||
| 						projections.push_back(m_deformableConstraints[i][j].m_normal); |             vecs2.push_back(btVector3(0,1,0)); | ||||||
| 					} |             vecs3.push_back(btVector3(0,0,1)); | ||||||
| 				} |             m_projections.push_back(btReducedVector(dof, indices, vecs1)); | ||||||
| 			} |             m_projections.push_back(btReducedVector(dof, indices, vecs2)); | ||||||
|  |             m_projections.push_back(btReducedVector(dof, indices, vecs3)); | ||||||
|  |         } | ||||||
|          |          | ||||||
| 			const btSoftBody::Node* node = m_deformableConstraints[i][j].m_node; |         for (int j = 0; j < m_nodeAnchorConstraints[i].size(); ++j) | ||||||
| 			int index = node->index; |         { | ||||||
| 			if (m_deformableConstraints[i][j].m_static) |             int index = m_nodeAnchorConstraints[i][j].m_anchor->m_node->index; | ||||||
|  |             m_nodeAnchorConstraints[i][j].m_anchor->m_node->m_penetration = SIMD_INFINITY; | ||||||
|  |             btAlignedObjectArray<int> indices; | ||||||
|  |             btAlignedObjectArray<btVector3> vecs1,vecs2,vecs3; | ||||||
|  |             indices.push_back(index); | ||||||
|  |             vecs1.push_back(btVector3(1,0,0)); | ||||||
|  |             vecs2.push_back(btVector3(0,1,0)); | ||||||
|  |             vecs3.push_back(btVector3(0,0,1)); | ||||||
|  |             m_projections.push_back(btReducedVector(dof, indices, vecs1)); | ||||||
|  |             m_projections.push_back(btReducedVector(dof, indices, vecs2)); | ||||||
|  |             m_projections.push_back(btReducedVector(dof, indices, vecs3)); | ||||||
|  |         } | ||||||
|  |         for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j) | ||||||
|  |         { | ||||||
|  |             int index = m_nodeRigidConstraints[i][j].m_node->index; | ||||||
|  |             m_nodeRigidConstraints[i][j].m_node->m_penetration = -m_nodeRigidConstraints[i][j].getContact()->m_cti.m_offset; | ||||||
|  |             btAlignedObjectArray<int> indices; | ||||||
|  |             indices.push_back(index); | ||||||
|  |             btAlignedObjectArray<btVector3> vecs1,vecs2,vecs3; | ||||||
|  |             if (m_nodeRigidConstraints[i][j].m_static) | ||||||
|  |             { | ||||||
|  |                 vecs1.push_back(btVector3(1,0,0)); | ||||||
|  |                 vecs2.push_back(btVector3(0,1,0)); | ||||||
|  |                 vecs3.push_back(btVector3(0,0,1)); | ||||||
|  |                 m_projections.push_back(btReducedVector(dof, indices, vecs1)); | ||||||
|  |                 m_projections.push_back(btReducedVector(dof, indices, vecs2)); | ||||||
|  |                 m_projections.push_back(btReducedVector(dof, indices, vecs3)); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 vecs1.push_back(m_nodeRigidConstraints[i][j].m_normal); | ||||||
|  |                 m_projections.push_back(btReducedVector(dof, indices, vecs1)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j) | ||||||
|  |         { | ||||||
|  |             const btSoftBody::Face* face = m_faceRigidConstraints[i][j].m_face; | ||||||
|  | 			btVector3 bary = m_faceRigidConstraints[i][j].getContact()->m_bary; | ||||||
|  |             btScalar penetration = -m_faceRigidConstraints[i][j].getContact()->m_cti.m_offset; | ||||||
|  |             for (int k = 0; k < 3; ++k) | ||||||
|  |             { | ||||||
|  |                 face->m_n[k]->m_penetration = btMax(face->m_n[k]->m_penetration, penetration); | ||||||
|  |             } | ||||||
|  | 			if (m_faceRigidConstraints[i][j].m_static) | ||||||
| 			{ | 			{ | ||||||
| 				if (m_projectionsDict.find(index) == NULL) | 				for (int l = 0; l < 3; ++l) | ||||||
| 				{ | 				{ | ||||||
| 					m_projectionsDict.insert(index, units); | 					 | ||||||
| 				} | 					btReducedVector rv(dof); | ||||||
| 				else |  | ||||||
| 				{ |  | ||||||
| 					btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; |  | ||||||
| 					for (int k = 0; k < 3; ++k) | 					for (int k = 0; k < 3; ++k) | ||||||
| 					{ | 					{ | ||||||
| 						projections.push_back(units[k]); | 						rv.m_indices.push_back(face->m_n[k]->index); | ||||||
|  | 						btVector3 v(0,0,0); | ||||||
|  | 						v[l] = bary[k]; | ||||||
|  | 						rv.m_vecs.push_back(v); | ||||||
|  |                         rv.sort(); | ||||||
| 					} | 					} | ||||||
|  | 					m_projections.push_back(rv); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				if (m_projectionsDict.find(index) == NULL) | 				btReducedVector rv(dof); | ||||||
|  | 				for (int k = 0; k < 3; ++k) | ||||||
| 				{ | 				{ | ||||||
| 					btAlignedObjectArray<btVector3> projections; | 					rv.m_indices.push_back(face->m_n[k]->index); | ||||||
| 					projections.push_back(m_deformableConstraints[i][j].m_normal); | 					rv.m_vecs.push_back(bary[k] * m_faceRigidConstraints[i][j].m_normal); | ||||||
| 					m_projectionsDict.insert(index, projections); |                     rv.sort(); | ||||||
| 				} |  | ||||||
| 				else |  | ||||||
| 				{ |  | ||||||
| 					btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index]; |  | ||||||
| 					projections.push_back(m_deformableConstraints[i][j].m_normal); |  | ||||||
| 				} | 				} | ||||||
|  | 				m_projections.push_back(rv); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |     } | ||||||
|  |     btModifiedGramSchmidt<btReducedVector> mgs(m_projections); | ||||||
|  |     mgs.solve(); | ||||||
|  |     m_projections = mgs.m_out; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void btDeformableContactProjection::checkConstraints(const TVStack& x) | ||||||
|  | { | ||||||
|  |     for (int i = 0; i < m_lagrangeMultipliers.size(); ++i) | ||||||
|  |     { | ||||||
|  |         btVector3 d(0,0,0); | ||||||
|  |         const LagrangeMultiplier& lm = m_lagrangeMultipliers[i]; | ||||||
|  |         for (int j = 0; j < lm.m_num_constraints; ++j) | ||||||
|  |         { | ||||||
|  |             for (int k = 0; k < lm.m_num_nodes; ++k) | ||||||
|  |             { | ||||||
|  |                 d[j] += lm.m_weights[k] * x[lm.m_indices[k]].dot(lm.m_dirs[j]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         printf("d = %f, %f, %f\n",d[0],d[1],d[2]); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void btDeformableContactProjection::setLagrangeMultiplier() | ||||||
|  | { | ||||||
|  |     for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
|  |     { | ||||||
|  |         btSoftBody* psb = m_softBodies[i]; | ||||||
|  |         if (!psb->isActive()) | ||||||
|  |         { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         for (int j = 0; j < m_staticConstraints[i].size(); ++j) | ||||||
|  |         { | ||||||
|  |             int index = m_staticConstraints[i][j].m_node->index; | ||||||
|  |             m_staticConstraints[i][j].m_node->m_penetration = SIMD_INFINITY; | ||||||
|  |             LagrangeMultiplier lm; | ||||||
|  |             lm.m_num_nodes = 1; | ||||||
|  |             lm.m_indices[0] = index; | ||||||
|  |             lm.m_weights[0] = 1.0; | ||||||
|  |             lm.m_num_constraints = 3; | ||||||
|  |             lm.m_dirs[0] = btVector3(1,0,0); | ||||||
|  |             lm.m_dirs[1] = btVector3(0,1,0); | ||||||
|  |             lm.m_dirs[2] = btVector3(0,0,1); | ||||||
|  |             m_lagrangeMultipliers.push_back(lm); | ||||||
|  |         } | ||||||
|  |         for (int j = 0; j < m_nodeAnchorConstraints[i].size(); ++j) | ||||||
|  |         { | ||||||
|  |             int index = m_nodeAnchorConstraints[i][j].m_anchor->m_node->index; | ||||||
|  |             m_nodeAnchorConstraints[i][j].m_anchor->m_node->m_penetration = SIMD_INFINITY; | ||||||
|  |             LagrangeMultiplier lm; | ||||||
|  |             lm.m_num_nodes = 1; | ||||||
|  |             lm.m_indices[0] = index; | ||||||
|  |             lm.m_weights[0] = 1.0; | ||||||
|  |             lm.m_num_constraints = 3; | ||||||
|  |             lm.m_dirs[0] = btVector3(1,0,0); | ||||||
|  |             lm.m_dirs[1] = btVector3(0,1,0); | ||||||
|  |             lm.m_dirs[2] = btVector3(0,0,1); | ||||||
|  |             m_lagrangeMultipliers.push_back(lm); | ||||||
|  |         } | ||||||
|  |         for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j) | ||||||
|  |         { | ||||||
|  |             int index = m_nodeRigidConstraints[i][j].m_node->index; | ||||||
|  |             m_nodeRigidConstraints[i][j].m_node->m_penetration = -m_nodeRigidConstraints[i][j].getContact()->m_cti.m_offset; | ||||||
|  |             LagrangeMultiplier lm; | ||||||
|  |             lm.m_num_nodes = 1; | ||||||
|  |             lm.m_indices[0] = index; | ||||||
|  |             lm.m_weights[0] = 1.0; | ||||||
|  |             if (m_nodeRigidConstraints[i][j].m_static) | ||||||
|  |             { | ||||||
|  |                 lm.m_num_constraints = 3; | ||||||
|  |                 lm.m_dirs[0] = btVector3(1,0,0); | ||||||
|  |                 lm.m_dirs[1] = btVector3(0,1,0); | ||||||
|  |                 lm.m_dirs[2] = btVector3(0,0,1); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 lm.m_num_constraints = 1; | ||||||
|  |                 lm.m_dirs[0] = m_nodeRigidConstraints[i][j].m_normal; | ||||||
|  |             } | ||||||
|  |             m_lagrangeMultipliers.push_back(lm); | ||||||
|  |         } | ||||||
|  |         for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j) | ||||||
|  |         { | ||||||
|  |             const btSoftBody::Face* face = m_faceRigidConstraints[i][j].m_face; | ||||||
|  | 			 | ||||||
|  |             btVector3 bary = m_faceRigidConstraints[i][j].getContact()->m_bary; | ||||||
|  |             btScalar penetration = -m_faceRigidConstraints[i][j].getContact()->m_cti.m_offset; | ||||||
|  | 			LagrangeMultiplier lm; | ||||||
|  | 			lm.m_num_nodes = 3; | ||||||
|  | 			for (int k = 0; k<3; ++k) | ||||||
|  | 			{ | ||||||
|  | 				face->m_n[k]->m_penetration = btMax(face->m_n[k]->m_penetration, penetration); | ||||||
|  | 				lm.m_indices[k] = face->m_n[k]->index; | ||||||
|  | 				lm.m_weights[k] = bary[k]; | ||||||
|  | 			} | ||||||
|  |             if (m_faceRigidConstraints[i][j].m_static) | ||||||
|  |             { | ||||||
|  | 				lm.m_num_constraints = 3; | ||||||
|  | 				lm.m_dirs[0] = btVector3(1,0,0); | ||||||
|  | 				lm.m_dirs[1] = btVector3(0,1,0); | ||||||
|  | 				lm.m_dirs[2] = btVector3(0,0,1); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				lm.m_num_constraints = 1; | ||||||
|  | 				lm.m_dirs[0] = m_faceRigidConstraints[i][j].m_normal; | ||||||
|  | 			} | ||||||
|  |             m_lagrangeMultipliers.push_back(lm); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | //
 | ||||||
| void btDeformableContactProjection::applyDynamicFriction(TVStack& f) | void btDeformableContactProjection::applyDynamicFriction(TVStack& f) | ||||||
| { | { | ||||||
| 	for (int i = 0; i < m_softBodies.size(); ++i) | 	for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
|  | @ -502,7 +622,12 @@ void btDeformableContactProjection::reinitialize(bool nodeUpdated) | ||||||
| 		m_faceRigidConstraints[i].clear(); | 		m_faceRigidConstraints[i].clear(); | ||||||
| 		m_deformableConstraints[i].clear(); | 		m_deformableConstraints[i].clear(); | ||||||
| 	} | 	} | ||||||
| 	m_projectionsDict.clear(); | #ifndef USE_MGS | ||||||
|  |     m_projectionsDict.clear(); | ||||||
|  | #else | ||||||
|  |     m_projections.clear(); | ||||||
|  | #endif | ||||||
|  |     m_lagrangeMultipliers.clear(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -21,29 +21,36 @@ | ||||||
| #include "BulletDynamics/Featherstone/btMultiBodyConstraint.h" | #include "BulletDynamics/Featherstone/btMultiBodyConstraint.h" | ||||||
| #include "btDeformableContactConstraint.h" | #include "btDeformableContactConstraint.h" | ||||||
| #include "LinearMath/btHashMap.h" | #include "LinearMath/btHashMap.h" | ||||||
|  | #include "LinearMath/btReducedVector.h" | ||||||
|  | #include "LinearMath/btModifiedGramSchmidt.h" | ||||||
| #include <vector> | #include <vector> | ||||||
|  | 
 | ||||||
|  | struct LagrangeMultiplier | ||||||
|  | { | ||||||
|  |     int m_num_constraints;        // Number of constraints
 | ||||||
|  |     int m_num_nodes;              // Number of nodes in these constraints
 | ||||||
|  |     btScalar m_weights[3];        // weights of the nodes involved, same size as m_num_nodes
 | ||||||
|  |     btVector3 m_dirs[3];          // Constraint directions, same size of m_num_constraints;
 | ||||||
|  |     int m_indices[3];             // indices of the nodes involved, same size as m_num_nodes;
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class btDeformableContactProjection | class btDeformableContactProjection | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     typedef btAlignedObjectArray<btVector3> TVStack; |     typedef btAlignedObjectArray<btVector3> TVStack; | ||||||
|     btAlignedObjectArray<btSoftBody *>& m_softBodies; |     btAlignedObjectArray<btSoftBody *>& m_softBodies; | ||||||
| 	 | 	 | ||||||
| //    // map from node index to static constraint
 |  | ||||||
| //    btHashMap<btHashInt, btDeformableStaticConstraint> m_staticConstraints;
 |  | ||||||
| //    // map from node index to node rigid constraint
 |  | ||||||
| //    btHashMap<btHashInt, btAlignedObjectArray<btDeformableNodeRigidContactConstraint> > m_nodeRigidConstraints;
 |  | ||||||
| //    // map from node index to face rigid constraint
 |  | ||||||
| //    btHashMap<btHashInt, btAlignedObjectArray<btDeformableFaceRigidContactConstraint*> > m_faceRigidConstraints;
 |  | ||||||
| //    // map from node index to deformable constraint
 |  | ||||||
| //    btHashMap<btHashInt, btAlignedObjectArray<btDeformableFaceNodeContactConstraint*> > m_deformableConstraints;
 |  | ||||||
| //    // map from node index to node anchor constraint
 |  | ||||||
| //    btHashMap<btHashInt, btDeformableNodeAnchorConstraint> m_nodeAnchorConstraints;
 |  | ||||||
| 	 |  | ||||||
|     // all constraints involving face
 |     // all constraints involving face
 | ||||||
|     btAlignedObjectArray<btDeformableContactConstraint*> m_allFaceConstraints; |     btAlignedObjectArray<btDeformableContactConstraint*> m_allFaceConstraints; | ||||||
|      | #ifndef USE_MGS | ||||||
|     // map from node index to projection directions
 |     // map from node index to projection directions
 | ||||||
|     btHashMap<btHashInt, btAlignedObjectArray<btVector3> > m_projectionsDict; |     btHashMap<btHashInt, btAlignedObjectArray<btVector3> > m_projectionsDict; | ||||||
|  | #else | ||||||
|  |     btAlignedObjectArray<btReducedVector> m_projections; | ||||||
|  | #endif | ||||||
|  |      | ||||||
|  |     btAlignedObjectArray<LagrangeMultiplier> m_lagrangeMultipliers; | ||||||
|      |      | ||||||
| 	// map from node index to static constraint
 | 	// map from node index to static constraint
 | ||||||
| 	btAlignedObjectArray<btAlignedObjectArray<btDeformableStaticConstraint> > m_staticConstraints; | 	btAlignedObjectArray<btAlignedObjectArray<btDeformableStaticConstraint> > m_staticConstraints; | ||||||
|  | @ -56,6 +63,8 @@ public: | ||||||
| 	// map from node index to node anchor constraint
 | 	// map from node index to node anchor constraint
 | ||||||
| 	btAlignedObjectArray<btAlignedObjectArray<btDeformableNodeAnchorConstraint> > m_nodeAnchorConstraints; | 	btAlignedObjectArray<btAlignedObjectArray<btDeformableNodeAnchorConstraint> > m_nodeAnchorConstraints; | ||||||
|      |      | ||||||
|  |     bool m_useStrainLimiting; | ||||||
|  |      | ||||||
|     btDeformableContactProjection(btAlignedObjectArray<btSoftBody *>& softBodies) |     btDeformableContactProjection(btAlignedObjectArray<btSoftBody *>& softBodies) | ||||||
|     : m_softBodies(softBodies) |     : m_softBodies(softBodies) | ||||||
|     { |     { | ||||||
|  | @ -72,13 +81,10 @@ public: | ||||||
|     virtual void applyDynamicFriction(TVStack& f); |     virtual void applyDynamicFriction(TVStack& f); | ||||||
|      |      | ||||||
|     // update and solve the constraints
 |     // update and solve the constraints
 | ||||||
|     virtual btScalar update(btCollisionObject** deformableBodies,int numDeformableBodies); |     virtual btScalar update(btCollisionObject** deformableBodies,int numDeformableBodies, const btContactSolverInfo& infoGlobal); | ||||||
|      |  | ||||||
|     // solve the position error using split impulse
 |  | ||||||
|     virtual btScalar solveSplitImpulse(const btContactSolverInfo& infoGlobal); |  | ||||||
|      |      | ||||||
|     // Add constraints to m_constraints. In addition, the constraints that each vertex own are recorded in m_constraintsDict.
 |     // Add constraints to m_constraints. In addition, the constraints that each vertex own are recorded in m_constraintsDict.
 | ||||||
|     virtual void setConstraints(); |     virtual void setConstraints(const btContactSolverInfo& infoGlobal); | ||||||
|      |      | ||||||
|     // Set up projections for each vertex by adding the projection direction to
 |     // Set up projections for each vertex by adding the projection direction to
 | ||||||
|     virtual void setProjection(); |     virtual void setProjection(); | ||||||
|  | @ -86,5 +92,9 @@ public: | ||||||
|     virtual void reinitialize(bool nodeUpdated); |     virtual void reinitialize(bool nodeUpdated); | ||||||
|      |      | ||||||
|     virtual void splitImpulseSetup(const btContactSolverInfo& infoGlobal); |     virtual void splitImpulseSetup(const btContactSolverInfo& infoGlobal); | ||||||
|  |      | ||||||
|  |     virtual void setLagrangeMultiplier(); | ||||||
|  |      | ||||||
|  |     void checkConstraints(const TVStack& x); | ||||||
| }; | }; | ||||||
| #endif /* btDeformableContactProjection_h */ | #endif /* btDeformableContactProjection_h */ | ||||||
|  |  | ||||||
|  | @ -114,6 +114,8 @@ public: | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA){} | ||||||
|  |      | ||||||
|     virtual btDeformableLagrangianForceType getForceType() |     virtual btDeformableLagrangianForceType getForceType() | ||||||
|     { |     { | ||||||
|         return BT_COROTATED_FORCE; |         return BT_COROTATED_FORCE; | ||||||
|  |  | ||||||
|  | @ -50,6 +50,8 @@ public: | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA){} | ||||||
|  |      | ||||||
|     virtual void addScaledGravityForce(btScalar scale, TVStack& force) |     virtual void addScaledGravityForce(btScalar scale, TVStack& force) | ||||||
|     { |     { | ||||||
|         int numNodes = getNumNodes(); |         int numNodes = getNumNodes(); | ||||||
|  |  | ||||||
|  | @ -26,7 +26,8 @@ enum btDeformableLagrangianForceType | ||||||
|     BT_MASSSPRING_FORCE = 2, |     BT_MASSSPRING_FORCE = 2, | ||||||
|     BT_COROTATED_FORCE = 3, |     BT_COROTATED_FORCE = 3, | ||||||
|     BT_NEOHOOKEAN_FORCE = 4, |     BT_NEOHOOKEAN_FORCE = 4, | ||||||
|     BT_LINEAR_ELASTICITY_FORCE = 5 |     BT_LINEAR_ELASTICITY_FORCE = 5, | ||||||
|  |     BT_MOUSE_PICKING_FORCE = 6 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static inline double randomDouble(double low, double high) | static inline double randomDouble(double low, double high) | ||||||
|  | @ -53,6 +54,9 @@ public: | ||||||
|     // add damping df
 |     // add damping df
 | ||||||
|     virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df) = 0; |     virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df) = 0; | ||||||
|      |      | ||||||
|  |     // build diagonal of A matrix
 | ||||||
|  |     virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA) = 0; | ||||||
|  |      | ||||||
|     // add elastic df
 |     // add elastic df
 | ||||||
|     virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df) = 0; |     virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df) = 0; | ||||||
|      |      | ||||||
|  | @ -85,6 +89,11 @@ public: | ||||||
|         m_softBodies.push_back(psb); |         m_softBodies.push_back(psb); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     virtual void removeSoftBody(btSoftBody* psb) | ||||||
|  |     { | ||||||
|  |         m_softBodies.remove(psb); | ||||||
|  |     } | ||||||
|  |      | ||||||
|     virtual void setIndices(const btAlignedObjectArray<btSoftBody::Node*>* nodes) |     virtual void setIndices(const btAlignedObjectArray<btSoftBody::Node*>* nodes) | ||||||
|     { |     { | ||||||
|         m_nodes = nodes; |         m_nodes = nodes; | ||||||
|  |  | ||||||
|  | @ -149,6 +149,52 @@ public: | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA) | ||||||
|  |     { | ||||||
|  |         // implicit damping force differential
 | ||||||
|  |         for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
|  |         { | ||||||
|  |             btSoftBody* psb = m_softBodies[i]; | ||||||
|  |             if (!psb->isActive()) | ||||||
|  |             { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             btScalar scaled_k_damp = m_dampingStiffness * scale; | ||||||
|  |             for (int j = 0; j < psb->m_links.size(); ++j) | ||||||
|  |             { | ||||||
|  |                 const btSoftBody::Link& link = psb->m_links[j]; | ||||||
|  |                 btSoftBody::Node* node1 = link.m_n[0]; | ||||||
|  |                 btSoftBody::Node* node2 = link.m_n[1]; | ||||||
|  |                 size_t id1 = node1->index; | ||||||
|  |                 size_t id2 = node2->index; | ||||||
|  |                 if (m_momentum_conserving) | ||||||
|  |                 { | ||||||
|  |                     if ((node2->m_x - node1->m_x).norm() > SIMD_EPSILON) | ||||||
|  |                     { | ||||||
|  |                         btVector3 dir = (node2->m_x - node1->m_x).normalized(); | ||||||
|  |                         for (int d = 0; d < 3; ++d) | ||||||
|  |                         { | ||||||
|  |                             if (node1->m_im > 0) | ||||||
|  |                                 diagA[id1][d] -= scaled_k_damp * dir[d] * dir[d]; | ||||||
|  |                             if (node2->m_im > 0) | ||||||
|  |                                 diagA[id2][d] -= scaled_k_damp * dir[d] * dir[d]; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                 { | ||||||
|  |                     for (int d = 0; d < 3; ++d) | ||||||
|  |                     { | ||||||
|  |                         if (node1->m_im > 0) | ||||||
|  |                             diagA[id1][d] -= scaled_k_damp; | ||||||
|  |                         if (node2->m_im > 0) | ||||||
|  |                             diagA[id2][d] -= scaled_k_damp; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|     virtual double totalElasticEnergy(btScalar dt) |     virtual double totalElasticEnergy(btScalar dt) | ||||||
|     { |     { | ||||||
|         double energy = 0; |         double energy = 0; | ||||||
|  |  | ||||||
							
								
								
									
										145
									
								
								thirdparty/bullet/BulletSoftBody/btDeformableMousePickingForce.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								thirdparty/bullet/BulletSoftBody/btDeformableMousePickingForce.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,145 @@ | ||||||
|  | /*
 | ||||||
|  |  Written by Xuchen Han <xuchenhan2015@u.northwestern.edu> | ||||||
|  |   | ||||||
|  |  Bullet Continuous Collision Detection and Physics Library | ||||||
|  |  Copyright (c) 2019 Google Inc. http://bulletphysics.org
 | ||||||
|  |  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. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef BT_MOUSE_PICKING_FORCE_H | ||||||
|  | #define BT_MOUSE_PICKING_FORCE_H | ||||||
|  | 
 | ||||||
|  | #include "btDeformableLagrangianForce.h" | ||||||
|  | 
 | ||||||
|  | class btDeformableMousePickingForce : public btDeformableLagrangianForce | ||||||
|  | { | ||||||
|  |     // If true, the damping force will be in the direction of the spring
 | ||||||
|  |     // If false, the damping force will be in the direction of the velocity
 | ||||||
|  |     btScalar m_elasticStiffness, m_dampingStiffness; | ||||||
|  |     const btSoftBody::Face& m_face; | ||||||
|  |     btVector3 m_mouse_pos; | ||||||
|  |     btScalar m_maxForce; | ||||||
|  | public: | ||||||
|  |     typedef btAlignedObjectArray<btVector3> TVStack; | ||||||
|  |     btDeformableMousePickingForce(btScalar k, btScalar d, const btSoftBody::Face& face, btVector3 mouse_pos, btScalar maxForce = 0.3) : m_elasticStiffness(k), m_dampingStiffness(d), m_face(face), m_mouse_pos(mouse_pos),  m_maxForce(maxForce) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     virtual void addScaledForces(btScalar scale, TVStack& force) | ||||||
|  |     { | ||||||
|  |         addScaledDampingForce(scale, force); | ||||||
|  |         addScaledElasticForce(scale, force); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     virtual void addScaledExplicitForce(btScalar scale, TVStack& force) | ||||||
|  |     { | ||||||
|  |         addScaledElasticForce(scale, force); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     virtual void addScaledDampingForce(btScalar scale, TVStack& force) | ||||||
|  |     { | ||||||
|  |         for (int i = 0; i < 3; ++i) | ||||||
|  |         { | ||||||
|  |             btVector3 v_diff = m_face.m_n[i]->m_v; | ||||||
|  |             btVector3 scaled_force = scale * m_dampingStiffness * v_diff; | ||||||
|  |             if ((m_face.m_n[i]->m_x - m_mouse_pos).norm() > SIMD_EPSILON) | ||||||
|  |             { | ||||||
|  |                 btVector3 dir = (m_face.m_n[i]->m_x - m_mouse_pos).normalized(); | ||||||
|  |                 scaled_force = scale * m_dampingStiffness * v_diff.dot(dir) * dir; | ||||||
|  |             } | ||||||
|  |             force[m_face.m_n[i]->index] -= scaled_force; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     virtual void addScaledElasticForce(btScalar scale, TVStack& force) | ||||||
|  |     { | ||||||
|  |         btScalar scaled_stiffness = scale * m_elasticStiffness; | ||||||
|  |         for (int i = 0; i < 3; ++i) | ||||||
|  |         { | ||||||
|  |             btVector3 dir = (m_face.m_n[i]->m_q - m_mouse_pos); | ||||||
|  |             btVector3 scaled_force = scaled_stiffness * dir; | ||||||
|  |             if (scaled_force.safeNorm() > m_maxForce) | ||||||
|  |             { | ||||||
|  |                 scaled_force.safeNormalize(); | ||||||
|  |                 scaled_force *= m_maxForce; | ||||||
|  |             } | ||||||
|  |             force[m_face.m_n[i]->index] -= scaled_force; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df) | ||||||
|  |     { | ||||||
|  |         btScalar scaled_k_damp = m_dampingStiffness * scale; | ||||||
|  |         for (int i = 0; i < 3; ++i) | ||||||
|  |         { | ||||||
|  |             btVector3 local_scaled_df = scaled_k_damp * dv[m_face.m_n[i]->index]; | ||||||
|  |             if ((m_face.m_n[i]->m_x - m_mouse_pos).norm() > SIMD_EPSILON) | ||||||
|  |             { | ||||||
|  |                 btVector3 dir = (m_face.m_n[i]->m_x - m_mouse_pos).normalized(); | ||||||
|  |                 local_scaled_df= scaled_k_damp * dv[m_face.m_n[i]->index].dot(dir) * dir; | ||||||
|  |             } | ||||||
|  |             df[m_face.m_n[i]->index] -= local_scaled_df; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA){} | ||||||
|  |      | ||||||
|  |     virtual double totalElasticEnergy(btScalar dt) | ||||||
|  |     { | ||||||
|  |         double energy = 0; | ||||||
|  |         for (int i = 0; i < 3; ++i) | ||||||
|  |         { | ||||||
|  |             btVector3 dir = (m_face.m_n[i]->m_q - m_mouse_pos); | ||||||
|  |             btVector3 scaled_force = m_elasticStiffness * dir; | ||||||
|  |             if (scaled_force.safeNorm() > m_maxForce) | ||||||
|  |             { | ||||||
|  |                 scaled_force.safeNormalize(); | ||||||
|  |                 scaled_force *= m_maxForce; | ||||||
|  |             } | ||||||
|  |             energy += 0.5 * scaled_force.dot(dir); | ||||||
|  |         } | ||||||
|  |         return energy; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     virtual double totalDampingEnergy(btScalar dt) | ||||||
|  |     { | ||||||
|  |         double energy = 0; | ||||||
|  |         for (int i = 0; i < 3; ++i) | ||||||
|  |         { | ||||||
|  |             btVector3 v_diff = m_face.m_n[i]->m_v; | ||||||
|  |             btVector3 scaled_force = m_dampingStiffness * v_diff; | ||||||
|  |             if ((m_face.m_n[i]->m_x - m_mouse_pos).norm() > SIMD_EPSILON) | ||||||
|  |             { | ||||||
|  |                 btVector3 dir = (m_face.m_n[i]->m_x - m_mouse_pos).normalized(); | ||||||
|  |                 scaled_force = m_dampingStiffness * v_diff.dot(dir) * dir; | ||||||
|  |             } | ||||||
|  |             energy -= scaled_force.dot(m_face.m_n[i]->m_v) / dt; | ||||||
|  |         } | ||||||
|  |         return energy; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df) | ||||||
|  |     { | ||||||
|  |         //TODO
 | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     void setMousePos(const btVector3& p) | ||||||
|  |     { | ||||||
|  |         m_mouse_pos = p; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     virtual btDeformableLagrangianForceType getForceType() | ||||||
|  |     { | ||||||
|  |         return BT_MOUSE_PICKING_FORCE; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif /* btMassSpring_h */ | ||||||
|  | @ -32,7 +32,7 @@ btScalar btDeformableMultiBodyConstraintSolver::solveDeformableGroupIterations(b | ||||||
|             m_leastSquaresResidual = solveSingleIteration(iteration, bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer); |             m_leastSquaresResidual = solveSingleIteration(iteration, bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer); | ||||||
|             // solver body velocity -> rigid body velocity
 |             // solver body velocity -> rigid body velocity
 | ||||||
|             solverBodyWriteBack(infoGlobal); |             solverBodyWriteBack(infoGlobal); | ||||||
|             btScalar deformableResidual = m_deformableSolver->solveContactConstraints(deformableBodies,numDeformableBodies); |             btScalar deformableResidual = m_deformableSolver->solveContactConstraints(deformableBodies,numDeformableBodies, infoGlobal); | ||||||
|             // update rigid body velocity in rigid/deformable contact
 |             // update rigid body velocity in rigid/deformable contact
 | ||||||
|             m_leastSquaresResidual = btMax(m_leastSquaresResidual, deformableResidual); |             m_leastSquaresResidual = btMax(m_leastSquaresResidual, deformableResidual); | ||||||
|             // solver body velocity <- rigid body velocity
 |             // solver body velocity <- rigid body velocity
 | ||||||
|  | @ -112,7 +112,7 @@ void btDeformableMultiBodyConstraintSolver::solveGroupCacheFriendlySplitImpulseI | ||||||
|     if (infoGlobal.m_splitImpulse) |     if (infoGlobal.m_splitImpulse) | ||||||
|     { |     { | ||||||
|         { |         { | ||||||
|             m_deformableSolver->splitImpulseSetup(infoGlobal); | //            m_deformableSolver->splitImpulseSetup(infoGlobal);
 | ||||||
|             for (iteration = 0; iteration < infoGlobal.m_numIterations; iteration++) |             for (iteration = 0; iteration < infoGlobal.m_numIterations; iteration++) | ||||||
|             { |             { | ||||||
|                 btScalar leastSquaresResidual = 0.f; |                 btScalar leastSquaresResidual = 0.f; | ||||||
|  | @ -127,8 +127,8 @@ void btDeformableMultiBodyConstraintSolver::solveGroupCacheFriendlySplitImpulseI | ||||||
|                         leastSquaresResidual = btMax(leastSquaresResidual, residual * residual); |                         leastSquaresResidual = btMax(leastSquaresResidual, residual * residual); | ||||||
|                     } |                     } | ||||||
|                     // solve the position correction between deformable and rigid/multibody
 |                     // solve the position correction between deformable and rigid/multibody
 | ||||||
|                     btScalar residual = m_deformableSolver->solveSplitImpulse(infoGlobal); | //                    btScalar residual = m_deformableSolver->solveSplitImpulse(infoGlobal);
 | ||||||
|                     leastSquaresResidual = btMax(leastSquaresResidual, residual * residual); | //                    leastSquaresResidual = btMax(leastSquaresResidual, residual * residual);
 | ||||||
|                 } |                 } | ||||||
|                 if (leastSquaresResidual <= infoGlobal.m_leastSquaresResidualThreshold || iteration >= (infoGlobal.m_numIterations - 1)) |                 if (leastSquaresResidual <= infoGlobal.m_leastSquaresResidualThreshold || iteration >= (infoGlobal.m_numIterations - 1)) | ||||||
|                 { |                 { | ||||||
|  |  | ||||||
|  | @ -22,7 +22,6 @@ Call internalStepSimulation multiple times, to achieve 240Hz (4 steps of 60Hz). | ||||||
| 2. Detect discrete collisions between rigid and deformable bodies at position x_{n+1}^* = x_n + dt * v_{n+1}^*. | 2. Detect discrete collisions between rigid and deformable bodies at position x_{n+1}^* = x_n + dt * v_{n+1}^*. | ||||||
| 
 | 
 | ||||||
| 3a. Solve all constraints, including LCP. Contact, position correction due to numerical drift, friction, and anchors for deformable. | 3a. Solve all constraints, including LCP. Contact, position correction due to numerical drift, friction, and anchors for deformable. | ||||||
|     TODO: add option for positional drift correction (using vel_target += erp * pos_error/dt |  | ||||||
| 
 | 
 | ||||||
| 3b. 5 Newton steps (multiple step). Conjugent Gradient solves linear system. Deformable Damping: Then velocities of deformable bodies v_{n+1} are solved in | 3b. 5 Newton steps (multiple step). Conjugent Gradient solves linear system. Deformable Damping: Then velocities of deformable bodies v_{n+1} are solved in | ||||||
|         M(v_{n+1} - v_{n+1}^*) = damping_force * dt / mass, |         M(v_{n+1} - v_{n+1}^*) = damping_force * dt / mass, | ||||||
|  | @ -58,14 +57,20 @@ m_deformableBodySolver(deformableBodySolver), m_solverCallback(0) | ||||||
| 	m_sbi.water_density = 0; | 	m_sbi.water_density = 0; | ||||||
| 	m_sbi.water_offset = 0; | 	m_sbi.water_offset = 0; | ||||||
| 	m_sbi.water_normal = btVector3(0, 0, 0); | 	m_sbi.water_normal = btVector3(0, 0, 0); | ||||||
| 	m_sbi.m_gravity.setValue(0, -10, 0); | 	m_sbi.m_gravity.setValue(0, -9.8, 0); | ||||||
| 	m_internalTime = 0.0; | 	m_internalTime = 0.0; | ||||||
| 	m_implicit = false; | 	m_implicit = false; | ||||||
| 	m_lineSearch = false; | 	m_lineSearch = false; | ||||||
| 	m_selfCollision = true; |     m_useProjection = true; | ||||||
|  | 	m_ccdIterations = 5; | ||||||
| 	m_solverDeformableBodyIslandCallback = new DeformableBodyInplaceSolverIslandCallback(constraintSolver, dispatcher); | 	m_solverDeformableBodyIslandCallback = new DeformableBodyInplaceSolverIslandCallback(constraintSolver, dispatcher); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | btDeformableMultiBodyDynamicsWorld::~btDeformableMultiBodyDynamicsWorld() | ||||||
|  | { | ||||||
|  |     delete m_solverDeformableBodyIslandCallback; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void btDeformableMultiBodyDynamicsWorld::internalSingleStepSimulation(btScalar timeStep) | void btDeformableMultiBodyDynamicsWorld::internalSingleStepSimulation(btScalar timeStep) | ||||||
| { | { | ||||||
|     BT_PROFILE("internalSingleStepSimulation"); |     BT_PROFILE("internalSingleStepSimulation"); | ||||||
|  | @ -74,20 +79,16 @@ void btDeformableMultiBodyDynamicsWorld::internalSingleStepSimulation(btScalar t | ||||||
|         (*m_internalPreTickCallback)(this, timeStep); |         (*m_internalPreTickCallback)(this, timeStep); | ||||||
|     } |     } | ||||||
|     reinitialize(timeStep); |     reinitialize(timeStep); | ||||||
|  |      | ||||||
|     // add gravity to velocity of rigid and multi bodys
 |     // add gravity to velocity of rigid and multi bodys
 | ||||||
|     applyRigidBodyGravity(timeStep); |     applyRigidBodyGravity(timeStep); | ||||||
|      |      | ||||||
|     ///apply gravity and explicit force to velocity, predict motion
 |     ///apply gravity and explicit force to velocity, predict motion
 | ||||||
|     predictUnconstraintMotion(timeStep); |     predictUnconstraintMotion(timeStep); | ||||||
|      |      | ||||||
|     ///perform collision detection
 |     ///perform collision detection that involves rigid/multi bodies
 | ||||||
|     btMultiBodyDynamicsWorld::performDiscreteCollisionDetection(); |     btMultiBodyDynamicsWorld::performDiscreteCollisionDetection(); | ||||||
|      |      | ||||||
|     if (m_selfCollision) |  | ||||||
|     { |  | ||||||
|         softBodySelfCollision(); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     btMultiBodyDynamicsWorld::calculateSimulationIslands(); |     btMultiBodyDynamicsWorld::calculateSimulationIslands(); | ||||||
|      |      | ||||||
|     beforeSolverCallbacks(timeStep); |     beforeSolverCallbacks(timeStep); | ||||||
|  | @ -97,6 +98,12 @@ void btDeformableMultiBodyDynamicsWorld::internalSingleStepSimulation(btScalar t | ||||||
|      |      | ||||||
|     afterSolverCallbacks(timeStep); |     afterSolverCallbacks(timeStep); | ||||||
| 
 | 
 | ||||||
|  | 	performDeformableCollisionDetection(); | ||||||
|  | 
 | ||||||
|  |     applyRepulsionForce(timeStep); | ||||||
|  | 
 | ||||||
|  |     performGeometricCollisions(timeStep); | ||||||
|  | 
 | ||||||
|     integrateTransforms(timeStep); |     integrateTransforms(timeStep); | ||||||
|      |      | ||||||
|     ///update vehicle simulation
 |     ///update vehicle simulation
 | ||||||
|  | @ -107,6 +114,27 @@ void btDeformableMultiBodyDynamicsWorld::internalSingleStepSimulation(btScalar t | ||||||
|     // ///////////////////////////////
 |     // ///////////////////////////////
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void btDeformableMultiBodyDynamicsWorld::performDeformableCollisionDetection() | ||||||
|  | { | ||||||
|  | 	for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
|  | 	{ | ||||||
|  | 		m_softBodies[i]->m_softSoftCollision = true; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
|  | 	{ | ||||||
|  | 		for (int j = i; j < m_softBodies.size(); ++j) | ||||||
|  | 		{ | ||||||
|  | 			m_softBodies[i]->defaultCollisionHandler(m_softBodies[j]); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
|  | 	{ | ||||||
|  | 		m_softBodies[i]->m_softSoftCollision = false; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void btDeformableMultiBodyDynamicsWorld::updateActivationState(btScalar timeStep) | void btDeformableMultiBodyDynamicsWorld::updateActivationState(btScalar timeStep) | ||||||
| { | { | ||||||
|     for (int i = 0; i < m_softBodies.size(); i++) |     for (int i = 0; i < m_softBodies.size(); i++) | ||||||
|  | @ -131,10 +159,106 @@ void btDeformableMultiBodyDynamicsWorld::updateActivationState(btScalar timeStep | ||||||
|     btMultiBodyDynamicsWorld::updateActivationState(timeStep); |     btMultiBodyDynamicsWorld::updateActivationState(timeStep); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void btDeformableMultiBodyDynamicsWorld::applyRepulsionForce(btScalar timeStep) | ||||||
|  | { | ||||||
|  |     BT_PROFILE("btDeformableMultiBodyDynamicsWorld::applyRepulsionForce"); | ||||||
|  |     for (int i = 0; i < m_softBodies.size(); i++) | ||||||
|  |     { | ||||||
|  |         btSoftBody* psb = m_softBodies[i]; | ||||||
|  |         if (psb->isActive()) | ||||||
|  |         { | ||||||
|  | 			psb->applyRepulsionForce(timeStep, true); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void btDeformableMultiBodyDynamicsWorld::performGeometricCollisions(btScalar timeStep) | ||||||
|  | { | ||||||
|  | 	BT_PROFILE("btDeformableMultiBodyDynamicsWorld::performGeometricCollisions"); | ||||||
|  |     // refit the BVH tree for CCD
 | ||||||
|  | 	for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
|  | 	{ | ||||||
|  | 		btSoftBody* psb = m_softBodies[i]; | ||||||
|  | 		if (psb->isActive()) | ||||||
|  | 		{ | ||||||
|  | 			m_softBodies[i]->updateFaceTree(true, false); | ||||||
|  | 			m_softBodies[i]->updateNodeTree(true, false); | ||||||
|  | 			for (int j = 0; j < m_softBodies[i]->m_faces.size(); ++j) | ||||||
|  | 			{ | ||||||
|  | 				btSoftBody::Face& f = m_softBodies[i]->m_faces[j]; | ||||||
|  | 				f.m_n0 = (f.m_n[1]->m_x - f.m_n[0]->m_x).cross(f.m_n[2]->m_x - f.m_n[0]->m_x); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// clear contact points & update DBVT
 | ||||||
|  | 	for (int r = 0; r < m_ccdIterations; ++r) | ||||||
|  | 	{ | ||||||
|  | 		for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
|  | 		{ | ||||||
|  | 			btSoftBody* psb = m_softBodies[i]; | ||||||
|  | 			if (psb->isActive()) | ||||||
|  | 			{ | ||||||
|  | 				// clear contact points in the previous iteration
 | ||||||
|  | 				psb->m_faceNodeContacts.clear(); | ||||||
|  | 
 | ||||||
|  | 				// update m_q and normals for CCD calculation
 | ||||||
|  | 				for (int j = 0; j < psb->m_nodes.size(); ++j) | ||||||
|  | 				{ | ||||||
|  | 					psb->m_nodes[j].m_q = psb->m_nodes[j].m_x + timeStep * psb->m_nodes[j].m_v; | ||||||
|  | 				} | ||||||
|  | 				for (int j = 0; j < psb->m_faces.size(); ++j) | ||||||
|  | 				{ | ||||||
|  | 					btSoftBody::Face& f = psb->m_faces[j]; | ||||||
|  | 					f.m_n1 = (f.m_n[1]->m_q - f.m_n[0]->m_q).cross(f.m_n[2]->m_q - f.m_n[0]->m_q); | ||||||
|  | 					f.m_vn = (f.m_n[1]->m_v - f.m_n[0]->m_v).cross(f.m_n[2]->m_v - f.m_n[0]->m_v) * timeStep * timeStep; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 		// apply CCD to register new contact points
 | ||||||
|  | 		for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
|  | 		{ | ||||||
|  | 			for (int j = i; j < m_softBodies.size(); ++j) | ||||||
|  | 			{ | ||||||
|  | 				btSoftBody* psb1 = m_softBodies[i]; | ||||||
|  | 				btSoftBody* psb2 = m_softBodies[j]; | ||||||
|  | 				if (psb1->isActive() && psb2->isActive()) | ||||||
|  | 				{ | ||||||
|  | 					m_softBodies[i]->geometricCollisionHandler(m_softBodies[j]); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 		int penetration_count = 0; | ||||||
|  | 		for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
|  | 		{ | ||||||
|  | 			btSoftBody* psb = m_softBodies[i]; | ||||||
|  | 			if (psb->isActive()) | ||||||
|  | 			{ | ||||||
|  | 				penetration_count += psb->m_faceNodeContacts.size(); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if (penetration_count == 0) | ||||||
|  | 		{ | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// apply inelastic impulse
 | ||||||
|  | 		for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
|  | 		{ | ||||||
|  | 			btSoftBody* psb = m_softBodies[i]; | ||||||
|  | 			if (psb->isActive()) | ||||||
|  | 			{ | ||||||
|  | 				psb->applyRepulsionForce(timeStep, false); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| void btDeformableMultiBodyDynamicsWorld::softBodySelfCollision() | void btDeformableMultiBodyDynamicsWorld::softBodySelfCollision() | ||||||
| { | { | ||||||
|     m_deformableBodySolver->updateSoftBodies(); |     BT_PROFILE("btDeformableMultiBodyDynamicsWorld::softBodySelfCollision"); | ||||||
|     for (int i = 0; i < m_softBodies.size(); i++) |     for (int i = 0; i < m_softBodies.size(); i++) | ||||||
|     { |     { | ||||||
|         btSoftBody* psb = m_softBodies[i]; |         btSoftBody* psb = m_softBodies[i]; | ||||||
|  | @ -192,8 +316,6 @@ void btDeformableMultiBodyDynamicsWorld::integrateTransforms(btScalar timeStep) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             node.m_x  =  node.m_x + timeStep * node.m_v; |             node.m_x  =  node.m_x + timeStep * node.m_v; | ||||||
|             node.m_v -= node.m_vsplit; |  | ||||||
|             node.m_vsplit.setZero(); |  | ||||||
|             node.m_q = node.m_x; |             node.m_q = node.m_x; | ||||||
|             node.m_vn = node.m_v; |             node.m_vn = node.m_v; | ||||||
|         } |         } | ||||||
|  | @ -255,6 +377,7 @@ void btDeformableMultiBodyDynamicsWorld::integrateTransforms(btScalar timeStep) | ||||||
| 
 | 
 | ||||||
| void btDeformableMultiBodyDynamicsWorld::solveConstraints(btScalar timeStep) | void btDeformableMultiBodyDynamicsWorld::solveConstraints(btScalar timeStep) | ||||||
| { | { | ||||||
|  |     BT_PROFILE("btDeformableMultiBodyDynamicsWorld::solveConstraints"); | ||||||
|     // save v_{n+1}^* velocity after explicit forces
 |     // save v_{n+1}^* velocity after explicit forces
 | ||||||
|     m_deformableBodySolver->backupVelocity(); |     m_deformableBodySolver->backupVelocity(); | ||||||
|      |      | ||||||
|  | @ -265,7 +388,10 @@ void btDeformableMultiBodyDynamicsWorld::solveConstraints(btScalar timeStep) | ||||||
|     solveContactConstraints(); |     solveContactConstraints(); | ||||||
|      |      | ||||||
|     // set up the directions in which the velocity does not change in the momentum solve
 |     // set up the directions in which the velocity does not change in the momentum solve
 | ||||||
|     m_deformableBodySolver->m_objective->m_projection.setProjection(); |     if (m_useProjection) | ||||||
|  |         m_deformableBodySolver->m_objective->m_projection.setProjection(); | ||||||
|  |     else | ||||||
|  |         m_deformableBodySolver->m_objective->m_projection.setLagrangeMultiplier(); | ||||||
| 
 | 
 | ||||||
|     // for explicit scheme, m_backupVelocity = v_{n+1}^*
 |     // for explicit scheme, m_backupVelocity = v_{n+1}^*
 | ||||||
|     // for implicit scheme, m_backupVelocity = v_n
 |     // for implicit scheme, m_backupVelocity = v_n
 | ||||||
|  | @ -280,7 +406,7 @@ void btDeformableMultiBodyDynamicsWorld::solveConstraints(btScalar timeStep) | ||||||
| void btDeformableMultiBodyDynamicsWorld::setupConstraints() | void btDeformableMultiBodyDynamicsWorld::setupConstraints() | ||||||
| { | { | ||||||
|     // set up constraints between multibody and deformable bodies
 |     // set up constraints between multibody and deformable bodies
 | ||||||
|     m_deformableBodySolver->setConstraints(); |     m_deformableBodySolver->setConstraints(m_solverInfo); | ||||||
|      |      | ||||||
|     // set up constraints among multibodies
 |     // set up constraints among multibodies
 | ||||||
|     { |     { | ||||||
|  | @ -403,6 +529,17 @@ void btDeformableMultiBodyDynamicsWorld::reinitialize(btScalar timeStep) | ||||||
|     dispatchInfo.m_stepCount = 0; |     dispatchInfo.m_stepCount = 0; | ||||||
|     dispatchInfo.m_debugDraw = btMultiBodyDynamicsWorld::getDebugDrawer(); |     dispatchInfo.m_debugDraw = btMultiBodyDynamicsWorld::getDebugDrawer(); | ||||||
|     btMultiBodyDynamicsWorld::getSolverInfo().m_timeStep = timeStep; |     btMultiBodyDynamicsWorld::getSolverInfo().m_timeStep = timeStep; | ||||||
|  |     if (m_useProjection) | ||||||
|  |     { | ||||||
|  |         m_deformableBodySolver->m_useProjection = true; | ||||||
|  | //        m_deformableBodySolver->m_objective->m_projection.m_useStrainLimiting = true;
 | ||||||
|  |         m_deformableBodySolver->m_objective->m_preconditioner =  m_deformableBodySolver->m_objective->m_massPreconditioner; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         m_deformableBodySolver->m_objective->m_preconditioner =  m_deformableBodySolver->m_objective->m_KKTPreconditioner; | ||||||
|  |     } | ||||||
|  |          | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -566,6 +703,24 @@ void btDeformableMultiBodyDynamicsWorld::addForce(btSoftBody* psb, btDeformableL | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void btDeformableMultiBodyDynamicsWorld::removeForce(btSoftBody* psb, btDeformableLagrangianForce* force) | ||||||
|  | { | ||||||
|  |     btAlignedObjectArray<btDeformableLagrangianForce*>& forces = m_deformableBodySolver->m_objective->m_lf; | ||||||
|  |     int removed_index = -1; | ||||||
|  |     for (int i = 0; i < forces.size(); ++i) | ||||||
|  |     { | ||||||
|  |         if (forces[i]->getForceType() == force->getForceType()) | ||||||
|  |         { | ||||||
|  |             forces[i]->removeSoftBody(psb); | ||||||
|  |             if (forces[i]->m_softBodies.size() == 0) | ||||||
|  |                 removed_index = i; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (removed_index >= 0) | ||||||
|  |         forces.removeAtIndex(removed_index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void btDeformableMultiBodyDynamicsWorld::removeSoftBody(btSoftBody* body) | void btDeformableMultiBodyDynamicsWorld::removeSoftBody(btSoftBody* body) | ||||||
| { | { | ||||||
|     m_softBodies.remove(body); |     m_softBodies.remove(body); | ||||||
|  |  | ||||||
|  | @ -46,10 +46,10 @@ class btDeformableMultiBodyDynamicsWorld : public btMultiBodyDynamicsWorld | ||||||
|     bool m_drawClusterTree; |     bool m_drawClusterTree; | ||||||
|     btSoftBodyWorldInfo m_sbi; |     btSoftBodyWorldInfo m_sbi; | ||||||
|     btScalar m_internalTime; |     btScalar m_internalTime; | ||||||
|     int m_contact_iterations; |     int m_ccdIterations; | ||||||
|     bool m_implicit; |     bool m_implicit; | ||||||
|     bool m_lineSearch; |     bool m_lineSearch; | ||||||
|     bool m_selfCollision; |     bool m_useProjection; | ||||||
|     DeformableBodyInplaceSolverIslandCallback* m_solverDeformableBodyIslandCallback; |     DeformableBodyInplaceSolverIslandCallback* m_solverDeformableBodyIslandCallback; | ||||||
|      |      | ||||||
|     typedef void (*btSolverCallback)(btScalar time, btDeformableMultiBodyDynamicsWorld* world); |     typedef void (*btSolverCallback)(btScalar time, btDeformableMultiBodyDynamicsWorld* world); | ||||||
|  | @ -80,9 +80,7 @@ public: | ||||||
|         m_solverCallback = cb; |         m_solverCallback = cb; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     virtual ~btDeformableMultiBodyDynamicsWorld() |     virtual ~btDeformableMultiBodyDynamicsWorld(); | ||||||
|     { |  | ||||||
|     } |  | ||||||
|      |      | ||||||
|     virtual btMultiBodyDynamicsWorld* getMultiBodyDynamicsWorld() |     virtual btMultiBodyDynamicsWorld* getMultiBodyDynamicsWorld() | ||||||
|     { |     { | ||||||
|  | @ -133,6 +131,8 @@ public: | ||||||
|      |      | ||||||
|     void addForce(btSoftBody* psb, btDeformableLagrangianForce* force); |     void addForce(btSoftBody* psb, btDeformableLagrangianForce* force); | ||||||
|      |      | ||||||
|  |     void removeForce(btSoftBody* psb, btDeformableLagrangianForce* force); | ||||||
|  |      | ||||||
|     void removeSoftBody(btSoftBody* body); |     void removeSoftBody(btSoftBody* body); | ||||||
|      |      | ||||||
|     void removeCollisionObject(btCollisionObject* collisionObject); |     void removeCollisionObject(btCollisionObject* collisionObject); | ||||||
|  | @ -142,6 +142,8 @@ public: | ||||||
|      |      | ||||||
|     void setupConstraints(); |     void setupConstraints(); | ||||||
|      |      | ||||||
|  |     void performDeformableCollisionDetection(); | ||||||
|  |      | ||||||
|     void solveMultiBodyConstraints(); |     void solveMultiBodyConstraints(); | ||||||
|      |      | ||||||
|     void solveContactConstraints(); |     void solveContactConstraints(); | ||||||
|  | @ -160,6 +162,150 @@ public: | ||||||
|         m_lineSearch = lineSearch; |         m_lineSearch = lineSearch; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     void applyRepulsionForce(btScalar timeStep); | ||||||
|  |      | ||||||
|  |     void performGeometricCollisions(btScalar timeStep); | ||||||
|  |      | ||||||
|  |     struct btDeformableSingleRayCallback : public btBroadphaseRayCallback | ||||||
|  |     { | ||||||
|  |         btVector3 m_rayFromWorld; | ||||||
|  |         btVector3 m_rayToWorld; | ||||||
|  |         btTransform m_rayFromTrans; | ||||||
|  |         btTransform m_rayToTrans; | ||||||
|  |         btVector3 m_hitNormal; | ||||||
|  |          | ||||||
|  |         const btDeformableMultiBodyDynamicsWorld* m_world; | ||||||
|  |         btCollisionWorld::RayResultCallback& m_resultCallback; | ||||||
|  |          | ||||||
|  |         btDeformableSingleRayCallback(const btVector3& rayFromWorld, const btVector3& rayToWorld, const btDeformableMultiBodyDynamicsWorld* 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 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
 | ||||||
|  |         btDeformableSingleRayCallback 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 rayTestSingle(const btTransform& rayFromTrans, const btTransform& rayToTrans, | ||||||
|  |                                                      btCollisionObject* collisionObject, | ||||||
|  |                                                      const btCollisionShape* collisionShape, | ||||||
|  |                                                      const btTransform& colObjWorldTransform, | ||||||
|  |                                                      RayResultCallback& resultCallback) const | ||||||
|  |     { | ||||||
|  |         if (collisionShape->isSoftBody()) | ||||||
|  |         { | ||||||
|  |             btSoftBody* softBody = btSoftBody::upcast(collisionObject); | ||||||
|  |             if (softBody) | ||||||
|  |             { | ||||||
|  |                 btSoftBody::sRayCast softResult; | ||||||
|  |                 if (softBody->rayFaceTest(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(); | ||||||
|  |                         { | ||||||
|  |                             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); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #endif  //BT_DEFORMABLE_MULTIBODY_DYNAMICS_WORLD_H
 | #endif  //BT_DEFORMABLE_MULTIBODY_DYNAMICS_WORLD_H
 | ||||||
|  |  | ||||||
|  | @ -24,21 +24,65 @@ class btDeformableNeoHookeanForce : public btDeformableLagrangianForce | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     typedef btAlignedObjectArray<btVector3> TVStack; |     typedef btAlignedObjectArray<btVector3> TVStack; | ||||||
|     btScalar m_mu, m_lambda; | 	btScalar m_mu, m_lambda; // Lame Parameters
 | ||||||
|  | 	btScalar m_E, m_nu;  // Young's modulus and Poisson ratio
 | ||||||
|     btScalar m_mu_damp, m_lambda_damp; |     btScalar m_mu_damp, m_lambda_damp; | ||||||
|     btDeformableNeoHookeanForce(): m_mu(1), m_lambda(1) |     btDeformableNeoHookeanForce(): m_mu(1), m_lambda(1) | ||||||
|     { |     { | ||||||
|         btScalar damping = 0.05; |         btScalar damping = 0.05; | ||||||
|         m_mu_damp = damping * m_mu; |         m_mu_damp = damping * m_mu; | ||||||
|         m_lambda_damp = damping * m_lambda; |         m_lambda_damp = damping * m_lambda; | ||||||
|  | 		updateYoungsModulusAndPoissonRatio(); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     btDeformableNeoHookeanForce(btScalar mu, btScalar lambda, btScalar damping = 0.05): m_mu(mu), m_lambda(lambda) |     btDeformableNeoHookeanForce(btScalar mu, btScalar lambda, btScalar damping = 0.05): m_mu(mu), m_lambda(lambda) | ||||||
|     { |     { | ||||||
|         m_mu_damp = damping * m_mu; |         m_mu_damp = damping * m_mu; | ||||||
|         m_lambda_damp = damping * m_lambda; |         m_lambda_damp = damping * m_lambda; | ||||||
|  | 		updateYoungsModulusAndPoissonRatio(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 	void updateYoungsModulusAndPoissonRatio() | ||||||
|  | 	{ | ||||||
|  | 		// conversion from Lame Parameters to Young's modulus and Poisson ratio
 | ||||||
|  | 		// https://en.wikipedia.org/wiki/Lam%C3%A9_parameters
 | ||||||
|  | 		m_E  = m_mu * (3*m_lambda + 2*m_mu)/(m_lambda + m_mu); | ||||||
|  | 		m_nu = m_lambda * 0.5 / (m_mu + m_lambda); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void updateLameParameters() | ||||||
|  | 	{ | ||||||
|  | 		// conversion from Young's modulus and Poisson ratio to Lame Parameters
 | ||||||
|  | 		// https://en.wikipedia.org/wiki/Lam%C3%A9_parameters
 | ||||||
|  | 		m_mu = m_E * 0.5 / (1 + m_nu); | ||||||
|  | 		m_lambda = m_E * m_nu / ((1 + m_nu) * (1- 2*m_nu)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  |     void setYoungsModulus(btScalar E) | ||||||
|  |     { | ||||||
|  | 		m_E = E; | ||||||
|  | 		updateLameParameters(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 	void setPoissonRatio(btScalar nu) | ||||||
|  | 	{ | ||||||
|  | 		m_nu = nu; | ||||||
|  | 		updateLameParameters(); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	void setDamping(btScalar damping) | ||||||
|  | 	{ | ||||||
|  | 		m_mu_damp = damping * m_mu; | ||||||
|  | 		m_lambda_damp = damping * m_lambda; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void setLameParameters(btScalar mu, btScalar lambda) | ||||||
|  | 	{ | ||||||
|  | 		m_mu = mu; | ||||||
|  | 		m_lambda = lambda; | ||||||
|  | 		updateYoungsModulusAndPoissonRatio(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|     virtual void addScaledForces(btScalar scale, TVStack& force) |     virtual void addScaledForces(btScalar scale, TVStack& force) | ||||||
|     { |     { | ||||||
|         addScaledDampingForce(scale, force); |         addScaledDampingForce(scale, force); | ||||||
|  | @ -269,6 +313,8 @@ public: | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA){} | ||||||
|  |      | ||||||
|     virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df) |     virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df) | ||||||
|     { |     { | ||||||
|         int numNodes = getNumNodes(); |         int numNodes = getNumNodes(); | ||||||
|  |  | ||||||
							
								
								
									
										213
									
								
								thirdparty/bullet/BulletSoftBody/btPreconditioner.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										213
									
								
								thirdparty/bullet/BulletSoftBody/btPreconditioner.h
									
										
									
									
										vendored
									
									
								
							|  | @ -68,12 +68,221 @@ public: | ||||||
|     virtual void operator()(const TVStack& x, TVStack& b) |     virtual void operator()(const TVStack& x, TVStack& b) | ||||||
|     { |     { | ||||||
|         btAssert(b.size() == x.size()); |         btAssert(b.size() == x.size()); | ||||||
|         btAssert(m_inv_mass.size() == x.size()); |         btAssert(m_inv_mass.size() <= x.size()); | ||||||
|         for (int i = 0; i < b.size(); ++i) |         for (int i = 0; i < m_inv_mass.size(); ++i) | ||||||
|         { |         { | ||||||
|             b[i] = x[i] * m_inv_mass[i]; |             b[i] = x[i] * m_inv_mass[i]; | ||||||
|         } |         } | ||||||
|  |         for (int i = m_inv_mass.size(); i < b.size(); ++i) | ||||||
|  |         { | ||||||
|  |             b[i] = x[i]; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | class KKTPreconditioner : public Preconditioner | ||||||
|  | { | ||||||
|  |     const btAlignedObjectArray<btSoftBody *>& m_softBodies; | ||||||
|  |     const btDeformableContactProjection& m_projections; | ||||||
|  |     const btAlignedObjectArray<btDeformableLagrangianForce*>& m_lf; | ||||||
|  |     TVStack m_inv_A, m_inv_S; | ||||||
|  |     const btScalar& m_dt; | ||||||
|  |     const bool& m_implicit; | ||||||
|  | public: | ||||||
|  |     KKTPreconditioner(const btAlignedObjectArray<btSoftBody *>& softBodies, const btDeformableContactProjection& projections, const btAlignedObjectArray<btDeformableLagrangianForce*>& lf, const btScalar& dt, const bool& implicit) | ||||||
|  |     : m_softBodies(softBodies) | ||||||
|  |     , m_projections(projections) | ||||||
|  |     , m_lf(lf) | ||||||
|  |     , m_dt(dt) | ||||||
|  |     , m_implicit(implicit) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     virtual void reinitialize(bool nodeUpdated) | ||||||
|  |     { | ||||||
|  |         if (nodeUpdated) | ||||||
|  |         { | ||||||
|  |             int num_nodes = 0; | ||||||
|  |             for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
|  |             { | ||||||
|  |                 btSoftBody* psb = m_softBodies[i]; | ||||||
|  |                 num_nodes += psb->m_nodes.size(); | ||||||
|  |             } | ||||||
|  |             m_inv_A.resize(num_nodes); | ||||||
|  |         } | ||||||
|  |         buildDiagonalA(m_inv_A); | ||||||
|  |         for (int i = 0; i < m_inv_A.size(); ++i) | ||||||
|  |         { | ||||||
|  | //            printf("A[%d] = %f, %f, %f \n", i, m_inv_A[i][0], m_inv_A[i][1], m_inv_A[i][2]);
 | ||||||
|  |             for (int d = 0; d < 3; ++d) | ||||||
|  |             { | ||||||
|  |                 m_inv_A[i][d] = (m_inv_A[i][d] == 0) ? 0.0 : 1.0/ m_inv_A[i][d]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         m_inv_S.resize(m_projections.m_lagrangeMultipliers.size()); | ||||||
|  | //        printf("S.size() = %d \n", m_inv_S.size());
 | ||||||
|  |         buildDiagonalS(m_inv_A, m_inv_S); | ||||||
|  |         for (int i = 0; i < m_inv_S.size(); ++i) | ||||||
|  |         { | ||||||
|  | //            printf("S[%d] = %f, %f, %f \n", i, m_inv_S[i][0], m_inv_S[i][1], m_inv_S[i][2]);
 | ||||||
|  |             for (int d = 0; d < 3; ++d) | ||||||
|  |             { | ||||||
|  |                 m_inv_S[i][d] = (m_inv_S[i][d] == 0) ? 0.0 : 1.0/ m_inv_S[i][d]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     void buildDiagonalA(TVStack& diagA) const | ||||||
|  |     { | ||||||
|  |         size_t counter = 0; | ||||||
|  |         for (int i = 0; i < m_softBodies.size(); ++i) | ||||||
|  |         { | ||||||
|  |             btSoftBody* psb = m_softBodies[i]; | ||||||
|  |             for (int j = 0; j < psb->m_nodes.size(); ++j) | ||||||
|  |             { | ||||||
|  |                 const btSoftBody::Node& node = psb->m_nodes[j]; | ||||||
|  |                 diagA[counter] = (node.m_im == 0) ? btVector3(0,0,0) : btVector3(1.0/node.m_im, 1.0 / node.m_im, 1.0 / node.m_im); | ||||||
|  |                 ++counter; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (m_implicit) | ||||||
|  |         { | ||||||
|  |             printf("implicit not implemented\n"); | ||||||
|  |             btAssert(false); | ||||||
|  |         } | ||||||
|  |         for (int i = 0; i < m_lf.size(); ++i) | ||||||
|  |         { | ||||||
|  |             // add damping matrix
 | ||||||
|  |             m_lf[i]->buildDampingForceDifferentialDiagonal(-m_dt, diagA); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     void buildDiagonalS(const TVStack& inv_A, TVStack& diagS) | ||||||
|  |     { | ||||||
|  |         for (int c = 0; c < m_projections.m_lagrangeMultipliers.size(); ++c) | ||||||
|  |         { | ||||||
|  |             // S[k,k] = e_k^T * C A_d^-1 C^T * e_k
 | ||||||
|  |             const LagrangeMultiplier& lm = m_projections.m_lagrangeMultipliers[c]; | ||||||
|  |             btVector3& t = diagS[c]; | ||||||
|  |             t.setZero(); | ||||||
|  |             for (int j = 0; j < lm.m_num_constraints; ++j) | ||||||
|  |             { | ||||||
|  |                 for (int i = 0; i < lm.m_num_nodes; ++i) | ||||||
|  |                 { | ||||||
|  |                     for (int d = 0; d < 3; ++d) | ||||||
|  |                     { | ||||||
|  |                         t[j] += inv_A[lm.m_indices[i]][d] * lm.m_dirs[j][d] * lm.m_dirs[j][d] * lm.m_weights[i] * lm.m_weights[i]; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #define USE_FULL_PRECONDITIONER | ||||||
|  | #ifndef USE_FULL_PRECONDITIONER | ||||||
|  |     virtual void operator()(const TVStack& x, TVStack& b) | ||||||
|  |     { | ||||||
|  |         btAssert(b.size() == x.size()); | ||||||
|  |         for (int i = 0; i < m_inv_A.size(); ++i) | ||||||
|  |         { | ||||||
|  |             b[i] = x[i] * m_inv_A[i]; | ||||||
|  |         } | ||||||
|  |         int offset = m_inv_A.size(); | ||||||
|  |         for (int i = 0; i < m_inv_S.size(); ++i) | ||||||
|  |         { | ||||||
|  |             b[i+offset] = x[i+offset] * m_inv_S[i]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #else | ||||||
|  |     virtual void operator()(const TVStack& x, TVStack& b) | ||||||
|  |     { | ||||||
|  |         btAssert(b.size() == x.size()); | ||||||
|  |         int offset = m_inv_A.size(); | ||||||
|  | 
 | ||||||
|  |         for (int i = 0; i < m_inv_A.size(); ++i) | ||||||
|  |         { | ||||||
|  |             b[i] = x[i] * m_inv_A[i]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (int i = 0; i < m_inv_S.size(); ++i) | ||||||
|  |         { | ||||||
|  |             b[i+offset].setZero(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (int c = 0; c < m_projections.m_lagrangeMultipliers.size(); ++c) | ||||||
|  |         { | ||||||
|  |             const LagrangeMultiplier& lm = m_projections.m_lagrangeMultipliers[c]; | ||||||
|  |             // C * x
 | ||||||
|  |             for (int d = 0; d < lm.m_num_constraints; ++d) | ||||||
|  |             { | ||||||
|  |                 for (int i = 0; i < lm.m_num_nodes; ++i) | ||||||
|  |                 { | ||||||
|  |                     b[offset+c][d] += lm.m_weights[i] * b[lm.m_indices[i]].dot(lm.m_dirs[d]); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (int i = 0; i < m_inv_S.size(); ++i) | ||||||
|  |         { | ||||||
|  |             b[i+offset] = b[i+offset] * m_inv_S[i]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (int i = 0; i < m_inv_A.size(); ++i) | ||||||
|  |         { | ||||||
|  |             b[i].setZero(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (int c = 0; c < m_projections.m_lagrangeMultipliers.size(); ++c) | ||||||
|  |         { | ||||||
|  |             // C^T * lambda
 | ||||||
|  |             const LagrangeMultiplier& lm = m_projections.m_lagrangeMultipliers[c]; | ||||||
|  |             for (int i = 0; i < lm.m_num_nodes; ++i) | ||||||
|  |             { | ||||||
|  |                 for (int j = 0; j < lm.m_num_constraints; ++j) | ||||||
|  |                 { | ||||||
|  |                     b[lm.m_indices[i]] += b[offset+c][j] * lm.m_weights[i] * lm.m_dirs[j]; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (int i = 0; i < m_inv_A.size(); ++i) | ||||||
|  |         { | ||||||
|  |             b[i] = (x[i] - b[i]) * m_inv_A[i]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         TVStack t; | ||||||
|  |         t.resize(b.size()); | ||||||
|  |         for (int i = 0; i < m_inv_S.size(); ++i) | ||||||
|  |         { | ||||||
|  |             t[i+offset] = x[i+offset] * m_inv_S[i]; | ||||||
|  |         } | ||||||
|  |         for (int i = 0; i < m_inv_A.size(); ++i) | ||||||
|  |         { | ||||||
|  |             t[i].setZero(); | ||||||
|  |         } | ||||||
|  |         for (int c = 0; c < m_projections.m_lagrangeMultipliers.size(); ++c) | ||||||
|  |         { | ||||||
|  |             // C^T * lambda
 | ||||||
|  |             const LagrangeMultiplier& lm = m_projections.m_lagrangeMultipliers[c]; | ||||||
|  |             for (int i = 0; i < lm.m_num_nodes; ++i) | ||||||
|  |             { | ||||||
|  |                 for (int j = 0; j < lm.m_num_constraints; ++j) | ||||||
|  |                 { | ||||||
|  |                     t[lm.m_indices[i]] += t[offset+c][j] * lm.m_weights[i] * lm.m_dirs[j]; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         for (int i = 0; i < m_inv_A.size(); ++i) | ||||||
|  |         { | ||||||
|  |             b[i] += t[i] * m_inv_A[i]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (int i = 0; i < m_inv_S.size(); ++i) | ||||||
|  |         { | ||||||
|  |             b[i+offset] -= x[i+offset] * m_inv_S[i]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| #endif /* BT_PRECONDITIONER_H */ | #endif /* BT_PRECONDITIONER_H */ | ||||||
|  |  | ||||||
							
								
								
									
										634
									
								
								thirdparty/bullet/BulletSoftBody/btSoftBody.cpp
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										634
									
								
								thirdparty/bullet/BulletSoftBody/btSoftBody.cpp
									
										
									
									
										vendored
									
									
								
							|  | @ -18,12 +18,114 @@ subject to the following restrictions: | ||||||
| #include "BulletSoftBody/btSoftBodySolvers.h" | #include "BulletSoftBody/btSoftBodySolvers.h" | ||||||
| #include "btSoftBodyData.h" | #include "btSoftBodyData.h" | ||||||
| #include "LinearMath/btSerializer.h" | #include "LinearMath/btSerializer.h" | ||||||
|  | #include "LinearMath/btImplicitQRSVD.h" | ||||||
| #include "LinearMath/btAlignedAllocator.h" | #include "LinearMath/btAlignedAllocator.h" | ||||||
| #include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h" | #include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h" | ||||||
| #include "BulletDynamics/Featherstone/btMultiBodyConstraint.h" | #include "BulletDynamics/Featherstone/btMultiBodyConstraint.h" | ||||||
| #include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h" | #include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h" | ||||||
| #include "BulletCollision/CollisionShapes/btTriangleShape.h" | #include "BulletCollision/CollisionShapes/btTriangleShape.h" | ||||||
| #include <iostream> | #include <iostream> | ||||||
|  | //
 | ||||||
|  | static inline btDbvtNode* buildTreeBottomUp(btAlignedObjectArray<btDbvtNode*>& leafNodes, btAlignedObjectArray<btAlignedObjectArray<int> >& adj) | ||||||
|  | { | ||||||
|  | 	int N = leafNodes.size(); | ||||||
|  | 	if (N == 0) | ||||||
|  | 	{ | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	while (N > 1) | ||||||
|  | 	{ | ||||||
|  | 		btAlignedObjectArray<bool> marked; | ||||||
|  | 		btAlignedObjectArray<btDbvtNode*> newLeafNodes; | ||||||
|  | 		btAlignedObjectArray<std::pair<int,int> > childIds; | ||||||
|  | 		btAlignedObjectArray<btAlignedObjectArray<int> > newAdj; | ||||||
|  | 		marked.resize(N); | ||||||
|  | 		for (int i = 0; i < N; ++i) | ||||||
|  | 			marked[i] = false; | ||||||
|  | 		 | ||||||
|  | 		// pair adjacent nodes into new(parent) node
 | ||||||
|  | 		for (int i = 0; i < N; ++i) | ||||||
|  | 		{ | ||||||
|  | 			if (marked[i]) | ||||||
|  | 				continue; | ||||||
|  | 			bool merged = false; | ||||||
|  | 			for (int j = 0; j < adj[i].size(); ++j) | ||||||
|  | 			{ | ||||||
|  | 				int n = adj[i][j]; | ||||||
|  | 				if (!marked[adj[i][j]]) | ||||||
|  | 				{ | ||||||
|  | 					btDbvtNode* node = new (btAlignedAlloc(sizeof(btDbvtNode), 16)) btDbvtNode(); | ||||||
|  | 					node->parent = NULL; | ||||||
|  | 					node->childs[0] = leafNodes[i]; | ||||||
|  | 					node->childs[1] = leafNodes[n]; | ||||||
|  | 					leafNodes[i]->parent = node; | ||||||
|  | 					leafNodes[n]->parent = node; | ||||||
|  | 					newLeafNodes.push_back(node); | ||||||
|  | 					childIds.push_back(std::make_pair(i,n)); | ||||||
|  | 					merged = true; | ||||||
|  | 					marked[n] = true; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if (!merged) | ||||||
|  | 			{ | ||||||
|  | 				newLeafNodes.push_back(leafNodes[i]); | ||||||
|  | 				childIds.push_back(std::make_pair(i,-1)); | ||||||
|  | 			} | ||||||
|  | 			marked[i] = true; | ||||||
|  | 		} | ||||||
|  | 		// update adjacency matrix
 | ||||||
|  | 		newAdj.resize(newLeafNodes.size()); | ||||||
|  | 		for (int i = 0; i < newLeafNodes.size(); ++i) | ||||||
|  | 		{ | ||||||
|  | 			for (int j = i+1; j < newLeafNodes.size(); ++j) | ||||||
|  | 			{ | ||||||
|  | 				bool neighbor = false; | ||||||
|  | 				const btAlignedObjectArray<int>& leftChildNeighbors = adj[childIds[i].first]; | ||||||
|  | 				for (int k = 0; k < leftChildNeighbors.size(); ++k) | ||||||
|  | 				{ | ||||||
|  | 					if (leftChildNeighbors[k] == childIds[j].first || leftChildNeighbors[k] == childIds[j].second) | ||||||
|  | 					{ | ||||||
|  | 						neighbor = true; | ||||||
|  | 						break; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				if (!neighbor && childIds[i].second != -1) | ||||||
|  | 				{ | ||||||
|  | 					const btAlignedObjectArray<int>& rightChildNeighbors = adj[childIds[i].second]; | ||||||
|  | 					for (int k = 0; k < rightChildNeighbors.size(); ++k) | ||||||
|  | 					{ | ||||||
|  | 						if (rightChildNeighbors[k] == childIds[j].first || rightChildNeighbors[k] == childIds[j].second) | ||||||
|  | 						{ | ||||||
|  | 							neighbor = true; | ||||||
|  | 							break; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				if (neighbor) | ||||||
|  | 				{ | ||||||
|  | 					newAdj[i].push_back(j); | ||||||
|  | 					newAdj[j].push_back(i); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		leafNodes = newLeafNodes; | ||||||
|  | 		//this assignment leaks memory, the assignment doesn't do a deep copy, for now a manual copy
 | ||||||
|  | 		//adj = newAdj;
 | ||||||
|  | 		adj.clear(); | ||||||
|  | 		adj.resize(newAdj.size()); | ||||||
|  | 		for (int i = 0; i < newAdj.size(); i++) | ||||||
|  | 		{ | ||||||
|  | 			for (int j = 0; j < newAdj[i].size(); j++) | ||||||
|  | 			{ | ||||||
|  | 				adj[i].push_back(newAdj[i][j]); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		N = leafNodes.size(); | ||||||
|  | 	} | ||||||
|  | 	return leafNodes[0]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| //
 | //
 | ||||||
| btSoftBody::btSoftBody(btSoftBodyWorldInfo* worldInfo, int node_count, const btVector3* x, const btScalar* m) | btSoftBody::btSoftBody(btSoftBodyWorldInfo* worldInfo, int node_count, const btVector3* x, const btScalar* m) | ||||||
| 	: m_softBodySolver(0), m_worldInfo(worldInfo) | 	: m_softBodySolver(0), m_worldInfo(worldInfo) | ||||||
|  | @ -41,6 +143,7 @@ btSoftBody::btSoftBody(btSoftBodyWorldInfo* worldInfo, int node_count, const btV | ||||||
| 	/* Nodes			*/ | 	/* Nodes			*/ | ||||||
| 	const btScalar margin = getCollisionShape()->getMargin(); | 	const btScalar margin = getCollisionShape()->getMargin(); | ||||||
| 	m_nodes.resize(node_count); | 	m_nodes.resize(node_count); | ||||||
|  |     m_X.resize(node_count); | ||||||
| 	for (int i = 0, ni = node_count; i < ni; ++i) | 	for (int i = 0, ni = node_count; i < ni; ++i) | ||||||
| 	{ | 	{ | ||||||
| 		Node& n = m_nodes[i]; | 		Node& n = m_nodes[i]; | ||||||
|  | @ -51,8 +154,11 @@ btSoftBody::btSoftBody(btSoftBodyWorldInfo* worldInfo, int node_count, const btV | ||||||
| 		n.m_im = n.m_im > 0 ? 1 / n.m_im : 0; | 		n.m_im = n.m_im > 0 ? 1 / n.m_im : 0; | ||||||
| 		n.m_leaf = m_ndbvt.insert(btDbvtVolume::FromCR(n.m_x, margin), &n); | 		n.m_leaf = m_ndbvt.insert(btDbvtVolume::FromCR(n.m_x, margin), &n); | ||||||
| 		n.m_material = pm; | 		n.m_material = pm; | ||||||
|  |         m_X[i] = n.m_x; | ||||||
| 	} | 	} | ||||||
| 	updateBounds(); | 	updateBounds(); | ||||||
|  | 	setCollisionQuadrature(3); | ||||||
|  | 	m_fdbvnt = 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| btSoftBody::btSoftBody(btSoftBodyWorldInfo* worldInfo) | btSoftBody::btSoftBody(btSoftBodyWorldInfo* worldInfo) | ||||||
|  | @ -111,15 +217,18 @@ void btSoftBody::initDefaults() | ||||||
| 	m_collisionShape = new btSoftBodyCollisionShape(this); | 	m_collisionShape = new btSoftBodyCollisionShape(this); | ||||||
| 	m_collisionShape->setMargin(0.25f); | 	m_collisionShape->setMargin(0.25f); | ||||||
| 
 | 
 | ||||||
| 	m_initialWorldTransform.setIdentity(); | 	m_worldTransform.setIdentity(); | ||||||
| 
 | 
 | ||||||
| 	m_windVelocity = btVector3(0, 0, 0); | 	m_windVelocity = btVector3(0, 0, 0); | ||||||
| 	m_restLengthScale = btScalar(1.0); | 	m_restLengthScale = btScalar(1.0); | ||||||
|     m_dampingCoefficient = 1; | 	m_dampingCoefficient = 1.0; | ||||||
|     m_sleepingThreshold = 0.1; | 	m_sleepingThreshold = .4; | ||||||
|     m_useFaceContact = true; |  | ||||||
| 	m_useSelfCollision = false; | 	m_useSelfCollision = false; | ||||||
|     m_collisionFlags = 0; | 	m_collisionFlags = 0; | ||||||
|  | 	m_softSoftCollision = false; | ||||||
|  | 	m_maxSpeedSquared = 0; | ||||||
|  | 	m_repulsionStiffness = 0.5; | ||||||
|  | 	m_fdbvnt = 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //
 | //
 | ||||||
|  | @ -134,6 +243,8 @@ btSoftBody::~btSoftBody() | ||||||
| 		btAlignedFree(m_materials[i]); | 		btAlignedFree(m_materials[i]); | ||||||
| 	for (i = 0; i < m_joints.size(); ++i) | 	for (i = 0; i < m_joints.size(); ++i) | ||||||
| 		btAlignedFree(m_joints[i]); | 		btAlignedFree(m_joints[i]); | ||||||
|  | 	if (m_fdbvnt) | ||||||
|  | 		delete m_fdbvnt; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //
 | //
 | ||||||
|  | @ -896,6 +1007,71 @@ void btSoftBody::setVolumeDensity(btScalar density) | ||||||
| 	setVolumeMass(volume * density / 6); | 	setVolumeMass(volume * density / 6); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | //
 | ||||||
|  | btVector3 btSoftBody::getLinearVelocity() | ||||||
|  | { | ||||||
|  |     btVector3 total_momentum = btVector3(0,0,0); | ||||||
|  |     for (int i = 0; i < m_nodes.size(); ++i) | ||||||
|  |     { | ||||||
|  |         btScalar mass = m_nodes[i].m_im == 0 ? 0 : 1.0/m_nodes[i].m_im; | ||||||
|  |         total_momentum += mass * m_nodes[i].m_v; | ||||||
|  |     } | ||||||
|  |     btScalar total_mass = getTotalMass(); | ||||||
|  |     return total_mass == 0 ? total_momentum : total_momentum / total_mass; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //
 | ||||||
|  | void btSoftBody::setLinearVelocity(const btVector3& linVel) | ||||||
|  | { | ||||||
|  |     btVector3 old_vel = getLinearVelocity(); | ||||||
|  |     btVector3 diff = linVel - old_vel; | ||||||
|  |     for (int i = 0; i < m_nodes.size(); ++i) | ||||||
|  |         m_nodes[i].m_v += diff; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //
 | ||||||
|  | void btSoftBody::setAngularVelocity(const btVector3& angVel) | ||||||
|  | { | ||||||
|  |     btVector3 old_vel = getLinearVelocity(); | ||||||
|  |     btVector3 com = getCenterOfMass(); | ||||||
|  |     for (int i = 0; i < m_nodes.size(); ++i) | ||||||
|  |     { | ||||||
|  |         m_nodes[i].m_v = angVel.cross(m_nodes[i].m_x - com) + old_vel; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //
 | ||||||
|  | btTransform btSoftBody::getRigidTransform() | ||||||
|  | { | ||||||
|  |     btVector3 t = getCenterOfMass(); | ||||||
|  |     btMatrix3x3 S; | ||||||
|  |     S.setZero(); | ||||||
|  |     // get rotation that minimizes L2 difference: \sum_i || RX_i + t - x_i ||
 | ||||||
|  |     for (int i = 0; i < m_nodes.size(); ++i) | ||||||
|  |     { | ||||||
|  |         S += OuterProduct(m_X[i], t-m_nodes[i].m_x); | ||||||
|  |     } | ||||||
|  |     btVector3 sigma; | ||||||
|  |     btMatrix3x3 U,V; | ||||||
|  |     singularValueDecomposition(S,U,sigma,V); | ||||||
|  |     btMatrix3x3 R = V * U.transpose(); | ||||||
|  |     btTransform trs; | ||||||
|  |     trs.setIdentity(); | ||||||
|  |     trs.setOrigin(t); | ||||||
|  |     trs.setBasis(R); | ||||||
|  |     return trs; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //
 | ||||||
|  | void btSoftBody::transformTo(const btTransform& trs) | ||||||
|  | { | ||||||
|  |     // get the current best rigid fit
 | ||||||
|  |     btTransform current_transform = getRigidTransform(); | ||||||
|  |     // apply transform in material space
 | ||||||
|  |     btTransform new_transform = trs * current_transform.inverse(); | ||||||
|  |     transform(new_transform); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| //
 | //
 | ||||||
| void btSoftBody::transform(const btTransform& trs) | void btSoftBody::transform(const btTransform& trs) | ||||||
| { | { | ||||||
|  | @ -916,7 +1092,6 @@ void btSoftBody::transform(const btTransform& trs) | ||||||
| 	updateNormals(); | 	updateNormals(); | ||||||
| 	updateBounds(); | 	updateBounds(); | ||||||
| 	updateConstants(); | 	updateConstants(); | ||||||
| 	m_initialWorldTransform = trs; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //
 | //
 | ||||||
|  | @ -1834,6 +2009,25 @@ bool btSoftBody::rayTest(const btVector3& rayFrom, | ||||||
| 	return (rayTest(rayFrom, rayTo, results.fraction, results.feature, results.index, false) != 0); | 	return (rayTest(rayFrom, rayTo, results.fraction, results.feature, results.index, false) != 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool btSoftBody::rayFaceTest(const btVector3& rayFrom, | ||||||
|  |                          const btVector3& rayTo, | ||||||
|  |                          sRayCast& results) | ||||||
|  | { | ||||||
|  | 	if (m_faces.size() == 0) | ||||||
|  | 		return false; | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  |     	if (m_fdbvt.empty()) | ||||||
|  |         	initializeFaceTree(); | ||||||
|  | 	} | ||||||
|  |      | ||||||
|  |     results.body = this; | ||||||
|  |     results.fraction = 1.f; | ||||||
|  |     results.index = -1; | ||||||
|  |      | ||||||
|  |     return (rayFaceTest(rayFrom, rayTo, results.fraction,  results.index) != 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| //
 | //
 | ||||||
| void btSoftBody::setSolver(eSolverPresets::_ preset) | void btSoftBody::setSolver(eSolverPresets::_ preset) | ||||||
| { | { | ||||||
|  | @ -2339,15 +2533,160 @@ int btSoftBody::rayTest(const btVector3& rayFrom, const btVector3& rayTo, | ||||||
| 	return (cnt); | 	return (cnt); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int btSoftBody::rayFaceTest(const btVector3& rayFrom, const btVector3& rayTo, | ||||||
|  | 						btScalar& mint, int& index) const | ||||||
|  | { | ||||||
|  | 	int cnt = 0; | ||||||
|  | 	{ /* Use dbvt	*/ | ||||||
|  | 		RayFromToCaster collider(rayFrom, rayTo, mint); | ||||||
|  | 		 | ||||||
|  | 		btDbvt::rayTest(m_fdbvt.m_root, rayFrom, rayTo, collider); | ||||||
|  | 		if (collider.m_face) | ||||||
|  | 		{ | ||||||
|  | 			mint = collider.m_mint; | ||||||
|  | 			index = (int)(collider.m_face - &m_faces[0]); | ||||||
|  | 			cnt = 1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return (cnt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| //
 | //
 | ||||||
|  | static inline btDbvntNode* copyToDbvnt(const btDbvtNode* n) | ||||||
|  | { | ||||||
|  | 	if (n == 0) | ||||||
|  | 		return 0; | ||||||
|  | 	btDbvntNode* root = new btDbvntNode(n); | ||||||
|  | 	if (n->isinternal()) | ||||||
|  | 	{ | ||||||
|  | 		btDbvntNode* c0 = copyToDbvnt(n->childs[0]); | ||||||
|  | 		root->childs[0] = c0; | ||||||
|  | 		btDbvntNode* c1 = copyToDbvnt(n->childs[1]); | ||||||
|  | 		root->childs[1] = c1; | ||||||
|  | 	} | ||||||
|  | 	return root; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void calculateNormalCone(btDbvntNode* root) | ||||||
|  | { | ||||||
|  | 	if (!root) | ||||||
|  | 		return; | ||||||
|  | 	if (root->isleaf()) | ||||||
|  | 	{ | ||||||
|  | 		const btSoftBody::Face* face = (btSoftBody::Face*)root->data; | ||||||
|  | 		root->normal = face->m_normal; | ||||||
|  | 		root->angle = 0; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		btVector3 n0(0,0,0), n1(0,0,0); | ||||||
|  | 		btScalar a0 = 0, a1 = 0; | ||||||
|  | 		if (root->childs[0]) | ||||||
|  | 		{ | ||||||
|  | 			calculateNormalCone(root->childs[0]); | ||||||
|  | 			n0 = root->childs[0]->normal; | ||||||
|  | 			a0 = root->childs[0]->angle; | ||||||
|  | 		} | ||||||
|  | 		if (root->childs[1]) | ||||||
|  | 		{ | ||||||
|  | 			calculateNormalCone(root->childs[1]); | ||||||
|  | 			n1 = root->childs[1]->normal; | ||||||
|  | 			a1 = root->childs[1]->angle; | ||||||
|  | 		} | ||||||
|  | 		root->normal = (n0+n1).safeNormalize(); | ||||||
|  | 		root->angle = btMax(a0,a1) + btAngle(n0, n1)*0.5; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void btSoftBody::initializeFaceTree() | void btSoftBody::initializeFaceTree() | ||||||
| { | { | ||||||
|  | 	BT_PROFILE("btSoftBody::initializeFaceTree"); | ||||||
| 	m_fdbvt.clear(); | 	m_fdbvt.clear(); | ||||||
|  | 	// create leaf nodes;
 | ||||||
|  | 	btAlignedObjectArray<btDbvtNode*> leafNodes; | ||||||
|  | 	leafNodes.resize(m_faces.size()); | ||||||
| 	for (int i = 0; i < m_faces.size(); ++i) | 	for (int i = 0; i < m_faces.size(); ++i) | ||||||
| 	{ | 	{ | ||||||
| 		Face& f = m_faces[i]; | 		Face& f = m_faces[i]; | ||||||
| 		f.m_leaf = m_fdbvt.insert(VolumeOf(f, 0), &f); | 		ATTRIBUTE_ALIGNED16(btDbvtVolume) vol = VolumeOf(f, 0); | ||||||
|  | 		btDbvtNode* node = new (btAlignedAlloc(sizeof(btDbvtNode), 16)) btDbvtNode(); | ||||||
|  | 		node->parent = NULL; | ||||||
|  | 		node->data = &f; | ||||||
|  | 		node->childs[1] = 0; | ||||||
|  | 		node->volume = vol; | ||||||
|  | 		leafNodes[i] = node; | ||||||
|  | 		f.m_leaf = node; | ||||||
| 	} | 	} | ||||||
|  | 	btAlignedObjectArray<btAlignedObjectArray<int> > adj; | ||||||
|  | 	adj.resize(m_faces.size()); | ||||||
|  | 	// construct the adjacency list for triangles
 | ||||||
|  | 	for (int i = 0; i < adj.size(); ++i) | ||||||
|  | 	{ | ||||||
|  | 		for (int j = i+1; j < adj.size(); ++j) | ||||||
|  | 		{ | ||||||
|  | 			int dup = 0; | ||||||
|  | 			for (int k = 0; k < 3; ++k) | ||||||
|  | 			{ | ||||||
|  | 				for (int l = 0; l < 3; ++l) | ||||||
|  | 				{ | ||||||
|  | 					if (m_faces[i].m_n[k] == m_faces[j].m_n[l]) | ||||||
|  | 					{ | ||||||
|  | 						++dup; | ||||||
|  | 						break; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				if (dup == 2) | ||||||
|  | 				{ | ||||||
|  | 					adj[i].push_back(j); | ||||||
|  | 					adj[j].push_back(i); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	m_fdbvt.m_root = buildTreeBottomUp(leafNodes, adj); | ||||||
|  | 	if (m_fdbvnt) | ||||||
|  | 		delete m_fdbvnt; | ||||||
|  | 	m_fdbvnt = copyToDbvnt(m_fdbvt.m_root); | ||||||
|  | 	updateFaceTree(false, false); | ||||||
|  | 	rebuildNodeTree(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //
 | ||||||
|  | void btSoftBody::rebuildNodeTree() | ||||||
|  | { | ||||||
|  | 	m_ndbvt.clear(); | ||||||
|  | 	btAlignedObjectArray<btDbvtNode*> leafNodes; | ||||||
|  | 	leafNodes.resize(m_nodes.size()); | ||||||
|  | 	for (int i = 0; i < m_nodes.size(); ++i) | ||||||
|  | 	{ | ||||||
|  | 		Node& n = m_nodes[i]; | ||||||
|  | 		ATTRIBUTE_ALIGNED16(btDbvtVolume) vol = btDbvtVolume::FromCR(n.m_x, 0); | ||||||
|  | 		btDbvtNode* node = new (btAlignedAlloc(sizeof(btDbvtNode), 16)) btDbvtNode(); | ||||||
|  | 		node->parent = NULL; | ||||||
|  | 		node->data = &n; | ||||||
|  | 		node->childs[1] = 0; | ||||||
|  | 		node->volume = vol; | ||||||
|  | 		leafNodes[i] = node; | ||||||
|  | 		n.m_leaf = node; | ||||||
|  | 	} | ||||||
|  | 	btAlignedObjectArray<btAlignedObjectArray<int> > adj; | ||||||
|  | 	adj.resize(m_nodes.size()); | ||||||
|  | 	btAlignedObjectArray<int> old_id; | ||||||
|  | 	old_id.resize(m_nodes.size()); | ||||||
|  | 	for (int i = 0; i < m_nodes.size(); ++i) | ||||||
|  | 		old_id[i] = m_nodes[i].index; | ||||||
|  | 	for (int i = 0; i < m_nodes.size(); ++i) | ||||||
|  | 		m_nodes[i].index = i; | ||||||
|  | 	for (int i = 0; i < m_links.size(); ++i) | ||||||
|  | 	{ | ||||||
|  | 		Link& l = m_links[i]; | ||||||
|  | 		adj[l.m_n[0]->index].push_back(l.m_n[1]->index); | ||||||
|  | 		adj[l.m_n[1]->index].push_back(l.m_n[0]->index); | ||||||
|  | 	} | ||||||
|  | 	m_ndbvt.m_root = buildTreeBottomUp(leafNodes, adj); | ||||||
|  | 	for (int i = 0; i < m_nodes.size(); ++i) | ||||||
|  | 		m_nodes[i].index = old_id[i]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //
 | //
 | ||||||
|  | @ -2403,10 +2742,9 @@ bool btSoftBody::checkDeformableContact(const btCollisionObjectWrapper* colObjWr | ||||||
|     const btCollisionObject* tmpCollisionObj = colObjWrap->getCollisionObject(); |     const btCollisionObject* tmpCollisionObj = colObjWrap->getCollisionObject(); | ||||||
|     // use the position x_{n+1}^* = x_n + dt * v_{n+1}^* where v_{n+1}^* = v_n + dtg for collision detect
 |     // use the position x_{n+1}^* = x_n + dt * v_{n+1}^* where v_{n+1}^* = v_n + dtg for collision detect
 | ||||||
|     // but resolve contact at x_n
 |     // but resolve contact at x_n
 | ||||||
| //    btTransform wtr = (predict) ?
 |     btTransform wtr = (predict) ? | ||||||
| //    (colObjWrap->m_preTransform != NULL ? tmpCollisionObj->getInterpolationWorldTransform()*(*colObjWrap->m_preTransform) : tmpCollisionObj->getInterpolationWorldTransform())
 |     (colObjWrap->m_preTransform != NULL ? tmpCollisionObj->getInterpolationWorldTransform()*(*colObjWrap->m_preTransform) : tmpCollisionObj->getInterpolationWorldTransform()) | ||||||
| //                 : colObjWrap->getWorldTransform();
 |                  : colObjWrap->getWorldTransform(); | ||||||
|     const btTransform& wtr = colObjWrap->getWorldTransform(); |  | ||||||
| 	btScalar dst = | 	btScalar dst = | ||||||
| 		m_worldInfo->m_sparsesdf.Evaluate( | 		m_worldInfo->m_sparsesdf.Evaluate( | ||||||
| 			wtr.invXform(x), | 			wtr.invXform(x), | ||||||
|  | @ -2457,7 +2795,6 @@ bool btSoftBody::checkDeformableFaceContact(const btCollisionObjectWrapper* colO | ||||||
|     btTransform wtr = (predict) ? |     btTransform wtr = (predict) ? | ||||||
|     (colObjWrap->m_preTransform != NULL ? tmpCollisionObj->getInterpolationWorldTransform()*(*colObjWrap->m_preTransform) : tmpCollisionObj->getInterpolationWorldTransform()) |     (colObjWrap->m_preTransform != NULL ? tmpCollisionObj->getInterpolationWorldTransform()*(*colObjWrap->m_preTransform) : tmpCollisionObj->getInterpolationWorldTransform()) | ||||||
|     : colObjWrap->getWorldTransform(); |     : colObjWrap->getWorldTransform(); | ||||||
| //    const btTransform& wtr = colObjWrap->getWorldTransform();
 |  | ||||||
|     btScalar dst; |     btScalar dst; | ||||||
|      |      | ||||||
| //#define USE_QUADRATURE 1
 | //#define USE_QUADRATURE 1
 | ||||||
|  | @ -2476,6 +2813,7 @@ bool btSoftBody::checkDeformableFaceContact(const btCollisionObjectWrapper* colO | ||||||
|                                           nrm, |                                           nrm, | ||||||
|                                           margin); |                                           margin); | ||||||
|         nrm = wtr.getBasis() * nrm; |         nrm = wtr.getBasis() * nrm; | ||||||
|  |         cti.m_colObj = colObjWrap->getCollisionObject(); | ||||||
|         // use cached contact point
 |         // use cached contact point
 | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
|  | @ -2492,10 +2830,11 @@ bool btSoftBody::checkDeformableFaceContact(const btCollisionObjectWrapper* colO | ||||||
|         contact_point = results.witnesses[0]; |         contact_point = results.witnesses[0]; | ||||||
|         getBarycentric(contact_point, f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, bary); |         getBarycentric(contact_point, f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, bary); | ||||||
|         nrm = results.normal; |         nrm = results.normal; | ||||||
|  |         cti.m_colObj = colObjWrap->getCollisionObject(); | ||||||
|         for (int i = 0; i < 3; ++i) |         for (int i = 0; i < 3; ++i) | ||||||
|             f.m_pcontact[i] = bary[i]; |             f.m_pcontact[i] = bary[i]; | ||||||
|     } |     } | ||||||
| 
 |     return (dst < 0); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     // use collision quadrature point
 |     // use collision quadrature point
 | ||||||
|  | @ -2505,7 +2844,11 @@ bool btSoftBody::checkDeformableFaceContact(const btCollisionObjectWrapper* colO | ||||||
|         btVector3 local_nrm; |         btVector3 local_nrm; | ||||||
|         for (int q = 0; q < m_quads.size(); ++q) |         for (int q = 0; q < m_quads.size(); ++q) | ||||||
|         { |         { | ||||||
|             btVector3 p = BaryEval(f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, m_quads[q]); |             btVector3 p; | ||||||
|  |             if (predict) | ||||||
|  |                 p = BaryEval(f.m_n[0]->m_q, f.m_n[1]->m_q, f.m_n[2]->m_q, m_quads[q]); | ||||||
|  |             else | ||||||
|  |                 p = BaryEval(f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, m_quads[q]); | ||||||
|             btScalar local_dst = m_worldInfo->m_sparsesdf.Evaluate( |             btScalar local_dst = m_worldInfo->m_sparsesdf.Evaluate( | ||||||
|                                                     wtr.invXform(p), |                                                     wtr.invXform(p), | ||||||
|                                                     shp, |                                                     shp, | ||||||
|  | @ -2513,43 +2856,83 @@ bool btSoftBody::checkDeformableFaceContact(const btCollisionObjectWrapper* colO | ||||||
|                                                     margin); |                                                     margin); | ||||||
|             if (local_dst < dst) |             if (local_dst < dst) | ||||||
|             { |             { | ||||||
|  |                 if (local_dst < 0 && predict) | ||||||
|  |                     return true; | ||||||
|                 dst = local_dst; |                 dst = local_dst; | ||||||
|                 contact_point = p; |                 contact_point = p; | ||||||
|                 bary = m_quads[q]; |                 bary = m_quads[q]; | ||||||
|                 nrm = wtr.getBasis() * local_nrm; |                 nrm = local_nrm; | ||||||
|  |             } | ||||||
|  |             if (!predict) | ||||||
|  |             { | ||||||
|  |                 cti.m_colObj = colObjWrap->getCollisionObject(); | ||||||
|  |                 cti.m_normal = wtr.getBasis() * nrm; | ||||||
|  |                 cti.m_offset = dst; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         return (dst < 0); | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
|      |      | ||||||
|  | //    // regular face contact
 | ||||||
|  | //    {
 | ||||||
|  | //        btGjkEpaSolver2::sResults results;
 | ||||||
|  | //        btTransform triangle_transform;
 | ||||||
|  | //        triangle_transform.setIdentity();
 | ||||||
|  | //        triangle_transform.setOrigin(f.m_n[0]->m_x);
 | ||||||
|  | //        btTriangleShape triangle(btVector3(0,0,0), f.m_n[1]->m_x-f.m_n[0]->m_x, f.m_n[2]->m_x-f.m_n[0]->m_x);
 | ||||||
|  | //        btVector3 guess(0,0,0);
 | ||||||
|  | //        if (predict)
 | ||||||
|  | //        {
 | ||||||
|  | //            triangle_transform.setOrigin(f.m_n[0]->m_q);
 | ||||||
|  | //            triangle = btTriangleShape(btVector3(0,0,0), f.m_n[1]->m_q-f.m_n[0]->m_q, f.m_n[2]->m_q-f.m_n[0]->m_q);
 | ||||||
|  | //        }
 | ||||||
|  | //        const btConvexShape* csh = static_cast<const btConvexShape*>(shp);
 | ||||||
|  | ////        btGjkEpaSolver2::SignedDistance(&triangle, triangle_transform, csh, wtr, guess, results);
 | ||||||
|  | ////        dst = results.distance - margin;
 | ||||||
|  | ////        contact_point = results.witnesses[0];
 | ||||||
|  | //        btGjkEpaSolver2::Penetration(&triangle, triangle_transform, csh, wtr, guess, results);
 | ||||||
|  | //        if (results.status == btGjkEpaSolver2::sResults::Separated)
 | ||||||
|  | //            return false;
 | ||||||
|  | //        dst = results.distance - margin;
 | ||||||
|  | //        contact_point = results.witnesses[1];
 | ||||||
|  | //        getBarycentric(contact_point, f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, bary);
 | ||||||
|  | //        nrm = results.normal;
 | ||||||
|  | //        for (int i = 0; i < 3; ++i)
 | ||||||
|  | //            f.m_pcontact[i] = bary[i];
 | ||||||
|  | //    }
 | ||||||
|  | //
 | ||||||
|  | //    if (!predict)
 | ||||||
|  | //    {
 | ||||||
|  | //        cti.m_colObj = colObjWrap->getCollisionObject();
 | ||||||
|  | //        cti.m_normal = nrm;
 | ||||||
|  | //        cti.m_offset = dst;
 | ||||||
|  | //    }
 | ||||||
|  | //
 | ||||||
|  |      | ||||||
|     // regular face contact
 |     // regular face contact
 | ||||||
|     { |     { | ||||||
|         btGjkEpaSolver2::sResults results; |         btGjkEpaSolver2::sResults results; | ||||||
|         btTransform triangle_transform; |         btTransform triangle_transform; | ||||||
|         triangle_transform.setIdentity(); |         triangle_transform.setIdentity(); | ||||||
|         triangle_transform.setOrigin(f.m_n[0]->m_x); |         triangle_transform.setOrigin(f.m_n[0]->m_q); | ||||||
|         btTriangleShape triangle(btVector3(0,0,0), f.m_n[1]->m_x-f.m_n[0]->m_x, f.m_n[2]->m_x-f.m_n[0]->m_x); |         btTriangleShape triangle(btVector3(0,0,0), f.m_n[1]->m_q-f.m_n[0]->m_q, f.m_n[2]->m_q-f.m_n[0]->m_q); | ||||||
|         btVector3 guess(0,0,0); |         btVector3 guess(0,0,0); | ||||||
|         const btConvexShape* csh = static_cast<const btConvexShape*>(shp); |         const btConvexShape* csh = static_cast<const btConvexShape*>(shp); | ||||||
|         btGjkEpaSolver2::SignedDistance(&triangle, triangle_transform, csh, wtr, guess, results); |         btGjkEpaSolver2::SignedDistance(&triangle, triangle_transform, csh, wtr, guess, results); | ||||||
|         dst = results.distance - margin; |         dst = results.distance-csh->getMargin(); | ||||||
|  |         dst -= margin; | ||||||
|  |         if (dst >= 0) | ||||||
|  |             return false; | ||||||
|         contact_point = results.witnesses[0]; |         contact_point = results.witnesses[0]; | ||||||
|         getBarycentric(contact_point, f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, bary); |         getBarycentric(contact_point, f.m_n[0]->m_q, f.m_n[1]->m_q, f.m_n[2]->m_q, bary); | ||||||
|  |         btVector3 curr = BaryEval(f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, bary); | ||||||
|         nrm = results.normal; |         nrm = results.normal; | ||||||
|         for (int i = 0; i < 3; ++i) |  | ||||||
|             f.m_pcontact[i] = bary[i]; |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     if (!predict) |  | ||||||
|     { |  | ||||||
|         cti.m_colObj = colObjWrap->getCollisionObject(); |         cti.m_colObj = colObjWrap->getCollisionObject(); | ||||||
|         cti.m_normal = nrm; |         cti.m_normal = nrm; | ||||||
|         cti.m_offset = dst; |         cti.m_offset = dst + (curr - contact_point).dot(nrm); | ||||||
|     } |     } | ||||||
|      |     return (dst < 0); | ||||||
|     if (dst < 0) |  | ||||||
|         return true; |  | ||||||
|     return (false); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //
 | //
 | ||||||
|  | @ -3075,6 +3458,7 @@ void btSoftBody::setSpringStiffness(btScalar k) | ||||||
|     { |     { | ||||||
|         m_links[i].Feature::m_material->m_kLST = k; |         m_links[i].Feature::m_material->m_kLST = k; | ||||||
|     } |     } | ||||||
|  |     m_repulsionStiffness = k; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void btSoftBody::initializeDmInverse() | void btSoftBody::initializeDmInverse() | ||||||
|  | @ -3372,18 +3756,39 @@ void btSoftBody::setMaxStress(btScalar maxStress) | ||||||
| //
 | //
 | ||||||
| void btSoftBody::interpolateRenderMesh() | void btSoftBody::interpolateRenderMesh() | ||||||
| { | { | ||||||
|     for (int i = 0; i < m_renderNodes.size(); ++i) | 	if (m_z.size() > 0) | ||||||
|     { | 	{ | ||||||
|         Node& n = m_renderNodes[i]; | 		for (int i = 0; i < m_renderNodes.size(); ++i) | ||||||
|         n.m_x.setZero(); | 		{ | ||||||
|         for (int j = 0; j < 4; ++j) | 			const Node* p0 = m_renderNodesParents[i][0]; | ||||||
|         { | 			const Node* p1 = m_renderNodesParents[i][1]; | ||||||
| 			if (m_renderNodesParents[i].size()) | 			const Node* p2 = m_renderNodesParents[i][2]; | ||||||
|  | 			btVector3 normal = btCross(p1->m_x - p0->m_x, p2->m_x - p0->m_x); | ||||||
|  | 			btVector3 unit_normal = normal.normalized(); | ||||||
|  | 			Node& n = m_renderNodes[i]; | ||||||
|  | 			n.m_x.setZero(); | ||||||
|  | 			for (int j = 0; j < 3; ++j) | ||||||
| 			{ | 			{ | ||||||
| 				n.m_x += m_renderNodesParents[i][j]->m_x * m_renderNodesInterpolationWeights[i][j]; | 				n.m_x += m_renderNodesParents[i][j]->m_x * m_renderNodesInterpolationWeights[i][j]; | ||||||
| 			} | 			} | ||||||
|         } | 			n.m_x += m_z[i] * unit_normal; | ||||||
|     } | 		} | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		for (int i = 0; i < m_renderNodes.size(); ++i) | ||||||
|  | 		{ | ||||||
|  | 			Node& n = m_renderNodes[i]; | ||||||
|  | 			n.m_x.setZero(); | ||||||
|  | 			for (int j = 0; j < 4; ++j) | ||||||
|  | 			{ | ||||||
|  | 				if (m_renderNodesParents[i].size()) | ||||||
|  | 				{ | ||||||
|  | 					n.m_x += m_renderNodesParents[i][j]->m_x * m_renderNodesInterpolationWeights[i][j]; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void btSoftBody::setCollisionQuadrature(int N) | void btSoftBody::setCollisionQuadrature(int N) | ||||||
|  | @ -3649,13 +4054,10 @@ void btSoftBody::defaultCollisionHandler(const btCollisionObjectWrapper* pcoWrap | ||||||
| 		break; | 		break; | ||||||
|         case fCollision::SDF_RD: |         case fCollision::SDF_RD: | ||||||
|         { |         { | ||||||
|              |  | ||||||
|             btRigidBody* prb1 = (btRigidBody*)btRigidBody::upcast(pcoWrap->getCollisionObject()); |             btRigidBody* prb1 = (btRigidBody*)btRigidBody::upcast(pcoWrap->getCollisionObject()); | ||||||
|             if (pcoWrap->getCollisionObject()->isActive() || this->isActive()) |             if (pcoWrap->getCollisionObject()->isActive() || this->isActive()) | ||||||
|             { |             { | ||||||
|                 const btTransform wtr = pcoWrap->getWorldTransform(); |                 const btTransform wtr = pcoWrap->getWorldTransform(); | ||||||
| //                const btTransform ctr = pcoWrap->getWorldTransform();
 |  | ||||||
| //                const btScalar timemargin = (wtr.getOrigin() - ctr.getOrigin()).length();
 |  | ||||||
|                 const btScalar timemargin = 0; |                 const btScalar timemargin = 0; | ||||||
|                 const btScalar basemargin = getCollisionShape()->getMargin(); |                 const btScalar basemargin = getCollisionShape()->getMargin(); | ||||||
|                 btVector3 mins; |                 btVector3 mins; | ||||||
|  | @ -3667,22 +4069,25 @@ void btSoftBody::defaultCollisionHandler(const btCollisionObjectWrapper* pcoWrap | ||||||
|                                                       maxs); |                                                       maxs); | ||||||
|                 volume = btDbvtVolume::FromMM(mins, maxs); |                 volume = btDbvtVolume::FromMM(mins, maxs); | ||||||
|                 volume.Expand(btVector3(basemargin, basemargin, basemargin)); |                 volume.Expand(btVector3(basemargin, basemargin, basemargin)); | ||||||
|                 btSoftColliders::CollideSDF_RD docollideNode; | 				if (m_cfg.collisions & fCollision::SDF_RDN) | ||||||
|                 docollideNode.psb = this; | 				{ | ||||||
|                 docollideNode.m_colObj1Wrap = pcoWrap; | 					btSoftColliders::CollideSDF_RD docollideNode; | ||||||
|                 docollideNode.m_rigidBody = prb1; | 					docollideNode.psb = this; | ||||||
|                 docollideNode.dynmargin = basemargin + timemargin; | 					docollideNode.m_colObj1Wrap = pcoWrap; | ||||||
|                 docollideNode.stamargin = basemargin; | 					docollideNode.m_rigidBody = prb1; | ||||||
|                 m_ndbvt.collideTV(m_ndbvt.m_root, volume, docollideNode); | 					docollideNode.dynmargin = basemargin + timemargin; | ||||||
|  | 					docollideNode.stamargin = basemargin; | ||||||
|  | 					m_ndbvt.collideTV(m_ndbvt.m_root, volume, docollideNode); | ||||||
|  | 				} | ||||||
| 
 | 
 | ||||||
|                 if (this->m_useFaceContact) |                 if (((pcoWrap->getCollisionObject()->getInternalType() == CO_RIGID_BODY) && (m_cfg.collisions & fCollision::SDF_RDF)) || ((pcoWrap->getCollisionObject()->getInternalType() == CO_FEATHERSTONE_LINK) && (m_cfg.collisions & fCollision::SDF_MDF))) | ||||||
|                 { |                 { | ||||||
|                     btSoftColliders::CollideSDF_RDF docollideFace; |                     btSoftColliders::CollideSDF_RDF docollideFace; | ||||||
|                     docollideFace.psb = this; |                     docollideFace.psb = this; | ||||||
|                     docollideFace.m_colObj1Wrap = pcoWrap; |                     docollideFace.m_colObj1Wrap = pcoWrap; | ||||||
|                     docollideFace.m_rigidBody = prb1; |                     docollideFace.m_rigidBody = prb1; | ||||||
|                     docollideFace.dynmargin = basemargin + timemargin; | 					docollideFace.dynmargin = basemargin + timemargin; | ||||||
|                     docollideFace.stamargin = basemargin; | 					docollideFace.stamargin = basemargin; | ||||||
|                     m_fdbvt.collideTV(m_fdbvt.m_root, volume, docollideFace); |                     m_fdbvt.collideTV(m_fdbvt.m_root, volume, docollideFace); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -3691,51 +4096,6 @@ void btSoftBody::defaultCollisionHandler(const btCollisionObjectWrapper* pcoWrap | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline btDbvntNode* copyToDbvnt(const btDbvtNode* n) |  | ||||||
| { |  | ||||||
|     if (n == 0) |  | ||||||
|         return 0; |  | ||||||
|     btDbvntNode* root = new btDbvntNode(n); |  | ||||||
|     if (n->isinternal()) |  | ||||||
|     { |  | ||||||
|         btDbvntNode* c0 = copyToDbvnt(n->childs[0]); |  | ||||||
|         root->childs[0] = c0; |  | ||||||
|         btDbvntNode* c1 = copyToDbvnt(n->childs[1]); |  | ||||||
|         root->childs[1] = c1; |  | ||||||
|     } |  | ||||||
|     return root; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline void calculateNormalCone(btDbvntNode* root) |  | ||||||
| { |  | ||||||
|     if (!root) |  | ||||||
|         return; |  | ||||||
|     if (root->isleaf()) |  | ||||||
|     { |  | ||||||
|         const btSoftBody::Face* face = (btSoftBody::Face*)root->data; |  | ||||||
|         root->normal = face->m_normal; |  | ||||||
|         root->angle = 0; |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
|         btVector3 n0(0,0,0), n1(0,0,0); |  | ||||||
|         btScalar a0 = 0, a1 = 0; |  | ||||||
|         if (root->childs[0]) |  | ||||||
|         { |  | ||||||
|             calculateNormalCone(root->childs[0]); |  | ||||||
|             n0 = root->childs[0]->normal; |  | ||||||
|             a0 = root->childs[0]->angle; |  | ||||||
|         } |  | ||||||
|         if (root->childs[1]) |  | ||||||
|         { |  | ||||||
|             calculateNormalCone(root->childs[1]); |  | ||||||
|             n1 = root->childs[1]->normal; |  | ||||||
|             a1 = root->childs[1]->angle; |  | ||||||
|         } |  | ||||||
|         root->normal = (n0+n1).safeNormalize(); |  | ||||||
|         root->angle = btMax(a0,a1) + btAngle(n0, n1)*0.5; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| //
 | //
 | ||||||
| void btSoftBody::defaultCollisionHandler(btSoftBody* psb) | void btSoftBody::defaultCollisionHandler(btSoftBody* psb) | ||||||
| { | { | ||||||
|  | @ -3779,6 +4139,8 @@ void btSoftBody::defaultCollisionHandler(btSoftBody* psb) | ||||||
| 		break; | 		break; | ||||||
|         case fCollision::VF_DD: |         case fCollision::VF_DD: | ||||||
|         { |         { | ||||||
|  |             if (!psb->m_softSoftCollision) | ||||||
|  |                 return; | ||||||
|             if (psb->isActive() || this->isActive()) |             if (psb->isActive() || this->isActive()) | ||||||
|             { |             { | ||||||
|                 if (this != psb) |                 if (this != psb) | ||||||
|  | @ -3797,6 +4159,7 @@ void btSoftBody::defaultCollisionHandler(btSoftBody* psb) | ||||||
|                     docollide.psb[0]->m_ndbvt.collideTT(docollide.psb[0]->m_ndbvt.m_root, |                     docollide.psb[0]->m_ndbvt.collideTT(docollide.psb[0]->m_ndbvt.m_root, | ||||||
|                                                         docollide.psb[1]->m_fdbvt.m_root, |                                                         docollide.psb[1]->m_fdbvt.m_root, | ||||||
|                                                         docollide); |                                                         docollide); | ||||||
|  | 
 | ||||||
|                     /* psb1 nodes vs psb0 faces    */ |                     /* psb1 nodes vs psb0 faces    */ | ||||||
|                     if (this->m_tetras.size() > 0) |                     if (this->m_tetras.size() > 0) | ||||||
|                         docollide.useFaceNormal = true; |                         docollide.useFaceNormal = true; | ||||||
|  | @ -3812,20 +4175,17 @@ void btSoftBody::defaultCollisionHandler(btSoftBody* psb) | ||||||
|                 { |                 { | ||||||
|                     if (psb->useSelfCollision()) |                     if (psb->useSelfCollision()) | ||||||
|                     { |                     { | ||||||
|                       btSoftColliders::CollideFF_DD docollide; |                         btSoftColliders::CollideFF_DD docollide; | ||||||
|                       docollide.mrg = getCollisionShape()->getMargin() + |                         docollide.mrg = 2*getCollisionShape()->getMargin(); | ||||||
|                       psb->getCollisionShape()->getMargin(); |                         docollide.psb[0] = this; | ||||||
|                       docollide.psb[0] = this; |                         docollide.psb[1] = psb; | ||||||
|                       docollide.psb[1] = psb; |                         if (this->m_tetras.size() > 0) | ||||||
|                       if (this->m_tetras.size() > 0) |                             docollide.useFaceNormal = true; | ||||||
|                           docollide.useFaceNormal = true; |                         else | ||||||
|                       else |                             docollide.useFaceNormal = false; | ||||||
|                           docollide.useFaceNormal = false; |                         /* psb0 faces vs psb0 faces    */ | ||||||
|                       /* psb0 faces vs psb0 faces    */ |                         calculateNormalCone(this->m_fdbvnt); | ||||||
|                       btDbvntNode* root = copyToDbvnt(this->m_fdbvt.m_root); |                         this->m_fdbvt.selfCollideT(m_fdbvnt,docollide); | ||||||
|                       calculateNormalCone(root); |  | ||||||
|                       this->m_fdbvt.selfCollideT(root,docollide); |  | ||||||
|                       delete root; |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -3837,6 +4197,58 @@ void btSoftBody::defaultCollisionHandler(btSoftBody* psb) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void btSoftBody::geometricCollisionHandler(btSoftBody* psb) | ||||||
|  | { | ||||||
|  | 	if (psb->isActive() || this->isActive()) | ||||||
|  | 	{ | ||||||
|  | 		if (this != psb) | ||||||
|  | 		{ | ||||||
|  | 			btSoftColliders::CollideCCD docollide; | ||||||
|  | 			/* common                    */ | ||||||
|  | 			docollide.mrg = SAFE_EPSILON; // for rounding error instead of actual margin
 | ||||||
|  | 			docollide.dt = psb->m_sst.sdt; | ||||||
|  | 			/* psb0 nodes vs psb1 faces    */ | ||||||
|  | 			if (psb->m_tetras.size() > 0) | ||||||
|  | 				docollide.useFaceNormal = true; | ||||||
|  | 			else | ||||||
|  | 				docollide.useFaceNormal = false; | ||||||
|  | 			docollide.psb[0] = this; | ||||||
|  | 			docollide.psb[1] = psb; | ||||||
|  | 			docollide.psb[0]->m_ndbvt.collideTT(docollide.psb[0]->m_ndbvt.m_root, | ||||||
|  | 												 docollide.psb[1]->m_fdbvt.m_root, | ||||||
|  | 												 docollide); | ||||||
|  | 			/* psb1 nodes vs psb0 faces    */ | ||||||
|  | 			if (this->m_tetras.size() > 0) | ||||||
|  | 				docollide.useFaceNormal = true; | ||||||
|  | 			else | ||||||
|  | 				docollide.useFaceNormal = false; | ||||||
|  | 			docollide.psb[0] = psb; | ||||||
|  | 			docollide.psb[1] = this; | ||||||
|  | 			docollide.psb[0]->m_ndbvt.collideTT(docollide.psb[0]->m_ndbvt.m_root, | ||||||
|  | 												 docollide.psb[1]->m_fdbvt.m_root, | ||||||
|  | 												 docollide); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			if (psb->useSelfCollision()) | ||||||
|  | 			{ | ||||||
|  | 				btSoftColliders::CollideCCD docollide; | ||||||
|  | 				docollide.mrg = SAFE_EPSILON; | ||||||
|  | 				docollide.psb[0] = this; | ||||||
|  | 				docollide.psb[1] = psb; | ||||||
|  |                 docollide.dt = psb->m_sst.sdt; | ||||||
|  | 				if (this->m_tetras.size() > 0) | ||||||
|  | 					docollide.useFaceNormal = true; | ||||||
|  | 				else | ||||||
|  | 					docollide.useFaceNormal = false; | ||||||
|  | 				/* psb0 faces vs psb0 faces    */ | ||||||
|  | 				calculateNormalCone(this->m_fdbvnt);  // should compute this outside of this scope
 | ||||||
|  | 				this->m_fdbvt.selfCollideT(m_fdbvnt,docollide); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void btSoftBody::setWindVelocity(const btVector3& velocity) | void btSoftBody::setWindVelocity(const btVector3& velocity) | ||||||
| { | { | ||||||
| 	m_windVelocity = velocity; | 	m_windVelocity = velocity; | ||||||
|  |  | ||||||
							
								
								
									
										242
									
								
								thirdparty/bullet/BulletSoftBody/btSoftBody.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										242
									
								
								thirdparty/bullet/BulletSoftBody/btSoftBody.h
									
										
									
									
										vendored
									
									
								
							|  | @ -35,6 +35,8 @@ subject to the following restrictions: | ||||||
| //#else
 | //#else
 | ||||||
| #define btSoftBodyData btSoftBodyFloatData | #define btSoftBodyData btSoftBodyFloatData | ||||||
| #define btSoftBodyDataName "btSoftBodyFloatData" | #define btSoftBodyDataName "btSoftBodyFloatData" | ||||||
|  | static const btScalar  OVERLAP_REDUCTION_FACTOR = 0.1; | ||||||
|  | static unsigned long seed = 243703; | ||||||
| //#endif //BT_USE_DOUBLE_PRECISION
 | //#endif //BT_USE_DOUBLE_PRECISION
 | ||||||
| 
 | 
 | ||||||
| class btBroadphaseInterface; | class btBroadphaseInterface; | ||||||
|  | @ -161,14 +163,18 @@ public: | ||||||
| 			RVSmask = 0x000f,  ///Rigid versus soft mask
 | 			RVSmask = 0x000f,  ///Rigid versus soft mask
 | ||||||
| 			SDF_RS = 0x0001,   ///SDF based rigid vs soft
 | 			SDF_RS = 0x0001,   ///SDF based rigid vs soft
 | ||||||
| 			CL_RS = 0x0002,    ///Cluster vs convex rigid vs soft
 | 			CL_RS = 0x0002,    ///Cluster vs convex rigid vs soft
 | ||||||
|             SDF_RD = 0x0003,   ///DF based rigid vs deformable
 | 			SDF_RD = 0x0004,   ///rigid vs deformable
 | ||||||
|             SDF_RDF = 0x0004,   ///DF based rigid vs deformable faces
 |  | ||||||
| 
 | 
 | ||||||
| 			SVSmask = 0x00F0,  ///Rigid versus soft mask
 | 			SVSmask = 0x00f0,  ///Rigid versus soft mask
 | ||||||
| 			VF_SS = 0x0010,    ///Vertex vs face soft vs soft handling
 | 			VF_SS = 0x0010,    ///Vertex vs face soft vs soft handling
 | ||||||
| 			CL_SS = 0x0020,    ///Cluster vs cluster soft vs soft handling
 | 			CL_SS = 0x0020,    ///Cluster vs cluster soft vs soft handling
 | ||||||
| 			CL_SELF = 0x0040,  ///Cluster soft body self collision
 | 			CL_SELF = 0x0040,  ///Cluster soft body self collision
 | ||||||
|             VF_DD = 0x0050,    ///Vertex vs face soft vs soft handling
 | 			VF_DD = 0x0080,    ///Vertex vs face soft vs soft handling
 | ||||||
|  | 
 | ||||||
|  | 			RVDFmask = 0x0f00, /// Rigid versus deformable face mask
 | ||||||
|  | 			SDF_RDF = 0x0100,  /// GJK based Rigid vs. deformable face
 | ||||||
|  | 			SDF_MDF = 0x0200,  /// GJK based Multibody vs. deformable face
 | ||||||
|  |             SDF_RDN = 0x0400,  /// SDF based Rigid vs. deformable node
 | ||||||
| 			/* presets	*/ | 			/* presets	*/ | ||||||
| 			Default = SDF_RS, | 			Default = SDF_RS, | ||||||
| 			END | 			END | ||||||
|  | @ -257,13 +263,13 @@ public: | ||||||
| 		btVector3 m_x;       // Position
 | 		btVector3 m_x;       // Position
 | ||||||
| 		btVector3 m_q;       // Previous step position/Test position
 | 		btVector3 m_q;       // Previous step position/Test position
 | ||||||
| 		btVector3 m_v;       // Velocity
 | 		btVector3 m_v;       // Velocity
 | ||||||
|         btVector3 m_vsplit;  // Temporary Velocity in addintion to velocity used in split impulse
 |  | ||||||
|         btVector3 m_vn;      // Previous step velocity
 |         btVector3 m_vn;      // Previous step velocity
 | ||||||
| 		btVector3 m_f;       // Force accumulator
 | 		btVector3 m_f;       // Force accumulator
 | ||||||
| 		btVector3 m_n;       // Normal
 | 		btVector3 m_n;       // Normal
 | ||||||
| 		btScalar m_im;       // 1/mass
 | 		btScalar m_im;       // 1/mass
 | ||||||
| 		btScalar m_area;     // Area
 | 		btScalar m_area;     // Area
 | ||||||
| 		btDbvtNode* m_leaf;  // Leaf data
 | 		btDbvtNode* m_leaf;  // Leaf data
 | ||||||
|  | 		btScalar m_penetration;   // depth of penetration
 | ||||||
| 		int m_battach : 1;   // Attached
 | 		int m_battach : 1;   // Attached
 | ||||||
|         int index; |         int index; | ||||||
| 	}; | 	}; | ||||||
|  | @ -289,6 +295,7 @@ public: | ||||||
| 		btScalar m_ra;       // Rest area
 | 		btScalar m_ra;       // Rest area
 | ||||||
| 		btDbvtNode* m_leaf;  // Leaf data
 | 		btDbvtNode* m_leaf;  // Leaf data
 | ||||||
|         btVector4 m_pcontact; // barycentric weights of the persistent contact
 |         btVector4 m_pcontact; // barycentric weights of the persistent contact
 | ||||||
|  |         btVector3 m_n0, m_n1, m_vn; | ||||||
|         int m_index; |         int m_index; | ||||||
| 	}; | 	}; | ||||||
| 	/* Tetra		*/ | 	/* Tetra		*/ | ||||||
|  | @ -717,6 +724,15 @@ public: | ||||||
| 	/* SolverState	*/ | 	/* SolverState	*/ | ||||||
| 	struct SolverState | 	struct SolverState | ||||||
| 	{ | 	{ | ||||||
|  | 		//if you add new variables, always initialize them!
 | ||||||
|  | 		SolverState() | ||||||
|  | 			:sdt(0), | ||||||
|  | 			isdt(0), | ||||||
|  | 			velmrg(0), | ||||||
|  | 			radmrg(0), | ||||||
|  | 			updmrg(0) | ||||||
|  | 		{ | ||||||
|  | 		} | ||||||
| 		btScalar sdt;     // dt*timescale
 | 		btScalar sdt;     // dt*timescale
 | ||||||
| 		btScalar isdt;    // 1/sdt
 | 		btScalar isdt;    // 1/sdt
 | ||||||
| 		btScalar velmrg;  // velocity margin
 | 		btScalar velmrg;  // velocity margin
 | ||||||
|  | @ -796,22 +812,24 @@ public: | ||||||
| 	bool m_bUpdateRtCst;               // Update runtime constants
 | 	bool m_bUpdateRtCst;               // Update runtime constants
 | ||||||
| 	btDbvt m_ndbvt;                    // Nodes tree
 | 	btDbvt m_ndbvt;                    // Nodes tree
 | ||||||
| 	btDbvt m_fdbvt;                    // Faces tree
 | 	btDbvt m_fdbvt;                    // Faces tree
 | ||||||
|  | 	btDbvntNode* m_fdbvnt;              // Faces tree with normals
 | ||||||
| 	btDbvt m_cdbvt;                    // Clusters tree
 | 	btDbvt m_cdbvt;                    // Clusters tree
 | ||||||
| 	tClusterArray m_clusters;          // Clusters
 | 	tClusterArray m_clusters;          // Clusters
 | ||||||
|     btScalar m_dampingCoefficient;     // Damping Coefficient
 | 	btScalar m_dampingCoefficient;     // Damping Coefficient
 | ||||||
|     btScalar m_sleepingThreshold; | 	btScalar m_sleepingThreshold; | ||||||
|     btScalar m_maxSpeedSquared; | 	btScalar m_maxSpeedSquared; | ||||||
|     bool m_useFaceContact; | 	btAlignedObjectArray<btVector3> m_quads; // quadrature points for collision detection
 | ||||||
|     btAlignedObjectArray<btVector3> m_quads; // quadrature points for collision detection
 | 	btScalar m_repulsionStiffness; | ||||||
|  |     btAlignedObjectArray<btVector3> m_X;   // initial positions
 | ||||||
| 
 | 
 | ||||||
|     btAlignedObjectArray<btVector4> m_renderNodesInterpolationWeights; | 	btAlignedObjectArray<btVector4> m_renderNodesInterpolationWeights; | ||||||
|     btAlignedObjectArray<btAlignedObjectArray<const btSoftBody::Node*> > m_renderNodesParents; | 	btAlignedObjectArray<btAlignedObjectArray<const btSoftBody::Node*> > m_renderNodesParents; | ||||||
|     bool m_useSelfCollision; | 	btAlignedObjectArray<btScalar> m_z; // vertical distance used in extrapolation
 | ||||||
|  | 	bool m_useSelfCollision; | ||||||
|  | 	bool m_softSoftCollision; | ||||||
| 
 | 
 | ||||||
| 	btAlignedObjectArray<bool> m_clusterConnectivity;  //cluster connectivity, for self-collision
 | 	btAlignedObjectArray<bool> m_clusterConnectivity;  //cluster connectivity, for self-collision
 | ||||||
| 
 | 
 | ||||||
| 	btTransform m_initialWorldTransform; |  | ||||||
| 
 |  | ||||||
| 	btVector3 m_windVelocity; | 	btVector3 m_windVelocity; | ||||||
| 
 | 
 | ||||||
| 	btScalar m_restLengthScale; | 	btScalar m_restLengthScale; | ||||||
|  | @ -844,11 +862,6 @@ public: | ||||||
|         m_dampingCoefficient = damping_coeff; |         m_dampingCoefficient = damping_coeff; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void setUseFaceContact(bool useFaceContact) |  | ||||||
|     { |  | ||||||
|         m_useFaceContact = false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 	///@todo: avoid internal softbody shape hack and move collision code to collision library
 | 	///@todo: avoid internal softbody shape hack and move collision code to collision library
 | ||||||
| 	virtual void setCollisionShape(btCollisionShape* collisionShape) | 	virtual void setCollisionShape(btCollisionShape* collisionShape) | ||||||
| 	{ | 	{ | ||||||
|  | @ -957,6 +970,16 @@ public: | ||||||
| 	void setVolumeMass(btScalar mass); | 	void setVolumeMass(btScalar mass); | ||||||
| 	/* Set volume density (using tetrahedrons)								*/ | 	/* Set volume density (using tetrahedrons)								*/ | ||||||
| 	void setVolumeDensity(btScalar density); | 	void setVolumeDensity(btScalar density); | ||||||
|  | 	/* Get the linear velocity of the center of mass                        */ | ||||||
|  | 	btVector3 getLinearVelocity(); | ||||||
|  | 	/* Set the linear velocity of the center of mass                        */ | ||||||
|  | 	void setLinearVelocity(const btVector3& linVel); | ||||||
|  | 	/* Set the angular velocity of the center of mass                       */ | ||||||
|  | 	void setAngularVelocity(const btVector3& angVel); | ||||||
|  |     /* Get best fit rigid transform                                         */ | ||||||
|  |     btTransform getRigidTransform(); | ||||||
|  |     /* Transform to given pose                                              */ | ||||||
|  |     void transformTo(const btTransform& trs); | ||||||
| 	/* Transform															*/ | 	/* Transform															*/ | ||||||
| 	void transform(const btTransform& trs); | 	void transform(const btTransform& trs); | ||||||
| 	/* Translate															*/ | 	/* Translate															*/ | ||||||
|  | @ -1023,6 +1046,11 @@ public: | ||||||
| 	bool rayTest(const btVector3& rayFrom, | 	bool rayTest(const btVector3& rayFrom, | ||||||
| 				 const btVector3& rayTo, | 				 const btVector3& rayTo, | ||||||
| 				 sRayCast& results); | 				 sRayCast& results); | ||||||
|  | 	bool rayFaceTest(const btVector3& rayFrom, | ||||||
|  | 					 const btVector3& rayTo, | ||||||
|  | 					 sRayCast& results); | ||||||
|  | 	int rayFaceTest(const btVector3& rayFrom, const btVector3& rayTo, | ||||||
|  | 					btScalar& mint, int& index) const; | ||||||
| 	/* Solver presets														*/ | 	/* Solver presets														*/ | ||||||
| 	void setSolver(eSolverPresets::_ preset); | 	void setSolver(eSolverPresets::_ preset); | ||||||
| 	/* predictMotion														*/ | 	/* predictMotion														*/ | ||||||
|  | @ -1120,6 +1148,7 @@ public: | ||||||
| 	int rayTest(const btVector3& rayFrom, const btVector3& rayTo, | 	int rayTest(const btVector3& rayFrom, const btVector3& rayTo, | ||||||
| 				btScalar& mint, eFeature::_& feature, int& index, bool bcountonly) const; | 				btScalar& mint, eFeature::_& feature, int& index, bool bcountonly) const; | ||||||
| 	void initializeFaceTree(); | 	void initializeFaceTree(); | ||||||
|  | 	void rebuildNodeTree(); | ||||||
| 	btVector3 evaluateCom() const; | 	btVector3 evaluateCom() const; | ||||||
| 	bool checkDeformableContact(const btCollisionObjectWrapper* colObjWrap, const btVector3& x, btScalar margin, btSoftBody::sCti& cti, bool predict = false) const; | 	bool checkDeformableContact(const btCollisionObjectWrapper* colObjWrap, const btVector3& x, btScalar margin, btSoftBody::sCti& cti, bool predict = false) const; | ||||||
|     bool checkDeformableFaceContact(const btCollisionObjectWrapper* colObjWrap, Face& f, btVector3& contact_point, btVector3& bary, btScalar margin, btSoftBody::sCti& cti, bool predict = false) const; |     bool checkDeformableFaceContact(const btCollisionObjectWrapper* colObjWrap, Face& f, btVector3& contact_point, btVector3& bary, btScalar margin, btSoftBody::sCti& cti, bool predict = false) const; | ||||||
|  | @ -1152,7 +1181,180 @@ public: | ||||||
| 	static void VSolve_Links(btSoftBody* psb, btScalar kst); | 	static void VSolve_Links(btSoftBody* psb, btScalar kst); | ||||||
| 	static psolver_t getSolver(ePSolver::_ solver); | 	static psolver_t getSolver(ePSolver::_ solver); | ||||||
| 	static vsolver_t getSolver(eVSolver::_ solver); | 	static vsolver_t getSolver(eVSolver::_ solver); | ||||||
|  | 	void geometricCollisionHandler(btSoftBody* psb); | ||||||
|  | #define SAFE_EPSILON SIMD_EPSILON*100.0 | ||||||
|  | 	void updateNode(btDbvtNode* node, bool use_velocity, bool margin) | ||||||
|  | 	{ | ||||||
|  | 		if (node->isleaf()) | ||||||
|  | 		{ | ||||||
|  | 			btSoftBody::Node* n = (btSoftBody::Node*)(node->data); | ||||||
|  | 			ATTRIBUTE_ALIGNED16(btDbvtVolume) vol; | ||||||
|  | 			btScalar pad = margin ? m_sst.radmrg : SAFE_EPSILON; // use user defined margin or margin for floating point precision
 | ||||||
|  | 			if (use_velocity) | ||||||
|  | 			{ | ||||||
|  | 				btVector3 points[2] = {n->m_x, n->m_x + m_sst.sdt * n->m_v}; | ||||||
|  | 				vol = btDbvtVolume::FromPoints(points, 2); | ||||||
|  | 				vol.Expand(btVector3(pad, pad, pad)); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				vol = btDbvtVolume::FromCR(n->m_x, pad); | ||||||
|  | 			} | ||||||
|  | 			node->volume = vol; | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			updateNode(node->childs[0], use_velocity, margin); | ||||||
|  | 			updateNode(node->childs[1], use_velocity, margin); | ||||||
|  | 			ATTRIBUTE_ALIGNED16(btDbvtVolume) vol; | ||||||
|  | 			Merge(node->childs[0]->volume, node->childs[1]->volume, vol); | ||||||
|  | 			node->volume = vol; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	 | 	 | ||||||
|  |     void updateNodeTree(bool use_velocity, bool margin) | ||||||
|  | 	{ | ||||||
|  | 		if (m_ndbvt.m_root) | ||||||
|  | 			updateNode(m_ndbvt.m_root, use_velocity, margin); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	template <class DBVTNODE> // btDbvtNode or btDbvntNode
 | ||||||
|  | 	void updateFace(DBVTNODE* node, bool use_velocity, bool margin) | ||||||
|  | 	{ | ||||||
|  | 		if (node->isleaf()) | ||||||
|  | 		{ | ||||||
|  | 			btSoftBody::Face* f = (btSoftBody::Face*)(node->data); | ||||||
|  | 			btScalar pad = margin ? m_sst.radmrg : SAFE_EPSILON; // use user defined margin or margin for floating point precision
 | ||||||
|  | 			ATTRIBUTE_ALIGNED16(btDbvtVolume) vol; | ||||||
|  | 			if (use_velocity) | ||||||
|  | 			{ | ||||||
|  | 				btVector3 points[6] = {f->m_n[0]->m_x, f->m_n[0]->m_x + m_sst.sdt * f->m_n[0]->m_v, | ||||||
|  | 					f->m_n[1]->m_x, f->m_n[1]->m_x + m_sst.sdt * f->m_n[1]->m_v, | ||||||
|  | 					f->m_n[2]->m_x, f->m_n[2]->m_x + m_sst.sdt * f->m_n[2]->m_v}; | ||||||
|  | 				vol = btDbvtVolume::FromPoints(points, 6); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				btVector3 points[3] = {f->m_n[0]->m_x, | ||||||
|  | 					f->m_n[1]->m_x, | ||||||
|  | 					f->m_n[2]->m_x}; | ||||||
|  | 				vol = btDbvtVolume::FromPoints(points, 3); | ||||||
|  | 			} | ||||||
|  | 			vol.Expand(btVector3(pad, pad, pad)); | ||||||
|  | 			node->volume = vol; | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			updateFace(node->childs[0], use_velocity, margin); | ||||||
|  | 			updateFace(node->childs[1], use_velocity, margin); | ||||||
|  | 			ATTRIBUTE_ALIGNED16(btDbvtVolume) vol; | ||||||
|  | 			Merge(node->childs[0]->volume, node->childs[1]->volume, vol); | ||||||
|  | 			node->volume = vol; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	void updateFaceTree(bool use_velocity, bool margin) | ||||||
|  | 	{ | ||||||
|  | 		if (m_fdbvt.m_root) | ||||||
|  | 			updateFace(m_fdbvt.m_root, use_velocity, margin); | ||||||
|  | 		if (m_fdbvnt) | ||||||
|  | 			updateFace(m_fdbvnt, use_velocity, margin); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	template <typename T> | ||||||
|  | 	static inline T BaryEval(const T& a, | ||||||
|  | 							 const T& b, | ||||||
|  | 							 const T& c, | ||||||
|  | 							 const btVector3& coord) | ||||||
|  | 	{ | ||||||
|  | 		return (a * coord.x() + b * coord.y() + c * coord.z()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  |     void applyRepulsionForce(btScalar timeStep, bool applySpringForce) | ||||||
|  | 	{ | ||||||
|  | 		btAlignedObjectArray<int> indices; | ||||||
|  | 		{ | ||||||
|  | 			// randomize the order of repulsive force
 | ||||||
|  | 			indices.resize(m_faceNodeContacts.size()); | ||||||
|  | 			for (int i = 0; i < m_faceNodeContacts.size(); ++i) | ||||||
|  | 				indices[i] = i; | ||||||
|  | #define NEXTRAND (seed = (1664525L * seed + 1013904223L) & 0xffffffff) | ||||||
|  | 			int i, ni; | ||||||
|  | 
 | ||||||
|  | 			for (i = 0, ni = indices.size(); i < ni; ++i) | ||||||
|  | 			{ | ||||||
|  | 				btSwap(indices[i], indices[NEXTRAND % ni]); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		for (int k = 0; k < m_faceNodeContacts.size(); ++k) | ||||||
|  | 		{ | ||||||
|  | 			int i = indices[k]; | ||||||
|  | 			btSoftBody::DeformableFaceNodeContact& c = m_faceNodeContacts[i]; | ||||||
|  | 			btSoftBody::Node* node = c.m_node; | ||||||
|  | 			btSoftBody::Face* face = c.m_face; | ||||||
|  | 			const btVector3& w = c.m_bary; | ||||||
|  | 			const btVector3& n = c.m_normal; | ||||||
|  | 			btVector3 l = node->m_x - BaryEval(face->m_n[0]->m_x, face->m_n[1]->m_x, face->m_n[2]->m_x, w); | ||||||
|  | 			btScalar d = c.m_margin - n.dot(l); | ||||||
|  | 			d = btMax(btScalar(0),d); | ||||||
|  | 			 | ||||||
|  | 			const btVector3& va = node->m_v; | ||||||
|  | 			btVector3 vb = BaryEval(face->m_n[0]->m_v, face->m_n[1]->m_v, face->m_n[2]->m_v, w); | ||||||
|  | 			btVector3 vr = va - vb; | ||||||
|  | 			const btScalar vn = btDot(vr, n); // dn < 0 <==> opposing
 | ||||||
|  | 			if (vn > OVERLAP_REDUCTION_FACTOR * d / timeStep) | ||||||
|  | 				continue; | ||||||
|  | 			btVector3 vt = vr - vn*n; | ||||||
|  | 			btScalar I = 0; | ||||||
|  | 			btScalar mass = node->m_im == 0 ? 0 : btScalar(1)/node->m_im; | ||||||
|  | 			if (applySpringForce) | ||||||
|  | 				I = -btMin(m_repulsionStiffness * timeStep * d, mass * (OVERLAP_REDUCTION_FACTOR * d / timeStep - vn)); | ||||||
|  | 			if (vn < 0) | ||||||
|  | 				I += 0.5 * mass * vn; | ||||||
|  | 			btScalar face_penetration = 0, node_penetration = node->m_penetration; | ||||||
|  | 			for (int i = 0; i < 3; ++i) | ||||||
|  | 				face_penetration =  btMax(face_penetration, face->m_n[i]->m_penetration); | ||||||
|  | 			btScalar I_tilde = .5 *I /(1.0+w.length2()); | ||||||
|  | 			 | ||||||
|  | //             double the impulse if node or face is constrained.
 | ||||||
|  |             if (face_penetration > 0 || node_penetration > 0) | ||||||
|  |                 I_tilde *= 2.0; | ||||||
|  |             if (face_penetration <= node_penetration) | ||||||
|  | 			{ | ||||||
|  | 				for (int j = 0; j < 3; ++j) | ||||||
|  | 					face->m_n[j]->m_v += w[j]*n*I_tilde*node->m_im; | ||||||
|  | 			} | ||||||
|  |             if (face_penetration >= node_penetration) | ||||||
|  | 			{ | ||||||
|  | 				node->m_v -= I_tilde*node->m_im*n; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			// apply frictional impulse
 | ||||||
|  | 			btScalar vt_norm = vt.safeNorm(); | ||||||
|  | 			if (vt_norm > SIMD_EPSILON) | ||||||
|  | 			{ | ||||||
|  | 				btScalar delta_vn = -2 * I * node->m_im; | ||||||
|  | 				btScalar mu = c.m_friction; | ||||||
|  | 				btScalar vt_new = btMax(btScalar(1) - mu * delta_vn / (vt_norm + SIMD_EPSILON), btScalar(0))*vt_norm; | ||||||
|  | 				I = 0.5 * mass * (vt_norm-vt_new); | ||||||
|  | 				vt.safeNormalize(); | ||||||
|  | 				I_tilde = .5 *I /(1.0+w.length2()); | ||||||
|  | //                 double the impulse if node or face is constrained.
 | ||||||
|  | //                if (face_penetration > 0 || node_penetration > 0)
 | ||||||
|  | //                    I_tilde *= 2.0;
 | ||||||
|  |                 if (face_penetration <= node_penetration) | ||||||
|  | 				{ | ||||||
|  | 					for (int j = 0; j < 3; ++j) | ||||||
|  | 						face->m_n[j]->m_v += w[j] * vt * I_tilde * (face->m_n[j])->m_im; | ||||||
|  | 				} | ||||||
|  |                 if (face_penetration >= node_penetration) | ||||||
|  | 				{ | ||||||
|  | 					node->m_v -= I_tilde * node->m_im * vt; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	virtual int calculateSerializeBufferSize() const; | 	virtual int calculateSerializeBufferSize() const; | ||||||
|    |    | ||||||
| 	///fills the dataBuffer and returns the struct name (and 0 on failure)
 | 	///fills the dataBuffer and returns the struct name (and 0 on failure)
 | ||||||
|  |  | ||||||
|  | @ -1300,13 +1300,23 @@ btSoftBody* btSoftBodyHelpers::CreateFromVtkFile(btSoftBodyWorldInfo& worldInfo, | ||||||
|         } |         } | ||||||
|         else if (reading_tets) |         else if (reading_tets) | ||||||
|         { |         { | ||||||
|  | 			int d; | ||||||
|  | 			ss >> d; | ||||||
|  | 			if (d != 4) | ||||||
|  | 			{ | ||||||
|  | 				printf("Load deformable failed: Only Tetrahedra are supported in VTK file.\n"); | ||||||
|  | 				fs.close(); | ||||||
|  | 				return 0; | ||||||
|  | 			} | ||||||
|             ss.ignore(128, ' '); // ignore "4"
 |             ss.ignore(128, ' '); // ignore "4"
 | ||||||
|             Index tet; |             Index tet; | ||||||
|             tet.resize(4); |             tet.resize(4); | ||||||
|             for (size_t i = 0; i < 4; i++) |             for (size_t i = 0; i < 4; i++) | ||||||
|             { |             { | ||||||
|                 ss >> tet[i]; |                 ss >> tet[i]; | ||||||
|  |                 printf("%d ", tet[i]); | ||||||
|             } |             } | ||||||
|  |             printf("\n"); | ||||||
|             indices[indices_count++] = tet; |             indices[indices_count++] = tet; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -1500,10 +1510,27 @@ void btSoftBodyHelpers::getBarycentricWeights(const btVector3& a, const btVector | ||||||
|     bary = btVector4(va6*v6, vb6*v6, vc6*v6, vd6*v6); |     bary = btVector4(va6*v6, vb6*v6, vc6*v6, vd6*v6); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Given a simplex with vertices a,b,c, find the barycentric weights of p in this simplex. bary[3] = 0.
 | ||||||
|  | void btSoftBodyHelpers::getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& p, btVector4& bary) | ||||||
|  | { | ||||||
|  |     btVector3 v0 = b - a, v1 = c - a, v2 = p - a; | ||||||
|  |     btScalar d00 = btDot(v0, v0); | ||||||
|  |     btScalar d01 = btDot(v0, v1); | ||||||
|  |     btScalar d11 = btDot(v1, v1); | ||||||
|  |     btScalar d20 = btDot(v2, v0); | ||||||
|  |     btScalar d21 = btDot(v2, v1); | ||||||
|  |     btScalar invDenom = 1.0 / (d00 * d11 - d01 * d01); | ||||||
|  |     bary[1] = (d11 * d20 - d01 * d21) * invDenom; | ||||||
|  |     bary[2] = (d00 * d21 - d01 * d20) * invDenom; | ||||||
|  |     bary[0] = 1.0 - bary[1] - bary[2]; | ||||||
|  |     bary[3] = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // Iterate through all render nodes to find the simulation tetrahedron that contains the render node and record the barycentric weights
 | // Iterate through all render nodes to find the simulation tetrahedron that contains the render node and record the barycentric weights
 | ||||||
| // If the node is not inside any tetrahedron, assign it to the tetrahedron in which the node has the least negative barycentric weight
 | // If the node is not inside any tetrahedron, assign it to the tetrahedron in which the node has the least negative barycentric weight
 | ||||||
| void btSoftBodyHelpers::interpolateBarycentricWeights(btSoftBody* psb) | void btSoftBodyHelpers::interpolateBarycentricWeights(btSoftBody* psb) | ||||||
| { | { | ||||||
|  |     psb->m_z.resize(0); | ||||||
|     psb->m_renderNodesInterpolationWeights.resize(psb->m_renderNodes.size()); |     psb->m_renderNodesInterpolationWeights.resize(psb->m_renderNodes.size()); | ||||||
|     psb->m_renderNodesParents.resize(psb->m_renderNodes.size()); |     psb->m_renderNodesParents.resize(psb->m_renderNodes.size()); | ||||||
|     for (int i = 0; i < psb->m_renderNodes.size(); ++i) |     for (int i = 0; i < psb->m_renderNodes.size(); ++i) | ||||||
|  | @ -1513,7 +1540,6 @@ void btSoftBodyHelpers::interpolateBarycentricWeights(btSoftBody* psb) | ||||||
|         btVector4 optimal_bary; |         btVector4 optimal_bary; | ||||||
|         btScalar min_bary_weight = -1e3; |         btScalar min_bary_weight = -1e3; | ||||||
|         btAlignedObjectArray<const btSoftBody::Node*> optimal_parents; |         btAlignedObjectArray<const btSoftBody::Node*> optimal_parents; | ||||||
|         bool found = false; |  | ||||||
|         for (int j = 0; j < psb->m_tetras.size(); ++j) |         for (int j = 0; j < psb->m_tetras.size(); ++j) | ||||||
|         { |         { | ||||||
|             const btSoftBody::Tetra& t = psb->m_tetras[j]; |             const btSoftBody::Tetra& t = psb->m_tetras[j]; | ||||||
|  | @ -1544,3 +1570,55 @@ void btSoftBodyHelpers::interpolateBarycentricWeights(btSoftBody* psb) | ||||||
|         psb->m_renderNodesParents[i] = optimal_parents; |         psb->m_renderNodesParents[i] = optimal_parents; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Iterate through all render nodes to find the simulation triangle that's closest to the node in the barycentric sense.
 | ||||||
|  | void btSoftBodyHelpers::extrapolateBarycentricWeights(btSoftBody* psb) | ||||||
|  | { | ||||||
|  |     psb->m_renderNodesInterpolationWeights.resize(psb->m_renderNodes.size()); | ||||||
|  |     psb->m_renderNodesParents.resize(psb->m_renderNodes.size()); | ||||||
|  |     psb->m_z.resize(psb->m_renderNodes.size()); | ||||||
|  |     for (int i = 0; i < psb->m_renderNodes.size(); ++i) | ||||||
|  |     { | ||||||
|  |         const btVector3& p = psb->m_renderNodes[i].m_x; | ||||||
|  |         btVector4 bary; | ||||||
|  |         btVector4 optimal_bary; | ||||||
|  |         btScalar min_bary_weight = -SIMD_INFINITY; | ||||||
|  |         btAlignedObjectArray<const btSoftBody::Node*> optimal_parents; | ||||||
|  |         btScalar dist = 0, optimal_dist = 0; | ||||||
|  |         for (int j = 0; j < psb->m_faces.size(); ++j) | ||||||
|  |         { | ||||||
|  |             const btSoftBody::Face& f = psb->m_faces[j]; | ||||||
|  |             btVector3 n = btCross(f.m_n[1]->m_x - f.m_n[0]->m_x,  f.m_n[2]->m_x - f.m_n[0]->m_x); | ||||||
|  |             btVector3 unit_n = n.normalized(); | ||||||
|  |             dist = (p-f.m_n[0]->m_x).dot(unit_n); | ||||||
|  |             btVector3 proj_p = p - dist*unit_n; | ||||||
|  |             getBarycentricWeights(f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, proj_p, bary); | ||||||
|  |             btScalar new_min_bary_weight = bary[0]; | ||||||
|  |             for (int k = 1; k < 3; ++k) | ||||||
|  |             { | ||||||
|  |                 new_min_bary_weight = btMin(new_min_bary_weight, bary[k]); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // p is out of the current best triangle, we found a traingle that's better
 | ||||||
|  |             bool better_than_closest_outisde = (new_min_bary_weight > min_bary_weight && min_bary_weight<0.); | ||||||
|  |             // p is inside of the current best triangle, we found a triangle that's better
 | ||||||
|  |             bool better_than_best_inside = (new_min_bary_weight>=0 &&  min_bary_weight>=0 && btFabs(dist)<btFabs(optimal_dist)); | ||||||
|  | 
 | ||||||
|  |             if (better_than_closest_outisde || better_than_best_inside) | ||||||
|  |             { | ||||||
|  |                 btAlignedObjectArray<const btSoftBody::Node*> parents; | ||||||
|  |                 parents.push_back(f.m_n[0]); | ||||||
|  |                 parents.push_back(f.m_n[1]); | ||||||
|  |                 parents.push_back(f.m_n[2]); | ||||||
|  |                 optimal_parents = parents; | ||||||
|  |                 optimal_bary = bary; | ||||||
|  |                 optimal_dist = dist; | ||||||
|  |                 min_bary_weight = new_min_bary_weight; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         psb->m_renderNodesInterpolationWeights[i] = optimal_bary; | ||||||
|  |         psb->m_renderNodesParents[i] = optimal_parents; | ||||||
|  |         psb->m_z[i] = optimal_dist; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -148,8 +148,12 @@ struct btSoftBodyHelpers | ||||||
|      |      | ||||||
|     static void getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, const btVector3& p, btVector4& bary); |     static void getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, const btVector3& p, btVector4& bary); | ||||||
|      |      | ||||||
|  |     static void getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& p, btVector4& bary); | ||||||
|  |      | ||||||
|     static void interpolateBarycentricWeights(btSoftBody* psb); |     static void interpolateBarycentricWeights(btSoftBody* psb); | ||||||
|      |      | ||||||
|  |     static void extrapolateBarycentricWeights(btSoftBody* psb); | ||||||
|  |      | ||||||
|     static void generateBoundaryFaces(btSoftBody* psb); |     static void generateBoundaryFaces(btSoftBody* psb); | ||||||
|      |      | ||||||
|     static void duplicateFaces(const char* filename, const btSoftBody* psb); |     static void duplicateFaces(const char* filename, const btSoftBody* psb); | ||||||
|  |  | ||||||
|  | @ -18,7 +18,6 @@ subject to the following restrictions: | ||||||
| #define _BT_SOFT_BODY_INTERNALS_H | #define _BT_SOFT_BODY_INTERNALS_H | ||||||
| 
 | 
 | ||||||
| #include "btSoftBody.h" | #include "btSoftBody.h" | ||||||
| 
 |  | ||||||
| #include "LinearMath/btQuickprof.h" | #include "LinearMath/btQuickprof.h" | ||||||
| #include "LinearMath/btPolarDecomposition.h" | #include "LinearMath/btPolarDecomposition.h" | ||||||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" | #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" | ||||||
|  | @ -29,9 +28,10 @@ subject to the following restrictions: | ||||||
| #include "BulletDynamics/Featherstone/btMultiBodyConstraint.h" | #include "BulletDynamics/Featherstone/btMultiBodyConstraint.h" | ||||||
| #include <string.h>  //for memset
 | #include <string.h>  //for memset
 | ||||||
| #include <cmath> | #include <cmath> | ||||||
|  | #include "poly34.h" | ||||||
| 
 | 
 | ||||||
| // Given a multibody link, a contact point and a contact direction, fill in the jacobian data needed to calculate the velocity change given an impulse in the contact direction
 | // Given a multibody link, a contact point and a contact direction, fill in the jacobian data needed to calculate the velocity change given an impulse in the contact direction
 | ||||||
| static void findJacobian(const btMultiBodyLinkCollider* multibodyLinkCol, | static SIMD_FORCE_INLINE void findJacobian(const btMultiBodyLinkCollider* multibodyLinkCol, | ||||||
|                          btMultiBodyJacobianData& jacobianData, |                          btMultiBodyJacobianData& jacobianData, | ||||||
|                          const btVector3& contact_point, |                          const btVector3& contact_point, | ||||||
|                          const btVector3& dir) |                          const btVector3& dir) | ||||||
|  | @ -44,7 +44,7 @@ static void findJacobian(const btMultiBodyLinkCollider* multibodyLinkCol, | ||||||
|     multibodyLinkCol->m_multiBody->fillContactJacobianMultiDof(multibodyLinkCol->m_link, contact_point, dir, jac, jacobianData.scratch_r, jacobianData.scratch_v, jacobianData.scratch_m); |     multibodyLinkCol->m_multiBody->fillContactJacobianMultiDof(multibodyLinkCol->m_link, contact_point, dir, jac, jacobianData.scratch_r, jacobianData.scratch_v, jacobianData.scratch_m); | ||||||
|     multibodyLinkCol->m_multiBody->calcAccelerationDeltasMultiDof(&jacobianData.m_jacobians[0], &jacobianData.m_deltaVelocitiesUnitImpulse[0], jacobianData.scratch_r, jacobianData.scratch_v); |     multibodyLinkCol->m_multiBody->calcAccelerationDeltasMultiDof(&jacobianData.m_jacobians[0], &jacobianData.m_deltaVelocitiesUnitImpulse[0], jacobianData.scratch_r, jacobianData.scratch_v); | ||||||
| } | } | ||||||
| static btVector3 generateUnitOrthogonalVector(const btVector3& u) | static SIMD_FORCE_INLINE btVector3 generateUnitOrthogonalVector(const btVector3& u) | ||||||
| { | { | ||||||
|     btScalar ux = u.getX(); |     btScalar ux = u.getX(); | ||||||
|     btScalar uy = u.getY(); |     btScalar uy = u.getY(); | ||||||
|  | @ -62,6 +62,571 @@ static btVector3 generateUnitOrthogonalVector(const btVector3& u) | ||||||
|     v.normalize(); |     v.normalize(); | ||||||
|     return v; |     return v; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE bool proximityTest(const btVector3& x1, const btVector3& x2, const btVector3& x3, const btVector3& x4, const btVector3& normal, const btScalar& mrg, btVector3& bary) | ||||||
|  | { | ||||||
|  |     btVector3 x43 = x4-x3; | ||||||
|  |     if (std::abs(x43.dot(normal)) > mrg) | ||||||
|  |         return false; | ||||||
|  |     btVector3 x13 = x1-x3; | ||||||
|  |     btVector3 x23 = x2-x3; | ||||||
|  |     btScalar a11 = x13.length2(); | ||||||
|  |     btScalar a22 = x23.length2(); | ||||||
|  |     btScalar a12 = x13.dot(x23); | ||||||
|  |     btScalar b1 = x13.dot(x43); | ||||||
|  |     btScalar b2 = x23.dot(x43); | ||||||
|  |     btScalar det = a11*a22 - a12*a12; | ||||||
|  |     if (det < SIMD_EPSILON) | ||||||
|  |         return false; | ||||||
|  |     btScalar w1 = (b1*a22-b2*a12)/det; | ||||||
|  |     btScalar w2 = (b2*a11-b1*a12)/det; | ||||||
|  |     btScalar w3 = 1-w1-w2; | ||||||
|  |     btScalar delta = mrg / std::sqrt(0.5*std::abs(x13.cross(x23).safeNorm())); | ||||||
|  |     bary = btVector3(w1,w2,w3); | ||||||
|  |     for (int i = 0; i < 3; ++i) | ||||||
|  |     { | ||||||
|  |         if (bary[i] < -delta || bary[i] > 1+delta) | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | static const int KDOP_COUNT = 13; | ||||||
|  | static btVector3 dop[KDOP_COUNT]={btVector3(1,0,0), | ||||||
|  | 	btVector3(0,1,0), | ||||||
|  | 	btVector3(0,0,1), | ||||||
|  | 	btVector3(1,1,0), | ||||||
|  | 	btVector3(1,0,1), | ||||||
|  | 	btVector3(0,1,1), | ||||||
|  | 	btVector3(1,-1,0), | ||||||
|  | 	btVector3(1,0,-1), | ||||||
|  | 	btVector3(0,1,-1), | ||||||
|  | 	btVector3(1,1,1), | ||||||
|  | 	btVector3(1,-1,1), | ||||||
|  | 	btVector3(1,1,-1), | ||||||
|  | 	btVector3(1,-1,-1) | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static inline int getSign(const btVector3& n, const btVector3& x) | ||||||
|  | { | ||||||
|  | 	btScalar d = n.dot(x); | ||||||
|  | 	if (d>SIMD_EPSILON) | ||||||
|  | 		return 1; | ||||||
|  | 	if (d<-SIMD_EPSILON) | ||||||
|  | 		return -1; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE bool hasSeparatingPlane(const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt) | ||||||
|  | { | ||||||
|  | 	btVector3 hex[6] = {face->m_n[0]->m_x - node->m_x, | ||||||
|  | 		face->m_n[1]->m_x - node->m_x, | ||||||
|  | 		face->m_n[2]->m_x - node->m_x, | ||||||
|  | 		face->m_n[0]->m_x + dt*face->m_n[0]->m_v - node->m_x, | ||||||
|  | 		face->m_n[1]->m_x + dt*face->m_n[1]->m_v - node->m_x, | ||||||
|  | 		face->m_n[2]->m_x + dt*face->m_n[2]->m_v - node->m_x | ||||||
|  | 	}; | ||||||
|  | 	btVector3 segment = dt*node->m_v; | ||||||
|  | 	for (int i = 0; i < KDOP_COUNT; ++i) | ||||||
|  | 	{ | ||||||
|  | 		int s = getSign(dop[i], segment); | ||||||
|  | 		int j = 0; | ||||||
|  | 		for (; j < 6; ++j) | ||||||
|  | 		{ | ||||||
|  | 			if (getSign(dop[i], hex[j]) == s) | ||||||
|  | 				break; | ||||||
|  | 		} | ||||||
|  | 		if (j == 6) | ||||||
|  | 			return true; | ||||||
|  | 	} | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE bool nearZero(const btScalar& a) | ||||||
|  | { | ||||||
|  |     return (a>-SAFE_EPSILON && a<SAFE_EPSILON); | ||||||
|  | } | ||||||
|  | static SIMD_FORCE_INLINE bool sameSign(const btScalar& a, const btScalar& b) | ||||||
|  | { | ||||||
|  |     return (nearZero(a) || nearZero(b) || (a>SAFE_EPSILON && b>SAFE_EPSILON) || (a<-SAFE_EPSILON && b<-SAFE_EPSILON)); | ||||||
|  | } | ||||||
|  | static SIMD_FORCE_INLINE bool diffSign(const btScalar& a, const btScalar& b) | ||||||
|  | { | ||||||
|  |     return !sameSign(a, b); | ||||||
|  | } | ||||||
|  | inline btScalar evaluateBezier2(const btScalar &p0, const btScalar &p1, const btScalar &p2, const btScalar &t, const btScalar &s) | ||||||
|  | { | ||||||
|  |     btScalar s2 = s*s; | ||||||
|  |     btScalar t2 = t*t; | ||||||
|  |      | ||||||
|  |     return p0*s2+p1*btScalar(2.0)*s*t+p2*t2; | ||||||
|  | } | ||||||
|  | inline btScalar evaluateBezier(const btScalar &p0, const btScalar &p1, const btScalar &p2, const btScalar &p3, const btScalar &t, const btScalar &s) | ||||||
|  | { | ||||||
|  |     btScalar s2 = s*s; | ||||||
|  |     btScalar s3 = s2*s; | ||||||
|  |     btScalar t2 = t*t; | ||||||
|  |     btScalar t3 = t2*t; | ||||||
|  |      | ||||||
|  |     return p0*s3+p1*btScalar(3.0)*s2*t+p2*btScalar(3.0)*s*t2+p3*t3; | ||||||
|  | } | ||||||
|  | static SIMD_FORCE_INLINE bool getSigns(bool type_c, const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& t0, const btScalar& t1, btScalar <0, btScalar <1) | ||||||
|  | { | ||||||
|  |     if (sameSign(t0, t1)) { | ||||||
|  |         lt0 = t0; | ||||||
|  |         lt1 = t0; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (type_c || diffSign(k0, k3)) { | ||||||
|  |         btScalar ft = evaluateBezier(k0, k1, k2, k3, t0, -t1); | ||||||
|  |         if (t0<-0) | ||||||
|  |             ft = -ft; | ||||||
|  |          | ||||||
|  |         if (sameSign(ft, k0)) { | ||||||
|  |             lt0 = t1; | ||||||
|  |             lt1 = t1; | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             lt0 = t0; | ||||||
|  |             lt1 = t0; | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (!type_c) { | ||||||
|  |         btScalar ft = evaluateBezier(k0, k1, k2, k3, t0, -t1); | ||||||
|  |         if (t0<-0) | ||||||
|  |             ft = -ft; | ||||||
|  |          | ||||||
|  |         if (diffSign(ft, k0)) { | ||||||
|  |             lt0 = t0; | ||||||
|  |             lt1 = t1; | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         btScalar fk = evaluateBezier2(k1-k0, k2-k1, k3-k2, t0, -t1); | ||||||
|  |          | ||||||
|  |         if (sameSign(fk, k1-k0)) | ||||||
|  |             lt0 = lt1 = t1; | ||||||
|  |         else | ||||||
|  |             lt0 = lt1 = t0; | ||||||
|  |          | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE void getBernsteinCoeff(const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt, btScalar& k0, btScalar& k1, btScalar& k2, btScalar& k3) | ||||||
|  | { | ||||||
|  |     const btVector3& n0 = face->m_n0; | ||||||
|  |     const btVector3& n1 = face->m_n1; | ||||||
|  |     btVector3 n_hat = n0 + n1 - face->m_vn; | ||||||
|  |     btVector3 p0ma0 = node->m_x - face->m_n[0]->m_x; | ||||||
|  |     btVector3 p1ma1 = node->m_q - face->m_n[0]->m_q; | ||||||
|  |     k0 = (p0ma0).dot(n0) * 3.0; | ||||||
|  |     k1 = (p0ma0).dot(n_hat) + (p1ma1).dot(n0); | ||||||
|  |     k2 = (p1ma1).dot(n_hat) + (p0ma0).dot(n1); | ||||||
|  |     k3 = (p1ma1).dot(n1) * 3.0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE void polyDecomposition(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& j0, const btScalar& j1, const btScalar& j2, btScalar& u0, btScalar& u1, btScalar& v0, btScalar& v1) | ||||||
|  | { | ||||||
|  |     btScalar denom = 4.0 * (j1-j2) * (j1-j0) + (j2-j0) * (j2-j0); | ||||||
|  |     u0 = (2.0*(j1-j2)*(3.0*k1-2.0*k0-k3) - (j0-j2)*(3.0*k2-2.0*k3-k0)) / denom; | ||||||
|  |     u1 = (2.0*(j1-j0)*(3.0*k2-2.0*k3-k0) - (j2-j0)*(3.0*k1-2.0*k0-k3)) / denom; | ||||||
|  |     v0 = k0-u0*j0; | ||||||
|  |     v1 = k3-u1*j2; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE bool rootFindingLemma(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3) | ||||||
|  | { | ||||||
|  |     btScalar u0, u1, v0, v1; | ||||||
|  |     btScalar j0 = 3.0*(k1-k0); | ||||||
|  |     btScalar j1 = 3.0*(k2-k1); | ||||||
|  |     btScalar j2 = 3.0*(k3-k2); | ||||||
|  |     polyDecomposition(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1); | ||||||
|  |     if (sameSign(v0, v1)) | ||||||
|  |     { | ||||||
|  |         btScalar Ypa = j0*(1.0-v0)*(1.0-v0) + 2.0*j1*v0*(1.0-v0) + j2*v0*v0; // Y'(v0)
 | ||||||
|  |         if (sameSign(Ypa, j0)) | ||||||
|  |         { | ||||||
|  |             return (diffSign(k0,v1)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return diffSign(k0,v0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE void getJs(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btSoftBody::Node* a, const btSoftBody::Node* b, const btSoftBody::Node* c, const btSoftBody::Node* p, const btScalar& dt, btScalar& j0,  btScalar& j1, btScalar& j2) | ||||||
|  | { | ||||||
|  |     const btVector3& a0 = a->m_x; | ||||||
|  |     const btVector3& b0 = b->m_x; | ||||||
|  |     const btVector3& c0 = c->m_x; | ||||||
|  |     const btVector3& va = a->m_v; | ||||||
|  |     const btVector3& vb = b->m_v; | ||||||
|  |     const btVector3& vc = c->m_v; | ||||||
|  |     const btVector3 a1 = a0 + dt*va; | ||||||
|  |     const btVector3 b1 = b0 + dt*vb; | ||||||
|  |     const btVector3 c1 = c0 + dt*vc; | ||||||
|  |     btVector3 n0 = (b0-a0).cross(c0-a0); | ||||||
|  |     btVector3 n1 = (b1-a1).cross(c1-a1); | ||||||
|  |     btVector3 n_hat = n0+n1 - dt*dt*(vb-va).cross(vc-va); | ||||||
|  |     const btVector3& p0 = p->m_x; | ||||||
|  |     const btVector3& vp = p->m_v; | ||||||
|  |     btVector3 p1 = p0 + dt*vp; | ||||||
|  |     btVector3 m0 = (b0-p0).cross(c0-p0); | ||||||
|  |     btVector3 m1 = (b1-p1).cross(c1-p1); | ||||||
|  |     btVector3 m_hat = m0+m1 - dt*dt*(vb-vp).cross(vc-vp); | ||||||
|  |     btScalar l0 = m0.dot(n0); | ||||||
|  |     btScalar l1 = 0.25 * (m0.dot(n_hat) + m_hat.dot(n0)); | ||||||
|  |     btScalar l2 = btScalar(1)/btScalar(6)*(m0.dot(n1) + m_hat.dot(n_hat) + m1.dot(n0)); | ||||||
|  |     btScalar l3 = 0.25 * (m_hat.dot(n1) + m1.dot(n_hat)); | ||||||
|  |     btScalar l4 = m1.dot(n1); | ||||||
|  |      | ||||||
|  |     btScalar k1p = 0.25 * k0 + 0.75 * k1; | ||||||
|  |     btScalar k2p = 0.5 * k1 + 0.5 * k2; | ||||||
|  |     btScalar k3p = 0.75 * k2 + 0.25 * k3; | ||||||
|  |      | ||||||
|  |     btScalar s0 = (l1 * k0 - l0 * k1p)*4.0; | ||||||
|  |     btScalar s1 = (l2 * k0 - l0 * k2p)*2.0; | ||||||
|  |     btScalar s2 = (l3 * k0 - l0 * k3p)*btScalar(4)/btScalar(3); | ||||||
|  |     btScalar s3 = l4 * k0 - l0 * k3; | ||||||
|  |      | ||||||
|  |     j0 = (s1*k0 - s0*k1) * 3.0; | ||||||
|  |     j1 = (s2*k0 - s0*k2) * 1.5; | ||||||
|  |     j2 = (s3*k0 - s0*k3); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE bool signDetermination1Internal(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& u0, const btScalar& u1, const btScalar& v0, const btScalar& v1) | ||||||
|  | { | ||||||
|  |     btScalar Yu0 = k0*(1.0-u0)*(1.0-u0)*(1.0-u0) + 3.0*k1*u0*(1.0-u0)*(1.0-u0) + 3.0*k2*u0*u0*(1.0-u0) + k3*u0*u0*u0; // Y(u0)
 | ||||||
|  |     btScalar Yv0 = k0*(1.0-v0)*(1.0-v0)*(1.0-v0) + 3.0*k1*v0*(1.0-v0)*(1.0-v0) + 3.0*k2*v0*v0*(1.0-v0) + k3*v0*v0*v0; // Y(v0)
 | ||||||
|  | 
 | ||||||
|  |     btScalar sign_Ytp = (u0 > u1) ? Yu0 : -Yu0; | ||||||
|  |     btScalar L = sameSign(sign_Ytp, k0) ? u1 : u0; | ||||||
|  |     sign_Ytp = (v0 > v1) ? Yv0 : -Yv0; | ||||||
|  |     btScalar K = (sameSign(sign_Ytp,k0)) ? v1 : v0; | ||||||
|  |     return diffSign(L,K); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE bool signDetermination2Internal(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& j0, const btScalar& j1, const btScalar& j2, const btScalar& u0, const btScalar& u1, const btScalar& v0, const btScalar& v1) | ||||||
|  | { | ||||||
|  |     btScalar Yu0 = k0*(1.0-u0)*(1.0-u0)*(1.0-u0) + 3.0*k1*u0*(1.0-u0)*(1.0-u0) + 3.0*k2*u0*u0*(1.0-u0) + k3*u0*u0*u0; // Y(u0)
 | ||||||
|  |     btScalar sign_Ytp = (u0 > u1) ? Yu0 : -Yu0, L1, L2; | ||||||
|  |     if (diffSign(sign_Ytp,k0)) | ||||||
|  |     { | ||||||
|  |         L1 = u0; | ||||||
|  |         L2 = u1; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         btScalar Yp_u0 = j0*(1.0-u0)*(1.0-u0) + 2.0*j1*(1.0-u0)*u0 + j2*u0*u0; | ||||||
|  |         if (sameSign(Yp_u0,j0)) | ||||||
|  |         { | ||||||
|  |             L1 = u1; | ||||||
|  |             L2 = u1; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             L1 = u0; | ||||||
|  |             L2 = u0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     btScalar Yv0 = k0*(1.0-v0)*(1.0-v0)*(1.0-v0) + 3.0*k1*v0*(1.0-v0)*(1.0-v0) + 3.0*k2*v0*v0*(1.0-v0) + k3*v0*v0*v0; // Y(uv0)
 | ||||||
|  |     sign_Ytp = (v0 > v1) ? Yv0 : -Yv0; | ||||||
|  |     btScalar K1, K2; | ||||||
|  |     if (diffSign(sign_Ytp,k0)) | ||||||
|  |     { | ||||||
|  |         K1 = v0; | ||||||
|  |         K2 = v1; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         btScalar Yp_v0 = j0*(1.0-v0)*(1.0-v0) + 2.0*j1*(1.0-v0)*v0 + j2*v0*v0; | ||||||
|  |         if (sameSign(Yp_v0,j0)) | ||||||
|  |         { | ||||||
|  |             K1 = v1; | ||||||
|  |             K2 = v1; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             K1 = v0; | ||||||
|  |             K2 = v0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return (diffSign(K1, L1) || diffSign(L2, K2)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE bool signDetermination1(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt) | ||||||
|  | { | ||||||
|  |     btScalar j0, j1, j2, u0, u1, v0, v1; | ||||||
|  |     // p1
 | ||||||
|  |     getJs(k0,k1,k2,k3,face->m_n[0], face->m_n[1], face->m_n[2], node, dt, j0, j1, j2); | ||||||
|  |     if (nearZero(j0+j2-j1*2.0)) | ||||||
|  |     { | ||||||
|  |         btScalar lt0, lt1; | ||||||
|  |         getSigns(true, k0, k1, k2, k3, j0, j2, lt0, lt1); | ||||||
|  |         if (lt0 < -SAFE_EPSILON) | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         polyDecomposition(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1); | ||||||
|  |         if (!signDetermination1Internal(k0,k1,k2,k3,u0,u1,v0,v1)) | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|  |     // p2
 | ||||||
|  |     getJs(k0,k1,k2,k3,face->m_n[1], face->m_n[2], face->m_n[0], node, dt, j0, j1, j2); | ||||||
|  |     if (nearZero(j0+j2-j1*2.0)) | ||||||
|  |     { | ||||||
|  |         btScalar lt0, lt1; | ||||||
|  |         getSigns(true, k0, k1, k2, k3, j0, j2, lt0, lt1); | ||||||
|  |         if (lt0 < -SAFE_EPSILON) | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         polyDecomposition(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1); | ||||||
|  |         if (!signDetermination1Internal(k0,k1,k2,k3,u0,u1,v0,v1)) | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|  |     // p3
 | ||||||
|  |     getJs(k0,k1,k2,k3,face->m_n[2], face->m_n[0], face->m_n[1], node, dt, j0, j1, j2); | ||||||
|  |     if (nearZero(j0+j2-j1*2.0)) | ||||||
|  |     { | ||||||
|  |         btScalar lt0, lt1; | ||||||
|  |         getSigns(true, k0, k1, k2, k3, j0, j2, lt0, lt1); | ||||||
|  |         if (lt0 < -SAFE_EPSILON) | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         polyDecomposition(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1); | ||||||
|  |         if (!signDetermination1Internal(k0,k1,k2,k3,u0,u1,v0,v1)) | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE bool signDetermination2(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt) | ||||||
|  | { | ||||||
|  |     btScalar j0, j1, j2, u0, u1, v0, v1; | ||||||
|  |     // p1
 | ||||||
|  |     getJs(k0,k1,k2,k3,face->m_n[0], face->m_n[1], face->m_n[2], node, dt, j0, j1, j2); | ||||||
|  |     if (nearZero(j0+j2-j1*2.0)) | ||||||
|  |     { | ||||||
|  |         btScalar lt0, lt1; | ||||||
|  |         bool bt0 = true, bt1=true; | ||||||
|  |         getSigns(false, k0, k1, k2, k3, j0, j2, lt0, lt1); | ||||||
|  |         if (lt0 < -SAFE_EPSILON) | ||||||
|  |             bt0 = false; | ||||||
|  |         if (lt1 < -SAFE_EPSILON) | ||||||
|  |             bt1 = false; | ||||||
|  |         if (!bt0 && !bt1) | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         polyDecomposition(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1); | ||||||
|  |         if (!signDetermination2Internal(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1)) | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|  |     // p2
 | ||||||
|  |     getJs(k0,k1,k2,k3,face->m_n[1], face->m_n[2], face->m_n[0], node, dt, j0, j1, j2); | ||||||
|  |     if (nearZero(j0+j2-j1*2.0)) | ||||||
|  |     { | ||||||
|  |         btScalar lt0, lt1; | ||||||
|  |         bool bt0=true, bt1=true; | ||||||
|  |         getSigns(false, k0, k1, k2, k3, j0, j2, lt0, lt1); | ||||||
|  |         if (lt0 < -SAFE_EPSILON) | ||||||
|  |             bt0 = false; | ||||||
|  |         if (lt1 < -SAFE_EPSILON) | ||||||
|  |             bt1 = false; | ||||||
|  |         if (!bt0 && !bt1) | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         polyDecomposition(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1); | ||||||
|  |         if (!signDetermination2Internal(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1)) | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|  |     // p3
 | ||||||
|  |     getJs(k0,k1,k2,k3,face->m_n[2], face->m_n[0], face->m_n[1], node, dt, j0, j1, j2); | ||||||
|  |     if (nearZero(j0+j2-j1*2.0)) | ||||||
|  |     { | ||||||
|  |         btScalar lt0, lt1; | ||||||
|  |         bool bt0=true, bt1=true; | ||||||
|  |         getSigns(false, k0, k1, k2, k3, j0, j2, lt0, lt1); | ||||||
|  |         if (lt0 < -SAFE_EPSILON) | ||||||
|  |             bt0 = false; | ||||||
|  |         if (lt1 < -SAFE_EPSILON) | ||||||
|  |             bt1 = false; | ||||||
|  |         if (!bt0 && !bt1) | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         polyDecomposition(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1); | ||||||
|  |         if (!signDetermination2Internal(k0,k1,k2,k3,j0,j1,j2,u0,u1,v0,v1)) | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE bool coplanarAndInsideTest(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt) | ||||||
|  | { | ||||||
|  |     // Coplanar test
 | ||||||
|  |     if (diffSign(k1-k0, k3-k2)) | ||||||
|  |     { | ||||||
|  |         // Case b:
 | ||||||
|  |         if (sameSign(k0, k3) && !rootFindingLemma(k0,k1,k2,k3)) | ||||||
|  |             return false; | ||||||
|  |         // inside test
 | ||||||
|  |         return signDetermination2(k0, k1, k2, k3, face, node, dt); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         // Case c:
 | ||||||
|  |         if (sameSign(k0, k3)) | ||||||
|  |             return false; | ||||||
|  |         // inside test
 | ||||||
|  |         return signDetermination1(k0, k1, k2, k3, face, node, dt); | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | static SIMD_FORCE_INLINE bool conservativeCulling(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& mrg) | ||||||
|  | { | ||||||
|  |     if (k0 > mrg && k1 > mrg && k2 > mrg && k3 > mrg) | ||||||
|  |         return true; | ||||||
|  |     if (k0 < -mrg && k1 < -mrg && k2 < -mrg && k3 < -mrg) | ||||||
|  |         return true; | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE bool bernsteinVFTest(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& mrg, const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt) | ||||||
|  | { | ||||||
|  |     if (conservativeCulling(k0, k1, k2, k3, mrg)) | ||||||
|  |         return false; | ||||||
|  |     return coplanarAndInsideTest(k0, k1, k2, k3, face, node, dt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE void deCasteljau(const btScalar& k0, const btScalar& k1, const btScalar& k2, const btScalar& k3, const btScalar& t0, btScalar& k10, btScalar& k20, btScalar& k30, btScalar& k21, btScalar& k12) | ||||||
|  | { | ||||||
|  |     k10 = k0*(1.0-t0) + k1*t0; | ||||||
|  |     btScalar k11 = k1*(1.0-t0) + k2*t0; | ||||||
|  |     k12 = k2*(1.0-t0) + k3*t0; | ||||||
|  |     k20 = k10*(1.0-t0) + k11*t0; | ||||||
|  |     k21 = k11*(1.0-t0) + k12*t0; | ||||||
|  |     k30 = k20*(1.0-t0) + k21*t0; | ||||||
|  | } | ||||||
|  | static SIMD_FORCE_INLINE bool bernsteinVFTest(const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt, const btScalar& mrg) | ||||||
|  | { | ||||||
|  |     btScalar k0, k1, k2, k3; | ||||||
|  |     getBernsteinCoeff(face, node, dt, k0, k1, k2, k3); | ||||||
|  |     if (conservativeCulling(k0, k1, k2, k3, mrg)) | ||||||
|  |         return false; | ||||||
|  |     return true; | ||||||
|  |     if (diffSign(k2-2.0*k1+k0, k3-2.0*k2+k1)) | ||||||
|  |     { | ||||||
|  |         btScalar k10, k20, k30, k21, k12; | ||||||
|  |         btScalar t0 = (k2-2.0*k1+k0)/(k0-3.0*k1+3.0*k2-k3); | ||||||
|  |         deCasteljau(k0, k1, k2, k3, t0, k10, k20, k30, k21, k12); | ||||||
|  |         return bernsteinVFTest(k0, k10, k20, k30, mrg, face, node, dt) || bernsteinVFTest(k30, k21, k12, k3, mrg, face, node, dt); | ||||||
|  |     } | ||||||
|  |     return coplanarAndInsideTest(k0, k1, k2, k3, face, node, dt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SIMD_FORCE_INLINE bool continuousCollisionDetection(const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt, const btScalar& mrg, btVector3& bary) | ||||||
|  | { | ||||||
|  |     if (hasSeparatingPlane(face, node, dt)) | ||||||
|  |         return false; | ||||||
|  |     btVector3 x21 = face->m_n[1]->m_x - face->m_n[0]->m_x; | ||||||
|  |     btVector3 x31 = face->m_n[2]->m_x - face->m_n[0]->m_x; | ||||||
|  |     btVector3 x41 = node->m_x - face->m_n[0]->m_x; | ||||||
|  |     btVector3 v21 = face->m_n[1]->m_v - face->m_n[0]->m_v; | ||||||
|  |     btVector3 v31 = face->m_n[2]->m_v - face->m_n[0]->m_v; | ||||||
|  |     btVector3 v41 = node->m_v - face->m_n[0]->m_v; | ||||||
|  |     btVector3 a = x21.cross(x31); | ||||||
|  |     btVector3 b = x21.cross(v31) + v21.cross(x31); | ||||||
|  |     btVector3 c = v21.cross(v31); | ||||||
|  |     btVector3 d = x41; | ||||||
|  |     btVector3 e = v41; | ||||||
|  |     btScalar a0 = a.dot(d); | ||||||
|  |     btScalar a1 = a.dot(e) + b.dot(d); | ||||||
|  |     btScalar a2 = c.dot(d) + b.dot(e); | ||||||
|  |     btScalar a3 = c.dot(e); | ||||||
|  |     btScalar eps = SAFE_EPSILON; | ||||||
|  |     int num_roots = 0; | ||||||
|  |     btScalar roots[3]; | ||||||
|  |     if (std::abs(a3) < eps) | ||||||
|  |     { | ||||||
|  |         // cubic term is zero
 | ||||||
|  |         if (std::abs(a2) < eps) | ||||||
|  |         { | ||||||
|  |             if (std::abs(a1) < eps) | ||||||
|  |             { | ||||||
|  |                 if (std::abs(a0) < eps) | ||||||
|  |                 { | ||||||
|  |                     num_roots = 2; | ||||||
|  |                     roots[0] = 0; | ||||||
|  |                     roots[1] = dt; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 num_roots = 1; | ||||||
|  |                 roots[0] = -a0/a1; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             num_roots = SolveP2(roots, a1/a2, a0/a2); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         num_roots = SolveP3(roots, a2/a3, a1/a3, a0/a3); | ||||||
|  |     } | ||||||
|  | //    std::sort(roots, roots+num_roots);
 | ||||||
|  |     if (num_roots > 1) | ||||||
|  |     { | ||||||
|  |         if (roots[0] > roots[1]) | ||||||
|  |             btSwap(roots[0], roots[1]); | ||||||
|  |     } | ||||||
|  |     if (num_roots > 2) | ||||||
|  |     { | ||||||
|  |         if (roots[0] > roots[2]) | ||||||
|  |             btSwap(roots[0], roots[2]); | ||||||
|  |         if (roots[1] > roots[2]) | ||||||
|  |             btSwap(roots[1], roots[2]); | ||||||
|  |     } | ||||||
|  |     for (int r = 0; r < num_roots; ++r) | ||||||
|  |     { | ||||||
|  |         double root = roots[r]; | ||||||
|  |         if (root <= 0) | ||||||
|  |             continue; | ||||||
|  |         if (root > dt + SIMD_EPSILON) | ||||||
|  |             return false; | ||||||
|  |         btVector3 x1 = face->m_n[0]->m_x + root * face->m_n[0]->m_v; | ||||||
|  |         btVector3 x2 = face->m_n[1]->m_x + root * face->m_n[1]->m_v; | ||||||
|  |         btVector3 x3 = face->m_n[2]->m_x + root * face->m_n[2]->m_v; | ||||||
|  |         btVector3 x4 = node->m_x + root * node->m_v; | ||||||
|  |         btVector3 normal = (x2-x1).cross(x3-x1); | ||||||
|  |         normal.safeNormalize(); | ||||||
|  |         if (proximityTest(x1, x2, x3, x4, normal, mrg, bary)) | ||||||
|  |             return true; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | static SIMD_FORCE_INLINE bool bernsteinCCD(const btSoftBody::Face* face, const btSoftBody::Node* node, const btScalar& dt, const btScalar& mrg, btVector3& bary) | ||||||
|  | { | ||||||
|  |     if (!bernsteinVFTest(face, node, dt, mrg)) | ||||||
|  |         return false; | ||||||
|  |     if (!continuousCollisionDetection(face, node, dt, 1e-6, bary)) | ||||||
|  |         return false; | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| //
 | //
 | ||||||
| // btSymMatrix
 | // btSymMatrix
 | ||||||
| //
 | //
 | ||||||
|  | @ -373,6 +938,26 @@ static inline btMatrix3x3 OuterProduct(const btScalar* v1,const btScalar* v2,con | ||||||
|     return (m); |     return (m); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static inline btMatrix3x3 OuterProduct(const btVector3& v1,const btVector3& v2) | ||||||
|  | { | ||||||
|  |     btMatrix3x3 m; | ||||||
|  |     btScalar a11 = v1[0] * v2[0]; | ||||||
|  |     btScalar a12 = v1[0] * v2[1]; | ||||||
|  |     btScalar a13 = v1[0] * v2[2]; | ||||||
|  |      | ||||||
|  |     btScalar a21 = v1[1] * v2[0]; | ||||||
|  |     btScalar a22 = v1[1] * v2[1]; | ||||||
|  |     btScalar a23 = v1[1] * v2[2]; | ||||||
|  |      | ||||||
|  |     btScalar a31 = v1[2] * v2[0]; | ||||||
|  |     btScalar a32 = v1[2] * v2[1]; | ||||||
|  |     btScalar a33 = v1[2] * v2[2]; | ||||||
|  |     m[0] = btVector3(a11, a12, a13); | ||||||
|  |     m[1] = btVector3(a21, a22, a23); | ||||||
|  |     m[2] = btVector3(a31, a32, a33); | ||||||
|  |     return (m); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| //
 | //
 | ||||||
| static inline btMatrix3x3 Add(const btMatrix3x3& a, | static inline btMatrix3x3 Add(const btMatrix3x3& a, | ||||||
|  | @ -1070,8 +1655,8 @@ struct btSoftColliders | ||||||
| 
 | 
 | ||||||
| 			if (!n.m_battach) | 			if (!n.m_battach) | ||||||
|             { |             { | ||||||
|                 // check for collision at x_{n+1}^* as well at x_n
 | 				// check for collision at x_{n+1}^*
 | ||||||
|                 if (psb->checkDeformableContact(m_colObj1Wrap, n.m_x, m, c.m_cti, /*predict = */ true) || psb->checkDeformableContact(m_colObj1Wrap, n.m_q, m, c.m_cti, /*predict = */ true)) | 				if (psb->checkDeformableContact(m_colObj1Wrap, n.m_q, m, c.m_cti, /*predict = */ true)) | ||||||
|                 { |                 { | ||||||
|                     const btScalar ima = n.m_im; |                     const btScalar ima = n.m_im; | ||||||
|                     // todo: collision between multibody and fixed deformable node will be missed.
 |                     // todo: collision between multibody and fixed deformable node will be missed.
 | ||||||
|  | @ -1159,7 +1744,6 @@ struct btSoftColliders | ||||||
|             btSoftBody::Node* n0 = f.m_n[0]; |             btSoftBody::Node* n0 = f.m_n[0]; | ||||||
|             btSoftBody::Node* n1 = f.m_n[1]; |             btSoftBody::Node* n1 = f.m_n[1]; | ||||||
|             btSoftBody::Node* n2 = f.m_n[2]; |             btSoftBody::Node* n2 = f.m_n[2]; | ||||||
|              |  | ||||||
|             const btScalar m = (n0->m_im > 0 && n1->m_im > 0 && n2->m_im > 0 )? dynmargin : stamargin; |             const btScalar m = (n0->m_im > 0 && n1->m_im > 0 && n2->m_im > 0 )? dynmargin : stamargin; | ||||||
|             btSoftBody::DeformableFaceRigidContact c; |             btSoftBody::DeformableFaceRigidContact c; | ||||||
|             btVector3 contact_point; |             btVector3 contact_point; | ||||||
|  | @ -1174,18 +1758,19 @@ struct btSoftColliders | ||||||
|                 if (ms > 0) |                 if (ms > 0) | ||||||
|                 { |                 { | ||||||
|                     // resolve contact at x_n
 |                     // resolve contact at x_n
 | ||||||
|                     psb->checkDeformableFaceContact(m_colObj1Wrap, f, contact_point, bary, m, c.m_cti, /*predict = */ false); | //                    psb->checkDeformableFaceContact(m_colObj1Wrap, f, contact_point, bary, m, c.m_cti, /*predict = */ false);
 | ||||||
|                     btSoftBody::sCti& cti = c.m_cti; |                     btSoftBody::sCti& cti = c.m_cti; | ||||||
|                     c.m_contactPoint = contact_point; |                     c.m_contactPoint = contact_point; | ||||||
|                     c.m_bary = bary; |                     c.m_bary = bary; | ||||||
|                     // todo xuchenhan@: this is assuming mass of all vertices are the same. Need to modify if mass are different for distinct vertices
 |                     // todo xuchenhan@: this is assuming mass of all vertices are the same. Need to modify if mass are different for distinct vertices
 | ||||||
|                     c.m_weights = btScalar(2)/(btScalar(1) + bary.length2()) * bary; |                     c.m_weights = btScalar(2)/(btScalar(1) + bary.length2()) * bary; | ||||||
|                     c.m_face = &f; |                     c.m_face = &f; | ||||||
|  | 					// friction is handled by the nodes to prevent sticking
 | ||||||
|  | //                    const btScalar fc = 0;
 | ||||||
|                     const btScalar fc = psb->m_cfg.kDF * m_colObj1Wrap->getCollisionObject()->getFriction(); |                     const btScalar fc = psb->m_cfg.kDF * m_colObj1Wrap->getCollisionObject()->getFriction(); | ||||||
|                      |                      | ||||||
|                     // the effective inverse mass of the face as in https://graphics.stanford.edu/papers/cloth-sig02/cloth.pdf
 |                     // the effective inverse mass of the face as in https://graphics.stanford.edu/papers/cloth-sig02/cloth.pdf
 | ||||||
|                     ima = bary.getX()*c.m_weights.getX() * n0->m_im + bary.getY()*c.m_weights.getY() * n1->m_im + bary.getZ()*c.m_weights.getZ() * n2->m_im; |                     ima = bary.getX()*c.m_weights.getX() * n0->m_im + bary.getY()*c.m_weights.getY() * n1->m_im + bary.getZ()*c.m_weights.getZ() * n2->m_im; | ||||||
|                      |  | ||||||
|                     c.m_c2 = ima; |                     c.m_c2 = ima; | ||||||
|                     c.m_c3 = fc; |                     c.m_c3 = fc; | ||||||
|                     c.m_c4 = m_colObj1Wrap->getCollisionObject()->isStaticOrKinematicObject() ? psb->m_cfg.kKHR : psb->m_cfg.kCHR; |                     c.m_c4 = m_colObj1Wrap->getCollisionObject()->isStaticOrKinematicObject() ? psb->m_cfg.kKHR : psb->m_cfg.kCHR; | ||||||
|  | @ -1316,19 +1901,11 @@ struct btSoftColliders | ||||||
|         { |         { | ||||||
|             btSoftBody::Node* node = (btSoftBody::Node*)lnode->data; |             btSoftBody::Node* node = (btSoftBody::Node*)lnode->data; | ||||||
|             btSoftBody::Face* face = (btSoftBody::Face*)lface->data; |             btSoftBody::Face* face = (btSoftBody::Face*)lface->data; | ||||||
|              |             btVector3 bary; | ||||||
|             btVector3 o = node->m_x; |             if (proximityTest(face->m_n[0]->m_x, face->m_n[1]->m_x, face->m_n[2]->m_x, node->m_x, face->m_normal, mrg, bary)) | ||||||
|             btVector3 p; |  | ||||||
|             btScalar d = SIMD_INFINITY; |  | ||||||
|             ProjectOrigin(face->m_n[0]->m_x - o, |  | ||||||
|                           face->m_n[1]->m_x - o, |  | ||||||
|                           face->m_n[2]->m_x - o, |  | ||||||
|                           p, d); |  | ||||||
|             const btScalar m = mrg + (o - node->m_q).safeNorm() * 2; |  | ||||||
|             if (d < (m * m)) |  | ||||||
|             { |             { | ||||||
|                 const btSoftBody::Node* n[] = {face->m_n[0], face->m_n[1], face->m_n[2]}; |                 const btSoftBody::Node* n[] = {face->m_n[0], face->m_n[1], face->m_n[2]}; | ||||||
|                 const btVector3 w = BaryCoord(n[0]->m_x, n[1]->m_x, n[2]->m_x, p + o); |                 const btVector3 w = bary; | ||||||
|                 const btScalar ma = node->m_im; |                 const btScalar ma = node->m_im; | ||||||
|                 btScalar mb = BaryEval(n[0]->m_im, n[1]->m_im, n[2]->m_im, w); |                 btScalar mb = BaryEval(n[0]->m_im, n[1]->m_im, n[2]->m_im, w); | ||||||
|                 if ((n[0]->m_im <= 0) || |                 if ((n[0]->m_im <= 0) || | ||||||
|  | @ -1341,20 +1918,14 @@ struct btSoftColliders | ||||||
|                 if (ms > 0) |                 if (ms > 0) | ||||||
|                 { |                 { | ||||||
|                     btSoftBody::DeformableFaceNodeContact c; |                     btSoftBody::DeformableFaceNodeContact c; | ||||||
|                     if (useFaceNormal) |                     c.m_normal = face->m_normal; | ||||||
|                         c.m_normal = face->m_normal; |                     if (!useFaceNormal && c.m_normal.dot(node->m_x - face->m_n[2]->m_x) < 0) | ||||||
|                     else |                         c.m_normal  = -face->m_normal; | ||||||
|                         c.m_normal = p / -btSqrt(d); |  | ||||||
|                     c.m_margin = mrg; |                     c.m_margin = mrg; | ||||||
|                     c.m_node = node; |                     c.m_node = node; | ||||||
|                     c.m_face = face; |                     c.m_face = face; | ||||||
|                     c.m_bary = w; |                     c.m_bary = w; | ||||||
|                     // todo xuchenhan@: this is assuming mass of all vertices are the same. Need to modify if mass are different for distinct vertices
 |  | ||||||
|                     c.m_weights = btScalar(2)/(btScalar(1) + w.length2()) * w; |  | ||||||
|                     c.m_friction = psb[0]->m_cfg.kDF * psb[1]->m_cfg.kDF; |                     c.m_friction = psb[0]->m_cfg.kDF * psb[1]->m_cfg.kDF; | ||||||
|                     // the effective inverse mass of the face as in https://graphics.stanford.edu/papers/cloth-sig02/cloth.pdf
 |  | ||||||
|                     c.m_imf = c.m_bary[0]*c.m_weights[0] * n[0]->m_im + c.m_bary[1]*c.m_weights[1] * n[1]->m_im + c.m_bary[2]*c.m_weights[2] * n[2]->m_im; |  | ||||||
|                     c.m_c0 = btScalar(1)/(ma + c.m_imf); |  | ||||||
|                     psb[0]->m_faceNodeContacts.push_back(c); |                     psb[0]->m_faceNodeContacts.push_back(c); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -1372,69 +1943,152 @@ struct btSoftColliders | ||||||
|         void Process(const btDbvntNode* lface1, |         void Process(const btDbvntNode* lface1, | ||||||
|                      const btDbvntNode* lface2) |                      const btDbvntNode* lface2) | ||||||
|         { |         { | ||||||
|             btSoftBody::Face* f = (btSoftBody::Face*)lface1->data; |             btSoftBody::Face* f1 = (btSoftBody::Face*)lface1->data; | ||||||
|             btSoftBody::Face* face = (btSoftBody::Face*)lface2->data; |             btSoftBody::Face* f2 = (btSoftBody::Face*)lface2->data; | ||||||
|  |             if (f1 != f2) | ||||||
|  |             { | ||||||
|  |                 Repel(f1, f2); | ||||||
|  |                 Repel(f2, f1); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         void Repel(btSoftBody::Face* f1, btSoftBody::Face* f2) | ||||||
|  |         { | ||||||
|  |             //#define REPEL_NEIGHBOR 1
 | ||||||
|  | #ifndef REPEL_NEIGHBOR | ||||||
|             for (int node_id = 0; node_id < 3; ++node_id) |             for (int node_id = 0; node_id < 3; ++node_id) | ||||||
|             { |             { | ||||||
|                 btSoftBody::Node* node = f->m_n[node_id]; |                 btSoftBody::Node* node = f1->m_n[node_id]; | ||||||
|                 bool skip = false; |  | ||||||
|                 for (int i = 0; i < 3; ++i) |                 for (int i = 0; i < 3; ++i) | ||||||
|                 { |                 { | ||||||
|                     if (face->m_n[i] == node) |                     if (f2->m_n[i] == node) | ||||||
|  |                         return; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | #endif | ||||||
|  |             bool skip = false; | ||||||
|  |             for (int node_id = 0; node_id < 3; ++node_id) | ||||||
|  |             { | ||||||
|  |                 btSoftBody::Node* node = f1->m_n[node_id]; | ||||||
|  | #ifdef REPEL_NEIGHBOR | ||||||
|  |                 for (int i = 0; i < 3; ++i) | ||||||
|  |                 { | ||||||
|  |                     if (f2->m_n[i] == node) | ||||||
|                     { |                     { | ||||||
|                         skip = true; |                         skip = true; | ||||||
|                         break; |                         break; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 if (skip) |                 if (skip) | ||||||
|                     continue; |  | ||||||
|                 btVector3 o = node->m_x; |  | ||||||
|                 btVector3 p; |  | ||||||
|                 btScalar d = SIMD_INFINITY; |  | ||||||
|                 ProjectOrigin(face->m_n[0]->m_x - o, |  | ||||||
|                               face->m_n[1]->m_x - o, |  | ||||||
|                               face->m_n[2]->m_x - o, |  | ||||||
|                               p, d); |  | ||||||
|                 const btScalar m = mrg + (o - node->m_q).safeNorm() * 2; |  | ||||||
|                 if (d < (m * m)) |  | ||||||
|                 { |                 { | ||||||
|                     const btSoftBody::Node* n[] = {face->m_n[0], face->m_n[1], face->m_n[2]}; |                     skip = false; | ||||||
|                     const btVector3 w = BaryCoord(n[0]->m_x, n[1]->m_x, n[2]->m_x, p + o); |                     continue; | ||||||
|                     const btScalar ma = node->m_im; |  | ||||||
|                     btScalar mb = BaryEval(n[0]->m_im, n[1]->m_im, n[2]->m_im, w); |  | ||||||
|                     if ((n[0]->m_im <= 0) || |  | ||||||
|                         (n[1]->m_im <= 0) || |  | ||||||
|                         (n[2]->m_im <= 0)) |  | ||||||
|                     { |  | ||||||
|                         mb = 0; |  | ||||||
|                     } |  | ||||||
|                     const btScalar ms = ma + mb; |  | ||||||
|                     if (ms > 0) |  | ||||||
|                     { |  | ||||||
|                         btSoftBody::DeformableFaceNodeContact c; |  | ||||||
|                         if (useFaceNormal) |  | ||||||
|                             c.m_normal = face->m_normal; |  | ||||||
|                         else |  | ||||||
|                             c.m_normal = p / -btSqrt(d); |  | ||||||
|                         c.m_margin = mrg; |  | ||||||
|                         c.m_node = node; |  | ||||||
|                         c.m_face = face; |  | ||||||
|                         c.m_bary = w; |  | ||||||
|                         // todo xuchenhan@: this is assuming mass of all vertices are the same. Need to modify if mass are different for distinct vertices
 |  | ||||||
|                         c.m_weights = btScalar(2)/(btScalar(1) + w.length2()) * w; |  | ||||||
|                         c.m_friction = psb[0]->m_cfg.kDF * psb[1]->m_cfg.kDF; |  | ||||||
|                         // the effective inverse mass of the face as in https://graphics.stanford.edu/papers/cloth-sig02/cloth.pdf
 |  | ||||||
|                         c.m_imf = c.m_bary[0]*c.m_weights[0] * n[0]->m_im + c.m_bary[1]*c.m_weights[1] * n[1]->m_im + c.m_bary[2]*c.m_weights[2] * n[2]->m_im; |  | ||||||
|                         c.m_c0 = btScalar(1)/(ma + c.m_imf); |  | ||||||
|                         psb[0]->m_faceNodeContacts.push_back(c); |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|  | #endif | ||||||
|  |                 btSoftBody::Face* face = f2; | ||||||
|  |                 btVector3 bary; | ||||||
|  |                 if (!proximityTest(face->m_n[0]->m_x, face->m_n[1]->m_x, face->m_n[2]->m_x, node->m_x, face->m_normal, mrg, bary)) | ||||||
|  |                     continue; | ||||||
|  |                 btSoftBody::DeformableFaceNodeContact c; | ||||||
|  |                 c.m_normal = face->m_normal; | ||||||
|  |                 if (!useFaceNormal && c.m_normal.dot(node->m_x - face->m_n[2]->m_x) < 0) | ||||||
|  |                     c.m_normal  = -face->m_normal; | ||||||
|  |                 c.m_margin = mrg; | ||||||
|  |                 c.m_node = node; | ||||||
|  |                 c.m_face = face; | ||||||
|  |                 c.m_bary = bary; | ||||||
|  |                 c.m_friction = psb[0]->m_cfg.kDF * psb[1]->m_cfg.kDF; | ||||||
|  |                 psb[0]->m_faceNodeContacts.push_back(c); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         btSoftBody* psb[2]; |         btSoftBody* psb[2]; | ||||||
|         btScalar mrg; |         btScalar mrg; | ||||||
|         bool useFaceNormal; |         bool useFaceNormal; | ||||||
|     }; |     }; | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
|  |     struct CollideCCD : btDbvt::ICollide | ||||||
|  |     { | ||||||
|  |         void Process(const btDbvtNode* lnode, | ||||||
|  |                      const btDbvtNode* lface) | ||||||
|  |         { | ||||||
|  |             btSoftBody::Node* node = (btSoftBody::Node*)lnode->data; | ||||||
|  |             btSoftBody::Face* face = (btSoftBody::Face*)lface->data; | ||||||
|  |             btVector3 bary; | ||||||
|  |             if (bernsteinCCD(face, node, dt, SAFE_EPSILON, bary)) | ||||||
|  |             { | ||||||
|  |                 btSoftBody::DeformableFaceNodeContact c; | ||||||
|  |                 c.m_normal = face->m_normal; | ||||||
|  |                 if (!useFaceNormal && c.m_normal.dot(node->m_x - face->m_n[2]->m_x) < 0) | ||||||
|  |                     c.m_normal  = -face->m_normal; | ||||||
|  |                 c.m_node = node; | ||||||
|  |                 c.m_face = face; | ||||||
|  |                 c.m_bary = bary; | ||||||
|  |                 c.m_friction = psb[0]->m_cfg.kDF * psb[1]->m_cfg.kDF; | ||||||
|  |                 psb[0]->m_faceNodeContacts.push_back(c); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         void Process(const btDbvntNode* lface1, | ||||||
|  |                      const btDbvntNode* lface2) | ||||||
|  |         { | ||||||
|  |             btSoftBody::Face* f1 = (btSoftBody::Face*)lface1->data; | ||||||
|  |             btSoftBody::Face* f2 = (btSoftBody::Face*)lface2->data; | ||||||
|  |             if (f1 != f2) | ||||||
|  |             { | ||||||
|  |                 Repel(f1, f2); | ||||||
|  |                 Repel(f2, f1); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         void Repel(btSoftBody::Face* f1, btSoftBody::Face* f2) | ||||||
|  |         { | ||||||
|  |             //#define REPEL_NEIGHBOR 1
 | ||||||
|  | #ifndef REPEL_NEIGHBOR | ||||||
|  |             for (int node_id = 0; node_id < 3; ++node_id) | ||||||
|  |             { | ||||||
|  |                 btSoftBody::Node* node = f1->m_n[node_id]; | ||||||
|  |                 for (int i = 0; i < 3; ++i) | ||||||
|  |                 { | ||||||
|  |                     if (f2->m_n[i] == node) | ||||||
|  |                         return; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | #endif | ||||||
|  |             bool skip = false; | ||||||
|  |             for (int node_id = 0; node_id < 3; ++node_id) | ||||||
|  |             { | ||||||
|  |                 btSoftBody::Node* node = f1->m_n[node_id]; | ||||||
|  | #ifdef REPEL_NEIGHBOR | ||||||
|  |                 for (int i = 0; i < 3; ++i) | ||||||
|  |                 { | ||||||
|  |                     if (f2->m_n[i] == node) | ||||||
|  |                     { | ||||||
|  |                         skip = true; | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if (skip) | ||||||
|  |                 { | ||||||
|  |                     skip = false; | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | #endif | ||||||
|  |                 btSoftBody::Face* face = f2; | ||||||
|  |                 btVector3 bary; | ||||||
|  | 				if (bernsteinCCD(face, node, dt, SAFE_EPSILON, bary)) | ||||||
|  |                 { | ||||||
|  |                     btSoftBody::DeformableFaceNodeContact c; | ||||||
|  |                     c.m_normal = face->m_normal; | ||||||
|  |                     if (!useFaceNormal && c.m_normal.dot(node->m_x - face->m_n[2]->m_x) < 0) | ||||||
|  |                         c.m_normal  = -face->m_normal; | ||||||
|  |                     c.m_node = node; | ||||||
|  |                     c.m_face = face; | ||||||
|  |                     c.m_bary = bary; | ||||||
|  |                     c.m_friction = psb[0]->m_cfg.kDF * psb[1]->m_cfg.kDF; | ||||||
|  |                     psb[0]->m_faceNodeContacts.push_back(c); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         btSoftBody* psb[2]; | ||||||
|  |         btScalar dt, mrg; | ||||||
|  |         bool useFaceNormal; | ||||||
|  |     }; | ||||||
|  | }; | ||||||
| #endif  //_BT_SOFT_BODY_INTERNALS_H
 | #endif  //_BT_SOFT_BODY_INTERNALS_H
 | ||||||
|  |  | ||||||
|  | @ -48,9 +48,10 @@ btSoftRigidCollisionAlgorithm::~btSoftRigidCollisionAlgorithm() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| 
 | #include "LinearMath/btQuickprof.h" | ||||||
| void btSoftRigidCollisionAlgorithm::processCollision(const btCollisionObjectWrapper* body0Wrap, const btCollisionObjectWrapper* body1Wrap, const btDispatcherInfo& dispatchInfo, btManifoldResult* resultOut) | void btSoftRigidCollisionAlgorithm::processCollision(const btCollisionObjectWrapper* body0Wrap, const btCollisionObjectWrapper* body1Wrap, const btDispatcherInfo& dispatchInfo, btManifoldResult* resultOut) | ||||||
| { | { | ||||||
|  | 	BT_PROFILE("btSoftRigidCollisionAlgorithm::processCollision"); | ||||||
| 	(void)dispatchInfo; | 	(void)dispatchInfo; | ||||||
| 	(void)resultOut; | 	(void)resultOut; | ||||||
| 	//printf("btSoftRigidCollisionAlgorithm\n");
 | 	//printf("btSoftRigidCollisionAlgorithm\n");
 | ||||||
|  |  | ||||||
							
								
								
									
										419
									
								
								thirdparty/bullet/BulletSoftBody/poly34.cpp
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										419
									
								
								thirdparty/bullet/BulletSoftBody/poly34.cpp
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,419 @@ | ||||||
|  | // poly34.cpp : solution of cubic and quartic equation
 | ||||||
|  | // (c) Khashin S.I. http://math.ivanovo.ac.ru/dalgebra/Khashin/index.html
 | ||||||
|  | // khash2 (at) gmail.com
 | ||||||
|  | // Thanks to Alexandr Rakhmanin <rakhmanin (at) gmail.com>
 | ||||||
|  | // public domain
 | ||||||
|  | //
 | ||||||
|  | #include <math.h> | ||||||
|  | 
 | ||||||
|  | #include "poly34.h" // solution of cubic and quartic equation
 | ||||||
|  | #define TwoPi 6.28318530717958648 | ||||||
|  | const btScalar eps = SIMD_EPSILON; | ||||||
|  | 
 | ||||||
|  | //=============================================================================
 | ||||||
|  | // _root3, root3 from http://prografix.narod.ru
 | ||||||
|  | //=============================================================================
 | ||||||
|  | static SIMD_FORCE_INLINE btScalar _root3(btScalar x) | ||||||
|  | { | ||||||
|  |     btScalar s = 1.; | ||||||
|  |     while (x < 1.) { | ||||||
|  |         x *= 8.; | ||||||
|  |         s *= 0.5; | ||||||
|  |     } | ||||||
|  |     while (x > 8.) { | ||||||
|  |         x *= 0.125; | ||||||
|  |         s *= 2.; | ||||||
|  |     } | ||||||
|  |     btScalar r = 1.5; | ||||||
|  |     r -= 1. / 3. * (r - x / (r * r)); | ||||||
|  |     r -= 1. / 3. * (r - x / (r * r)); | ||||||
|  |     r -= 1. / 3. * (r - x / (r * r)); | ||||||
|  |     r -= 1. / 3. * (r - x / (r * r)); | ||||||
|  |     r -= 1. / 3. * (r - x / (r * r)); | ||||||
|  |     r -= 1. / 3. * (r - x / (r * r)); | ||||||
|  |     return r * s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | btScalar SIMD_FORCE_INLINE root3(btScalar x) | ||||||
|  | { | ||||||
|  |     if (x > 0) | ||||||
|  |         return _root3(x); | ||||||
|  |     else if (x < 0) | ||||||
|  |         return -_root3(-x); | ||||||
|  |     else | ||||||
|  |         return 0.; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // x - array of size 2
 | ||||||
|  | // return 2: 2 real roots x[0], x[1]
 | ||||||
|  | // return 0: pair of complex roots: x[0]i*x[1]
 | ||||||
|  | int SolveP2(btScalar* x, btScalar a, btScalar b) | ||||||
|  | { // solve equation x^2 + a*x + b = 0
 | ||||||
|  |     btScalar D = 0.25 * a * a - b; | ||||||
|  |     if (D >= 0) { | ||||||
|  |         D = sqrt(D); | ||||||
|  |         x[0] = -0.5 * a + D; | ||||||
|  |         x[1] = -0.5 * a - D; | ||||||
|  |         return 2; | ||||||
|  |     } | ||||||
|  |     x[0] = -0.5 * a; | ||||||
|  |     x[1] = sqrt(-D); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | //---------------------------------------------------------------------------
 | ||||||
|  | // x - array of size 3
 | ||||||
|  | // In case 3 real roots: => x[0], x[1], x[2], return 3
 | ||||||
|  | //         2 real roots: x[0], x[1],          return 2
 | ||||||
|  | //         1 real root : x[0], x[1]  i*x[2], return 1
 | ||||||
|  | int SolveP3(btScalar* x, btScalar a, btScalar b, btScalar c) | ||||||
|  | { // solve cubic equation x^3 + a*x^2 + b*x + c = 0
 | ||||||
|  |     btScalar a2 = a * a; | ||||||
|  |     btScalar q = (a2 - 3 * b) / 9; | ||||||
|  |     if (q < 0) | ||||||
|  |         q = eps; | ||||||
|  |     btScalar r = (a * (2 * a2 - 9 * b) + 27 * c) / 54; | ||||||
|  |     // equation x^3 + q*x + r = 0
 | ||||||
|  |     btScalar r2 = r * r; | ||||||
|  |     btScalar q3 = q * q * q; | ||||||
|  |     btScalar A, B; | ||||||
|  |     if (r2 <= (q3 + eps)) { //<<-- FIXED!
 | ||||||
|  |         btScalar t = r / sqrt(q3); | ||||||
|  |         if (t < -1) | ||||||
|  |             t = -1; | ||||||
|  |         if (t > 1) | ||||||
|  |             t = 1; | ||||||
|  |         t = acos(t); | ||||||
|  |         a /= 3; | ||||||
|  |         q = -2 * sqrt(q); | ||||||
|  |         x[0] = q * cos(t / 3) - a; | ||||||
|  |         x[1] = q * cos((t + TwoPi) / 3) - a; | ||||||
|  |         x[2] = q * cos((t - TwoPi) / 3) - a; | ||||||
|  |         return (3); | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         //A =-pow(fabs(r)+sqrt(r2-q3),1./3);
 | ||||||
|  |         A = -root3(fabs(r) + sqrt(r2 - q3)); | ||||||
|  |         if (r < 0) | ||||||
|  |             A = -A; | ||||||
|  |         B = (A == 0 ? 0 : q / A); | ||||||
|  |          | ||||||
|  |         a /= 3; | ||||||
|  |         x[0] = (A + B) - a; | ||||||
|  |         x[1] = -0.5 * (A + B) - a; | ||||||
|  |         x[2] = 0.5 * sqrt(3.) * (A - B); | ||||||
|  |         if (fabs(x[2]) < eps) { | ||||||
|  |             x[2] = x[1]; | ||||||
|  |             return (2); | ||||||
|  |         } | ||||||
|  |         return (1); | ||||||
|  |     } | ||||||
|  | } // SolveP3(btScalar *x,btScalar a,btScalar b,btScalar c) {
 | ||||||
|  | //---------------------------------------------------------------------------
 | ||||||
|  | // a>=0!
 | ||||||
|  | void CSqrt(btScalar x, btScalar y, btScalar& a, btScalar& b) // returns:  a+i*s = sqrt(x+i*y)
 | ||||||
|  | { | ||||||
|  |     btScalar r = sqrt(x * x + y * y); | ||||||
|  |     if (y == 0) { | ||||||
|  |         r = sqrt(r); | ||||||
|  |         if (x >= 0) { | ||||||
|  |             a = r; | ||||||
|  |             b = 0; | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             a = 0; | ||||||
|  |             b = r; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else { // y != 0
 | ||||||
|  |         a = sqrt(0.5 * (x + r)); | ||||||
|  |         b = 0.5 * y / a; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | //---------------------------------------------------------------------------
 | ||||||
|  | int SolveP4Bi(btScalar* x, btScalar b, btScalar d) // solve equation x^4 + b*x^2 + d = 0
 | ||||||
|  | { | ||||||
|  |     btScalar D = b * b - 4 * d; | ||||||
|  |     if (D >= 0) { | ||||||
|  |         btScalar sD = sqrt(D); | ||||||
|  |         btScalar x1 = (-b + sD) / 2; | ||||||
|  |         btScalar x2 = (-b - sD) / 2; // x2 <= x1
 | ||||||
|  |         if (x2 >= 0) // 0 <= x2 <= x1, 4 real roots
 | ||||||
|  |         { | ||||||
|  |             btScalar sx1 = sqrt(x1); | ||||||
|  |             btScalar sx2 = sqrt(x2); | ||||||
|  |             x[0] = -sx1; | ||||||
|  |             x[1] = sx1; | ||||||
|  |             x[2] = -sx2; | ||||||
|  |             x[3] = sx2; | ||||||
|  |             return 4; | ||||||
|  |         } | ||||||
|  |         if (x1 < 0) // x2 <= x1 < 0, two pair of imaginary roots
 | ||||||
|  |         { | ||||||
|  |             btScalar sx1 = sqrt(-x1); | ||||||
|  |             btScalar sx2 = sqrt(-x2); | ||||||
|  |             x[0] = 0; | ||||||
|  |             x[1] = sx1; | ||||||
|  |             x[2] = 0; | ||||||
|  |             x[3] = sx2; | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |         // now x2 < 0 <= x1 , two real roots and one pair of imginary root
 | ||||||
|  |         btScalar sx1 = sqrt(x1); | ||||||
|  |         btScalar sx2 = sqrt(-x2); | ||||||
|  |         x[0] = -sx1; | ||||||
|  |         x[1] = sx1; | ||||||
|  |         x[2] = 0; | ||||||
|  |         x[3] = sx2; | ||||||
|  |         return 2; | ||||||
|  |     } | ||||||
|  |     else { // if( D < 0 ), two pair of compex roots
 | ||||||
|  |         btScalar sD2 = 0.5 * sqrt(-D); | ||||||
|  |         CSqrt(-0.5 * b, sD2, x[0], x[1]); | ||||||
|  |         CSqrt(-0.5 * b, -sD2, x[2], x[3]); | ||||||
|  |         return 0; | ||||||
|  |     } // if( D>=0 )
 | ||||||
|  | } // SolveP4Bi(btScalar *x, btScalar b, btScalar d)    // solve equation x^4 + b*x^2 d
 | ||||||
|  | //---------------------------------------------------------------------------
 | ||||||
|  | #define SWAP(a, b) \ | ||||||
|  | {              \ | ||||||
|  | t = b;     \ | ||||||
|  | b = a;     \ | ||||||
|  | a = t;     \ | ||||||
|  | } | ||||||
|  | static void dblSort3(btScalar& a, btScalar& b, btScalar& c) // make: a <= b <= c
 | ||||||
|  | { | ||||||
|  |     btScalar t; | ||||||
|  |     if (a > b) | ||||||
|  |         SWAP(a, b); // now a<=b
 | ||||||
|  |     if (c < b) { | ||||||
|  |         SWAP(b, c); // now a<=b, b<=c
 | ||||||
|  |         if (a > b) | ||||||
|  |             SWAP(a, b); // now a<=b
 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | //---------------------------------------------------------------------------
 | ||||||
|  | int SolveP4De(btScalar* x, btScalar b, btScalar c, btScalar d) // solve equation x^4 + b*x^2 + c*x + d
 | ||||||
|  | { | ||||||
|  |     //if( c==0 ) return SolveP4Bi(x,b,d); // After that, c!=0
 | ||||||
|  |     if (fabs(c) < 1e-14 * (fabs(b) + fabs(d))) | ||||||
|  |         return SolveP4Bi(x, b, d); // After that, c!=0
 | ||||||
|  |      | ||||||
|  |     int res3 = SolveP3(x, 2 * b, b * b - 4 * d, -c * c); // solve resolvent
 | ||||||
|  |     // by Viet theorem:  x1*x2*x3=-c*c not equals to 0, so x1!=0, x2!=0, x3!=0
 | ||||||
|  |     if (res3 > 1) // 3 real roots,
 | ||||||
|  |     { | ||||||
|  |         dblSort3(x[0], x[1], x[2]); // sort roots to x[0] <= x[1] <= x[2]
 | ||||||
|  |         // Note: x[0]*x[1]*x[2]= c*c > 0
 | ||||||
|  |         if (x[0] > 0) // all roots are positive
 | ||||||
|  |         { | ||||||
|  |             btScalar sz1 = sqrt(x[0]); | ||||||
|  |             btScalar sz2 = sqrt(x[1]); | ||||||
|  |             btScalar sz3 = sqrt(x[2]); | ||||||
|  |             // Note: sz1*sz2*sz3= -c (and not equal to 0)
 | ||||||
|  |             if (c > 0) { | ||||||
|  |                 x[0] = (-sz1 - sz2 - sz3) / 2; | ||||||
|  |                 x[1] = (-sz1 + sz2 + sz3) / 2; | ||||||
|  |                 x[2] = (+sz1 - sz2 + sz3) / 2; | ||||||
|  |                 x[3] = (+sz1 + sz2 - sz3) / 2; | ||||||
|  |                 return 4; | ||||||
|  |             } | ||||||
|  |             // now: c<0
 | ||||||
|  |             x[0] = (-sz1 - sz2 + sz3) / 2; | ||||||
|  |             x[1] = (-sz1 + sz2 - sz3) / 2; | ||||||
|  |             x[2] = (+sz1 - sz2 - sz3) / 2; | ||||||
|  |             x[3] = (+sz1 + sz2 + sz3) / 2; | ||||||
|  |             return 4; | ||||||
|  |         } // if( x[0] > 0) // all roots are positive
 | ||||||
|  |         // now x[0] <= x[1] < 0, x[2] > 0
 | ||||||
|  |         // two pair of comlex roots
 | ||||||
|  |         btScalar sz1 = sqrt(-x[0]); | ||||||
|  |         btScalar sz2 = sqrt(-x[1]); | ||||||
|  |         btScalar sz3 = sqrt(x[2]); | ||||||
|  |          | ||||||
|  |         if (c > 0) // sign = -1
 | ||||||
|  |         { | ||||||
|  |             x[0] = -sz3 / 2; | ||||||
|  |             x[1] = (sz1 - sz2) / 2; // x[0]i*x[1]
 | ||||||
|  |             x[2] = sz3 / 2; | ||||||
|  |             x[3] = (-sz1 - sz2) / 2; // x[2]i*x[3]
 | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |         // now: c<0 , sign = +1
 | ||||||
|  |         x[0] = sz3 / 2; | ||||||
|  |         x[1] = (-sz1 + sz2) / 2; | ||||||
|  |         x[2] = -sz3 / 2; | ||||||
|  |         x[3] = (sz1 + sz2) / 2; | ||||||
|  |         return 0; | ||||||
|  |     } // if( res3>1 )    // 3 real roots,
 | ||||||
|  |     // now resoventa have 1 real and pair of compex roots
 | ||||||
|  |     // x[0] - real root, and x[0]>0,
 | ||||||
|  |     // x[1]i*x[2] - complex roots,
 | ||||||
|  |     // x[0] must be >=0. But one times x[0]=~ 1e-17, so:
 | ||||||
|  |     if (x[0] < 0) | ||||||
|  |         x[0] = 0; | ||||||
|  |     btScalar sz1 = sqrt(x[0]); | ||||||
|  |     btScalar szr, szi; | ||||||
|  |     CSqrt(x[1], x[2], szr, szi); // (szr+i*szi)^2 = x[1]+i*x[2]
 | ||||||
|  |     if (c > 0) // sign = -1
 | ||||||
|  |     { | ||||||
|  |         x[0] = -sz1 / 2 - szr; // 1st real root
 | ||||||
|  |         x[1] = -sz1 / 2 + szr; // 2nd real root
 | ||||||
|  |         x[2] = sz1 / 2; | ||||||
|  |         x[3] = szi; | ||||||
|  |         return 2; | ||||||
|  |     } | ||||||
|  |     // now: c<0 , sign = +1
 | ||||||
|  |     x[0] = sz1 / 2 - szr; // 1st real root
 | ||||||
|  |     x[1] = sz1 / 2 + szr; // 2nd real root
 | ||||||
|  |     x[2] = -sz1 / 2; | ||||||
|  |     x[3] = szi; | ||||||
|  |     return 2; | ||||||
|  | } // SolveP4De(btScalar *x, btScalar b, btScalar c, btScalar d)    // solve equation x^4 + b*x^2 + c*x + d
 | ||||||
|  | //-----------------------------------------------------------------------------
 | ||||||
|  | btScalar N4Step(btScalar x, btScalar a, btScalar b, btScalar c, btScalar d) // one Newton step for x^4 + a*x^3 + b*x^2 + c*x + d
 | ||||||
|  | { | ||||||
|  |     btScalar fxs = ((4 * x + 3 * a) * x + 2 * b) * x + c; // f'(x)
 | ||||||
|  |     if (fxs == 0) | ||||||
|  |         return x; //return 1e99; <<-- FIXED!
 | ||||||
|  |     btScalar fx = (((x + a) * x + b) * x + c) * x + d; // f(x)
 | ||||||
|  |     return x - fx / fxs; | ||||||
|  | } | ||||||
|  | //-----------------------------------------------------------------------------
 | ||||||
|  | // x - array of size 4
 | ||||||
|  | // return 4: 4 real roots x[0], x[1], x[2], x[3], possible multiple roots
 | ||||||
|  | // return 2: 2 real roots x[0], x[1] and complex x[2]i*x[3],
 | ||||||
|  | // return 0: two pair of complex roots: x[0]i*x[1],  x[2]i*x[3],
 | ||||||
|  | int SolveP4(btScalar* x, btScalar a, btScalar b, btScalar c, btScalar d) | ||||||
|  | { // solve equation x^4 + a*x^3 + b*x^2 + c*x + d by Dekart-Euler method
 | ||||||
|  |     // move to a=0:
 | ||||||
|  |     btScalar d1 = d + 0.25 * a * (0.25 * b * a - 3. / 64 * a * a * a - c); | ||||||
|  |     btScalar c1 = c + 0.5 * a * (0.25 * a * a - b); | ||||||
|  |     btScalar b1 = b - 0.375 * a * a; | ||||||
|  |     int res = SolveP4De(x, b1, c1, d1); | ||||||
|  |     if (res == 4) { | ||||||
|  |         x[0] -= a / 4; | ||||||
|  |         x[1] -= a / 4; | ||||||
|  |         x[2] -= a / 4; | ||||||
|  |         x[3] -= a / 4; | ||||||
|  |     } | ||||||
|  |     else if (res == 2) { | ||||||
|  |         x[0] -= a / 4; | ||||||
|  |         x[1] -= a / 4; | ||||||
|  |         x[2] -= a / 4; | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         x[0] -= a / 4; | ||||||
|  |         x[2] -= a / 4; | ||||||
|  |     } | ||||||
|  |     // one Newton step for each real root:
 | ||||||
|  |     if (res > 0) { | ||||||
|  |         x[0] = N4Step(x[0], a, b, c, d); | ||||||
|  |         x[1] = N4Step(x[1], a, b, c, d); | ||||||
|  |     } | ||||||
|  |     if (res > 2) { | ||||||
|  |         x[2] = N4Step(x[2], a, b, c, d); | ||||||
|  |         x[3] = N4Step(x[3], a, b, c, d); | ||||||
|  |     } | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | //-----------------------------------------------------------------------------
 | ||||||
|  | #define F5(t) (((((t + a) * t + b) * t + c) * t + d) * t + e) | ||||||
|  | //-----------------------------------------------------------------------------
 | ||||||
|  | btScalar SolveP5_1(btScalar a, btScalar b, btScalar c, btScalar d, btScalar e) // return real root of x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
 | ||||||
|  | { | ||||||
|  |     int cnt; | ||||||
|  |     if (fabs(e) < eps) | ||||||
|  |         return 0; | ||||||
|  |      | ||||||
|  |     btScalar brd = fabs(a); // brd - border of real roots
 | ||||||
|  |     if (fabs(b) > brd) | ||||||
|  |         brd = fabs(b); | ||||||
|  |     if (fabs(c) > brd) | ||||||
|  |         brd = fabs(c); | ||||||
|  |     if (fabs(d) > brd) | ||||||
|  |         brd = fabs(d); | ||||||
|  |     if (fabs(e) > brd) | ||||||
|  |         brd = fabs(e); | ||||||
|  |     brd++; // brd - border of real roots
 | ||||||
|  |      | ||||||
|  |     btScalar x0, f0; // less than root
 | ||||||
|  |     btScalar x1, f1; // greater than root
 | ||||||
|  |     btScalar x2, f2, f2s; // next values, f(x2), f'(x2)
 | ||||||
|  |     btScalar dx = 0; | ||||||
|  |      | ||||||
|  |     if (e < 0) { | ||||||
|  |         x0 = 0; | ||||||
|  |         x1 = brd; | ||||||
|  |         f0 = e; | ||||||
|  |         f1 = F5(x1); | ||||||
|  |         x2 = 0.01 * brd; | ||||||
|  |     } // positive root
 | ||||||
|  |     else { | ||||||
|  |         x0 = -brd; | ||||||
|  |         x1 = 0; | ||||||
|  |         f0 = F5(x0); | ||||||
|  |         f1 = e; | ||||||
|  |         x2 = -0.01 * brd; | ||||||
|  |     } // negative root
 | ||||||
|  |      | ||||||
|  |     if (fabs(f0) < eps) | ||||||
|  |         return x0; | ||||||
|  |     if (fabs(f1) < eps) | ||||||
|  |         return x1; | ||||||
|  |      | ||||||
|  |     // now x0<x1, f(x0)<0, f(x1)>0
 | ||||||
|  |     // Firstly 10 bisections
 | ||||||
|  |     for (cnt = 0; cnt < 10; cnt++) { | ||||||
|  |         x2 = (x0 + x1) / 2; // next point
 | ||||||
|  |         //x2 = x0 - f0*(x1 - x0) / (f1 - f0);        // next point
 | ||||||
|  |         f2 = F5(x2); // f(x2)
 | ||||||
|  |         if (fabs(f2) < eps) | ||||||
|  |             return x2; | ||||||
|  |         if (f2 > 0) { | ||||||
|  |             x1 = x2; | ||||||
|  |             f1 = f2; | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             x0 = x2; | ||||||
|  |             f0 = f2; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // At each step:
 | ||||||
|  |     // x0<x1, f(x0)<0, f(x1)>0.
 | ||||||
|  |     // x2 - next value
 | ||||||
|  |     // we hope that x0 < x2 < x1, but not necessarily
 | ||||||
|  |     do { | ||||||
|  |         if (cnt++ > 50) | ||||||
|  |             break; | ||||||
|  |         if (x2 <= x0 || x2 >= x1) | ||||||
|  |             x2 = (x0 + x1) / 2; // now  x0 < x2 < x1
 | ||||||
|  |         f2 = F5(x2); // f(x2)
 | ||||||
|  |         if (fabs(f2) < eps) | ||||||
|  |             return x2; | ||||||
|  |         if (f2 > 0) { | ||||||
|  |             x1 = x2; | ||||||
|  |             f1 = f2; | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             x0 = x2; | ||||||
|  |             f0 = f2; | ||||||
|  |         } | ||||||
|  |         f2s = (((5 * x2 + 4 * a) * x2 + 3 * b) * x2 + 2 * c) * x2 + d; // f'(x2)
 | ||||||
|  |         if (fabs(f2s) < eps) { | ||||||
|  |             x2 = 1e99; | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         dx = f2 / f2s; | ||||||
|  |         x2 -= dx; | ||||||
|  |     } while (fabs(dx) > eps); | ||||||
|  |     return x2; | ||||||
|  | } // SolveP5_1(btScalar a,btScalar b,btScalar c,btScalar d,btScalar e)    // return real root of x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
 | ||||||
|  | //-----------------------------------------------------------------------------
 | ||||||
|  | int SolveP5(btScalar* x, btScalar a, btScalar b, btScalar c, btScalar d, btScalar e) // solve equation x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
 | ||||||
|  | { | ||||||
|  |     btScalar r = x[0] = SolveP5_1(a, b, c, d, e); | ||||||
|  |     btScalar a1 = a + r, b1 = b + r * a1, c1 = c + r * b1, d1 = d + r * c1; | ||||||
|  |     return 1 + SolveP4(x + 1, a1, b1, c1, d1); | ||||||
|  | } // SolveP5(btScalar *x,btScalar a,btScalar b,btScalar c,btScalar d,btScalar e)    // solve equation x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
 | ||||||
|  | //-----------------------------------------------------------------------------
 | ||||||
							
								
								
									
										38
									
								
								thirdparty/bullet/BulletSoftBody/poly34.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								thirdparty/bullet/BulletSoftBody/poly34.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | ||||||
|  | // poly34.h : solution of cubic and quartic equation
 | ||||||
|  | // (c) Khashin S.I. http://math.ivanovo.ac.ru/dalgebra/Khashin/index.html
 | ||||||
|  | // khash2 (at) gmail.com
 | ||||||
|  | 
 | ||||||
|  | #ifndef POLY_34 | ||||||
|  | #define POLY_34 | ||||||
|  | #include "LinearMath/btScalar.h" | ||||||
|  | // x - array of size 2
 | ||||||
|  | // return 2: 2 real roots x[0], x[1]
 | ||||||
|  | // return 0: pair of complex roots: x[0]i*x[1]
 | ||||||
|  | int SolveP2(btScalar* x, btScalar a, btScalar b); // solve equation x^2 + a*x + b = 0
 | ||||||
|  | 
 | ||||||
|  | // x - array of size 3
 | ||||||
|  | // return 3: 3 real roots x[0], x[1], x[2]
 | ||||||
|  | // return 1: 1 real root x[0] and pair of complex roots: x[1]i*x[2]
 | ||||||
|  | int SolveP3(btScalar* x, btScalar a, btScalar b, btScalar c); // solve cubic equation x^3 + a*x^2 + b*x + c = 0
 | ||||||
|  | 
 | ||||||
|  | // x - array of size 4
 | ||||||
|  | // return 4: 4 real roots x[0], x[1], x[2], x[3], possible multiple roots
 | ||||||
|  | // return 2: 2 real roots x[0], x[1] and complex x[2]i*x[3],
 | ||||||
|  | // return 0: two pair of complex roots: x[0]i*x[1],  x[2]i*x[3],
 | ||||||
|  | int SolveP4(btScalar* x, btScalar a, btScalar b, btScalar c, btScalar d); // solve equation x^4 + a*x^3 + b*x^2 + c*x + d = 0 by Dekart-Euler method
 | ||||||
|  | 
 | ||||||
|  | // x - array of size 5
 | ||||||
|  | // return 5: 5 real roots x[0], x[1], x[2], x[3], x[4], possible multiple roots
 | ||||||
|  | // return 3: 3 real roots x[0], x[1], x[2] and complex x[3]i*x[4],
 | ||||||
|  | // return 1: 1 real root x[0] and two pair of complex roots: x[1]i*x[2],  x[3]i*x[4],
 | ||||||
|  | int SolveP5(btScalar* x, btScalar a, btScalar b, btScalar c, btScalar d, btScalar e); // solve equation x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
 | ||||||
|  | 
 | ||||||
|  | //-----------------------------------------------------------------------------
 | ||||||
|  | // And some additional functions for internal use.
 | ||||||
|  | // Your may remove this definitions from here
 | ||||||
|  | int SolveP4Bi(btScalar* x, btScalar b, btScalar d); // solve equation x^4 + b*x^2 + d = 0
 | ||||||
|  | int SolveP4De(btScalar* x, btScalar b, btScalar c, btScalar d); // solve equation x^4 + b*x^2 + c*x + d = 0
 | ||||||
|  | void CSqrt(btScalar x, btScalar y, btScalar& a, btScalar& b); // returns as a+i*s,  sqrt(x+i*y)
 | ||||||
|  | btScalar N4Step(btScalar x, btScalar a, btScalar b, btScalar c, btScalar d); // one Newton step for x^4 + a*x^3 + b*x^2 + c*x + d
 | ||||||
|  | btScalar SolveP5_1(btScalar a, btScalar b, btScalar c, btScalar d, btScalar e); // return real root of x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
 | ||||||
|  | #endif | ||||||
|  | @ -41,7 +41,7 @@ | ||||||
| 
 | 
 | ||||||
| #ifndef btImplicitQRSVD_h | #ifndef btImplicitQRSVD_h | ||||||
| #define btImplicitQRSVD_h | #define btImplicitQRSVD_h | ||||||
| 
 | #include <limits> | ||||||
| #include "btMatrix3x3.h" | #include "btMatrix3x3.h" | ||||||
| class btMatrix2x2 | class btMatrix2x2 | ||||||
| { | { | ||||||
|  | @ -753,7 +753,7 @@ inline int singularValueDecomposition(const btMatrix3x3& A, | ||||||
|                                      btMatrix3x3& V, |                                      btMatrix3x3& V, | ||||||
|                                      btScalar tol = 128*std::numeric_limits<btScalar>::epsilon()) |                                      btScalar tol = 128*std::numeric_limits<btScalar>::epsilon()) | ||||||
| { | { | ||||||
|     using std::fabs; | //    using std::fabs;
 | ||||||
|     btMatrix3x3 B = A; |     btMatrix3x3 B = A; | ||||||
|     U.setIdentity(); |     U.setIdentity(); | ||||||
|     V.setIdentity(); |     V.setIdentity(); | ||||||
|  |  | ||||||
							
								
								
									
										16
									
								
								thirdparty/bullet/LinearMath/btMatrix3x3.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								thirdparty/bullet/LinearMath/btMatrix3x3.h
									
										
									
									
										vendored
									
									
								
							|  | @ -26,10 +26,12 @@ subject to the following restrictions: | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #if defined(BT_USE_SSE) | #if defined(BT_USE_SSE) | ||||||
|  | #define v0000 (_mm_set_ps(0.0f, 0.0f, 0.0f, 0.0f)) | ||||||
| #define v1000 (_mm_set_ps(0.0f, 0.0f, 0.0f, 1.0f)) | #define v1000 (_mm_set_ps(0.0f, 0.0f, 0.0f, 1.0f)) | ||||||
| #define v0100 (_mm_set_ps(0.0f, 0.0f, 1.0f, 0.0f)) | #define v0100 (_mm_set_ps(0.0f, 0.0f, 1.0f, 0.0f)) | ||||||
| #define v0010 (_mm_set_ps(0.0f, 1.0f, 0.0f, 0.0f)) | #define v0010 (_mm_set_ps(0.0f, 1.0f, 0.0f, 0.0f)) | ||||||
| #elif defined(BT_USE_NEON) | #elif defined(BT_USE_NEON) | ||||||
|  | const btSimdFloat4 ATTRIBUTE_ALIGNED16(v0000) = {0.0f, 0.0f, 0.0f, 0.0f}; | ||||||
| const btSimdFloat4 ATTRIBUTE_ALIGNED16(v1000) = {1.0f, 0.0f, 0.0f, 0.0f}; | const btSimdFloat4 ATTRIBUTE_ALIGNED16(v1000) = {1.0f, 0.0f, 0.0f, 0.0f}; | ||||||
| const btSimdFloat4 ATTRIBUTE_ALIGNED16(v0100) = {0.0f, 1.0f, 0.0f, 0.0f}; | const btSimdFloat4 ATTRIBUTE_ALIGNED16(v0100) = {0.0f, 1.0f, 0.0f, 0.0f}; | ||||||
| const btSimdFloat4 ATTRIBUTE_ALIGNED16(v0010) = {0.0f, 0.0f, 1.0f, 0.0f}; | const btSimdFloat4 ATTRIBUTE_ALIGNED16(v0010) = {0.0f, 0.0f, 1.0f, 0.0f}; | ||||||
|  | @ -331,6 +333,20 @@ public: | ||||||
| #endif | #endif | ||||||
| 	} | 	} | ||||||
|      |      | ||||||
|  |     /**@brief Set the matrix to the identity */ | ||||||
|  |     void setZero() | ||||||
|  |     { | ||||||
|  | #if (defined(BT_USE_SSE_IN_API) && defined(BT_USE_SSE)) || defined(BT_USE_NEON) | ||||||
|  |         m_el[0] = v0000; | ||||||
|  |         m_el[1] = v0000; | ||||||
|  |         m_el[2] = v0000; | ||||||
|  | #else | ||||||
|  |         setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0), | ||||||
|  |                  btScalar(0.0), btScalar(0.0), btScalar(0.0), | ||||||
|  |                  btScalar(0.0), btScalar(0.0), btScalar(0.0)); | ||||||
|  | #endif | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| 	static const btMatrix3x3& getIdentity() | 	static const btMatrix3x3& getIdentity() | ||||||
| 	{ | 	{ | ||||||
| #if (defined(BT_USE_SSE_IN_API) && defined(BT_USE_SSE)) || defined(BT_USE_NEON) | #if (defined(BT_USE_SSE_IN_API) && defined(BT_USE_SSE)) || defined(BT_USE_NEON) | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								thirdparty/bullet/LinearMath/btMatrixX.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								thirdparty/bullet/LinearMath/btMatrixX.h
									
										
									
									
										vendored
									
									
								
							|  | @ -346,10 +346,9 @@ struct btMatrixX | ||||||
| 					T dotProd = 0; | 					T dotProd = 0; | ||||||
| 					{ | 					{ | ||||||
| 						{ | 						{ | ||||||
| 							int r = rows(); |  | ||||||
| 							int c = cols(); | 							int c = cols(); | ||||||
| 
 | 
 | ||||||
| 							for (int k = 0; k < cols(); k++) | 							for (int k = 0; k < c; k++) | ||||||
| 							{ | 							{ | ||||||
| 								T w = (*this)(i, k); | 								T w = (*this)(i, k); | ||||||
| 								if (other(k, j) != 0.f) | 								if (other(k, j) != 0.f) | ||||||
|  |  | ||||||
							
								
								
									
										83
									
								
								thirdparty/bullet/LinearMath/btModifiedGramSchmidt.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								thirdparty/bullet/LinearMath/btModifiedGramSchmidt.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,83 @@ | ||||||
|  | //
 | ||||||
|  | //  btModifiedGramSchmidt.h
 | ||||||
|  | //  LinearMath
 | ||||||
|  | //
 | ||||||
|  | //  Created by Xuchen Han on 4/4/20.
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | #ifndef btModifiedGramSchmidt_h | ||||||
|  | #define btModifiedGramSchmidt_h | ||||||
|  | 
 | ||||||
|  | #include "btReducedVector.h" | ||||||
|  | #include "btAlignedObjectArray.h" | ||||||
|  | #include <iostream> | ||||||
|  | #include <cmath> | ||||||
|  | template<class TV> | ||||||
|  | class btModifiedGramSchmidt | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     btAlignedObjectArray<TV> m_in; | ||||||
|  |     btAlignedObjectArray<TV> m_out; | ||||||
|  |      | ||||||
|  |     btModifiedGramSchmidt(const btAlignedObjectArray<TV>& vecs): m_in(vecs) | ||||||
|  |     { | ||||||
|  |         m_out.resize(0); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     void solve() | ||||||
|  |     { | ||||||
|  |         m_out.resize(m_in.size()); | ||||||
|  |         for (int i = 0; i < m_in.size(); ++i) | ||||||
|  |         { | ||||||
|  | //            printf("========= starting %d ==========\n", i);
 | ||||||
|  |             TV v(m_in[i]); | ||||||
|  | //            v.print();
 | ||||||
|  |             for (int j = 0; j < i; ++j) | ||||||
|  |             { | ||||||
|  |                 v = v - v.proj(m_out[j]); | ||||||
|  | //                v.print();
 | ||||||
|  |             } | ||||||
|  |             v.normalize(); | ||||||
|  |             m_out[i] = v; | ||||||
|  | //            v.print();
 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     void test() | ||||||
|  |     { | ||||||
|  |         std::cout << SIMD_EPSILON << std::endl; | ||||||
|  |         printf("=======inputs=========\n"); | ||||||
|  |         for (int i = 0; i < m_out.size(); ++i) | ||||||
|  |         { | ||||||
|  |             m_in[i].print(); | ||||||
|  |         } | ||||||
|  |         printf("=======output=========\n"); | ||||||
|  |         for (int i = 0; i < m_out.size(); ++i) | ||||||
|  |         { | ||||||
|  |             m_out[i].print(); | ||||||
|  |         } | ||||||
|  |         btScalar eps = SIMD_EPSILON; | ||||||
|  |         for (int i = 0; i < m_out.size(); ++i) | ||||||
|  |         { | ||||||
|  |             for (int j = 0; j < m_out.size(); ++j) | ||||||
|  |             { | ||||||
|  |                 if (i == j) | ||||||
|  |                 { | ||||||
|  |                     if (std::abs(1.0-m_out[i].dot(m_out[j])) > eps)// && std::abs(m_out[i].dot(m_out[j])) > eps)
 | ||||||
|  |                     { | ||||||
|  |                         printf("vec[%d] is not unit, norm squared = %f\n", i,m_out[i].dot(m_out[j])); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                 { | ||||||
|  |                     if (std::abs(m_out[i].dot(m_out[j])) > eps) | ||||||
|  |                     { | ||||||
|  |                         printf("vec[%d] and vec[%d] is not orthogonal, dot product = %f\n", i, j, m_out[i].dot(m_out[j])); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | template class btModifiedGramSchmidt<btReducedVector>; | ||||||
|  | #endif /* btModifiedGramSchmidt_h */ | ||||||
							
								
								
									
										170
									
								
								thirdparty/bullet/LinearMath/btReducedVector.cpp
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								thirdparty/bullet/LinearMath/btReducedVector.cpp
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,170 @@ | ||||||
|  | //
 | ||||||
|  | //  btReducedVector.cpp
 | ||||||
|  | //  LinearMath
 | ||||||
|  | //
 | ||||||
|  | //  Created by Xuchen Han on 4/4/20.
 | ||||||
|  | //
 | ||||||
|  | #include <stdio.h> | ||||||
|  | #include "btReducedVector.h" | ||||||
|  | #include <cmath> | ||||||
|  | 
 | ||||||
|  | // returns the projection of this onto other
 | ||||||
|  | btReducedVector btReducedVector::proj(const btReducedVector& other) const | ||||||
|  | { | ||||||
|  |     btReducedVector ret(m_sz); | ||||||
|  |     btScalar other_length2 = other.length2(); | ||||||
|  |     if (other_length2 < SIMD_EPSILON) | ||||||
|  |     { | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |     return other*(this->dot(other))/other_length2; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void btReducedVector::normalize() | ||||||
|  | { | ||||||
|  |     if (this->length2() < SIMD_EPSILON) | ||||||
|  |     { | ||||||
|  |         m_indices.clear(); | ||||||
|  |         m_vecs.clear(); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     *this /= std::sqrt(this->length2()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool btReducedVector::testAdd() const | ||||||
|  | { | ||||||
|  |     int sz = 5; | ||||||
|  |     btAlignedObjectArray<int> id1; | ||||||
|  |     id1.push_back(1); | ||||||
|  |     id1.push_back(3); | ||||||
|  |     btAlignedObjectArray<btVector3> v1; | ||||||
|  |     v1.push_back(btVector3(1,0,1)); | ||||||
|  |     v1.push_back(btVector3(3,1,5)); | ||||||
|  |     btAlignedObjectArray<int> id2; | ||||||
|  |     id2.push_back(2); | ||||||
|  |     id2.push_back(3); | ||||||
|  |     id2.push_back(5); | ||||||
|  |     btAlignedObjectArray<btVector3> v2; | ||||||
|  |     v2.push_back(btVector3(2,3,1)); | ||||||
|  |     v2.push_back(btVector3(3,4,9)); | ||||||
|  |     v2.push_back(btVector3(0,4,0)); | ||||||
|  |     btAlignedObjectArray<int> id3; | ||||||
|  |     id3.push_back(1); | ||||||
|  |     id3.push_back(2); | ||||||
|  |     id3.push_back(3); | ||||||
|  |     id3.push_back(5); | ||||||
|  |     btAlignedObjectArray<btVector3> v3; | ||||||
|  |     v3.push_back(btVector3(1,0,1)); | ||||||
|  |     v3.push_back(btVector3(2,3,1)); | ||||||
|  |     v3.push_back(btVector3(6,5,14)); | ||||||
|  |     v3.push_back(btVector3(0,4,0)); | ||||||
|  |     btReducedVector rv1(sz, id1, v1); | ||||||
|  |     btReducedVector rv2(sz, id2, v2); | ||||||
|  |     btReducedVector ans(sz, id3, v3); | ||||||
|  |     bool ret = ((ans == rv1+rv2) && (ans == rv2+rv1)); | ||||||
|  |     if (!ret) | ||||||
|  |         printf("btReducedVector testAdd failed\n"); | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool btReducedVector::testMinus() const | ||||||
|  | { | ||||||
|  |     int sz = 5; | ||||||
|  |     btAlignedObjectArray<int> id1; | ||||||
|  |     id1.push_back(1); | ||||||
|  |     id1.push_back(3); | ||||||
|  |     btAlignedObjectArray<btVector3> v1; | ||||||
|  |     v1.push_back(btVector3(1,0,1)); | ||||||
|  |     v1.push_back(btVector3(3,1,5)); | ||||||
|  |     btAlignedObjectArray<int> id2; | ||||||
|  |     id2.push_back(2); | ||||||
|  |     id2.push_back(3); | ||||||
|  |     id2.push_back(5); | ||||||
|  |     btAlignedObjectArray<btVector3> v2; | ||||||
|  |     v2.push_back(btVector3(2,3,1)); | ||||||
|  |     v2.push_back(btVector3(3,4,9)); | ||||||
|  |     v2.push_back(btVector3(0,4,0)); | ||||||
|  |     btAlignedObjectArray<int> id3; | ||||||
|  |     id3.push_back(1); | ||||||
|  |     id3.push_back(2); | ||||||
|  |     id3.push_back(3); | ||||||
|  |     id3.push_back(5); | ||||||
|  |     btAlignedObjectArray<btVector3> v3; | ||||||
|  |     v3.push_back(btVector3(-1,-0,-1)); | ||||||
|  |     v3.push_back(btVector3(2,3,1)); | ||||||
|  |     v3.push_back(btVector3(0,3,4)); | ||||||
|  |     v3.push_back(btVector3(0,4,0)); | ||||||
|  |     btReducedVector rv1(sz, id1, v1); | ||||||
|  |     btReducedVector rv2(sz, id2, v2); | ||||||
|  |     btReducedVector ans(sz, id3, v3); | ||||||
|  |     bool ret = (ans == rv2-rv1); | ||||||
|  |     if (!ret) | ||||||
|  |         printf("btReducedVector testMinus failed\n"); | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool btReducedVector::testDot() const | ||||||
|  | { | ||||||
|  |     int sz = 5; | ||||||
|  |     btAlignedObjectArray<int> id1; | ||||||
|  |     id1.push_back(1); | ||||||
|  |     id1.push_back(3); | ||||||
|  |     btAlignedObjectArray<btVector3> v1; | ||||||
|  |     v1.push_back(btVector3(1,0,1)); | ||||||
|  |     v1.push_back(btVector3(3,1,5)); | ||||||
|  |     btAlignedObjectArray<int> id2; | ||||||
|  |     id2.push_back(2); | ||||||
|  |     id2.push_back(3); | ||||||
|  |     id2.push_back(5); | ||||||
|  |     btAlignedObjectArray<btVector3> v2; | ||||||
|  |     v2.push_back(btVector3(2,3,1)); | ||||||
|  |     v2.push_back(btVector3(3,4,9)); | ||||||
|  |     v2.push_back(btVector3(0,4,0)); | ||||||
|  |     btReducedVector rv1(sz, id1, v1); | ||||||
|  |     btReducedVector rv2(sz, id2, v2); | ||||||
|  |     btScalar ans = 58; | ||||||
|  |     bool ret = (ans == rv2.dot(rv1) && ans == rv1.dot(rv2)); | ||||||
|  |     ans = 14+16+9+16+81; | ||||||
|  |     ret &= (ans==rv2.dot(rv2)); | ||||||
|  |      | ||||||
|  |     if (!ret) | ||||||
|  |         printf("btReducedVector testDot failed\n"); | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool btReducedVector::testMultiply() const | ||||||
|  | { | ||||||
|  |     int sz = 5; | ||||||
|  |     btAlignedObjectArray<int> id1; | ||||||
|  |     id1.push_back(1); | ||||||
|  |     id1.push_back(3); | ||||||
|  |     btAlignedObjectArray<btVector3> v1; | ||||||
|  |     v1.push_back(btVector3(1,0,1)); | ||||||
|  |     v1.push_back(btVector3(3,1,5)); | ||||||
|  |     btScalar s = 2; | ||||||
|  |     btReducedVector rv1(sz, id1, v1); | ||||||
|  |     btAlignedObjectArray<int> id2; | ||||||
|  |     id2.push_back(1); | ||||||
|  |     id2.push_back(3); | ||||||
|  |     btAlignedObjectArray<btVector3> v2; | ||||||
|  |     v2.push_back(btVector3(2,0,2)); | ||||||
|  |     v2.push_back(btVector3(6,2,10)); | ||||||
|  |     btReducedVector ans(sz, id2, v2); | ||||||
|  |     bool ret = (ans == rv1*s); | ||||||
|  |     if (!ret) | ||||||
|  |         printf("btReducedVector testMultiply failed\n"); | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void btReducedVector::test() const | ||||||
|  | { | ||||||
|  |     bool ans = testAdd() && testMinus() && testDot() && testMultiply(); | ||||||
|  |     if (ans) | ||||||
|  |     { | ||||||
|  |         printf("All tests passed\n"); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         printf("Tests failed\n"); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										320
									
								
								thirdparty/bullet/LinearMath/btReducedVector.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										320
									
								
								thirdparty/bullet/LinearMath/btReducedVector.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,320 @@ | ||||||
|  | //
 | ||||||
|  | //  btReducedVectors.h
 | ||||||
|  | //  BulletLinearMath
 | ||||||
|  | //
 | ||||||
|  | //  Created by Xuchen Han on 4/4/20.
 | ||||||
|  | //
 | ||||||
|  | #ifndef btReducedVectors_h | ||||||
|  | #define btReducedVectors_h | ||||||
|  | #include "btVector3.h" | ||||||
|  | #include "btMatrix3x3.h" | ||||||
|  | #include "btAlignedObjectArray.h" | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <vector> | ||||||
|  | #include <algorithm> | ||||||
|  | struct TwoInts | ||||||
|  | { | ||||||
|  |     int a,b; | ||||||
|  | }; | ||||||
|  | inline bool operator<(const TwoInts& A, const TwoInts& B) | ||||||
|  | { | ||||||
|  |     return A.b < B.b; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // A helper vector type used for CG projections
 | ||||||
|  | class btReducedVector | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     btAlignedObjectArray<int> m_indices; | ||||||
|  |     btAlignedObjectArray<btVector3> m_vecs; | ||||||
|  |     int m_sz; // all m_indices value < m_sz
 | ||||||
|  | public: | ||||||
|  | 	btReducedVector():m_sz(0) | ||||||
|  | 	{ | ||||||
|  | 		m_indices.resize(0); | ||||||
|  | 		m_vecs.resize(0); | ||||||
|  |         m_indices.clear(); | ||||||
|  |         m_vecs.clear(); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  |     btReducedVector(int sz): m_sz(sz) | ||||||
|  |     { | ||||||
|  |         m_indices.resize(0); | ||||||
|  |         m_vecs.resize(0); | ||||||
|  |         m_indices.clear(); | ||||||
|  |         m_vecs.clear(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     btReducedVector(int sz, const btAlignedObjectArray<int>& indices, const btAlignedObjectArray<btVector3>& vecs): m_sz(sz), m_indices(indices), m_vecs(vecs) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     void simplify() | ||||||
|  |     { | ||||||
|  |         btAlignedObjectArray<int> old_indices(m_indices); | ||||||
|  |         btAlignedObjectArray<btVector3> old_vecs(m_vecs); | ||||||
|  |         m_indices.resize(0); | ||||||
|  |         m_vecs.resize(0); | ||||||
|  |         m_indices.clear(); | ||||||
|  |         m_vecs.clear(); | ||||||
|  |         for (int i = 0; i < old_indices.size(); ++i) | ||||||
|  |         { | ||||||
|  |             if (old_vecs[i].length2() > SIMD_EPSILON) | ||||||
|  |             { | ||||||
|  |                 m_indices.push_back(old_indices[i]); | ||||||
|  |                 m_vecs.push_back(old_vecs[i]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     btReducedVector operator+(const btReducedVector& other) | ||||||
|  |     { | ||||||
|  | 		btReducedVector ret(m_sz); | ||||||
|  | 		int i=0, j=0; | ||||||
|  | 		while (i < m_indices.size() && j < other.m_indices.size()) | ||||||
|  | 		{ | ||||||
|  | 			if (m_indices[i] < other.m_indices[j]) | ||||||
|  | 			{ | ||||||
|  | 				ret.m_indices.push_back(m_indices[i]); | ||||||
|  | 				ret.m_vecs.push_back(m_vecs[i]); | ||||||
|  | 				++i; | ||||||
|  | 			} | ||||||
|  | 			else if (m_indices[i] > other.m_indices[j]) | ||||||
|  | 			{ | ||||||
|  | 				ret.m_indices.push_back(other.m_indices[j]); | ||||||
|  | 				ret.m_vecs.push_back(other.m_vecs[j]); | ||||||
|  | 				++j; | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				ret.m_indices.push_back(other.m_indices[j]); | ||||||
|  | 				ret.m_vecs.push_back(m_vecs[i] + other.m_vecs[j]); | ||||||
|  | 				++i; ++j; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		while (i < m_indices.size()) | ||||||
|  | 		{ | ||||||
|  | 			ret.m_indices.push_back(m_indices[i]); | ||||||
|  | 			ret.m_vecs.push_back(m_vecs[i]); | ||||||
|  | 			++i; | ||||||
|  | 		} | ||||||
|  | 		while (j < other.m_indices.size()) | ||||||
|  | 		{ | ||||||
|  | 			ret.m_indices.push_back(other.m_indices[j]); | ||||||
|  | 			ret.m_vecs.push_back(other.m_vecs[j]); | ||||||
|  | 			++j; | ||||||
|  | 		} | ||||||
|  |         ret.simplify(); | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     btReducedVector operator-() | ||||||
|  |     { | ||||||
|  |         btReducedVector ret(m_sz); | ||||||
|  |         for (int i = 0; i < m_indices.size(); ++i) | ||||||
|  |         { | ||||||
|  |             ret.m_indices.push_back(m_indices[i]); | ||||||
|  |             ret.m_vecs.push_back(-m_vecs[i]); | ||||||
|  |         } | ||||||
|  |         ret.simplify(); | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     btReducedVector operator-(const btReducedVector& other) | ||||||
|  |     { | ||||||
|  | 		btReducedVector ret(m_sz); | ||||||
|  | 		int i=0, j=0; | ||||||
|  | 		while (i < m_indices.size() && j < other.m_indices.size()) | ||||||
|  | 		{ | ||||||
|  | 			if (m_indices[i] < other.m_indices[j]) | ||||||
|  | 			{ | ||||||
|  | 				ret.m_indices.push_back(m_indices[i]); | ||||||
|  | 				ret.m_vecs.push_back(m_vecs[i]); | ||||||
|  | 				++i; | ||||||
|  | 			} | ||||||
|  | 			else if (m_indices[i] > other.m_indices[j]) | ||||||
|  | 			{ | ||||||
|  | 				ret.m_indices.push_back(other.m_indices[j]); | ||||||
|  | 				ret.m_vecs.push_back(-other.m_vecs[j]); | ||||||
|  | 				++j; | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				ret.m_indices.push_back(other.m_indices[j]); | ||||||
|  | 				ret.m_vecs.push_back(m_vecs[i] - other.m_vecs[j]); | ||||||
|  | 				++i; ++j; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		while (i < m_indices.size()) | ||||||
|  | 		{ | ||||||
|  | 			ret.m_indices.push_back(m_indices[i]); | ||||||
|  | 			ret.m_vecs.push_back(m_vecs[i]); | ||||||
|  | 			++i; | ||||||
|  | 		} | ||||||
|  | 		while (j < other.m_indices.size()) | ||||||
|  | 		{ | ||||||
|  | 			ret.m_indices.push_back(other.m_indices[j]); | ||||||
|  | 			ret.m_vecs.push_back(-other.m_vecs[j]); | ||||||
|  | 			++j; | ||||||
|  | 		} | ||||||
|  |         ret.simplify(); | ||||||
|  | 		return ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     bool operator==(const btReducedVector& other) const | ||||||
|  |     { | ||||||
|  |         if (m_sz != other.m_sz) | ||||||
|  |             return false; | ||||||
|  |         if (m_indices.size() != other.m_indices.size()) | ||||||
|  |             return false; | ||||||
|  |         for (int i = 0; i < m_indices.size(); ++i) | ||||||
|  |         { | ||||||
|  |             if (m_indices[i] != other.m_indices[i] || m_vecs[i] != other.m_vecs[i]) | ||||||
|  |             { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     bool operator!=(const btReducedVector& other) const | ||||||
|  |     { | ||||||
|  |         return !(*this == other); | ||||||
|  |     } | ||||||
|  | 	 | ||||||
|  | 	btReducedVector& operator=(const btReducedVector& other) | ||||||
|  | 	{ | ||||||
|  | 		if (this == &other) | ||||||
|  | 		{ | ||||||
|  | 			return *this; | ||||||
|  | 		} | ||||||
|  |         m_sz = other.m_sz; | ||||||
|  | 		m_indices.copyFromArray(other.m_indices); | ||||||
|  | 		m_vecs.copyFromArray(other.m_vecs); | ||||||
|  | 		return *this; | ||||||
|  | 	} | ||||||
|  |      | ||||||
|  |     btScalar dot(const btReducedVector& other) const | ||||||
|  |     { | ||||||
|  |         btScalar ret = 0; | ||||||
|  |         int j = 0; | ||||||
|  |         for (int i = 0; i < m_indices.size(); ++i) | ||||||
|  |         { | ||||||
|  |             while (j < other.m_indices.size() && other.m_indices[j] < m_indices[i]) | ||||||
|  |             { | ||||||
|  |                 ++j; | ||||||
|  |             } | ||||||
|  |             if (j < other.m_indices.size() && other.m_indices[j] == m_indices[i]) | ||||||
|  |             { | ||||||
|  |                 ret += m_vecs[i].dot(other.m_vecs[j]); | ||||||
|  | //                ++j;
 | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     btScalar dot(const btAlignedObjectArray<btVector3>& other) const | ||||||
|  |     { | ||||||
|  |         btScalar ret = 0; | ||||||
|  |         for (int i = 0; i < m_indices.size(); ++i) | ||||||
|  |         { | ||||||
|  |             ret += m_vecs[i].dot(other[m_indices[i]]); | ||||||
|  |         } | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     btScalar length2() const | ||||||
|  |     { | ||||||
|  |         return this->dot(*this); | ||||||
|  |     } | ||||||
|  | 	 | ||||||
|  | 	void normalize(); | ||||||
|  |      | ||||||
|  |     // returns the projection of this onto other
 | ||||||
|  |     btReducedVector proj(const btReducedVector& other) const; | ||||||
|  |      | ||||||
|  |     bool testAdd() const; | ||||||
|  |      | ||||||
|  |     bool testMinus() const; | ||||||
|  |      | ||||||
|  |     bool testDot() const; | ||||||
|  |      | ||||||
|  |     bool testMultiply() const; | ||||||
|  |      | ||||||
|  |     void test() const; | ||||||
|  |      | ||||||
|  |     void print() const | ||||||
|  |     { | ||||||
|  |         for (int i = 0; i < m_indices.size(); ++i) | ||||||
|  |         { | ||||||
|  |             printf("%d: (%f, %f, %f)/", m_indices[i], m_vecs[i][0],m_vecs[i][1],m_vecs[i][2]); | ||||||
|  |         } | ||||||
|  |         printf("\n"); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |      | ||||||
|  |     void sort() | ||||||
|  |     { | ||||||
|  |         std::vector<TwoInts> tuples; | ||||||
|  |         for (int i = 0; i < m_indices.size(); ++i) | ||||||
|  |         { | ||||||
|  |             TwoInts ti; | ||||||
|  |             ti.a = i; | ||||||
|  |             ti.b = m_indices[i]; | ||||||
|  |             tuples.push_back(ti); | ||||||
|  |         } | ||||||
|  |         std::sort(tuples.begin(), tuples.end()); | ||||||
|  |         btAlignedObjectArray<int> new_indices; | ||||||
|  |         btAlignedObjectArray<btVector3> new_vecs; | ||||||
|  |         for (int i = 0; i < tuples.size(); ++i) | ||||||
|  |         { | ||||||
|  |             new_indices.push_back(tuples[i].b); | ||||||
|  |             new_vecs.push_back(m_vecs[tuples[i].a]); | ||||||
|  |         } | ||||||
|  |         m_indices = new_indices; | ||||||
|  |         m_vecs = new_vecs; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | SIMD_FORCE_INLINE btReducedVector operator*(const btReducedVector& v, btScalar s) | ||||||
|  | { | ||||||
|  |     btReducedVector ret(v.m_sz); | ||||||
|  |     for (int i = 0; i < v.m_indices.size(); ++i) | ||||||
|  |     { | ||||||
|  |         ret.m_indices.push_back(v.m_indices[i]); | ||||||
|  |         ret.m_vecs.push_back(s*v.m_vecs[i]); | ||||||
|  |     } | ||||||
|  |     ret.simplify(); | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SIMD_FORCE_INLINE btReducedVector operator*(btScalar s, const btReducedVector& v) | ||||||
|  | { | ||||||
|  |     return v*s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SIMD_FORCE_INLINE btReducedVector operator/(const btReducedVector& v, btScalar s) | ||||||
|  | { | ||||||
|  | 	return v * (1.0/s); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SIMD_FORCE_INLINE btReducedVector& operator/=(btReducedVector& v, btScalar s) | ||||||
|  | { | ||||||
|  | 	v = v/s; | ||||||
|  | 	return v; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SIMD_FORCE_INLINE btReducedVector& operator+=(btReducedVector& v1, const btReducedVector& v2) | ||||||
|  | { | ||||||
|  | 	v1 = v1+v2; | ||||||
|  | 	return v1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SIMD_FORCE_INLINE btReducedVector& operator-=(btReducedVector& v1, const btReducedVector& v2) | ||||||
|  | { | ||||||
|  | 	v1 = v1-v2; | ||||||
|  | 	return v1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif /* btReducedVectors_h */ | ||||||
							
								
								
									
										1
									
								
								thirdparty/bullet/btBulletCollisionAll.cpp
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								thirdparty/bullet/btBulletCollisionAll.cpp
									
										
									
									
										vendored
									
									
								
							|  | @ -23,6 +23,7 @@ | ||||||
| #include "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp" | #include "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp" | ||||||
| #include "BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp" | #include "BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp" | ||||||
| #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp" | #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp" | ||||||
|  | #include "BulletCollision/CollisionDispatch/btCollisionDispatcherMt.cpp" | ||||||
| #include "BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp" | #include "BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp" | ||||||
| #include "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp" | #include "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp" | ||||||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.cpp" | #include "BulletCollision/CollisionDispatch/btCollisionObject.cpp" | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								thirdparty/bullet/btLinearMathAll.cpp
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								thirdparty/bullet/btLinearMathAll.cpp
									
										
									
									
										vendored
									
									
								
							|  | @ -8,6 +8,7 @@ | ||||||
| #include "LinearMath/btConvexHullComputer.cpp" | #include "LinearMath/btConvexHullComputer.cpp" | ||||||
| #include "LinearMath/btQuickprof.cpp" | #include "LinearMath/btQuickprof.cpp" | ||||||
| #include "LinearMath/btThreads.cpp" | #include "LinearMath/btThreads.cpp" | ||||||
|  | #include "LinearMath/btReducedVector.cpp" | ||||||
| #include "LinearMath/TaskScheduler/btTaskScheduler.cpp" | #include "LinearMath/TaskScheduler/btTaskScheduler.cpp" | ||||||
| #include "LinearMath/TaskScheduler/btThreadSupportPosix.cpp" | #include "LinearMath/TaskScheduler/btThreadSupportPosix.cpp" | ||||||
| #include "LinearMath/TaskScheduler/btThreadSupportWin32.cpp" | #include "LinearMath/TaskScheduler/btThreadSupportWin32.cpp" | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 PouleyKetchoupp
						PouleyKetchoupp