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 #include <stdio.h>
25 
26 // static helper method
27 static btVector3
29 {
30  btVector3 n(0, 0, 0);
31 
32  if (v.length() > SIMD_EPSILON)
33  {
34  n = v.normalized();
35  }
36  return n;
37 }
38 
46 {
47 public:
49  {
50  m_me = me;
51  }
52 
53  virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace)
54  {
55  if (rayResult.m_collisionObject == m_me)
56  return 1.0;
57 
58  return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
59  }
60 
61 protected:
63 };
64 
66 {
67 public:
69  : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), m_me(me), m_up(up), m_minSlopeDot(minSlopeDot)
70  {
71  }
72 
73  virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace)
74  {
75  if (convexResult.m_hitCollisionObject == m_me)
76  return btScalar(1.0);
77 
78  if (!convexResult.m_hitCollisionObject->hasContactResponse())
79  return btScalar(1.0);
80 
81  btVector3 hitNormalWorld;
82  if (normalInWorldSpace)
83  {
84  hitNormalWorld = convexResult.m_hitNormalLocal;
85  }
86  else
87  {
89  hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis() * convexResult.m_hitNormalLocal;
90  }
91 
92  btScalar dotUp = m_up.dot(hitNormalWorld);
93  if (dotUp < m_minSlopeDot)
94  {
95  return btScalar(1.0);
96  }
97 
98  return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
99  }
100 
101 protected:
105 };
106 
107 /*
108  * Returns the reflection direction of a ray going 'direction' hitting a surface with normal 'normal'
109  *
110  * from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html
111  */
113 {
114  return direction - (btScalar(2.0) * direction.dot(normal)) * normal;
115 }
116 
117 /*
118  * Returns the portion of 'direction' that is parallel to 'normal'
119  */
121 {
122  btScalar magnitude = direction.dot(normal);
123  return normal * magnitude;
124 }
125 
126 /*
127  * Returns the portion of 'direction' that is perpindicular to 'normal'
128  */
130 {
131  return direction - parallelComponent(direction, normal);
132 }
133 
135 {
136  m_ghostObject = ghostObject;
137  m_up.setValue(0.0f, 0.0f, 1.0f);
138  m_jumpAxis.setValue(0.0f, 0.0f, 1.0f);
139  m_addedMargin = 0.02;
140  m_walkDirection.setValue(0.0, 0.0, 0.0);
141  m_AngVel.setValue(0.0, 0.0, 0.0);
143  m_turnAngle = btScalar(0.0);
144  m_convexShape = convexShape;
145  m_useWalkDirection = true; // use walk direction by default, legacy behavior
147  m_verticalVelocity = 0.0;
148  m_verticalOffset = 0.0;
149  m_gravity = 9.8 * 3.0; // 3G acceleration.
150  m_fallSpeed = 55.0; // Terminal velocity of a sky diver in m/s.
151  m_jumpSpeed = 10.0; // ?
153  m_wasOnGround = false;
154  m_wasJumping = false;
155  m_interpolateUp = true;
156  m_currentStepOffset = 0.0;
157  m_maxPenetrationDepth = 0.2;
158  full_drop = false;
159  bounce_fix = false;
160  m_linearDamping = btScalar(0.0);
161  m_angularDamping = btScalar(0.0);
162 
163  setUp(up);
164  setStepHeight(stepHeight);
165  setMaxSlope(btRadians(45.0));
166 }
167 
169 {
170 }
171 
173 {
174  return m_ghostObject;
175 }
176 
178 {
179  // Here we must refresh the overlapping paircache as the penetrating movement itself or the
180  // previous recovery iteration might have used setWorldTransform and pushed us into an object
181  // that is not in the previous cache contents from the last timestep, as will happen if we
182  // are pushed into a new AABB overlap. Unhandled this means the next convex sweep gets stuck.
183  //
184  // Do this by calling the broadphase's setAabb with the moved AABB, this will update the broadphase
185  // paircache and the ghostobject's internal paircache at the same time. /BW
186 
187  btVector3 minAabb, maxAabb;
188  m_convexShape->getAabb(m_ghostObject->getWorldTransform(), minAabb, maxAabb);
190  minAabb,
191  maxAabb,
192  collisionWorld->getDispatcher());
193 
194  bool penetration = false;
195 
196  collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher());
197 
199 
200  // btScalar maxPen = btScalar(0.0);
201  for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++)
202  {
204 
206 
207  btCollisionObject* obj0 = static_cast<btCollisionObject*>(collisionPair->m_pProxy0->m_clientObject);
208  btCollisionObject* obj1 = static_cast<btCollisionObject*>(collisionPair->m_pProxy1->m_clientObject);
209 
210  if ((obj0 && !obj0->hasContactResponse()) || (obj1 && !obj1->hasContactResponse()))
211  continue;
212 
213  if (!needsCollision(obj0, obj1))
214  continue;
215 
216  if (collisionPair->m_algorithm)
218 
219  for (int j = 0; j < m_manifoldArray.size(); j++)
220  {
221  btPersistentManifold* manifold = m_manifoldArray[j];
222  btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0);
223  for (int p = 0; p < manifold->getNumContacts(); p++)
224  {
225  const btManifoldPoint& pt = manifold->getContactPoint(p);
226 
227  btScalar dist = pt.getDistance();
228 
229  if (dist < -m_maxPenetrationDepth)
230  {
231  // TODO: cause problems on slopes, not sure if it is needed
232  //if (dist < maxPen)
233  //{
234  // maxPen = dist;
235  // m_touchingNormal = pt.m_normalWorldOnB * directionSign;//??
236 
237  //}
238  m_currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2);
239  penetration = true;
240  }
241  else
242  {
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  }
333  else
334  {
335  m_currentStepOffset = stepHeight;
337  }
338 }
339 
341 {
342  bool collides = (body0->getBroadphaseHandle()->m_collisionFilterGroup & body1->getBroadphaseHandle()->m_collisionFilterMask) != 0;
343  collides = collides && (body1->getBroadphaseHandle()->m_collisionFilterGroup & body0->getBroadphaseHandle()->m_collisionFilterMask);
344  return collides;
345 }
346 
348 {
349  btVector3 movementDirection = m_targetPosition - m_currentPosition;
350  btScalar movementLength = movementDirection.length();
351  if (movementLength > SIMD_EPSILON)
352  {
353  movementDirection.normalize();
354 
355  btVector3 reflectDir = computeReflectionDirection(movementDirection, hitNormal);
356  reflectDir.normalize();
357 
358  btVector3 parallelDir, perpindicularDir;
359 
360  parallelDir = parallelComponent(reflectDir, hitNormal);
361  perpindicularDir = perpindicularComponent(reflectDir, hitNormal);
362 
364  if (0) //tangentMag != 0.0)
365  {
366  btVector3 parComponent = parallelDir * btScalar(tangentMag * movementLength);
367  // printf("parComponent=%f,%f,%f\n",parComponent[0],parComponent[1],parComponent[2]);
368  m_targetPosition += parComponent;
369  }
370 
371  if (normalMag != 0.0)
372  {
373  btVector3 perpComponent = perpindicularDir * btScalar(normalMag * movementLength);
374  // printf("perpComponent=%f,%f,%f\n",perpComponent[0],perpComponent[1],perpComponent[2]);
375  m_targetPosition += perpComponent;
376  }
377  }
378  else
379  {
380  // printf("movementLength don't normalize a zero vector\n");
381  }
382 }
383 
385 {
386  // printf("m_normalizedDirection=%f,%f,%f\n",
387  // m_normalizedDirection[0],m_normalizedDirection[1],m_normalizedDirection[2]);
388  // phase 2: forward and strafe
389  btTransform start, end;
390 
391  m_targetPosition = m_currentPosition + walkMove;
392 
393  start.setIdentity();
394  end.setIdentity();
395 
396  btScalar fraction = 1.0;
397  btScalar distance2 = (m_currentPosition - m_targetPosition).length2();
398  // printf("distance2=%f\n",distance2);
399 
400  int maxIter = 10;
401 
402  while (fraction > btScalar(0.01) && maxIter-- > 0)
403  {
406  btVector3 sweepDirNegative(m_currentPosition - m_targetPosition);
407 
410 
411  btKinematicClosestNotMeConvexResultCallback callback(m_ghostObject, sweepDirNegative, btScalar(0.0));
414 
415  btScalar margin = m_convexShape->getMargin();
417 
418  if (!(start == end))
419  {
421  {
422  m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
423  }
424  else
425  {
426  collisionWorld->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
427  }
428  }
429  m_convexShape->setMargin(margin);
430 
431  fraction -= callback.m_closestHitFraction;
432 
434  {
435  // we moved only a fraction
436  //btScalar hitDistance;
437  //hitDistance = (callback.m_hitPointWorld - m_currentPosition).length();
438 
439  // m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
440 
443  distance2 = currentDir.length2();
444  if (distance2 > SIMD_EPSILON)
445  {
446  currentDir.normalize();
447  /* See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." */
448  if (currentDir.dot(m_normalizedDirection) <= btScalar(0.0))
449  {
450  break;
451  }
452  }
453  else
454  {
455  // printf("currentDir: don't normalize a zero vector\n");
456  break;
457  }
458  }
459  else
460  {
462  }
463  }
464 }
465 
467 {
468  btTransform start, end, end_double;
469  bool runonce = false;
470 
471  // phase 3: down
472  /*btScalar additionalDownStep = (m_wasOnGround && !onGround()) ? m_stepHeight : 0.0;
473  btVector3 step_drop = m_up * (m_currentStepOffset + additionalDownStep);
474  btScalar downVelocity = (additionalDownStep == 0.0 && m_verticalVelocity<0.0?-m_verticalVelocity:0.0) * dt;
475  btVector3 gravity_drop = m_up * downVelocity;
476  m_targetPosition -= (step_drop + gravity_drop);*/
477 
478  btVector3 orig_position = m_targetPosition;
479 
480  btScalar downVelocity = (m_verticalVelocity < 0.f ? -m_verticalVelocity : 0.f) * dt;
481 
482  if (m_verticalVelocity > 0.0)
483  return;
484 
485  if (downVelocity > 0.0 && downVelocity > m_fallSpeed && (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  }
525  else
526  {
527  collisionWorld->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
528 
529  if (!callback.hasHit() && m_ghostObject->hasContactResponse())
530  {
531  //test a double fall height, to see if the character should interpolate it's fall (large) or not (small)
532  collisionWorld->convexSweepTest(m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
533  }
534  }
535 
536  btScalar downVelocity2 = (m_verticalVelocity < 0.f ? -m_verticalVelocity : 0.f) * dt;
537  bool has_hit;
538  if (bounce_fix == true)
539  has_hit = (callback.hasHit() || callback2.hasHit()) && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback.m_hitCollisionObject);
540  else
541  has_hit = callback2.hasHit() && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback2.m_hitCollisionObject);
542 
543  btScalar stepHeight = 0.0f;
544  if (m_verticalVelocity < 0.0)
545  stepHeight = m_stepHeight;
546 
547  if (downVelocity2 > 0.0 && downVelocity2 < stepHeight && has_hit == true && runonce == false && (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  }
587  else
588  {
589  // we dropped the full height
590 
591  full_drop = true;
592 
593  if (bounce_fix == true)
594  {
595  downVelocity = (m_verticalVelocity < 0.f ? -m_verticalVelocity : 0.f) * dt;
596  if (downVelocity > m_fallSpeed && (m_wasOnGround || !m_wasJumping))
597  {
598  m_targetPosition += step_drop; //undo previous target change
599  downVelocity = m_fallSpeed;
600  step_drop = m_up * (m_currentStepOffset + downVelocity);
601  m_targetPosition -= step_drop;
602  }
603  }
604  //printf("full drop - %g, %g\n", m_currentPosition.getY(), m_targetPosition.getY());
605 
607  }
608 }
609 
611  const btVector3& walkDirection)
612 {
613  m_useWalkDirection = true;
614  m_walkDirection = walkDirection;
616 }
617 
619  const btVector3& velocity,
620  btScalar timeInterval)
621 {
622  // printf("setVelocity!\n");
623  // printf(" interval: %f\n", timeInterval);
624  // printf(" velocity: (%f, %f, %f)\n",
625  // velocity.x(), velocity.y(), velocity.z());
626 
627  m_useWalkDirection = false;
628  m_walkDirection = velocity;
630  m_velocityTimeInterval += timeInterval;
631 }
632 
634 {
635  m_AngVel = velocity;
636 }
637 
639 {
640  return m_AngVel;
641 }
642 
644 {
645  m_walkDirection = velocity;
646 
647  // HACK: if we are moving in the direction of the up, treat it as a jump :(
648  if (m_walkDirection.length2() > 0)
649  {
650  btVector3 w = velocity.normalized();
651  btScalar c = w.dot(m_up);
652  if (c != 0)
653  {
654  //there is a component in walkdirection for vertical velocity
655  btVector3 upComponent = m_up * (btSin(SIMD_HALF_PI - btAcos(c)) * m_walkDirection.length());
656  m_walkDirection -= upComponent;
657  m_verticalVelocity = (c < 0.0f ? -1 : 1) * upComponent.length();
658 
659  if (c > 0.0f)
660  {
661  m_wasJumping = true;
663  }
664  }
665  }
666  else
667  m_verticalVelocity = 0.0f;
668 }
669 
671 {
673 }
674 
676 {
677  m_verticalVelocity = 0.0;
678  m_verticalOffset = 0.0;
679  m_wasOnGround = false;
680  m_wasJumping = false;
681  m_walkDirection.setValue(0, 0, 0);
683 
684  //clear pair cache
686  while (cache->getOverlappingPairArray().size() > 0)
687  {
688  cache->removeOverlappingPair(cache->getOverlappingPairArray()[0].m_pProxy0, cache->getOverlappingPairArray()[0].m_pProxy1, collisionWorld->getDispatcher());
689  }
690 }
691 
693 {
694  btTransform xform;
695  xform.setIdentity();
696  xform.setOrigin(origin);
698 }
699 
701 {
704 
707  // printf("m_targetPosition=%f,%f,%f\n",m_targetPosition[0],m_targetPosition[1],m_targetPosition[2]);
708 }
709 
711 {
712  // printf("playerStep(): ");
713  // printf(" dt = %f", dt);
714 
715  if (m_AngVel.length2() > 0.0f)
716  {
718  }
719 
720  // integrate for angular velocity
721  if (m_AngVel.length2() > 0.0f)
722  {
723  btTransform xform;
724  xform = m_ghostObject->getWorldTransform();
725 
727 
728  btQuaternion orn = rot * xform.getRotation();
729 
730  xform.setRotation(orn);
732 
737  }
738 
739  // quick check...
741  {
742  // printf("\n");
743  return; // no motion
744  }
745 
747 
748  //btVector3 lvel = m_walkDirection;
749  //btScalar c = 0.0f;
750 
751  if (m_walkDirection.length2() > 0)
752  {
753  // apply damping
755  }
756 
758 
759  // Update fall velocity.
762  {
764  }
766  {
768  }
770 
771  btTransform xform;
772  xform = m_ghostObject->getWorldTransform();
773 
774  // printf("walkDirection(%f,%f,%f)\n",walkDirection[0],walkDirection[1],walkDirection[2]);
775  // printf("walkSpeed=%f\n",walkSpeed);
776 
777  stepUp(collisionWorld);
778  //todo: Experimenting with behavior of controller when it hits a ceiling..
779  //bool hitUp = stepUp (collisionWorld);
780  //if (hitUp)
781  //{
782  // m_verticalVelocity -= m_gravity * dt;
783  // if (m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed)
784  // {
785  // m_verticalVelocity = m_jumpSpeed;
786  // }
787  // if (m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed))
788  // {
789  // m_verticalVelocity = -btFabs(m_fallSpeed);
790  // }
791  // m_verticalOffset = m_verticalVelocity * dt;
792 
793  // xform = m_ghostObject->getWorldTransform();
794  //}
795 
796  if (m_useWalkDirection)
797  {
798  stepForwardAndStrafe(collisionWorld, m_walkDirection);
799  }
800  else
801  {
802  //printf(" time: %f", m_velocityTimeInterval);
803  // still have some time left for moving!
804  btScalar dtMoving =
807 
808  // how far will we move while we are moving?
809  btVector3 move = m_walkDirection * dtMoving;
810 
811  //printf(" dtMoving: %f", dtMoving);
812 
813  // okay, step
814  stepForwardAndStrafe(collisionWorld, move);
815  }
816  stepDown(collisionWorld, dt);
817 
818  //todo: Experimenting with max jump height
819  //if (m_wasJumping)
820  //{
821  // btScalar ds = m_currentPosition[m_upAxis] - m_jumpPosition[m_upAxis];
822  // if (ds > m_maxJumpHeight)
823  // {
824  // // substract the overshoot
825  // m_currentPosition[m_upAxis] -= ds - m_maxJumpHeight;
826 
827  // // max height was reached, so potential energy is at max
828  // // and kinematic energy is 0, thus velocity is 0.
829  // if (m_verticalVelocity > 0.0)
830  // m_verticalVelocity = 0.0;
831  // }
832  //}
833  // printf("\n");
834 
837 
838  int numPenetrationLoops = 0;
839  m_touchingContact = false;
840  while (recoverFromPenetration(collisionWorld))
841  {
842  numPenetrationLoops++;
843  m_touchingContact = true;
844  if (numPenetrationLoops > 4)
845  {
846  //printf("character could not recover from penetration = %d\n", numPenetrationLoops);
847  break;
848  }
849  }
850 }
851 
853 {
854  m_fallSpeed = fallSpeed;
855 }
856 
858 {
859  m_jumpSpeed = jumpSpeed;
861 }
862 
864 {
865  m_maxJumpHeight = maxJumpHeight;
866 }
867 
869 {
870  return onGround();
871 }
872 
874 {
875  m_jumpSpeed = v.length2() == 0 ? m_SetjumpSpeed : v.length();
877  m_wasJumping = true;
878 
879  m_jumpAxis = v.length2() == 0 ? m_up : v.normalized();
880 
882 
883 #if 0
884  currently no jumping.
885  btTransform xform;
886  m_rigidBody->getMotionState()->getWorldTransform (xform);
887  btVector3 up = xform.getBasis()[1];
888  up.normalize ();
889  btScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0);
890  m_rigidBody->applyCentralImpulse (up * magnitude);
891 #endif
892 }
893 
895 {
896  if (gravity.length2() > 0) setUpVector(-gravity);
897 
898  m_gravity = gravity.length();
899 }
900 
902 {
903  return -m_gravity * m_up;
904 }
905 
907 {
908  m_maxSlopeRadians = slopeRadians;
909  m_maxSlopeCosine = btCos(slopeRadians);
910 }
911 
913 {
914  return m_maxSlopeRadians;
915 }
916 
918 {
920 }
921 
923 {
924  return m_maxPenetrationDepth;
925 }
926 
928 {
929  return (fabs(m_verticalVelocity) < SIMD_EPSILON) && (fabs(m_verticalOffset) < SIMD_EPSILON);
930 }
931 
933 {
934  m_stepHeight = h;
935 }
936 
938 {
939  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)};
940 
941  return sUpAxisDirection;
942 }
943 
945 {
946 }
947 
949 {
950  m_interpolateUp = value;
951 }
952 
954 {
955  if (up.length2() > 0 && m_gravity > 0.0f)
956  {
958  return;
959  }
960 
961  setUpVector(up);
962 }
963 
965 {
966  if (m_up == up)
967  return;
968 
969  btVector3 u = m_up;
970 
971  if (up.length2() > 0)
972  m_up = up.normalized();
973  else
974  m_up = btVector3(0.0, 0.0, 0.0);
975 
976  if (!m_ghostObject) return;
977  btQuaternion rot = getRotation(m_up, u);
978 
979  //set orientation with new up
980  btTransform xform;
981  xform = m_ghostObject->getWorldTransform();
982  btQuaternion orn = rot.inverse() * xform.getRotation();
983  xform.setRotation(orn);
985 }
986 
988 {
989  if (v0.length2() == 0.0f || v1.length2() == 0.0f)
990  {
991  btQuaternion q;
992  return q;
993  }
994 
995  return shortestArcQuatNormalize2(v0, v1);
996 }
static btVector3 getNormalizedVector(const btVector3 &v)
btQuaternion shortestArcQuatNormalize2(btVector3 &v0, btVector3 &v1)
Definition: btQuaternion.h:959
btScalar btPow(btScalar x, btScalar y)
Definition: btScalar.h:521
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition: btScalar.h:314
btScalar btSin(btScalar x)
Definition: btScalar.h:499
btScalar btFabs(btScalar x)
Definition: btScalar.h:497
btScalar btCos(btScalar x)
Definition: btScalar.h:498
btScalar btRadians(btScalar x)
Definition: btScalar.h:588
#define SIMD_EPSILON
Definition: btScalar.h:543
btScalar btAcos(btScalar x)
Definition: btScalar.h:501
#define SIMD_HALF_PI
Definition: btScalar.h:528
int size() const
return the number of elements in the array
void resize(int newsize, const T &fillData=T())
virtual void setAabb(btBroadphaseProxy *proxy, const btVector3 &aabbMin, const btVector3 &aabbMax, btDispatcher *dispatcher)=0
virtual void getAllContactManifolds(btManifoldArray &manifoldArray)=0
btCollisionObject can be used to manage collision detection objects.
btTransform & getWorldTransform()
btBroadphaseProxy * getBroadphaseHandle()
bool hasContactResponse() const
void setWorldTransform(const btTransform &worldTrans)
CollisionWorld is interface and container for the collision detection.
const btBroadphaseInterface * getBroadphase() const
btDispatcher * getDispatcher()
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()
The btConvexShape is an abstract shape interface, implemented by all convex shapes such as btBoxShape...
Definition: btConvexShape.h:33
virtual void setMargin(btScalar margin)=0
virtual btScalar getMargin() const =0
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...
virtual void dispatchAllCollisionPairs(btOverlappingPairCache *pairCache, const btDispatcherInfo &dispatchInfo, btDispatcher *dispatcher)=0
void convexSweepTest(const class btConvexShape *castShape, const btTransform &convexFromWorld, const btTransform &convexToWorld, btCollisionWorld::ConvexResultCallback &resultCallback, btScalar allowedCcdPenetration=0.f) const
Hash-space based Pair Cache, thanks to Erin Catto, Box2D, http://www.box2d.org, and Pierre Terdiman,...
virtual void * removeOverlappingPair(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1, btDispatcher *dispatcher)
btBroadphasePairArray & getOverlappingPairArray()
The btIDebugDraw interface class allows hooking up a debug renderer to visually debug simulations.
Definition: btIDebugDraw.h:27
btVector3 perpindicularComponent(const btVector3 &direction, const btVector3 &normal)
btVector3 m_walkDirection
this is the desired walk direction, set by the user
virtual void setWalkDirection(const btVector3 &walkDirection)
This should probably be called setPositionIncrementPerSimulatorStep.
virtual bool needsCollision(const btCollisionObject *body0, const btCollisionObject *body1)
void reset(btCollisionWorld *collisionWorld)
void playerStep(btCollisionWorld *collisionWorld, btScalar dt)
void preStep(btCollisionWorld *collisionWorld)
btVector3 computeReflectionDirection(const btVector3 &direction, const btVector3 &normal)
virtual void setLinearVelocity(const btVector3 &velocity)
void stepDown(btCollisionWorld *collisionWorld, btScalar dt)
virtual const btVector3 & getAngularVelocity() const
btManifoldArray m_manifoldArray
keep track of the contact manifolds
btKinematicCharacterController(btPairCachingGhostObject *ghostObject, btConvexShape *convexShape, btScalar stepHeight, const btVector3 &up=btVector3(1.0, 0.0, 0.0))
void jump(const btVector3 &v=btVector3(0, 0, 0))
void stepForwardAndStrafe(btCollisionWorld *collisionWorld, const btVector3 &walkMove)
virtual void setVelocityForTimeInterval(const btVector3 &velocity, btScalar timeInterval)
Caller provides a velocity with which the character should move for the given time period.
void setMaxSlope(btScalar slopeRadians)
The max slope determines the maximum angle that the controller can walk up.
void debugDraw(btIDebugDraw *debugDrawer)
btActionInterface interface
void updateTargetPositionBasedOnCollision(const btVector3 &hit_normal, btScalar tangentMag=btScalar(0.0), btScalar normalMag=btScalar(1.0))
void stepUp(btCollisionWorld *collisionWorld)
virtual void setAngularVelocity(const btVector3 &velocity)
btQuaternion getRotation(btVector3 &v0, btVector3 &v1) const
btVector3 parallelComponent(const btVector3 &direction, const btVector3 &normal)
bool recoverFromPenetration(btCollisionWorld *collisionWorld)
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace)
btKinematicClosestNotMeConvexResultCallback(btCollisionObject *me, const btVector3 &up, btScalar minSlopeDot)
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult &rayResult, bool normalInWorldSpace)
ManifoldContactPoint collects and maintains persistent contactpoints.
btScalar getDistance() const
btVector3 m_normalWorldOnB
btHashedOverlappingPairCache * getOverlappingPairCache()
btPersistentManifold is a contact point cache, it stays persistent as long as objects are overlapping...
const btCollisionObject * getBody0() const
const btManifoldPoint & getContactPoint(int index) const
The btQuaternion implements quaternion to perform linear algebra rotations in combination with btMatr...
Definition: btQuaternion.h:50
btQuaternion inverse() const
Return the inverse of this quaternion.
Definition: btQuaternion.h:497
The btTransform class supports rigid transforms with only translation and rotation and no scaling/she...
Definition: btTransform.h:30
btMatrix3x3 & getBasis()
Return the basis matrix for the rotation.
Definition: btTransform.h:108
btVector3 & getOrigin()
Return the origin vector translation.
Definition: btTransform.h:113
void setRotation(const btQuaternion &q)
Set the rotational element by btQuaternion.
Definition: btTransform.h:160
void setIdentity()
Set this transformation to the identity.
Definition: btTransform.h:166
btQuaternion getRotation() const
Return a quaternion representing the rotation.
Definition: btTransform.h:118
void setOrigin(const btVector3 &origin)
Set the translational element.
Definition: btTransform.h:146
btVector3 can be used to represent 3D points and vectors.
Definition: btVector3.h:82
btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition: btVector3.h:303
void setInterpolate3(const btVector3 &v0, const btVector3 &v1, btScalar rt)
Definition: btVector3.h:492
btScalar length() const
Return the length of the vector.
Definition: btVector3.h:257
btScalar dot(const btVector3 &v) const
Return the dot product.
Definition: btVector3.h:229
void setValue(const btScalar &_x, const btScalar &_y, const btScalar &_z)
Definition: btVector3.h:640
btVector3 normalized() const
Return a normalized version of this vector.
Definition: btVector3.h:949
const btScalar & getY() const
Return the y value.
Definition: btVector3.h:563
btScalar length2() const
Return the length of the vector squared.
Definition: btVector3.h:251
bool fuzzyZero() const
Definition: btVector3.h:688
The btBroadphasePair class contains a pair of aabb-overlapping objects.
btBroadphaseProxy * m_pProxy1
btBroadphaseProxy * m_pProxy0
btCollisionAlgorithm * m_algorithm
ClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld)
ClosestRayResultCallback(const btVector3 &rayFromWorld, const btVector3 &rayToWorld)
const btCollisionObject * m_hitCollisionObject
const btCollisionObject * m_collisionObject
btScalar m_allowedCcdPenetration
Definition: btDispatcher.h:62