Bullet Collision Detection & Physics Library
btKinematicCharacterController.cpp
Go to the documentation of this file.
1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com
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 
17 #include <stdio.h>
26 
27 
28 // static helper method
29 static btVector3
31 {
32  btVector3 n(0, 0, 0);
33 
34  if (v.length() > SIMD_EPSILON) {
35  n = v.normalized();
36  }
37  return n;
38 }
39 
40 
48 {
49 public:
51  {
52  m_me = me;
53  }
54 
55  virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
56  {
57  if (rayResult.m_collisionObject == m_me)
58  return 1.0;
59 
60  return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace);
61  }
62 protected:
64 };
65 
67 {
68 public:
70  : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
71  , m_me(me)
72  , m_up(up)
73  , m_minSlopeDot(minSlopeDot)
74  {
75  }
76 
77  virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
78  {
79  if (convexResult.m_hitCollisionObject == m_me)
80  return btScalar(1.0);
81 
82  if (!convexResult.m_hitCollisionObject->hasContactResponse())
83  return btScalar(1.0);
84 
85  btVector3 hitNormalWorld;
86  if (normalInWorldSpace)
87  {
88  hitNormalWorld = convexResult.m_hitNormalLocal;
89  } else
90  {
92  hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
93  }
94 
95  btScalar dotUp = m_up.dot(hitNormalWorld);
96  if (dotUp < m_minSlopeDot) {
97  return btScalar(1.0);
98  }
99 
100  return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace);
101  }
102 protected:
106 };
107 
108 /*
109  * Returns the reflection direction of a ray going 'direction' hitting a surface with normal 'normal'
110  *
111  * from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html
112  */
114 {
115  return direction - (btScalar(2.0) * direction.dot(normal)) * normal;
116 }
117 
118 /*
119  * Returns the portion of 'direction' that is parallel to 'normal'
120  */
122 {
123  btScalar magnitude = direction.dot(normal);
124  return normal * magnitude;
125 }
126 
127 /*
128  * Returns the portion of 'direction' that is perpindicular to 'normal'
129  */
131 {
132  return direction - parallelComponent(direction, normal);
133 }
134 
136 {
137  m_ghostObject = ghostObject;
138  m_up.setValue(0.0f, 0.0f, 1.0f);
139  m_jumpAxis.setValue(0.0f, 0.0f, 1.0f);
140  m_addedMargin = 0.02;
141  m_walkDirection.setValue(0.0,0.0,0.0);
142  m_AngVel.setValue(0.0, 0.0, 0.0);
144  m_turnAngle = btScalar(0.0);
145  m_convexShape=convexShape;
146  m_useWalkDirection = true; // use walk direction by default, legacy behavior
148  m_verticalVelocity = 0.0;
149  m_verticalOffset = 0.0;
150  m_gravity = 9.8 * 3.0 ; // 3G acceleration.
151  m_fallSpeed = 55.0; // Terminal velocity of a sky diver in m/s.
152  m_jumpSpeed = 10.0; // ?
154  m_wasOnGround = false;
155  m_wasJumping = false;
156  m_interpolateUp = true;
157  m_currentStepOffset = 0.0;
158  m_maxPenetrationDepth = 0.2;
159  full_drop = false;
160  bounce_fix = false;
161  m_linearDamping = btScalar(0.0);
162  m_angularDamping = btScalar(0.0);
163 
164  setUp(up);
165  setStepHeight(stepHeight);
166  setMaxSlope(btRadians(45.0));
167 }
168 
170 {
171 }
172 
174 {
175  return m_ghostObject;
176 }
177 
179 {
180  // Here we must refresh the overlapping paircache as the penetrating movement itself or the
181  // previous recovery iteration might have used setWorldTransform and pushed us into an object
182  // that is not in the previous cache contents from the last timestep, as will happen if we
183  // are pushed into a new AABB overlap. Unhandled this means the next convex sweep gets stuck.
184  //
185  // Do this by calling the broadphase's setAabb with the moved AABB, this will update the broadphase
186  // paircache and the ghostobject's internal paircache at the same time. /BW
187 
188  btVector3 minAabb, maxAabb;
191  minAabb,
192  maxAabb,
193  collisionWorld->getDispatcher());
194 
195  bool penetration = false;
196 
197  collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher());
198 
200 
201 // btScalar maxPen = btScalar(0.0);
202  for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++)
203  {
205 
207 
208  btCollisionObject* obj0 = static_cast<btCollisionObject*>(collisionPair->m_pProxy0->m_clientObject);
209  btCollisionObject* obj1 = static_cast<btCollisionObject*>(collisionPair->m_pProxy1->m_clientObject);
210 
211  if ((obj0 && !obj0->hasContactResponse()) || (obj1 && !obj1->hasContactResponse()))
212  continue;
213 
214  if (!needsCollision(obj0, obj1))
215  continue;
216 
217  if (collisionPair->m_algorithm)
219 
220 
221  for (int j=0;j<m_manifoldArray.size();j++)
222  {
223  btPersistentManifold* manifold = m_manifoldArray[j];
224  btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0);
225  for (int p=0;p<manifold->getNumContacts();p++)
226  {
227  const btManifoldPoint&pt = manifold->getContactPoint(p);
228 
229  btScalar dist = pt.getDistance();
230 
231  if (dist < -m_maxPenetrationDepth)
232  {
233  // TODO: cause problems on slopes, not sure if it is needed
234  //if (dist < maxPen)
235  //{
236  // maxPen = dist;
237  // m_touchingNormal = pt.m_normalWorldOnB * directionSign;//??
238 
239  //}
240  m_currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2);
241  penetration = true;
242  } else {
243  //printf("touching %f\n", dist);
244  }
245  }
246 
247  //manifold->clearManifold();
248  }
249  }
251  newTrans.setOrigin(m_currentPosition);
252  m_ghostObject->setWorldTransform(newTrans);
253 // printf("m_touchingNormal = %f,%f,%f\n",m_touchingNormal[0],m_touchingNormal[1],m_touchingNormal[2]);
254  return penetration;
255 }
256 
258 {
259  btScalar stepHeight = 0.0f;
260  if (m_verticalVelocity < 0.0)
261  stepHeight = m_stepHeight;
262 
263  // phase 1: up
264  btTransform start, end;
265 
266  start.setIdentity ();
267  end.setIdentity ();
268 
269  /* FIXME: Handle penetration properly */
271 
272  m_targetPosition = m_currentPosition + m_up * (stepHeight) + m_jumpAxis * ((m_verticalOffset > 0.f ? m_verticalOffset : 0.f));
274 
276 
279 
283 
285  {
287  }
288  else
289  {
290  world->convexSweepTest(m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration);
291  }
292 
294  {
295  // Only modify the position if the hit was a slope and not a wall or ceiling.
296  if (callback.m_hitNormalWorld.dot(m_up) > 0.0)
297  {
298  // we moved up only a fraction of the step height
299  m_currentStepOffset = stepHeight * callback.m_closestHitFraction;
300  if (m_interpolateUp == true)
302  else
304  }
305 
309 
310  // fix penetration if we hit a ceiling for example
311  int numPenetrationLoops = 0;
312  m_touchingContact = false;
313  while (recoverFromPenetration(world))
314  {
315  numPenetrationLoops++;
316  m_touchingContact = true;
317  if (numPenetrationLoops > 4)
318  {
319  //printf("character could not recover from penetration = %d\n", numPenetrationLoops);
320  break;
321  }
322  }
325 
326  if (m_verticalOffset > 0)
327  {
328  m_verticalOffset = 0.0;
329  m_verticalVelocity = 0.0;
331  }
332  } else {
333  m_currentStepOffset = stepHeight;
335  }
336 }
337 
339 {
340  bool collides = (body0->getBroadphaseHandle()->m_collisionFilterGroup & body1->getBroadphaseHandle()->m_collisionFilterMask) != 0;
341  collides = collides && (body1->getBroadphaseHandle()->m_collisionFilterGroup & body0->getBroadphaseHandle()->m_collisionFilterMask);
342  return collides;
343 }
344 
346 {
347  btVector3 movementDirection = m_targetPosition - m_currentPosition;
348  btScalar movementLength = movementDirection.length();
349  if (movementLength>SIMD_EPSILON)
350  {
351  movementDirection.normalize();
352 
353  btVector3 reflectDir = computeReflectionDirection (movementDirection, hitNormal);
354  reflectDir.normalize();
355 
356  btVector3 parallelDir, perpindicularDir;
357 
358  parallelDir = parallelComponent (reflectDir, hitNormal);
359  perpindicularDir = perpindicularComponent (reflectDir, hitNormal);
360 
362  if (0)//tangentMag != 0.0)
363  {
364  btVector3 parComponent = parallelDir * btScalar (tangentMag*movementLength);
365 // printf("parComponent=%f,%f,%f\n",parComponent[0],parComponent[1],parComponent[2]);
366  m_targetPosition += parComponent;
367  }
368 
369  if (normalMag != 0.0)
370  {
371  btVector3 perpComponent = perpindicularDir * btScalar (normalMag*movementLength);
372 // printf("perpComponent=%f,%f,%f\n",perpComponent[0],perpComponent[1],perpComponent[2]);
373  m_targetPosition += perpComponent;
374  }
375  } else
376  {
377 // printf("movementLength don't normalize a zero vector\n");
378  }
379 }
380 
382 {
383  // printf("m_normalizedDirection=%f,%f,%f\n",
384  // m_normalizedDirection[0],m_normalizedDirection[1],m_normalizedDirection[2]);
385  // phase 2: forward and strafe
386  btTransform start, end;
387 
388  m_targetPosition = m_currentPosition + walkMove;
389 
390  start.setIdentity ();
391  end.setIdentity ();
392 
393  btScalar fraction = 1.0;
394  btScalar distance2 = (m_currentPosition-m_targetPosition).length2();
395 // printf("distance2=%f\n",distance2);
396 
397  int maxIter = 10;
398 
399  while (fraction > btScalar(0.01) && maxIter-- > 0)
400  {
403  btVector3 sweepDirNegative(m_currentPosition - m_targetPosition);
404 
407 
408  btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, sweepDirNegative, btScalar(0.0));
411 
412 
413  btScalar margin = m_convexShape->getMargin();
415 
416  if (!(start == end))
417  {
419  {
420  m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
421  }
422  else
423  {
424  collisionWorld->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
425  }
426  }
427  m_convexShape->setMargin(margin);
428 
429 
430  fraction -= callback.m_closestHitFraction;
431 
433  {
434  // we moved only a fraction
435  //btScalar hitDistance;
436  //hitDistance = (callback.m_hitPointWorld - m_currentPosition).length();
437 
438 // m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
439 
442  distance2 = currentDir.length2();
443  if (distance2 > SIMD_EPSILON)
444  {
445  currentDir.normalize();
446  /* See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." */
447  if (currentDir.dot(m_normalizedDirection) <= btScalar(0.0))
448  {
449  break;
450  }
451  } else
452  {
453 // printf("currentDir: don't normalize a zero vector\n");
454  break;
455  }
456 
457  }
458  else
459  {
461  }
462  }
463 }
464 
466 {
467  btTransform start, end, end_double;
468  bool runonce = false;
469 
470  // phase 3: down
471  /*btScalar additionalDownStep = (m_wasOnGround && !onGround()) ? m_stepHeight : 0.0;
472  btVector3 step_drop = m_up * (m_currentStepOffset + additionalDownStep);
473  btScalar downVelocity = (additionalDownStep == 0.0 && m_verticalVelocity<0.0?-m_verticalVelocity:0.0) * dt;
474  btVector3 gravity_drop = m_up * downVelocity;
475  m_targetPosition -= (step_drop + gravity_drop);*/
476 
477  btVector3 orig_position = m_targetPosition;
478 
479  btScalar downVelocity = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt;
480 
481  if (m_verticalVelocity > 0.0)
482  return;
483 
484  if(downVelocity > 0.0 && downVelocity > m_fallSpeed
485  && (m_wasOnGround || !m_wasJumping))
486  downVelocity = m_fallSpeed;
487 
488  btVector3 step_drop = m_up * (m_currentStepOffset + downVelocity);
489  m_targetPosition -= step_drop;
490 
494 
498 
499  while (1)
500  {
501  start.setIdentity ();
502  end.setIdentity ();
503 
504  end_double.setIdentity ();
505 
508 
511 
512  //set double test for 2x the step drop, to check for a large drop vs small drop
513  end_double.setOrigin (m_targetPosition - step_drop);
514 
516  {
517  m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
518 
519  if (!callback.hasHit() && m_ghostObject->hasContactResponse())
520  {
521  //test a double fall height, to see if the character should interpolate it's fall (full) or not (partial)
522  m_ghostObject->convexSweepTest (m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
523  }
524  } else
525  {
526  collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
527 
528  if (!callback.hasHit() && m_ghostObject->hasContactResponse())
529  {
530  //test a double fall height, to see if the character should interpolate it's fall (large) or not (small)
531  collisionWorld->convexSweepTest (m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
532  }
533  }
534 
535  btScalar downVelocity2 = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt;
536  bool has_hit;
537  if (bounce_fix == true)
538  has_hit = (callback.hasHit() || callback2.hasHit()) && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback.m_hitCollisionObject);
539  else
540  has_hit = callback2.hasHit() && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback2.m_hitCollisionObject);
541 
542  btScalar stepHeight = 0.0f;
543  if (m_verticalVelocity < 0.0)
544  stepHeight = m_stepHeight;
545 
546  if (downVelocity2 > 0.0 && downVelocity2 < stepHeight && has_hit == true && runonce == false
547  && (m_wasOnGround || !m_wasJumping))
548  {
549  //redo the velocity calculation when falling a small amount, for fast stairs motion
550  //for larger falls, use the smoother/slower interpolated movement by not touching the target position
551 
552  m_targetPosition = orig_position;
553  downVelocity = stepHeight;
554 
555  step_drop = m_up * (m_currentStepOffset + downVelocity);
556  m_targetPosition -= step_drop;
557  runonce = true;
558  continue; //re-run previous tests
559  }
560  break;
561  }
562 
563  if ((m_ghostObject->hasContactResponse() && (callback.hasHit() && needsCollision(m_ghostObject, callback.m_hitCollisionObject))) || runonce == true)
564  {
565  // we dropped a fraction of the height -> hit floor
566  btScalar fraction = (m_currentPosition.getY() - callback.m_hitPointWorld.getY()) / 2;
567 
568  //printf("hitpoint: %g - pos %g\n", callback.m_hitPointWorld.getY(), m_currentPosition.getY());
569 
570  if (bounce_fix == true)
571  {
572  if (full_drop == true)
574  else
575  //due to errors in the closestHitFraction variable when used with large polygons, calculate the hit fraction manually
577  }
578  else
580 
581  full_drop = false;
582 
583  m_verticalVelocity = 0.0;
584  m_verticalOffset = 0.0;
585  m_wasJumping = false;
586  } else {
587  // we dropped the full height
588 
589  full_drop = true;
590 
591  if (bounce_fix == true)
592  {
593  downVelocity = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt;
594  if (downVelocity > m_fallSpeed && (m_wasOnGround || !m_wasJumping))
595  {
596  m_targetPosition += step_drop; //undo previous target change
597  downVelocity = m_fallSpeed;
598  step_drop = m_up * (m_currentStepOffset + downVelocity);
599  m_targetPosition -= step_drop;
600  }
601  }
602  //printf("full drop - %g, %g\n", m_currentPosition.getY(), m_targetPosition.getY());
603 
605  }
606 }
607 
608 
609 
611 (
612 const btVector3& walkDirection
613 )
614 {
615  m_useWalkDirection = true;
616  m_walkDirection = walkDirection;
617  m_normalizedDirection = getNormalizedVector(m_walkDirection);
618 }
619 
620 
621 
623 (
624 const btVector3& velocity,
625 btScalar timeInterval
626 )
627 {
628 // printf("setVelocity!\n");
629 // printf(" interval: %f\n", timeInterval);
630 // printf(" velocity: (%f, %f, %f)\n",
631 // velocity.x(), velocity.y(), velocity.z());
632 
633  m_useWalkDirection = false;
634  m_walkDirection = velocity;
635  m_normalizedDirection = getNormalizedVector(m_walkDirection);
636  m_velocityTimeInterval += timeInterval;
637 }
638 
640 {
641  m_AngVel = velocity;
642 }
643 
645 {
646  return m_AngVel;
647 }
648 
650 {
651  m_walkDirection = velocity;
652 
653  // HACK: if we are moving in the direction of the up, treat it as a jump :(
654  if (m_walkDirection.length2() > 0)
655  {
656  btVector3 w = velocity.normalized();
657  btScalar c = w.dot(m_up);
658  if (c != 0)
659  {
660  //there is a component in walkdirection for vertical velocity
661  btVector3 upComponent = m_up * (btSin(SIMD_HALF_PI - btAcos(c)) * m_walkDirection.length());
662  m_walkDirection -= upComponent;
663  m_verticalVelocity = (c < 0.0f ? -1 : 1) * upComponent.length();
664 
665  if (c > 0.0f)
666  {
667  m_wasJumping = true;
669  }
670  }
671  }
672  else
673  m_verticalVelocity = 0.0f;
674 }
675 
677 {
679 }
680 
682 {
683  m_verticalVelocity = 0.0;
684  m_verticalOffset = 0.0;
685  m_wasOnGround = false;
686  m_wasJumping = false;
687  m_walkDirection.setValue(0,0,0);
689 
690  //clear pair cache
692  while (cache->getOverlappingPairArray().size() > 0)
693  {
694  cache->removeOverlappingPair(cache->getOverlappingPairArray()[0].m_pProxy0, cache->getOverlappingPairArray()[0].m_pProxy1, collisionWorld->getDispatcher());
695  }
696 }
697 
699 {
700  btTransform xform;
701  xform.setIdentity();
702  xform.setOrigin (origin);
704 }
705 
706 
708 {
711 
714 // printf("m_targetPosition=%f,%f,%f\n",m_targetPosition[0],m_targetPosition[1],m_targetPosition[2]);
715 }
716 
718 {
719 // printf("playerStep(): ");
720 // printf(" dt = %f", dt);
721 
722  if (m_AngVel.length2() > 0.0f)
723  {
725  }
726 
727  // integrate for angular velocity
728  if (m_AngVel.length2() > 0.0f)
729  {
730  btTransform xform;
731  xform = m_ghostObject->getWorldTransform();
732 
734 
735  btQuaternion orn = rot * xform.getRotation();
736 
737  xform.setRotation(orn);
739 
744  }
745 
746  // quick check...
747  if (!m_useWalkDirection && (m_velocityTimeInterval <= 0.0)) {
748 // printf("\n");
749  return; // no motion
750  }
751 
753 
754  //btVector3 lvel = m_walkDirection;
755  //btScalar c = 0.0f;
756 
757  if (m_walkDirection.length2() > 0)
758  {
759  // apply damping
761  }
762 
764 
765  // Update fall velocity.
768  {
770  }
772  {
774  }
776 
777  btTransform xform;
778  xform = m_ghostObject->getWorldTransform();
779 
780 // printf("walkDirection(%f,%f,%f)\n",walkDirection[0],walkDirection[1],walkDirection[2]);
781 // printf("walkSpeed=%f\n",walkSpeed);
782 
783  stepUp(collisionWorld);
784  //todo: Experimenting with behavior of controller when it hits a ceiling..
785  //bool hitUp = stepUp (collisionWorld);
786  //if (hitUp)
787  //{
788  // m_verticalVelocity -= m_gravity * dt;
789  // if (m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed)
790  // {
791  // m_verticalVelocity = m_jumpSpeed;
792  // }
793  // if (m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed))
794  // {
795  // m_verticalVelocity = -btFabs(m_fallSpeed);
796  // }
797  // m_verticalOffset = m_verticalVelocity * dt;
798 
799  // xform = m_ghostObject->getWorldTransform();
800  //}
801 
802  if (m_useWalkDirection) {
803  stepForwardAndStrafe (collisionWorld, m_walkDirection);
804  } else {
805  //printf(" time: %f", m_velocityTimeInterval);
806  // still have some time left for moving!
807  btScalar dtMoving =
810 
811  // how far will we move while we are moving?
812  btVector3 move = m_walkDirection * dtMoving;
813 
814  //printf(" dtMoving: %f", dtMoving);
815 
816  // okay, step
817  stepForwardAndStrafe(collisionWorld, move);
818  }
819  stepDown (collisionWorld, dt);
820 
821  //todo: Experimenting with max jump height
822  //if (m_wasJumping)
823  //{
824  // btScalar ds = m_currentPosition[m_upAxis] - m_jumpPosition[m_upAxis];
825  // if (ds > m_maxJumpHeight)
826  // {
827  // // substract the overshoot
828  // m_currentPosition[m_upAxis] -= ds - m_maxJumpHeight;
829 
830  // // max height was reached, so potential energy is at max
831  // // and kinematic energy is 0, thus velocity is 0.
832  // if (m_verticalVelocity > 0.0)
833  // m_verticalVelocity = 0.0;
834  // }
835  //}
836  // printf("\n");
837 
840 
841  int numPenetrationLoops = 0;
842  m_touchingContact = false;
843  while (recoverFromPenetration(collisionWorld))
844  {
845  numPenetrationLoops++;
846  m_touchingContact = true;
847  if (numPenetrationLoops > 4)
848  {
849  //printf("character could not recover from penetration = %d\n", numPenetrationLoops);
850  break;
851  }
852  }
853 }
854 
856 {
857  m_fallSpeed = fallSpeed;
858 }
859 
861 {
862  m_jumpSpeed = jumpSpeed;
864 }
865 
867 {
868  m_maxJumpHeight = maxJumpHeight;
869 }
870 
872 {
873  return onGround();
874 }
875 
877 {
878  m_jumpSpeed = v.length2() == 0 ? m_SetjumpSpeed : v.length();
880  m_wasJumping = true;
881 
882  m_jumpAxis = v.length2() == 0 ? m_up : v.normalized();
883 
885 
886 #if 0
887  currently no jumping.
888  btTransform xform;
889  m_rigidBody->getMotionState()->getWorldTransform (xform);
890  btVector3 up = xform.getBasis()[1];
891  up.normalize ();
892  btScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0);
893  m_rigidBody->applyCentralImpulse (up * magnitude);
894 #endif
895 }
896 
898 {
899  if (gravity.length2() > 0) setUpVector(-gravity);
900 
901  m_gravity = gravity.length();
902 }
903 
905 {
906  return -m_gravity * m_up;
907 }
908 
910 {
911  m_maxSlopeRadians = slopeRadians;
912  m_maxSlopeCosine = btCos(slopeRadians);
913 }
914 
916 {
917  return m_maxSlopeRadians;
918 }
919 
921 {
923 }
924 
926 {
927  return m_maxPenetrationDepth;
928 }
929 
931 {
932  return (fabs(m_verticalVelocity) < SIMD_EPSILON) && (fabs(m_verticalOffset) < SIMD_EPSILON);
933 }
934 
936 {
937  m_stepHeight = h;
938 }
939 
941 {
942  static btVector3 sUpAxisDirection[3] = { btVector3(1.0f, 0.0f, 0.0f), btVector3(0.0f, 1.0f, 0.0f), btVector3(0.0f, 0.0f, 1.0f) };
943 
944  return sUpAxisDirection;
945 }
946 
948 {
949 }
950 
952 {
953  m_interpolateUp = value;
954 }
955 
957 {
958  if (up.length2() > 0 && m_gravity > 0.0f)
959  {
961  return;
962  }
963 
964  setUpVector(up);
965 }
966 
968 {
969  if (m_up == up)
970  return;
971 
972  btVector3 u = m_up;
973 
974  if (up.length2() > 0)
975  m_up = up.normalized();
976  else
977  m_up = btVector3(0.0, 0.0, 0.0);
978 
979  if (!m_ghostObject) return;
980  btQuaternion rot = getRotation(m_up, u);
981 
982  //set orientation with new up
983  btTransform xform;
984  xform = m_ghostObject->getWorldTransform();
985  btQuaternion orn = rot.inverse() * xform.getRotation();
986  xform.setRotation(orn);
988 }
989 
991 {
992  if (v0.length2() == 0.0f || v1.length2() == 0.0f)
993  {
994  btQuaternion q;
995  return q;
996  }
997 
998  return shortestArcQuatNormalize2(v0, v1);
999 }
1000 
void setOrigin(const btVector3 &origin)
Set the translational element.
Definition: btTransform.h:150
#define SIMD_EPSILON
Definition: btScalar.h:521
btPersistentManifold is a contact point cache, it stays persistent as long as objects are overlapping...
void playerStep(btCollisionWorld *collisionWorld, btScalar dt)
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult &rayResult, bool normalInWorldSpace)
void stepDown(btCollisionWorld *collisionWorld, btScalar dt)
btScalar btRadians(btScalar x)
Definition: btScalar.h:566
void setValue(const btScalar &_x, const btScalar &_y, const btScalar &_z)
Definition: btVector3.h:652
btScalar btSin(btScalar x)
Definition: btScalar.h:477
btQuaternion getRotation(btVector3 &v0, btVector3 &v1) const
btScalar length2() const
Return the length of the vector squared.
Definition: btVector3.h:257
virtual void dispatchAllCollisionPairs(btOverlappingPairCache *pairCache, const btDispatcherInfo &dispatchInfo, btDispatcher *dispatcher)=0
btVector3 computeReflectionDirection(const btVector3 &direction, const btVector3 &normal)
void setIdentity()
Set this transformation to the identity.
Definition: btTransform.h:172
btQuaternion getRotation() const
Return a quaternion representing the rotation.
Definition: btTransform.h:122
btBroadphasePairArray & getOverlappingPairArray()
const btScalar & getY() const
Return the y value.
Definition: btVector3.h:575
ManifoldContactPoint collects and maintains persistent contactpoints.
virtual void setVelocityForTimeInterval(const btVector3 &velocity, btScalar timeInterval)
Caller provides a velocity with which the character should move for the given time period.
#define SIMD_HALF_PI
Definition: btScalar.h:506
void debugDraw(btIDebugDraw *debugDrawer)
btActionInterface interface
btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition: btVector3.h:309
btVector3 normalized() const
Return a normalized version of this vector.
Definition: btVector3.h:964
The btConvexShape is an abstract shape interface, implemented by all convex shapes such as btBoxShape...
Definition: btConvexShape.h:31
const btManifoldPoint & getContactPoint(int index) const
btHashedOverlappingPairCache * getOverlappingPairCache()
const btCollisionObject * m_hitCollisionObject
btQuaternion inverse() const
Return the inverse of this quaternion.
Definition: btQuaternion.h:482
btTransform & getWorldTransform()
btVector3 m_normalWorldOnB
btVector3 & getOrigin()
Return the origin vector translation.
Definition: btTransform.h:117
void getAabb(const btTransform &t, btVector3 &aabbMin, btVector3 &aabbMax) const =0
getAabb's default implementation is brute force, expected derived classes to implement a fast dedicat...
btBroadphaseProxy * getBroadphaseHandle()
static btVector3 getNormalizedVector(const btVector3 &v)
const btCollisionObject * getBody0() const
virtual void setLinearVelocity(const btVector3 &velocity)
btQuaternion shortestArcQuatNormalize2(btVector3 &v0, btVector3 &v1)
Definition: btQuaternion.h:950
btScalar dot(const btVector3 &v) const
Return the dot product.
Definition: btVector3.h:235
ClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld)
void jump(const btVector3 &v=btVector3())
void setMaxSlope(btScalar slopeRadians)
The max slope determines the maximum angle that the controller can walk up.
btCollisionObject can be used to manage collision detection objects.
void setRotation(const btQuaternion &q)
Set the rotational element by btQuaternion.
Definition: btTransform.h:165
bool recoverFromPenetration(btCollisionWorld *collisionWorld)
btMatrix3x3 & getBasis()
Return the basis matrix for the rotation.
Definition: btTransform.h:112
bool hasContactResponse() const
The btIDebugDraw interface class allows hooking up a debug renderer to visually debug simulations.
Definition: btIDebugDraw.h:29
const btCollisionObject * m_collisionObject
void setWorldTransform(const btTransform &worldTrans)
btDispatcher * getDispatcher()
virtual btScalar getMargin() const =0
btVector3 parallelComponent(const btVector3 &direction, const btVector3 &normal)
btBroadphaseProxy * m_pProxy1
btCollisionAlgorithm * m_algorithm
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace)
btVector3 can be used to represent 3D points and vectors.
Definition: btVector3.h:83
btManifoldArray m_manifoldArray
keep track of the contact manifolds
virtual void * removeOverlappingPair(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1, btDispatcher *dispatcher)
btScalar btPow(btScalar x, btScalar y)
Definition: btScalar.h:499
virtual void getAllContactManifolds(btManifoldArray &manifoldArray)=0
btScalar btAcos(btScalar x)
Definition: btScalar.h:479
int size() const
return the number of elements in the array
btVector3 m_walkDirection
this is the desired walk direction, set by the user
btBroadphaseProxy * m_pProxy0
The btTransform class supports rigid transforms with only translation and rotation and no scaling/she...
Definition: btTransform.h:34
void updateTargetPositionBasedOnCollision(const btVector3 &hit_normal, btScalar tangentMag=btScalar(0.0), btScalar normalMag=btScalar(1.0))
CollisionWorld is interface and container for the collision detection.
void convexSweepTest(const btConvexShape *castShape, const btTransform &from, const btTransform &to, ConvexResultCallback &resultCallback, btScalar allowedCcdPenetration=btScalar(0.)) const
convexTest performs a swept convex cast on all objects in the btCollisionWorld, and calls the resultC...
btDispatcherInfo & getDispatchInfo()
void stepUp(btCollisionWorld *collisionWorld)
btScalar m_allowedCcdPenetration
Definition: btDispatcher.h:62
void resize(int newsize, const T &fillData=T())
void convexSweepTest(const class btConvexShape *castShape, const btTransform &convexFromWorld, const btTransform &convexToWorld, btCollisionWorld::ConvexResultCallback &resultCallback, btScalar allowedCcdPenetration=0.f) const
virtual void setAngularVelocity(const btVector3 &velocity)
btVector3 perpindicularComponent(const btVector3 &direction, const btVector3 &normal)
void reset(btCollisionWorld *collisionWorld)
virtual const btVector3 & getAngularVelocity() const
btKinematicClosestNotMeConvexResultCallback(btCollisionObject *me, const btVector3 &up, btScalar minSlopeDot)
virtual void setAabb(btBroadphaseProxy *proxy, const btVector3 &aabbMin, const btVector3 &aabbMax, btDispatcher *dispatcher)=0
void stepForwardAndStrafe(btCollisionWorld *collisionWorld, const btVector3 &walkMove)
void preStep(btCollisionWorld *collisionWorld)
The btQuaternion implements quaternion to perform linear algebra rotations in combination with btMatr...
Definition: btQuaternion.h:55
virtual void setWalkDirection(const btVector3 &walkDirection)
This should probably be called setPositionIncrementPerSimulatorStep.
virtual void setMargin(btScalar margin)=0
virtual bool needsCollision(const btCollisionObject *body0, const btCollisionObject *body1)
btKinematicCharacterController(btPairCachingGhostObject *ghostObject, btConvexShape *convexShape, btScalar stepHeight, const btVector3 &up=btVector3(1.0, 0.0, 0.0))
void setInterpolate3(const btVector3 &v0, const btVector3 &v1, btScalar rt)
Definition: btVector3.h:503
const btBroadphaseInterface * getBroadphase() const
Hash-space based Pair Cache, thanks to Erin Catto, Box2D, http://www.box2d.org, and Pierre Terdiman,...
btScalar getDistance() const
ClosestRayResultCallback(const btVector3 &rayFromWorld, const btVector3 &rayToWorld)
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition: btScalar.h:292
btScalar btCos(btScalar x)
Definition: btScalar.h:476
btScalar length() const
Return the length of the vector.
Definition: btVector3.h:263
btScalar btFabs(btScalar x)
Definition: btScalar.h:475
The btBroadphasePair class contains a pair of aabb-overlapping objects.