242 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			242 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /*
 | ||
|  | Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans  http://continuousphysics.com/Bullet/
 | ||
|  | 
 | ||
|  | This software is provided 'as-is', without any express or implied warranty. | ||
|  | In no event will the authors be held liable for any damages arising from the use of this software. | ||
|  | Permission is granted to anyone to use this software for any purpose,  | ||
|  | including commercial applications, and to alter it and redistribute it freely,  | ||
|  | subject to the following restrictions: | ||
|  | 
 | ||
|  | 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | ||
|  | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | ||
|  | 3. This notice may not be removed or altered from any source distribution. | ||
|  | */ | ||
|  | 
 | ||
|  | 
 | ||
|  | #ifndef BT_TRANSFORM_UTIL_H
 | ||
|  | #define BT_TRANSFORM_UTIL_H
 | ||
|  | 
 | ||
|  | #include "btTransform.h"
 | ||
|  | #define ANGULAR_MOTION_THRESHOLD btScalar(0.5)*SIMD_HALF_PI
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | SIMD_FORCE_INLINE btVector3 btAabbSupport(const btVector3& halfExtents,const btVector3& supportDir) | ||
|  | { | ||
|  | 	return btVector3(supportDir.x() < btScalar(0.0) ? -halfExtents.x() : halfExtents.x(), | ||
|  |       supportDir.y() < btScalar(0.0) ? -halfExtents.y() : halfExtents.y(), | ||
|  |       supportDir.z() < btScalar(0.0) ? -halfExtents.z() : halfExtents.z());  | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /// Utils related to temporal transforms
 | ||
|  | class btTransformUtil | ||
|  | { | ||
|  | 
 | ||
|  | public: | ||
|  | 
 | ||
|  | 	static void integrateTransform(const btTransform& curTrans,const btVector3& linvel,const btVector3& angvel,btScalar timeStep,btTransform& predictedTransform) | ||
|  | 	{ | ||
|  | 		predictedTransform.setOrigin(curTrans.getOrigin() + linvel * timeStep); | ||
|  | //	#define QUATERNION_DERIVATIVE
 | ||
|  | 	#ifdef QUATERNION_DERIVATIVE
 | ||
|  | 		btQuaternion predictedOrn = curTrans.getRotation(); | ||
|  | 		predictedOrn += (angvel * predictedOrn) * (timeStep * btScalar(0.5)); | ||
|  | 		predictedOrn.safeNormalize(); | ||
|  | 	#else
 | ||
|  | 		//Exponential map
 | ||
|  | 		//google for "Practical Parameterization of Rotations Using the Exponential Map", F. Sebastian Grassia
 | ||
|  | 
 | ||
|  | 		btVector3 axis; | ||
|  | 		btScalar	fAngle2 = angvel.length2(); | ||
|  |         	btScalar    fAngle = 0; | ||
|  |         	if (fAngle2>SIMD_EPSILON) | ||
|  |         	{ | ||
|  |             		fAngle = btSqrt(fAngle2); | ||
|  |         	} | ||
|  | 
 | ||
|  | 		//limit the angular motion
 | ||
|  | 		if (fAngle*timeStep > ANGULAR_MOTION_THRESHOLD) | ||
|  | 		{ | ||
|  | 			fAngle = ANGULAR_MOTION_THRESHOLD / timeStep; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if ( fAngle < btScalar(0.001) ) | ||
|  | 		{ | ||
|  | 			// use Taylor's expansions of sync function
 | ||
|  | 			axis   = angvel*( btScalar(0.5)*timeStep-(timeStep*timeStep*timeStep)*(btScalar(0.020833333333))*fAngle*fAngle ); | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			// sync(fAngle) = sin(c*fAngle)/t
 | ||
|  | 			axis   = angvel*( btSin(btScalar(0.5)*fAngle*timeStep)/fAngle ); | ||
|  | 		} | ||
|  | 		btQuaternion dorn (axis.x(),axis.y(),axis.z(),btCos( fAngle*timeStep*btScalar(0.5) )); | ||
|  | 		btQuaternion orn0 = curTrans.getRotation(); | ||
|  | 
 | ||
|  | 		btQuaternion predictedOrn = dorn * orn0; | ||
|  | 		predictedOrn.safeNormalize(); | ||
|  | 	#endif
 | ||
|  | 		if (predictedOrn.length2()>SIMD_EPSILON) | ||
|  | 		{ | ||
|  | 			predictedTransform.setRotation(predictedOrn); | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			predictedTransform.setBasis(curTrans.getBasis()); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static void	calculateVelocityQuaternion(const btVector3& pos0,const btVector3& pos1,const btQuaternion& orn0,const btQuaternion& orn1,btScalar timeStep,btVector3& linVel,btVector3& angVel) | ||
|  | 	{ | ||
|  | 		linVel = (pos1 - pos0) / timeStep; | ||
|  | 		btVector3 axis; | ||
|  | 		btScalar  angle; | ||
|  | 		if (orn0 != orn1) | ||
|  | 		{ | ||
|  | 			calculateDiffAxisAngleQuaternion(orn0,orn1,axis,angle); | ||
|  | 			angVel = axis * angle / timeStep; | ||
|  | 		} else | ||
|  | 		{ | ||
|  | 			angVel.setValue(0,0,0); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static void calculateDiffAxisAngleQuaternion(const btQuaternion& orn0,const btQuaternion& orn1a,btVector3& axis,btScalar& angle) | ||
|  | 	{ | ||
|  | 		btQuaternion orn1 = orn0.nearest(orn1a); | ||
|  | 		btQuaternion dorn = orn1 * orn0.inverse(); | ||
|  | 		angle = dorn.getAngle(); | ||
|  | 		axis = btVector3(dorn.x(),dorn.y(),dorn.z()); | ||
|  | 		axis[3] = btScalar(0.); | ||
|  | 		//check for axis length
 | ||
|  | 		btScalar len = axis.length2(); | ||
|  | 		if (len < SIMD_EPSILON*SIMD_EPSILON) | ||
|  | 			axis = btVector3(btScalar(1.),btScalar(0.),btScalar(0.)); | ||
|  | 		else | ||
|  | 			axis /= btSqrt(len); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static void	calculateVelocity(const btTransform& transform0,const btTransform& transform1,btScalar timeStep,btVector3& linVel,btVector3& angVel) | ||
|  | 	{ | ||
|  | 		linVel = (transform1.getOrigin() - transform0.getOrigin()) / timeStep; | ||
|  | 		btVector3 axis; | ||
|  | 		btScalar  angle; | ||
|  | 		calculateDiffAxisAngle(transform0,transform1,axis,angle); | ||
|  | 		angVel = axis * angle / timeStep; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static void calculateDiffAxisAngle(const btTransform& transform0,const btTransform& transform1,btVector3& axis,btScalar& angle) | ||
|  | 	{ | ||
|  | 		btMatrix3x3 dmat = transform1.getBasis() * transform0.getBasis().inverse(); | ||
|  | 		btQuaternion dorn; | ||
|  | 		dmat.getRotation(dorn); | ||
|  | 
 | ||
|  | 		///floating point inaccuracy can lead to w component > 1..., which breaks 
 | ||
|  | 		dorn.normalize(); | ||
|  | 		 | ||
|  | 		angle = dorn.getAngle(); | ||
|  | 		axis = btVector3(dorn.x(),dorn.y(),dorn.z()); | ||
|  | 		axis[3] = btScalar(0.); | ||
|  | 		//check for axis length
 | ||
|  | 		btScalar len = axis.length2(); | ||
|  | 		if (len < SIMD_EPSILON*SIMD_EPSILON) | ||
|  | 			axis = btVector3(btScalar(1.),btScalar(0.),btScalar(0.)); | ||
|  | 		else | ||
|  | 			axis /= btSqrt(len); | ||
|  | 	} | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | ///The btConvexSeparatingDistanceUtil can help speed up convex collision detection 
 | ||
|  | ///by conservatively updating a cached separating distance/vector instead of re-calculating the closest distance
 | ||
|  | class	btConvexSeparatingDistanceUtil | ||
|  | { | ||
|  | 	btQuaternion	m_ornA; | ||
|  | 	btQuaternion	m_ornB; | ||
|  | 	btVector3	m_posA; | ||
|  | 	btVector3	m_posB; | ||
|  | 	 | ||
|  | 	btVector3	m_separatingNormal; | ||
|  | 
 | ||
|  | 	btScalar	m_boundingRadiusA; | ||
|  | 	btScalar	m_boundingRadiusB; | ||
|  | 	btScalar	m_separatingDistance; | ||
|  | 
 | ||
|  | public: | ||
|  | 
 | ||
|  | 	btConvexSeparatingDistanceUtil(btScalar	boundingRadiusA,btScalar	boundingRadiusB) | ||
|  | 		:m_boundingRadiusA(boundingRadiusA), | ||
|  | 		m_boundingRadiusB(boundingRadiusB), | ||
|  | 		m_separatingDistance(0.f) | ||
|  | 	{ | ||
|  | 	} | ||
|  | 
 | ||
|  | 	btScalar	getConservativeSeparatingDistance() | ||
|  | 	{ | ||
|  | 		return m_separatingDistance; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void	updateSeparatingDistance(const btTransform& transA,const btTransform& transB) | ||
|  | 	{ | ||
|  | 		const btVector3& toPosA = transA.getOrigin(); | ||
|  | 		const btVector3& toPosB = transB.getOrigin(); | ||
|  | 		btQuaternion toOrnA = transA.getRotation(); | ||
|  | 		btQuaternion toOrnB = transB.getRotation(); | ||
|  | 
 | ||
|  | 		if (m_separatingDistance>0.f) | ||
|  | 		{ | ||
|  | 			 | ||
|  | 
 | ||
|  | 			btVector3 linVelA,angVelA,linVelB,angVelB; | ||
|  | 			btTransformUtil::calculateVelocityQuaternion(m_posA,toPosA,m_ornA,toOrnA,btScalar(1.),linVelA,angVelA); | ||
|  | 			btTransformUtil::calculateVelocityQuaternion(m_posB,toPosB,m_ornB,toOrnB,btScalar(1.),linVelB,angVelB); | ||
|  | 			btScalar maxAngularProjectedVelocity = angVelA.length() * m_boundingRadiusA + angVelB.length() * m_boundingRadiusB; | ||
|  | 			btVector3 relLinVel = (linVelB-linVelA); | ||
|  | 			btScalar relLinVelocLength = relLinVel.dot(m_separatingNormal); | ||
|  | 			if (relLinVelocLength<0.f) | ||
|  | 			{ | ||
|  | 				relLinVelocLength = 0.f; | ||
|  | 			} | ||
|  | 	 | ||
|  | 			btScalar	projectedMotion = maxAngularProjectedVelocity +relLinVelocLength; | ||
|  | 			m_separatingDistance -= projectedMotion; | ||
|  | 		} | ||
|  | 	 | ||
|  | 		m_posA = toPosA; | ||
|  | 		m_posB = toPosB; | ||
|  | 		m_ornA = toOrnA; | ||
|  | 		m_ornB = toOrnB; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void	initSeparatingDistance(const btVector3& separatingVector,btScalar separatingDistance,const btTransform& transA,const btTransform& transB) | ||
|  | 	{ | ||
|  | 		m_separatingDistance = separatingDistance; | ||
|  | 
 | ||
|  | 		if (m_separatingDistance>0.f) | ||
|  | 		{ | ||
|  | 			m_separatingNormal = separatingVector; | ||
|  | 			 | ||
|  | 			const btVector3& toPosA = transA.getOrigin(); | ||
|  | 			const btVector3& toPosB = transB.getOrigin(); | ||
|  | 			btQuaternion toOrnA = transA.getRotation(); | ||
|  | 			btQuaternion toOrnB = transB.getRotation(); | ||
|  | 			m_posA = toPosA; | ||
|  | 			m_posB = toPosB; | ||
|  | 			m_ornA = toOrnA; | ||
|  | 			m_ornB = toOrnB; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | #endif //BT_TRANSFORM_UTIL_H
 | ||
|  | 
 |