Bullet Collision Detection & Physics Library
btKinematicCharacterController.cpp
Go to the documentation of this file.
1/*
2Bullet Continuous Collision Detection and Physics Library
3Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com
4
5This software is provided 'as-is', without any express or implied warranty.
6In no event will the authors be held liable for any damages arising from the use of this software.
7Permission is granted to anyone to use this software for any purpose,
8including commercial applications, and to alter it and redistribute it freely,
9subject to the following restrictions:
10
111. 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.
122. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
133. 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
29static 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{
49public:
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 }
62protected:
64};
65
67{
68public:
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 }
102protected:
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;
159 full_drop = false;
160 bounce_fix = false;
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 {
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 }
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
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
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
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
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
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(
612const btVector3& walkDirection
613)
614{
615 m_useWalkDirection = true;
616 m_walkDirection = walkDirection;
618}
619
620
621
623(
624const btVector3& velocity,
625btScalar 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;
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;
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;
732
734
735 btQuaternion orn = rot * xform.getRotation();
736
737 xform.setRotation(orn);
739
744 }
745
746 // quick check...
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;
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{
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;
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
static btVector3 getNormalizedVector(const btVector3 &v)
btQuaternion shortestArcQuatNormalize2(btVector3 &v0, btVector3 &v1)
Definition: btQuaternion.h:950
btScalar btPow(btScalar x, btScalar y)
Definition: btScalar.h:499
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition: btScalar.h:292
btScalar btSin(btScalar x)
Definition: btScalar.h:477
btScalar btFabs(btScalar x)
Definition: btScalar.h:475
btScalar btCos(btScalar x)
Definition: btScalar.h:476
btScalar btRadians(btScalar x)
Definition: btScalar.h:566
#define SIMD_EPSILON
Definition: btScalar.h:521
btScalar btAcos(btScalar x)
Definition: btScalar.h:479
#define SIMD_HALF_PI
Definition: btScalar.h:506
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.
btDispatcher * getDispatcher()
btDispatcherInfo & getDispatchInfo()
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...
const btBroadphaseInterface * getBroadphase() const
The btConvexShape is an abstract shape interface, implemented by all convex shapes such as btBoxShape...
Definition: btConvexShape.h:32
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:30
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 jump(const btVector3 &v=btVector3())
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 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 btManifoldPoint & getContactPoint(int index) const
const btCollisionObject * getBody0() const
The btQuaternion implements quaternion to perform linear algebra rotations in combination with btMatr...
Definition: btQuaternion.h:55
btQuaternion inverse() const
Return the inverse of this quaternion.
Definition: btQuaternion.h:482
The btTransform class supports rigid transforms with only translation and rotation and no scaling/she...
Definition: btTransform.h:34
btMatrix3x3 & getBasis()
Return the basis matrix for the rotation.
Definition: btTransform.h:112
void setRotation(const btQuaternion &q)
Set the rotational element by btQuaternion.
Definition: btTransform.h:165
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
btVector3 & getOrigin()
Return the origin vector translation.
Definition: btTransform.h:117
void setOrigin(const btVector3 &origin)
Set the translational element.
Definition: btTransform.h:150
btVector3 can be used to represent 3D points and vectors.
Definition: btVector3.h:84
void setInterpolate3(const btVector3 &v0, const btVector3 &v1, btScalar rt)
Definition: btVector3.h:503
btScalar length() const
Return the length of the vector.
Definition: btVector3.h:263
btScalar dot(const btVector3 &v) const
Return the dot product.
Definition: btVector3.h:235
void setValue(const btScalar &_x, const btScalar &_y, const btScalar &_z)
Definition: btVector3.h:652
btVector3 normalized() const
Return a normalized version of this vector.
Definition: btVector3.h:964
btScalar length2() const
Return the length of the vector squared.
Definition: btVector3.h:257
const btScalar & getY() const
Return the y value.
Definition: btVector3.h:575
btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition: btVector3.h:309
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