856 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			856 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | /*
 | ||
|  | Bullet Continuous Collision Detection and Physics Library | ||
|  | Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
 | ||
|  | 
 | ||
|  | This software is provided 'as-is', without any express or implied warranty. | ||
|  | In no event will the authors be held liable for any damages arising from the use of this software. | ||
|  | Permission is granted to anyone to use this software for any purpose, | ||
|  | including commercial applications, and to alter it and redistribute it freely, | ||
|  | subject to the following restrictions: | ||
|  | 
 | ||
|  | 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | ||
|  | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | ||
|  | 3. This notice may not be removed or altered from any source distribution. | ||
|  | */ | ||
|  | 
 | ||
|  | /*
 | ||
|  | Added by Roman Ponomarev (rponom@gmail.com) | ||
|  | April 04, 2008 | ||
|  | */ | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #include "btSliderConstraint.h"
 | ||
|  | #include "BulletDynamics/Dynamics/btRigidBody.h"
 | ||
|  | #include "LinearMath/btTransformUtil.h"
 | ||
|  | #include <new>
 | ||
|  | 
 | ||
|  | #define USE_OFFSET_FOR_CONSTANT_FRAME true
 | ||
|  | 
 | ||
|  | void btSliderConstraint::initParams() | ||
|  | { | ||
|  |     m_lowerLinLimit = btScalar(1.0); | ||
|  |     m_upperLinLimit = btScalar(-1.0); | ||
|  |     m_lowerAngLimit = btScalar(0.); | ||
|  |     m_upperAngLimit = btScalar(0.); | ||
|  | 	m_softnessDirLin = SLIDER_CONSTRAINT_DEF_SOFTNESS; | ||
|  | 	m_restitutionDirLin = SLIDER_CONSTRAINT_DEF_RESTITUTION; | ||
|  | 	m_dampingDirLin = btScalar(0.); | ||
|  | 	m_cfmDirLin = SLIDER_CONSTRAINT_DEF_CFM; | ||
|  | 	m_softnessDirAng = SLIDER_CONSTRAINT_DEF_SOFTNESS; | ||
|  | 	m_restitutionDirAng = SLIDER_CONSTRAINT_DEF_RESTITUTION; | ||
|  | 	m_dampingDirAng = btScalar(0.); | ||
|  | 	m_cfmDirAng = SLIDER_CONSTRAINT_DEF_CFM; | ||
|  | 	m_softnessOrthoLin = SLIDER_CONSTRAINT_DEF_SOFTNESS; | ||
|  | 	m_restitutionOrthoLin = SLIDER_CONSTRAINT_DEF_RESTITUTION; | ||
|  | 	m_dampingOrthoLin = SLIDER_CONSTRAINT_DEF_DAMPING; | ||
|  | 	m_cfmOrthoLin = SLIDER_CONSTRAINT_DEF_CFM; | ||
|  | 	m_softnessOrthoAng = SLIDER_CONSTRAINT_DEF_SOFTNESS; | ||
|  | 	m_restitutionOrthoAng = SLIDER_CONSTRAINT_DEF_RESTITUTION; | ||
|  | 	m_dampingOrthoAng = SLIDER_CONSTRAINT_DEF_DAMPING; | ||
|  | 	m_cfmOrthoAng = SLIDER_CONSTRAINT_DEF_CFM; | ||
|  | 	m_softnessLimLin = SLIDER_CONSTRAINT_DEF_SOFTNESS; | ||
|  | 	m_restitutionLimLin = SLIDER_CONSTRAINT_DEF_RESTITUTION; | ||
|  | 	m_dampingLimLin = SLIDER_CONSTRAINT_DEF_DAMPING; | ||
|  | 	m_cfmLimLin = SLIDER_CONSTRAINT_DEF_CFM; | ||
|  | 	m_softnessLimAng = SLIDER_CONSTRAINT_DEF_SOFTNESS; | ||
|  | 	m_restitutionLimAng = SLIDER_CONSTRAINT_DEF_RESTITUTION; | ||
|  | 	m_dampingLimAng = SLIDER_CONSTRAINT_DEF_DAMPING; | ||
|  | 	m_cfmLimAng = SLIDER_CONSTRAINT_DEF_CFM; | ||
|  | 
 | ||
|  | 	m_poweredLinMotor = false; | ||
|  |     m_targetLinMotorVelocity = btScalar(0.); | ||
|  |     m_maxLinMotorForce = btScalar(0.); | ||
|  | 	m_accumulatedLinMotorImpulse = btScalar(0.0); | ||
|  | 
 | ||
|  | 	m_poweredAngMotor = false; | ||
|  |     m_targetAngMotorVelocity = btScalar(0.); | ||
|  |     m_maxAngMotorForce = btScalar(0.); | ||
|  | 	m_accumulatedAngMotorImpulse = btScalar(0.0); | ||
|  | 
 | ||
|  | 	m_flags = 0; | ||
|  | 	m_flags = 0; | ||
|  | 
 | ||
|  | 	m_useOffsetForConstraintFrame = USE_OFFSET_FOR_CONSTANT_FRAME; | ||
|  | 
 | ||
|  | 	calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | btSliderConstraint::btSliderConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA) | ||
|  |         : btTypedConstraint(SLIDER_CONSTRAINT_TYPE, rbA, rbB), | ||
|  | 		m_useSolveConstraintObsolete(false), | ||
|  | 		m_frameInA(frameInA), | ||
|  |         m_frameInB(frameInB), | ||
|  | 		m_useLinearReferenceFrameA(useLinearReferenceFrameA) | ||
|  | { | ||
|  | 	initParams(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | btSliderConstraint::btSliderConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameA) | ||
|  |         : btTypedConstraint(SLIDER_CONSTRAINT_TYPE, getFixedBody(), rbB), | ||
|  | 		m_useSolveConstraintObsolete(false), | ||
|  | 		m_frameInB(frameInB), | ||
|  | 		m_useLinearReferenceFrameA(useLinearReferenceFrameA) | ||
|  | { | ||
|  | 	///not providing rigidbody A means implicitly using worldspace for body A
 | ||
|  | 	m_frameInA = rbB.getCenterOfMassTransform() * m_frameInB; | ||
|  | //	m_frameInA.getOrigin() = m_rbA.getCenterOfMassTransform()(m_frameInA.getOrigin());
 | ||
|  | 
 | ||
|  | 	initParams(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | void btSliderConstraint::getInfo1(btConstraintInfo1* info) | ||
|  | { | ||
|  | 	if (m_useSolveConstraintObsolete) | ||
|  | 	{ | ||
|  | 		info->m_numConstraintRows = 0; | ||
|  | 		info->nub = 0; | ||
|  | 	} | ||
|  | 	else | ||
|  | 	{ | ||
|  | 		info->m_numConstraintRows = 4; // Fixed 2 linear + 2 angular
 | ||
|  | 		info->nub = 2;  | ||
|  | 		//prepare constraint
 | ||
|  | 		calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); | ||
|  | 		testAngLimits(); | ||
|  | 		testLinLimits(); | ||
|  | 		if(getSolveLinLimit() || getPoweredLinMotor()) | ||
|  | 		{ | ||
|  | 			info->m_numConstraintRows++; // limit 3rd linear as well
 | ||
|  | 			info->nub--;  | ||
|  | 		} | ||
|  | 		if(getSolveAngLimit() || getPoweredAngMotor()) | ||
|  | 		{ | ||
|  | 			info->m_numConstraintRows++; // limit 3rd angular as well
 | ||
|  | 			info->nub--;  | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | void btSliderConstraint::getInfo1NonVirtual(btConstraintInfo1* info) | ||
|  | { | ||
|  | 
 | ||
|  | 	info->m_numConstraintRows = 6; // Fixed 2 linear + 2 angular + 1 limit (even if not used)
 | ||
|  | 	info->nub = 0;  | ||
|  | } | ||
|  | 
 | ||
|  | void btSliderConstraint::getInfo2(btConstraintInfo2* info) | ||
|  | { | ||
|  | 	getInfo2NonVirtual(info,m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(), m_rbA.getLinearVelocity(),m_rbB.getLinearVelocity(), m_rbA.getInvMass(),m_rbB.getInvMass()); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | void btSliderConstraint::calculateTransforms(const btTransform& transA,const btTransform& transB) | ||
|  | { | ||
|  | 	if(m_useLinearReferenceFrameA || (!m_useSolveConstraintObsolete)) | ||
|  | 	{ | ||
|  | 		m_calculatedTransformA = transA * m_frameInA; | ||
|  | 		m_calculatedTransformB = transB * m_frameInB; | ||
|  | 	} | ||
|  | 	else | ||
|  | 	{ | ||
|  | 		m_calculatedTransformA = transB * m_frameInB; | ||
|  | 		m_calculatedTransformB = transA * m_frameInA; | ||
|  | 	} | ||
|  | 	m_realPivotAInW = m_calculatedTransformA.getOrigin(); | ||
|  | 	m_realPivotBInW = m_calculatedTransformB.getOrigin(); | ||
|  | 	m_sliderAxis = m_calculatedTransformA.getBasis().getColumn(0); // along X
 | ||
|  | 	if(m_useLinearReferenceFrameA || m_useSolveConstraintObsolete) | ||
|  | 	{ | ||
|  | 		m_delta = m_realPivotBInW - m_realPivotAInW; | ||
|  | 	} | ||
|  | 	else | ||
|  | 	{ | ||
|  | 		m_delta = m_realPivotAInW - m_realPivotBInW; | ||
|  | 	} | ||
|  | 	m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis; | ||
|  |     btVector3 normalWorld; | ||
|  |     int i; | ||
|  |     //linear part
 | ||
|  |     for(i = 0; i < 3; i++) | ||
|  |     { | ||
|  | 		normalWorld = m_calculatedTransformA.getBasis().getColumn(i); | ||
|  | 		m_depth[i] = m_delta.dot(normalWorld); | ||
|  |     } | ||
|  | } | ||
|  |   | ||
|  | 
 | ||
|  | 
 | ||
|  | void btSliderConstraint::testLinLimits(void) | ||
|  | { | ||
|  | 	m_solveLinLim = false; | ||
|  | 	m_linPos = m_depth[0]; | ||
|  | 	if(m_lowerLinLimit <= m_upperLinLimit) | ||
|  | 	{ | ||
|  | 		if(m_depth[0] > m_upperLinLimit) | ||
|  | 		{ | ||
|  | 			m_depth[0] -= m_upperLinLimit; | ||
|  | 			m_solveLinLim = true; | ||
|  | 		} | ||
|  | 		else if(m_depth[0] < m_lowerLinLimit) | ||
|  | 		{ | ||
|  | 			m_depth[0] -= m_lowerLinLimit; | ||
|  | 			m_solveLinLim = true; | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			m_depth[0] = btScalar(0.); | ||
|  | 		} | ||
|  | 	} | ||
|  | 	else | ||
|  | 	{ | ||
|  | 		m_depth[0] = btScalar(0.); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | void btSliderConstraint::testAngLimits(void) | ||
|  | { | ||
|  | 	m_angDepth = btScalar(0.); | ||
|  | 	m_solveAngLim = false; | ||
|  | 	if(m_lowerAngLimit <= m_upperAngLimit) | ||
|  | 	{ | ||
|  | 		const btVector3 axisA0 = m_calculatedTransformA.getBasis().getColumn(1); | ||
|  | 		const btVector3 axisA1 = m_calculatedTransformA.getBasis().getColumn(2); | ||
|  | 		const btVector3 axisB0 = m_calculatedTransformB.getBasis().getColumn(1); | ||
|  | //		btScalar rot = btAtan2Fast(axisB0.dot(axisA1), axisB0.dot(axisA0));  
 | ||
|  | 		btScalar rot = btAtan2(axisB0.dot(axisA1), axisB0.dot(axisA0));   | ||
|  | 		rot = btAdjustAngleToLimits(rot, m_lowerAngLimit, m_upperAngLimit); | ||
|  | 		m_angPos = rot; | ||
|  | 		if(rot < m_lowerAngLimit) | ||
|  | 		{ | ||
|  | 			m_angDepth = rot - m_lowerAngLimit; | ||
|  | 			m_solveAngLim = true; | ||
|  | 		}  | ||
|  | 		else if(rot > m_upperAngLimit) | ||
|  | 		{ | ||
|  | 			m_angDepth = rot - m_upperAngLimit; | ||
|  | 			m_solveAngLim = true; | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | btVector3 btSliderConstraint::getAncorInA(void) | ||
|  | { | ||
|  | 	btVector3 ancorInA; | ||
|  | 	ancorInA = m_realPivotAInW + (m_lowerLinLimit + m_upperLinLimit) * btScalar(0.5) * m_sliderAxis; | ||
|  | 	ancorInA = m_rbA.getCenterOfMassTransform().inverse() * ancorInA; | ||
|  | 	return ancorInA; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | btVector3 btSliderConstraint::getAncorInB(void) | ||
|  | { | ||
|  | 	btVector3 ancorInB; | ||
|  | 	ancorInB = m_frameInB.getOrigin(); | ||
|  | 	return ancorInB; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void btSliderConstraint::getInfo2NonVirtual(btConstraintInfo2* info, const btTransform& transA,const btTransform& transB, const btVector3& linVelA,const btVector3& linVelB, btScalar rbAinvMass,btScalar rbBinvMass  ) | ||
|  | { | ||
|  | 	const btTransform& trA = getCalculatedTransformA(); | ||
|  | 	const btTransform& trB = getCalculatedTransformB(); | ||
|  | 	 | ||
|  | 	btAssert(!m_useSolveConstraintObsolete); | ||
|  | 	int i, s = info->rowskip; | ||
|  | 	 | ||
|  | 	btScalar signFact = m_useLinearReferenceFrameA ? btScalar(1.0f) : btScalar(-1.0f); | ||
|  | 	 | ||
|  | 	// difference between frames in WCS
 | ||
|  | 	btVector3 ofs = trB.getOrigin() - trA.getOrigin(); | ||
|  | 	// now get weight factors depending on masses
 | ||
|  | 	btScalar miA = rbAinvMass; | ||
|  | 	btScalar miB = rbBinvMass; | ||
|  | 	bool hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON); | ||
|  | 	btScalar miS = miA + miB; | ||
|  | 	btScalar factA, factB; | ||
|  | 	if(miS > btScalar(0.f)) | ||
|  | 	{ | ||
|  | 		factA = miB / miS; | ||
|  | 	} | ||
|  | 	else  | ||
|  | 	{ | ||
|  | 		factA = btScalar(0.5f); | ||
|  | 	} | ||
|  | 	factB = btScalar(1.0f) - factA; | ||
|  | 	btVector3 ax1, p, q; | ||
|  | 	btVector3 ax1A = trA.getBasis().getColumn(0); | ||
|  | 	btVector3 ax1B = trB.getBasis().getColumn(0); | ||
|  | 	if(m_useOffsetForConstraintFrame) | ||
|  | 	{ | ||
|  | 		// get the desired direction of slider axis
 | ||
|  | 		// as weighted sum of X-orthos of frameA and frameB in WCS
 | ||
|  | 		ax1 = ax1A * factA + ax1B * factB; | ||
|  | 		ax1.normalize(); | ||
|  | 		// construct two orthos to slider axis
 | ||
|  | 		btPlaneSpace1 (ax1, p, q); | ||
|  | 	} | ||
|  | 	else | ||
|  | 	{ // old way - use frameA
 | ||
|  | 		ax1 = trA.getBasis().getColumn(0); | ||
|  | 		// get 2 orthos to slider axis (Y, Z)
 | ||
|  | 		p = trA.getBasis().getColumn(1); | ||
|  | 		q = trA.getBasis().getColumn(2); | ||
|  | 	} | ||
|  | 	// make rotations around these orthos equal
 | ||
|  | 	// the slider axis should be the only unconstrained
 | ||
|  | 	// rotational axis, the angular velocity of the two bodies perpendicular to
 | ||
|  | 	// the slider axis should be equal. thus the constraint equations are
 | ||
|  | 	//    p*w1 - p*w2 = 0
 | ||
|  | 	//    q*w1 - q*w2 = 0
 | ||
|  | 	// where p and q are unit vectors normal to the slider axis, and w1 and w2
 | ||
|  | 	// are the angular velocity vectors of the two bodies.
 | ||
|  | 	info->m_J1angularAxis[0] = p[0]; | ||
|  | 	info->m_J1angularAxis[1] = p[1]; | ||
|  | 	info->m_J1angularAxis[2] = p[2]; | ||
|  | 	info->m_J1angularAxis[s+0] = q[0]; | ||
|  | 	info->m_J1angularAxis[s+1] = q[1]; | ||
|  | 	info->m_J1angularAxis[s+2] = q[2]; | ||
|  | 
 | ||
|  | 	info->m_J2angularAxis[0] = -p[0]; | ||
|  | 	info->m_J2angularAxis[1] = -p[1]; | ||
|  | 	info->m_J2angularAxis[2] = -p[2]; | ||
|  | 	info->m_J2angularAxis[s+0] = -q[0]; | ||
|  | 	info->m_J2angularAxis[s+1] = -q[1]; | ||
|  | 	info->m_J2angularAxis[s+2] = -q[2]; | ||
|  | 	// compute the right hand side of the constraint equation. set relative
 | ||
|  | 	// body velocities along p and q to bring the slider back into alignment.
 | ||
|  | 	// if ax1A,ax1B are the unit length slider axes as computed from bodyA and
 | ||
|  | 	// bodyB, we need to rotate both bodies along the axis u = (ax1 x ax2).
 | ||
|  | 	// if "theta" is the angle between ax1 and ax2, we need an angular velocity
 | ||
|  | 	// along u to cover angle erp*theta in one step :
 | ||
|  | 	//   |angular_velocity| = angle/time = erp*theta / stepsize
 | ||
|  | 	//                      = (erp*fps) * theta
 | ||
|  | 	//    angular_velocity  = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2|
 | ||
|  | 	//                      = (erp*fps) * theta * (ax1 x ax2) / sin(theta)
 | ||
|  | 	// ...as ax1 and ax2 are unit length. if theta is smallish,
 | ||
|  | 	// theta ~= sin(theta), so
 | ||
|  | 	//    angular_velocity  = (erp*fps) * (ax1 x ax2)
 | ||
|  | 	// ax1 x ax2 is in the plane space of ax1, so we project the angular
 | ||
|  | 	// velocity to p and q to find the right hand side.
 | ||
|  | //	btScalar k = info->fps * info->erp * getSoftnessOrthoAng();
 | ||
|  | 	btScalar currERP = (m_flags & BT_SLIDER_FLAGS_ERP_ORTANG) ? m_softnessOrthoAng : m_softnessOrthoAng * info->erp; | ||
|  | 	btScalar k = info->fps * currERP; | ||
|  | 
 | ||
|  | 	btVector3 u = ax1A.cross(ax1B); | ||
|  | 	info->m_constraintError[0] = k * u.dot(p); | ||
|  | 	info->m_constraintError[s] = k * u.dot(q); | ||
|  | 	if(m_flags & BT_SLIDER_FLAGS_CFM_ORTANG) | ||
|  | 	{ | ||
|  | 		info->cfm[0] = m_cfmOrthoAng; | ||
|  | 		info->cfm[s] = m_cfmOrthoAng; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	int nrow = 1; // last filled row
 | ||
|  | 	int srow; | ||
|  | 	btScalar limit_err; | ||
|  | 	int limit; | ||
|  | 
 | ||
|  | 	// next two rows. 
 | ||
|  | 	// we want: velA + wA x relA == velB + wB x relB ... but this would
 | ||
|  | 	// result in three equations, so we project along two orthos to the slider axis
 | ||
|  | 
 | ||
|  | 	btTransform bodyA_trans = transA; | ||
|  | 	btTransform bodyB_trans = transB; | ||
|  | 	nrow++; | ||
|  | 	int s2 = nrow * s; | ||
|  | 	nrow++; | ||
|  | 	int s3 = nrow * s; | ||
|  | 	btVector3 tmpA(0,0,0), tmpB(0,0,0), relA(0,0,0), relB(0,0,0), c(0,0,0); | ||
|  | 	if(m_useOffsetForConstraintFrame) | ||
|  | 	{ | ||
|  | 		// get vector from bodyB to frameB in WCS
 | ||
|  | 		relB = trB.getOrigin() - bodyB_trans.getOrigin(); | ||
|  | 		// get its projection to slider axis
 | ||
|  | 		btVector3 projB = ax1 * relB.dot(ax1); | ||
|  | 		// get vector directed from bodyB to slider axis (and orthogonal to it)
 | ||
|  | 		btVector3 orthoB = relB - projB; | ||
|  | 		// same for bodyA
 | ||
|  | 		relA = trA.getOrigin() - bodyA_trans.getOrigin(); | ||
|  | 		btVector3 projA = ax1 * relA.dot(ax1); | ||
|  | 		btVector3 orthoA = relA - projA; | ||
|  | 		// get desired offset between frames A and B along slider axis
 | ||
|  | 		btScalar sliderOffs = m_linPos - m_depth[0]; | ||
|  | 		// desired vector from projection of center of bodyA to projection of center of bodyB to slider axis
 | ||
|  | 		btVector3 totalDist = projA + ax1 * sliderOffs - projB; | ||
|  | 		// get offset vectors relA and relB
 | ||
|  | 		relA = orthoA + totalDist * factA; | ||
|  | 		relB = orthoB - totalDist * factB; | ||
|  | 		// now choose average ortho to slider axis
 | ||
|  | 		p = orthoB * factA + orthoA * factB; | ||
|  | 		btScalar len2 = p.length2(); | ||
|  | 		if(len2 > SIMD_EPSILON) | ||
|  | 		{ | ||
|  | 			p /= btSqrt(len2); | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			p = trA.getBasis().getColumn(1); | ||
|  | 		} | ||
|  | 		// make one more ortho
 | ||
|  | 		q = ax1.cross(p); | ||
|  | 		// fill two rows
 | ||
|  | 		tmpA = relA.cross(p); | ||
|  | 		tmpB = relB.cross(p); | ||
|  | 		for (i=0; i<3; i++) info->m_J1angularAxis[s2+i] = tmpA[i]; | ||
|  | 		for (i=0; i<3; i++) info->m_J2angularAxis[s2+i] = -tmpB[i]; | ||
|  | 		tmpA = relA.cross(q); | ||
|  | 		tmpB = relB.cross(q); | ||
|  | 		if(hasStaticBody && getSolveAngLimit()) | ||
|  | 		{ // to make constraint between static and dynamic objects more rigid
 | ||
|  | 			// remove wA (or wB) from equation if angular limit is hit
 | ||
|  | 			tmpB *= factB; | ||
|  | 			tmpA *= factA; | ||
|  | 		} | ||
|  | 		for (i=0; i<3; i++) info->m_J1angularAxis[s3+i] = tmpA[i]; | ||
|  | 		for (i=0; i<3; i++) info->m_J2angularAxis[s3+i] = -tmpB[i]; | ||
|  | 		for (i=0; i<3; i++) info->m_J1linearAxis[s2+i] = p[i]; | ||
|  | 		for (i=0; i<3; i++) info->m_J1linearAxis[s3+i] = q[i]; | ||
|  | 		for (i=0; i<3; i++) info->m_J2linearAxis[s2+i] = -p[i]; | ||
|  | 		for (i=0; i<3; i++) info->m_J2linearAxis[s3+i] = -q[i]; | ||
|  | 	} | ||
|  | 	else | ||
|  | 	{	// old way - maybe incorrect if bodies are not on the slider axis
 | ||
|  | 		// see discussion "Bug in slider constraint" http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=4024&start=0
 | ||
|  | 		c = bodyB_trans.getOrigin() - bodyA_trans.getOrigin(); | ||
|  | 		btVector3 tmp = c.cross(p); | ||
|  | 		for (i=0; i<3; i++) info->m_J1angularAxis[s2+i] = factA*tmp[i]; | ||
|  | 		for (i=0; i<3; i++) info->m_J2angularAxis[s2+i] = factB*tmp[i]; | ||
|  | 		tmp = c.cross(q); | ||
|  | 		for (i=0; i<3; i++) info->m_J1angularAxis[s3+i] = factA*tmp[i]; | ||
|  | 		for (i=0; i<3; i++) info->m_J2angularAxis[s3+i] = factB*tmp[i]; | ||
|  | 
 | ||
|  | 		for (i=0; i<3; i++) info->m_J1linearAxis[s2+i] = p[i]; | ||
|  | 		for (i=0; i<3; i++) info->m_J1linearAxis[s3+i] = q[i]; | ||
|  | 		for (i=0; i<3; i++) info->m_J2linearAxis[s2+i] = -p[i]; | ||
|  | 		for (i=0; i<3; i++) info->m_J2linearAxis[s3+i] = -q[i]; | ||
|  | 	} | ||
|  | 	// compute two elements of right hand side
 | ||
|  | 
 | ||
|  | 	//	k = info->fps * info->erp * getSoftnessOrthoLin();
 | ||
|  | 	currERP = (m_flags & BT_SLIDER_FLAGS_ERP_ORTLIN) ? m_softnessOrthoLin : m_softnessOrthoLin * info->erp; | ||
|  | 	k = info->fps * currERP; | ||
|  | 
 | ||
|  | 	btScalar rhs = k * p.dot(ofs); | ||
|  | 	info->m_constraintError[s2] = rhs; | ||
|  | 	rhs = k * q.dot(ofs); | ||
|  | 	info->m_constraintError[s3] = rhs; | ||
|  | 	if(m_flags & BT_SLIDER_FLAGS_CFM_ORTLIN) | ||
|  | 	{ | ||
|  | 		info->cfm[s2] = m_cfmOrthoLin; | ||
|  | 		info->cfm[s3] = m_cfmOrthoLin; | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | 	// check linear limits
 | ||
|  | 	limit_err = btScalar(0.0); | ||
|  | 	limit = 0; | ||
|  | 	if(getSolveLinLimit()) | ||
|  | 	{ | ||
|  | 		limit_err = getLinDepth() *  signFact; | ||
|  | 		limit = (limit_err > btScalar(0.0)) ? 2 : 1; | ||
|  | 	} | ||
|  | 	bool powered = getPoweredLinMotor(); | ||
|  | 	// if the slider has joint limits or motor, add in the extra row
 | ||
|  | 	if (limit || powered) | ||
|  | 	{ | ||
|  | 		nrow++; | ||
|  | 		srow = nrow * info->rowskip; | ||
|  | 		info->m_J1linearAxis[srow+0] = ax1[0]; | ||
|  | 		info->m_J1linearAxis[srow+1] = ax1[1]; | ||
|  | 		info->m_J1linearAxis[srow+2] = ax1[2]; | ||
|  | 		info->m_J2linearAxis[srow+0] = -ax1[0]; | ||
|  | 		info->m_J2linearAxis[srow+1] = -ax1[1]; | ||
|  | 		info->m_J2linearAxis[srow+2] = -ax1[2]; | ||
|  | 		// linear torque decoupling step:
 | ||
|  | 		//
 | ||
|  | 		// we have to be careful that the linear constraint forces (+/- ax1) applied to the two bodies
 | ||
|  | 		// do not create a torque couple. in other words, the points that the
 | ||
|  | 		// constraint force is applied at must lie along the same ax1 axis.
 | ||
|  | 		// a torque couple will result in limited slider-jointed free
 | ||
|  | 		// bodies from gaining angular momentum.
 | ||
|  | 		if(m_useOffsetForConstraintFrame) | ||
|  | 		{ | ||
|  | 			// this is needed only when bodyA and bodyB are both dynamic.
 | ||
|  | 			if(!hasStaticBody) | ||
|  | 			{ | ||
|  | 				tmpA = relA.cross(ax1); | ||
|  | 				tmpB = relB.cross(ax1); | ||
|  | 				info->m_J1angularAxis[srow+0] = tmpA[0]; | ||
|  | 				info->m_J1angularAxis[srow+1] = tmpA[1]; | ||
|  | 				info->m_J1angularAxis[srow+2] = tmpA[2]; | ||
|  | 				info->m_J2angularAxis[srow+0] = -tmpB[0]; | ||
|  | 				info->m_J2angularAxis[srow+1] = -tmpB[1]; | ||
|  | 				info->m_J2angularAxis[srow+2] = -tmpB[2]; | ||
|  | 			} | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ // The old way. May be incorrect if bodies are not on the slider axis
 | ||
|  | 			btVector3 ltd;	// Linear Torque Decoupling vector (a torque)
 | ||
|  | 			ltd = c.cross(ax1); | ||
|  | 			info->m_J1angularAxis[srow+0] = factA*ltd[0]; | ||
|  | 			info->m_J1angularAxis[srow+1] = factA*ltd[1]; | ||
|  | 			info->m_J1angularAxis[srow+2] = factA*ltd[2]; | ||
|  | 			info->m_J2angularAxis[srow+0] = factB*ltd[0]; | ||
|  | 			info->m_J2angularAxis[srow+1] = factB*ltd[1]; | ||
|  | 			info->m_J2angularAxis[srow+2] = factB*ltd[2]; | ||
|  | 		} | ||
|  | 		// right-hand part
 | ||
|  | 		btScalar lostop = getLowerLinLimit(); | ||
|  | 		btScalar histop = getUpperLinLimit(); | ||
|  | 		if(limit && (lostop == histop)) | ||
|  | 		{  // the joint motor is ineffective
 | ||
|  | 			powered = false; | ||
|  | 		} | ||
|  | 		info->m_constraintError[srow] = 0.; | ||
|  | 		info->m_lowerLimit[srow] = 0.; | ||
|  | 		info->m_upperLimit[srow] = 0.; | ||
|  | 		currERP = (m_flags & BT_SLIDER_FLAGS_ERP_LIMLIN) ? m_softnessLimLin : info->erp; | ||
|  | 		if(powered) | ||
|  | 		{ | ||
|  | 			if(m_flags & BT_SLIDER_FLAGS_CFM_DIRLIN) | ||
|  | 			{ | ||
|  | 				info->cfm[srow] = m_cfmDirLin; | ||
|  | 			} | ||
|  | 			btScalar tag_vel = getTargetLinMotorVelocity(); | ||
|  | 			btScalar mot_fact = getMotorFactor(m_linPos, m_lowerLinLimit, m_upperLinLimit, tag_vel, info->fps * currERP); | ||
|  | 			info->m_constraintError[srow] -= signFact * mot_fact * getTargetLinMotorVelocity(); | ||
|  | 			info->m_lowerLimit[srow] += -getMaxLinMotorForce() / info->fps; | ||
|  | 			info->m_upperLimit[srow] += getMaxLinMotorForce() / info->fps; | ||
|  | 		} | ||
|  | 		if(limit) | ||
|  | 		{ | ||
|  | 			k = info->fps * currERP; | ||
|  | 			info->m_constraintError[srow] += k * limit_err; | ||
|  | 			if(m_flags & BT_SLIDER_FLAGS_CFM_LIMLIN) | ||
|  | 			{ | ||
|  | 				info->cfm[srow] = m_cfmLimLin; | ||
|  | 			} | ||
|  | 			if(lostop == histop)  | ||
|  | 			{	// limited low and high simultaneously
 | ||
|  | 				info->m_lowerLimit[srow] = -SIMD_INFINITY; | ||
|  | 				info->m_upperLimit[srow] = SIMD_INFINITY; | ||
|  | 			} | ||
|  | 			else if(limit == 1)  | ||
|  | 			{ // low limit
 | ||
|  | 				info->m_lowerLimit[srow] = -SIMD_INFINITY; | ||
|  | 				info->m_upperLimit[srow] = 0; | ||
|  | 			} | ||
|  | 			else  | ||
|  | 			{ // high limit
 | ||
|  | 				info->m_lowerLimit[srow] = 0; | ||
|  | 				info->m_upperLimit[srow] = SIMD_INFINITY; | ||
|  | 			} | ||
|  | 			// bounce (we'll use slider parameter abs(1.0 - m_dampingLimLin) for that)
 | ||
|  | 			btScalar bounce = btFabs(btScalar(1.0) - getDampingLimLin()); | ||
|  | 			if(bounce > btScalar(0.0)) | ||
|  | 			{ | ||
|  | 				btScalar vel = linVelA.dot(ax1); | ||
|  | 				vel -= linVelB.dot(ax1); | ||
|  | 				vel *= signFact; | ||
|  | 				// only apply bounce if the velocity is incoming, and if the
 | ||
|  | 				// resulting c[] exceeds what we already have.
 | ||
|  | 				if(limit == 1) | ||
|  | 				{	// low limit
 | ||
|  | 					if(vel < 0) | ||
|  | 					{ | ||
|  | 						btScalar newc = -bounce * vel; | ||
|  | 						if (newc > info->m_constraintError[srow]) | ||
|  | 						{ | ||
|  | 							info->m_constraintError[srow] = newc; | ||
|  | 						} | ||
|  | 					} | ||
|  | 				} | ||
|  | 				else | ||
|  | 				{ // high limit - all those computations are reversed
 | ||
|  | 					if(vel > 0) | ||
|  | 					{ | ||
|  | 						btScalar newc = -bounce * vel; | ||
|  | 						if(newc < info->m_constraintError[srow])  | ||
|  | 						{ | ||
|  | 							info->m_constraintError[srow] = newc; | ||
|  | 						} | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 			info->m_constraintError[srow] *= getSoftnessLimLin(); | ||
|  | 		} // if(limit)
 | ||
|  | 	} // if linear limit
 | ||
|  | 	// check angular limits
 | ||
|  | 	limit_err = btScalar(0.0); | ||
|  | 	limit = 0; | ||
|  | 	if(getSolveAngLimit()) | ||
|  | 	{ | ||
|  | 		limit_err = getAngDepth(); | ||
|  | 		limit = (limit_err > btScalar(0.0)) ? 1 : 2; | ||
|  | 	} | ||
|  | 	// if the slider has joint limits, add in the extra row
 | ||
|  | 	powered = getPoweredAngMotor(); | ||
|  | 	if(limit || powered) | ||
|  | 	{ | ||
|  | 		nrow++; | ||
|  | 		srow = nrow * info->rowskip; | ||
|  | 		info->m_J1angularAxis[srow+0] = ax1[0]; | ||
|  | 		info->m_J1angularAxis[srow+1] = ax1[1]; | ||
|  | 		info->m_J1angularAxis[srow+2] = ax1[2]; | ||
|  | 
 | ||
|  | 		info->m_J2angularAxis[srow+0] = -ax1[0]; | ||
|  | 		info->m_J2angularAxis[srow+1] = -ax1[1]; | ||
|  | 		info->m_J2angularAxis[srow+2] = -ax1[2]; | ||
|  | 
 | ||
|  | 		btScalar lostop = getLowerAngLimit(); | ||
|  | 		btScalar histop = getUpperAngLimit(); | ||
|  | 		if(limit && (lostop == histop)) | ||
|  | 		{  // the joint motor is ineffective
 | ||
|  | 			powered = false; | ||
|  | 		} | ||
|  | 		currERP = (m_flags & BT_SLIDER_FLAGS_ERP_LIMANG) ? m_softnessLimAng : info->erp; | ||
|  | 		if(powered) | ||
|  | 		{ | ||
|  | 			if(m_flags & BT_SLIDER_FLAGS_CFM_DIRANG) | ||
|  | 			{ | ||
|  | 				info->cfm[srow] = m_cfmDirAng; | ||
|  | 			} | ||
|  | 			btScalar mot_fact = getMotorFactor(m_angPos, m_lowerAngLimit, m_upperAngLimit, getTargetAngMotorVelocity(), info->fps * currERP); | ||
|  | 			info->m_constraintError[srow] = mot_fact * getTargetAngMotorVelocity(); | ||
|  | 			info->m_lowerLimit[srow] = -getMaxAngMotorForce() / info->fps; | ||
|  | 			info->m_upperLimit[srow] = getMaxAngMotorForce() / info->fps; | ||
|  | 		} | ||
|  | 		if(limit) | ||
|  | 		{ | ||
|  | 			k = info->fps * currERP; | ||
|  | 			info->m_constraintError[srow] += k * limit_err; | ||
|  | 			if(m_flags & BT_SLIDER_FLAGS_CFM_LIMANG) | ||
|  | 			{ | ||
|  | 				info->cfm[srow] = m_cfmLimAng; | ||
|  | 			} | ||
|  | 			if(lostop == histop)  | ||
|  | 			{ | ||
|  | 				// limited low and high simultaneously
 | ||
|  | 				info->m_lowerLimit[srow] = -SIMD_INFINITY; | ||
|  | 				info->m_upperLimit[srow] = SIMD_INFINITY; | ||
|  | 			} | ||
|  | 			else if(limit == 1)  | ||
|  | 			{ // low limit
 | ||
|  | 				info->m_lowerLimit[srow] = 0; | ||
|  | 				info->m_upperLimit[srow] = SIMD_INFINITY; | ||
|  | 			} | ||
|  | 			else  | ||
|  | 			{ // high limit
 | ||
|  | 				info->m_lowerLimit[srow] = -SIMD_INFINITY; | ||
|  | 				info->m_upperLimit[srow] = 0; | ||
|  | 			} | ||
|  | 			// bounce (we'll use slider parameter abs(1.0 - m_dampingLimAng) for that)
 | ||
|  | 			btScalar bounce = btFabs(btScalar(1.0) - getDampingLimAng()); | ||
|  | 			if(bounce > btScalar(0.0)) | ||
|  | 			{ | ||
|  | 				btScalar vel = m_rbA.getAngularVelocity().dot(ax1); | ||
|  | 				vel -= m_rbB.getAngularVelocity().dot(ax1); | ||
|  | 				// only apply bounce if the velocity is incoming, and if the
 | ||
|  | 				// resulting c[] exceeds what we already have.
 | ||
|  | 				if(limit == 1) | ||
|  | 				{	// low limit
 | ||
|  | 					if(vel < 0) | ||
|  | 					{ | ||
|  | 						btScalar newc = -bounce * vel; | ||
|  | 						if(newc > info->m_constraintError[srow]) | ||
|  | 						{ | ||
|  | 							info->m_constraintError[srow] = newc; | ||
|  | 						} | ||
|  | 					} | ||
|  | 				} | ||
|  | 				else | ||
|  | 				{	// high limit - all those computations are reversed
 | ||
|  | 					if(vel > 0) | ||
|  | 					{ | ||
|  | 						btScalar newc = -bounce * vel; | ||
|  | 						if(newc < info->m_constraintError[srow]) | ||
|  | 						{ | ||
|  | 							info->m_constraintError[srow] = newc; | ||
|  | 						} | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 			info->m_constraintError[srow] *= getSoftnessLimAng(); | ||
|  | 		} // if(limit)
 | ||
|  | 	} // if angular limit or powered
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). 
 | ||
|  | ///If no axis is provided, it uses the default axis for this constraint.
 | ||
|  | void btSliderConstraint::setParam(int num, btScalar value, int axis) | ||
|  | { | ||
|  | 	switch(num) | ||
|  | 	{ | ||
|  | 	case BT_CONSTRAINT_STOP_ERP : | ||
|  | 		if(axis < 1) | ||
|  | 		{ | ||
|  | 			m_softnessLimLin = value; | ||
|  | 			m_flags |= BT_SLIDER_FLAGS_ERP_LIMLIN; | ||
|  | 		} | ||
|  | 		else if(axis < 3) | ||
|  | 		{ | ||
|  | 			m_softnessOrthoLin = value; | ||
|  | 			m_flags |= BT_SLIDER_FLAGS_ERP_ORTLIN; | ||
|  | 		} | ||
|  | 		else if(axis == 3) | ||
|  | 		{ | ||
|  | 			m_softnessLimAng = value; | ||
|  | 			m_flags |= BT_SLIDER_FLAGS_ERP_LIMANG; | ||
|  | 		} | ||
|  | 		else if(axis < 6) | ||
|  | 		{ | ||
|  | 			m_softnessOrthoAng = value; | ||
|  | 			m_flags |= BT_SLIDER_FLAGS_ERP_ORTANG; | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(0); | ||
|  | 		} | ||
|  | 		break; | ||
|  | 	case BT_CONSTRAINT_CFM : | ||
|  | 		if(axis < 1) | ||
|  | 		{ | ||
|  | 			m_cfmDirLin = value; | ||
|  | 			m_flags |= BT_SLIDER_FLAGS_CFM_DIRLIN; | ||
|  | 		} | ||
|  | 		else if(axis == 3) | ||
|  | 		{ | ||
|  | 			m_cfmDirAng = value; | ||
|  | 			m_flags |= BT_SLIDER_FLAGS_CFM_DIRANG; | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(0); | ||
|  | 		} | ||
|  | 		break; | ||
|  | 	case BT_CONSTRAINT_STOP_CFM : | ||
|  | 		if(axis < 1) | ||
|  | 		{ | ||
|  | 			m_cfmLimLin = value; | ||
|  | 			m_flags |= BT_SLIDER_FLAGS_CFM_LIMLIN; | ||
|  | 		} | ||
|  | 		else if(axis < 3) | ||
|  | 		{ | ||
|  | 			m_cfmOrthoLin = value; | ||
|  | 			m_flags |= BT_SLIDER_FLAGS_CFM_ORTLIN; | ||
|  | 		} | ||
|  | 		else if(axis == 3) | ||
|  | 		{ | ||
|  | 			m_cfmLimAng = value; | ||
|  | 			m_flags |= BT_SLIDER_FLAGS_CFM_LIMANG; | ||
|  | 		} | ||
|  | 		else if(axis < 6) | ||
|  | 		{ | ||
|  | 			m_cfmOrthoAng = value; | ||
|  | 			m_flags |= BT_SLIDER_FLAGS_CFM_ORTANG; | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(0); | ||
|  | 		} | ||
|  | 		break; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | ///return the local value of parameter
 | ||
|  | btScalar btSliderConstraint::getParam(int num, int axis) const  | ||
|  | { | ||
|  | 	btScalar retVal(SIMD_INFINITY); | ||
|  | 	switch(num) | ||
|  | 	{ | ||
|  | 	case BT_CONSTRAINT_STOP_ERP : | ||
|  | 		if(axis < 1) | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_LIMLIN); | ||
|  | 			retVal = m_softnessLimLin; | ||
|  | 		} | ||
|  | 		else if(axis < 3) | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_ORTLIN); | ||
|  | 			retVal = m_softnessOrthoLin; | ||
|  | 		} | ||
|  | 		else if(axis == 3) | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_LIMANG); | ||
|  | 			retVal = m_softnessLimAng; | ||
|  | 		} | ||
|  | 		else if(axis < 6) | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_ORTANG); | ||
|  | 			retVal = m_softnessOrthoAng; | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(0); | ||
|  | 		} | ||
|  | 		break; | ||
|  | 	case BT_CONSTRAINT_CFM : | ||
|  | 		if(axis < 1) | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_DIRLIN); | ||
|  | 			retVal = m_cfmDirLin; | ||
|  | 		} | ||
|  | 		else if(axis == 3) | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_DIRANG); | ||
|  | 			retVal = m_cfmDirAng; | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(0); | ||
|  | 		} | ||
|  | 		break; | ||
|  | 	case BT_CONSTRAINT_STOP_CFM : | ||
|  | 		if(axis < 1) | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_LIMLIN); | ||
|  | 			retVal = m_cfmLimLin; | ||
|  | 		} | ||
|  | 		else if(axis < 3) | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_ORTLIN); | ||
|  | 			retVal = m_cfmOrthoLin; | ||
|  | 		} | ||
|  | 		else if(axis == 3) | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_LIMANG); | ||
|  | 			retVal = m_cfmLimAng; | ||
|  | 		} | ||
|  | 		else if(axis < 6) | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_ORTANG); | ||
|  | 			retVal = m_cfmOrthoAng; | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			btAssertConstrParams(0); | ||
|  | 		} | ||
|  | 		break; | ||
|  | 	} | ||
|  | 	return retVal; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 |