• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
4 
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
10 
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15 
16 #include "btRigidBody.h"
17 #include "BulletCollision/CollisionShapes/btConvexShape.h"
18 #include "LinearMath/btMinMax.h"
19 #include "LinearMath/btTransformUtil.h"
20 #include "LinearMath/btMotionState.h"
21 #include "BulletDynamics/ConstraintSolver/btTypedConstraint.h"
22 #include "LinearMath/btSerializer.h"
23 
24 //'temporarily' global variables
25 btScalar	gDeactivationTime = btScalar(2.);
26 bool	gDisableDeactivation = false;
27 static int uniqueId = 0;
28 
29 
btRigidBody(const btRigidBody::btRigidBodyConstructionInfo & constructionInfo)30 btRigidBody::btRigidBody(const btRigidBody::btRigidBodyConstructionInfo& constructionInfo)
31 {
32 	setupRigidBody(constructionInfo);
33 }
34 
btRigidBody(btScalar mass,btMotionState * motionState,btCollisionShape * collisionShape,const btVector3 & localInertia)35 btRigidBody::btRigidBody(btScalar mass, btMotionState *motionState, btCollisionShape *collisionShape, const btVector3 &localInertia)
36 {
37 	btRigidBodyConstructionInfo cinfo(mass,motionState,collisionShape,localInertia);
38 	setupRigidBody(cinfo);
39 }
40 
setupRigidBody(const btRigidBody::btRigidBodyConstructionInfo & constructionInfo)41 void	btRigidBody::setupRigidBody(const btRigidBody::btRigidBodyConstructionInfo& constructionInfo)
42 {
43 
44 	m_internalType=CO_RIGID_BODY;
45 
46 	m_linearVelocity.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0));
47 	m_angularVelocity.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
48 	m_angularFactor.setValue(1,1,1);
49 	m_linearFactor.setValue(1,1,1);
50 	m_gravity.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0));
51 	m_gravity_acceleration.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0));
52 	m_totalForce.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0));
53 	m_totalTorque.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)),
54     setDamping(constructionInfo.m_linearDamping, constructionInfo.m_angularDamping);
55 
56 	m_linearSleepingThreshold = constructionInfo.m_linearSleepingThreshold;
57 	m_angularSleepingThreshold = constructionInfo.m_angularSleepingThreshold;
58 	m_optionalMotionState = constructionInfo.m_motionState;
59 	m_contactSolverType = 0;
60 	m_frictionSolverType = 0;
61 	m_additionalDamping = constructionInfo.m_additionalDamping;
62 	m_additionalDampingFactor = constructionInfo.m_additionalDampingFactor;
63 	m_additionalLinearDampingThresholdSqr = constructionInfo.m_additionalLinearDampingThresholdSqr;
64 	m_additionalAngularDampingThresholdSqr = constructionInfo.m_additionalAngularDampingThresholdSqr;
65 	m_additionalAngularDampingFactor = constructionInfo.m_additionalAngularDampingFactor;
66 
67 	if (m_optionalMotionState)
68 	{
69 		m_optionalMotionState->getWorldTransform(m_worldTransform);
70 	} else
71 	{
72 		m_worldTransform = constructionInfo.m_startWorldTransform;
73 	}
74 
75 	m_interpolationWorldTransform = m_worldTransform;
76 	m_interpolationLinearVelocity.setValue(0,0,0);
77 	m_interpolationAngularVelocity.setValue(0,0,0);
78 
79 	//moved to btCollisionObject
80 	m_friction = constructionInfo.m_friction;
81 	m_rollingFriction = constructionInfo.m_rollingFriction;
82 	m_restitution = constructionInfo.m_restitution;
83 
84 	setCollisionShape( constructionInfo.m_collisionShape );
85 	m_debugBodyId = uniqueId++;
86 
87 	setMassProps(constructionInfo.m_mass, constructionInfo.m_localInertia);
88 	updateInertiaTensor();
89 
90 	m_rigidbodyFlags = BT_ENABLE_GYROSCOPIC_FORCE_IMPLICIT_BODY;
91 
92 
93 	m_deltaLinearVelocity.setZero();
94 	m_deltaAngularVelocity.setZero();
95 	m_invMass = m_inverseMass*m_linearFactor;
96 	m_pushVelocity.setZero();
97 	m_turnVelocity.setZero();
98 
99 
100 
101 }
102 
103 
predictIntegratedTransform(btScalar timeStep,btTransform & predictedTransform)104 void btRigidBody::predictIntegratedTransform(btScalar timeStep,btTransform& predictedTransform)
105 {
106 	btTransformUtil::integrateTransform(m_worldTransform,m_linearVelocity,m_angularVelocity,timeStep,predictedTransform);
107 }
108 
saveKinematicState(btScalar timeStep)109 void			btRigidBody::saveKinematicState(btScalar timeStep)
110 {
111 	//todo: clamp to some (user definable) safe minimum timestep, to limit maximum angular/linear velocities
112 	if (timeStep != btScalar(0.))
113 	{
114 		//if we use motionstate to synchronize world transforms, get the new kinematic/animated world transform
115 		if (getMotionState())
116 			getMotionState()->getWorldTransform(m_worldTransform);
117 		btVector3 linVel,angVel;
118 
119 		btTransformUtil::calculateVelocity(m_interpolationWorldTransform,m_worldTransform,timeStep,m_linearVelocity,m_angularVelocity);
120 		m_interpolationLinearVelocity = m_linearVelocity;
121 		m_interpolationAngularVelocity = m_angularVelocity;
122 		m_interpolationWorldTransform = m_worldTransform;
123 		//printf("angular = %f %f %f\n",m_angularVelocity.getX(),m_angularVelocity.getY(),m_angularVelocity.getZ());
124 	}
125 }
126 
getAabb(btVector3 & aabbMin,btVector3 & aabbMax) const127 void	btRigidBody::getAabb(btVector3& aabbMin,btVector3& aabbMax) const
128 {
129 	getCollisionShape()->getAabb(m_worldTransform,aabbMin,aabbMax);
130 }
131 
132 
133 
134 
setGravity(const btVector3 & acceleration)135 void btRigidBody::setGravity(const btVector3& acceleration)
136 {
137 	if (m_inverseMass != btScalar(0.0))
138 	{
139 		m_gravity = acceleration * (btScalar(1.0) / m_inverseMass);
140 	}
141 	m_gravity_acceleration = acceleration;
142 }
143 
144 
145 
146 
147 
148 
setDamping(btScalar lin_damping,btScalar ang_damping)149 void btRigidBody::setDamping(btScalar lin_damping, btScalar ang_damping)
150 {
151 	m_linearDamping = btClamped(lin_damping, (btScalar)btScalar(0.0), (btScalar)btScalar(1.0));
152 	m_angularDamping = btClamped(ang_damping, (btScalar)btScalar(0.0), (btScalar)btScalar(1.0));
153 }
154 
155 
156 
157 
158 ///applyDamping damps the velocity, using the given m_linearDamping and m_angularDamping
applyDamping(btScalar timeStep)159 void			btRigidBody::applyDamping(btScalar timeStep)
160 {
161 	//On new damping: see discussion/issue report here: http://code.google.com/p/bullet/issues/detail?id=74
162 	//todo: do some performance comparisons (but other parts of the engine are probably bottleneck anyway
163 
164 //#define USE_OLD_DAMPING_METHOD 1
165 #ifdef USE_OLD_DAMPING_METHOD
166 	m_linearVelocity *= GEN_clamped((btScalar(1.) - timeStep * m_linearDamping), (btScalar)btScalar(0.0), (btScalar)btScalar(1.0));
167 	m_angularVelocity *= GEN_clamped((btScalar(1.) - timeStep * m_angularDamping), (btScalar)btScalar(0.0), (btScalar)btScalar(1.0));
168 #else
169 	m_linearVelocity *= btPow(btScalar(1)-m_linearDamping, timeStep);
170 	m_angularVelocity *= btPow(btScalar(1)-m_angularDamping, timeStep);
171 #endif
172 
173 	if (m_additionalDamping)
174 	{
175 		//Additional damping can help avoiding lowpass jitter motion, help stability for ragdolls etc.
176 		//Such damping is undesirable, so once the overall simulation quality of the rigid body dynamics system has improved, this should become obsolete
177 		if ((m_angularVelocity.length2() < m_additionalAngularDampingThresholdSqr) &&
178 			(m_linearVelocity.length2() < m_additionalLinearDampingThresholdSqr))
179 		{
180 			m_angularVelocity *= m_additionalDampingFactor;
181 			m_linearVelocity *= m_additionalDampingFactor;
182 		}
183 
184 
185 		btScalar speed = m_linearVelocity.length();
186 		if (speed < m_linearDamping)
187 		{
188 			btScalar dampVel = btScalar(0.005);
189 			if (speed > dampVel)
190 			{
191 				btVector3 dir = m_linearVelocity.normalized();
192 				m_linearVelocity -=  dir * dampVel;
193 			} else
194 			{
195 				m_linearVelocity.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
196 			}
197 		}
198 
199 		btScalar angSpeed = m_angularVelocity.length();
200 		if (angSpeed < m_angularDamping)
201 		{
202 			btScalar angDampVel = btScalar(0.005);
203 			if (angSpeed > angDampVel)
204 			{
205 				btVector3 dir = m_angularVelocity.normalized();
206 				m_angularVelocity -=  dir * angDampVel;
207 			} else
208 			{
209 				m_angularVelocity.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
210 			}
211 		}
212 	}
213 }
214 
215 
applyGravity()216 void btRigidBody::applyGravity()
217 {
218 	if (isStaticOrKinematicObject())
219 		return;
220 
221 	applyCentralForce(m_gravity);
222 
223 }
224 
proceedToTransform(const btTransform & newTrans)225 void btRigidBody::proceedToTransform(const btTransform& newTrans)
226 {
227 	setCenterOfMassTransform( newTrans );
228 }
229 
230 
setMassProps(btScalar mass,const btVector3 & inertia)231 void btRigidBody::setMassProps(btScalar mass, const btVector3& inertia)
232 {
233 	if (mass == btScalar(0.))
234 	{
235 		m_collisionFlags |= btCollisionObject::CF_STATIC_OBJECT;
236 		m_inverseMass = btScalar(0.);
237 	} else
238 	{
239 		m_collisionFlags &= (~btCollisionObject::CF_STATIC_OBJECT);
240 		m_inverseMass = btScalar(1.0) / mass;
241 	}
242 
243 	//Fg = m * a
244 	m_gravity = mass * m_gravity_acceleration;
245 
246 	m_invInertiaLocal.setValue(inertia.x() != btScalar(0.0) ? btScalar(1.0) / inertia.x(): btScalar(0.0),
247 				   inertia.y() != btScalar(0.0) ? btScalar(1.0) / inertia.y(): btScalar(0.0),
248 				   inertia.z() != btScalar(0.0) ? btScalar(1.0) / inertia.z(): btScalar(0.0));
249 
250 	m_invMass = m_linearFactor*m_inverseMass;
251 }
252 
253 
updateInertiaTensor()254 void btRigidBody::updateInertiaTensor()
255 {
256 	m_invInertiaTensorWorld = m_worldTransform.getBasis().scaled(m_invInertiaLocal) * m_worldTransform.getBasis().transpose();
257 }
258 
259 
260 
getLocalInertia() const261 btVector3 btRigidBody::getLocalInertia() const
262 {
263 
264 	btVector3 inertiaLocal;
265 	const btVector3 inertia = m_invInertiaLocal;
266 	inertiaLocal.setValue(inertia.x() != btScalar(0.0) ? btScalar(1.0) / inertia.x() : btScalar(0.0),
267 		inertia.y() != btScalar(0.0) ? btScalar(1.0) / inertia.y() : btScalar(0.0),
268 		inertia.z() != btScalar(0.0) ? btScalar(1.0) / inertia.z() : btScalar(0.0));
269 	return inertiaLocal;
270 }
271 
evalEulerEqn(const btVector3 & w1,const btVector3 & w0,const btVector3 & T,const btScalar dt,const btMatrix3x3 & I)272 inline btVector3 evalEulerEqn(const btVector3& w1, const btVector3& w0, const btVector3& T, const btScalar dt,
273 	const btMatrix3x3 &I)
274 {
275 	const btVector3 w2 = I*w1 + w1.cross(I*w1)*dt - (T*dt + I*w0);
276 	return w2;
277 }
278 
evalEulerEqnDeriv(const btVector3 & w1,const btVector3 & w0,const btScalar dt,const btMatrix3x3 & I)279 inline btMatrix3x3 evalEulerEqnDeriv(const btVector3& w1, const btVector3& w0, const btScalar dt,
280 	const btMatrix3x3 &I)
281 {
282 
283 	btMatrix3x3 w1x, Iw1x;
284 	const btVector3 Iwi = (I*w1);
285 	w1.getSkewSymmetricMatrix(&w1x[0], &w1x[1], &w1x[2]);
286 	Iwi.getSkewSymmetricMatrix(&Iw1x[0], &Iw1x[1], &Iw1x[2]);
287 
288 	const btMatrix3x3 dfw1 = I + (w1x*I - Iw1x)*dt;
289 	return dfw1;
290 }
291 
computeGyroscopicForceExplicit(btScalar maxGyroscopicForce) const292 btVector3 btRigidBody::computeGyroscopicForceExplicit(btScalar maxGyroscopicForce) const
293 {
294 	btVector3 inertiaLocal = getLocalInertia();
295 	btMatrix3x3 inertiaTensorWorld = getWorldTransform().getBasis().scaled(inertiaLocal) * getWorldTransform().getBasis().transpose();
296 	btVector3 tmp = inertiaTensorWorld*getAngularVelocity();
297 	btVector3 gf = getAngularVelocity().cross(tmp);
298 	btScalar l2 = gf.length2();
299 	if (l2>maxGyroscopicForce*maxGyroscopicForce)
300 	{
301 		gf *= btScalar(1.)/btSqrt(l2)*maxGyroscopicForce;
302 	}
303 	return gf;
304 }
305 
btSetCrossMatrixMinus(btMatrix3x3 & res,const btVector3 & a)306 void btSetCrossMatrixMinus(btMatrix3x3& res, const btVector3& a)
307 {
308 	const btScalar a_0 = a[0], a_1 = a[1], a_2 = a[2];
309 	res.setValue(0, +a_2, -a_1,
310 		-a_2, 0, +a_0,
311 		+a_1, -a_0, 0);
312 }
313 
computeGyroscopicImpulseImplicit_Body(btScalar step) const314 btVector3 btRigidBody::computeGyroscopicImpulseImplicit_Body(btScalar step) const
315 {
316 	btVector3 idl = getLocalInertia();
317 	btVector3 omega1 = getAngularVelocity();
318 	btQuaternion q = getWorldTransform().getRotation();
319 
320 	// Convert to body coordinates
321 	btVector3 omegab = quatRotate(q.inverse(), omega1);
322 	btMatrix3x3 Ib;
323 	Ib.setValue(idl.x(),0,0,
324 				0,idl.y(),0,
325 				0,0,idl.z());
326 
327 	btVector3 ibo = Ib*omegab;
328 
329 	// Residual vector
330 	btVector3 f = step * omegab.cross(ibo);
331 
332 	btMatrix3x3 skew0;
333 	omegab.getSkewSymmetricMatrix(&skew0[0], &skew0[1], &skew0[2]);
334 	btVector3 om = Ib*omegab;
335 	btMatrix3x3 skew1;
336 	om.getSkewSymmetricMatrix(&skew1[0],&skew1[1],&skew1[2]);
337 
338 	// Jacobian
339 	btMatrix3x3 J = Ib +  (skew0*Ib - skew1)*step;
340 
341 //	btMatrix3x3 Jinv = J.inverse();
342 //	btVector3 omega_div = Jinv*f;
343 	btVector3 omega_div = J.solve33(f);
344 
345 	// Single Newton-Raphson update
346 	omegab = omegab - omega_div;//Solve33(J, f);
347 	// Back to world coordinates
348 	btVector3 omega2 = quatRotate(q,omegab);
349 	btVector3 gf = omega2-omega1;
350 	return gf;
351 }
352 
353 
354 
computeGyroscopicImpulseImplicit_World(btScalar step) const355 btVector3 btRigidBody::computeGyroscopicImpulseImplicit_World(btScalar step) const
356 {
357 	// use full newton-euler equations.  common practice to drop the wxIw term. want it for better tumbling behavior.
358 	// calculate using implicit euler step so it's stable.
359 
360 	const btVector3 inertiaLocal = getLocalInertia();
361 	const btVector3 w0 = getAngularVelocity();
362 
363 	btMatrix3x3 I;
364 
365 	I = m_worldTransform.getBasis().scaled(inertiaLocal) *
366 		m_worldTransform.getBasis().transpose();
367 
368 	// use newtons method to find implicit solution for new angular velocity (w')
369 	// f(w') = -(T*step + Iw) + Iw' + w' + w'xIw'*step = 0
370 	// df/dw' = I + 1xIw'*step + w'xI*step
371 
372 	btVector3 w1 = w0;
373 
374 	// one step of newton's method
375 	{
376 		const btVector3 fw = evalEulerEqn(w1, w0, btVector3(0, 0, 0), step, I);
377 		const btMatrix3x3 dfw = evalEulerEqnDeriv(w1, w0, step, I);
378 
379 		btVector3 dw;
380 		dw = dfw.solve33(fw);
381 		//const btMatrix3x3 dfw_inv = dfw.inverse();
382 		//dw = dfw_inv*fw;
383 
384 		w1 -= dw;
385 	}
386 
387 	btVector3 gf = (w1 - w0);
388 	return gf;
389 }
390 
391 
integrateVelocities(btScalar step)392 void btRigidBody::integrateVelocities(btScalar step)
393 {
394 	if (isStaticOrKinematicObject())
395 		return;
396 
397 	m_linearVelocity += m_totalForce * (m_inverseMass * step);
398 	m_angularVelocity += m_invInertiaTensorWorld * m_totalTorque * step;
399 
400 #define MAX_ANGVEL SIMD_HALF_PI
401 	/// clamp angular velocity. collision calculations will fail on higher angular velocities
402 	btScalar angvel = m_angularVelocity.length();
403 	if (angvel*step > MAX_ANGVEL)
404 	{
405 		m_angularVelocity *= (MAX_ANGVEL/step) /angvel;
406 	}
407 
408 }
409 
getOrientation() const410 btQuaternion btRigidBody::getOrientation() const
411 {
412 		btQuaternion orn;
413 		m_worldTransform.getBasis().getRotation(orn);
414 		return orn;
415 }
416 
417 
setCenterOfMassTransform(const btTransform & xform)418 void btRigidBody::setCenterOfMassTransform(const btTransform& xform)
419 {
420 
421 	if (isKinematicObject())
422 	{
423 		m_interpolationWorldTransform = m_worldTransform;
424 	} else
425 	{
426 		m_interpolationWorldTransform = xform;
427 	}
428 	m_interpolationLinearVelocity = getLinearVelocity();
429 	m_interpolationAngularVelocity = getAngularVelocity();
430 	m_worldTransform = xform;
431 	updateInertiaTensor();
432 }
433 
434 
435 
436 
437 
addConstraintRef(btTypedConstraint * c)438 void btRigidBody::addConstraintRef(btTypedConstraint* c)
439 {
440 	///disable collision with the 'other' body
441 
442 	int index = m_constraintRefs.findLinearSearch(c);
443 	//don't add constraints that are already referenced
444 	//btAssert(index == m_constraintRefs.size());
445 	if (index == m_constraintRefs.size())
446 	{
447 		m_constraintRefs.push_back(c);
448 		btCollisionObject* colObjA = &c->getRigidBodyA();
449 		btCollisionObject* colObjB = &c->getRigidBodyB();
450 		if (colObjA == this)
451 		{
452 			colObjA->setIgnoreCollisionCheck(colObjB, true);
453 		}
454 		else
455 		{
456 			colObjB->setIgnoreCollisionCheck(colObjA, true);
457 		}
458 	}
459 }
460 
removeConstraintRef(btTypedConstraint * c)461 void btRigidBody::removeConstraintRef(btTypedConstraint* c)
462 {
463 	int index = m_constraintRefs.findLinearSearch(c);
464 	//don't remove constraints that are not referenced
465 	if(index < m_constraintRefs.size())
466     {
467         m_constraintRefs.remove(c);
468         btCollisionObject* colObjA = &c->getRigidBodyA();
469         btCollisionObject* colObjB = &c->getRigidBodyB();
470         if (colObjA == this)
471         {
472             colObjA->setIgnoreCollisionCheck(colObjB, false);
473         }
474         else
475         {
476             colObjB->setIgnoreCollisionCheck(colObjA, false);
477         }
478     }
479 }
480 
calculateSerializeBufferSize() const481 int	btRigidBody::calculateSerializeBufferSize()	const
482 {
483 	int sz = sizeof(btRigidBodyData);
484 	return sz;
485 }
486 
487 	///fills the dataBuffer and returns the struct name (and 0 on failure)
serialize(void * dataBuffer,class btSerializer * serializer) const488 const char*	btRigidBody::serialize(void* dataBuffer, class btSerializer* serializer) const
489 {
490 	btRigidBodyData* rbd = (btRigidBodyData*) dataBuffer;
491 
492 	btCollisionObject::serialize(&rbd->m_collisionObjectData, serializer);
493 
494 	m_invInertiaTensorWorld.serialize(rbd->m_invInertiaTensorWorld);
495 	m_linearVelocity.serialize(rbd->m_linearVelocity);
496 	m_angularVelocity.serialize(rbd->m_angularVelocity);
497 	rbd->m_inverseMass = m_inverseMass;
498 	m_angularFactor.serialize(rbd->m_angularFactor);
499 	m_linearFactor.serialize(rbd->m_linearFactor);
500 	m_gravity.serialize(rbd->m_gravity);
501 	m_gravity_acceleration.serialize(rbd->m_gravity_acceleration);
502 	m_invInertiaLocal.serialize(rbd->m_invInertiaLocal);
503 	m_totalForce.serialize(rbd->m_totalForce);
504 	m_totalTorque.serialize(rbd->m_totalTorque);
505 	rbd->m_linearDamping = m_linearDamping;
506 	rbd->m_angularDamping = m_angularDamping;
507 	rbd->m_additionalDamping = m_additionalDamping;
508 	rbd->m_additionalDampingFactor = m_additionalDampingFactor;
509 	rbd->m_additionalLinearDampingThresholdSqr = m_additionalLinearDampingThresholdSqr;
510 	rbd->m_additionalAngularDampingThresholdSqr = m_additionalAngularDampingThresholdSqr;
511 	rbd->m_additionalAngularDampingFactor = m_additionalAngularDampingFactor;
512 	rbd->m_linearSleepingThreshold=m_linearSleepingThreshold;
513 	rbd->m_angularSleepingThreshold = m_angularSleepingThreshold;
514 
515 	return btRigidBodyDataName;
516 }
517 
518 
519 
serializeSingleObject(class btSerializer * serializer) const520 void btRigidBody::serializeSingleObject(class btSerializer* serializer) const
521 {
522 	btChunk* chunk = serializer->allocate(calculateSerializeBufferSize(),1);
523 	const char* structType = serialize(chunk->m_oldPtr, serializer);
524 	serializer->finalizeChunk(chunk,structType,BT_RIGIDBODY_CODE,(void*)this);
525 }
526 
527 
528