Blender V2.61 - r43446
|
00001 /* 00002 Bullet Continuous Collision Detection and Physics Library 00003 Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com 00004 00005 This software is provided 'as-is', without any express or implied warranty. 00006 In no event will the authors be held liable for any damages arising from the use of this software. 00007 Permission is granted to anyone to use this software for any purpose, 00008 including commercial applications, and to alter it and redistribute it freely, 00009 subject to the following restrictions: 00010 00011 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. 00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 00013 3. This notice may not be removed or altered from any source distribution. 00014 */ 00015 00016 00017 #include "LinearMath/btIDebugDraw.h" 00018 #include "BulletCollision/CollisionDispatch/btGhostObject.h" 00019 #include "BulletCollision/CollisionShapes/btMultiSphereShape.h" 00020 #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" 00021 #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" 00022 #include "BulletCollision/CollisionDispatch/btCollisionWorld.h" 00023 #include "LinearMath/btDefaultMotionState.h" 00024 #include "btKinematicCharacterController.h" 00025 00026 00027 // static helper method 00028 static btVector3 00029 getNormalizedVector(const btVector3& v) 00030 { 00031 btVector3 n = v.normalized(); 00032 if (n.length() < SIMD_EPSILON) { 00033 n.setValue(0, 0, 0); 00034 } 00035 return n; 00036 } 00037 00038 00045 class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback 00046 { 00047 public: 00048 btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) 00049 { 00050 m_me = me; 00051 } 00052 00053 virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) 00054 { 00055 if (rayResult.m_collisionObject == m_me) 00056 return 1.0; 00057 00058 return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace); 00059 } 00060 protected: 00061 btCollisionObject* m_me; 00062 }; 00063 00064 class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback 00065 { 00066 public: 00067 btKinematicClosestNotMeConvexResultCallback (btCollisionObject* me, const btVector3& up, btScalar minSlopeDot) 00068 : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) 00069 , m_me(me) 00070 , m_up(up) 00071 , m_minSlopeDot(minSlopeDot) 00072 { 00073 } 00074 00075 virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) 00076 { 00077 if (convexResult.m_hitCollisionObject == m_me) 00078 return btScalar(1.0); 00079 00080 btVector3 hitNormalWorld; 00081 if (normalInWorldSpace) 00082 { 00083 hitNormalWorld = convexResult.m_hitNormalLocal; 00084 } else 00085 { 00087 hitNormalWorld = m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal; 00088 } 00089 00090 btScalar dotUp = m_up.dot(hitNormalWorld); 00091 if (dotUp < m_minSlopeDot) { 00092 return btScalar(1.0); 00093 } 00094 00095 return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace); 00096 } 00097 protected: 00098 btCollisionObject* m_me; 00099 const btVector3 m_up; 00100 btScalar m_minSlopeDot; 00101 }; 00102 00103 /* 00104 * Returns the reflection direction of a ray going 'direction' hitting a surface with normal 'normal' 00105 * 00106 * from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html 00107 */ 00108 btVector3 btKinematicCharacterController::computeReflectionDirection (const btVector3& direction, const btVector3& normal) 00109 { 00110 return direction - (btScalar(2.0) * direction.dot(normal)) * normal; 00111 } 00112 00113 /* 00114 * Returns the portion of 'direction' that is parallel to 'normal' 00115 */ 00116 btVector3 btKinematicCharacterController::parallelComponent (const btVector3& direction, const btVector3& normal) 00117 { 00118 btScalar magnitude = direction.dot(normal); 00119 return normal * magnitude; 00120 } 00121 00122 /* 00123 * Returns the portion of 'direction' that is perpindicular to 'normal' 00124 */ 00125 btVector3 btKinematicCharacterController::perpindicularComponent (const btVector3& direction, const btVector3& normal) 00126 { 00127 return direction - parallelComponent(direction, normal); 00128 } 00129 00130 btKinematicCharacterController::btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, int upAxis) 00131 { 00132 m_upAxis = upAxis; 00133 m_addedMargin = 0.02; 00134 m_walkDirection.setValue(0,0,0); 00135 m_useGhostObjectSweepTest = true; 00136 m_ghostObject = ghostObject; 00137 m_stepHeight = stepHeight; 00138 m_turnAngle = btScalar(0.0); 00139 m_convexShape=convexShape; 00140 m_useWalkDirection = true; // use walk direction by default, legacy behavior 00141 m_velocityTimeInterval = 0.0; 00142 m_verticalVelocity = 0.0; 00143 m_verticalOffset = 0.0; 00144 m_gravity = 9.8 * 3 ; // 3G acceleration. 00145 m_fallSpeed = 55.0; // Terminal velocity of a sky diver in m/s. 00146 m_jumpSpeed = 10.0; // ? 00147 m_wasOnGround = false; 00148 m_wasJumping = false; 00149 setMaxSlope(btRadians(45.0)); 00150 } 00151 00152 btKinematicCharacterController::~btKinematicCharacterController () 00153 { 00154 } 00155 00156 btPairCachingGhostObject* btKinematicCharacterController::getGhostObject() 00157 { 00158 return m_ghostObject; 00159 } 00160 00161 bool btKinematicCharacterController::recoverFromPenetration ( btCollisionWorld* collisionWorld) 00162 { 00163 00164 bool penetration = false; 00165 00166 collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher()); 00167 00168 m_currentPosition = m_ghostObject->getWorldTransform().getOrigin(); 00169 00170 btScalar maxPen = btScalar(0.0); 00171 for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++) 00172 { 00173 m_manifoldArray.resize(0); 00174 00175 btBroadphasePair* collisionPair = &m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i]; 00176 00177 if (collisionPair->m_algorithm) 00178 collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray); 00179 00180 00181 for (int j=0;j<m_manifoldArray.size();j++) 00182 { 00183 btPersistentManifold* manifold = m_manifoldArray[j]; 00184 btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0); 00185 for (int p=0;p<manifold->getNumContacts();p++) 00186 { 00187 const btManifoldPoint&pt = manifold->getContactPoint(p); 00188 00189 btScalar dist = pt.getDistance(); 00190 00191 if (dist < 0.0) 00192 { 00193 if (dist < maxPen) 00194 { 00195 maxPen = dist; 00196 m_touchingNormal = pt.m_normalWorldOnB * directionSign;//?? 00197 00198 } 00199 m_currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2); 00200 penetration = true; 00201 } else { 00202 //printf("touching %f\n", dist); 00203 } 00204 } 00205 00206 //manifold->clearManifold(); 00207 } 00208 } 00209 btTransform newTrans = m_ghostObject->getWorldTransform(); 00210 newTrans.setOrigin(m_currentPosition); 00211 m_ghostObject->setWorldTransform(newTrans); 00212 // printf("m_touchingNormal = %f,%f,%f\n",m_touchingNormal[0],m_touchingNormal[1],m_touchingNormal[2]); 00213 return penetration; 00214 } 00215 00216 void btKinematicCharacterController::stepUp ( btCollisionWorld* world) 00217 { 00218 // phase 1: up 00219 btTransform start, end; 00220 m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_stepHeight + (m_verticalOffset > 0.f?m_verticalOffset:0.f)); 00221 00222 start.setIdentity (); 00223 end.setIdentity (); 00224 00225 /* FIXME: Handle penetration properly */ 00226 start.setOrigin (m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_convexShape->getMargin() + m_addedMargin)); 00227 end.setOrigin (m_targetPosition); 00228 00229 btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, -getUpAxisDirections()[m_upAxis], btScalar(0.7071)); 00230 callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; 00231 callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; 00232 00233 if (m_useGhostObjectSweepTest) 00234 { 00235 m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration); 00236 } 00237 else 00238 { 00239 world->convexSweepTest (m_convexShape, start, end, callback); 00240 } 00241 00242 if (callback.hasHit()) 00243 { 00244 // Only modify the position if the hit was a slope and not a wall or ceiling. 00245 if(callback.m_hitNormalWorld.dot(getUpAxisDirections()[m_upAxis]) > 0.0) 00246 { 00247 // we moved up only a fraction of the step height 00248 m_currentStepOffset = m_stepHeight * callback.m_closestHitFraction; 00249 m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); 00250 } 00251 m_verticalVelocity = 0.0; 00252 m_verticalOffset = 0.0; 00253 } else { 00254 m_currentStepOffset = m_stepHeight; 00255 m_currentPosition = m_targetPosition; 00256 } 00257 } 00258 00259 void btKinematicCharacterController::updateTargetPositionBasedOnCollision (const btVector3& hitNormal, btScalar tangentMag, btScalar normalMag) 00260 { 00261 btVector3 movementDirection = m_targetPosition - m_currentPosition; 00262 btScalar movementLength = movementDirection.length(); 00263 if (movementLength>SIMD_EPSILON) 00264 { 00265 movementDirection.normalize(); 00266 00267 btVector3 reflectDir = computeReflectionDirection (movementDirection, hitNormal); 00268 reflectDir.normalize(); 00269 00270 btVector3 parallelDir, perpindicularDir; 00271 00272 parallelDir = parallelComponent (reflectDir, hitNormal); 00273 perpindicularDir = perpindicularComponent (reflectDir, hitNormal); 00274 00275 m_targetPosition = m_currentPosition; 00276 if (0)//tangentMag != 0.0) 00277 { 00278 btVector3 parComponent = parallelDir * btScalar (tangentMag*movementLength); 00279 // printf("parComponent=%f,%f,%f\n",parComponent[0],parComponent[1],parComponent[2]); 00280 m_targetPosition += parComponent; 00281 } 00282 00283 if (normalMag != 0.0) 00284 { 00285 btVector3 perpComponent = perpindicularDir * btScalar (normalMag*movementLength); 00286 // printf("perpComponent=%f,%f,%f\n",perpComponent[0],perpComponent[1],perpComponent[2]); 00287 m_targetPosition += perpComponent; 00288 } 00289 } else 00290 { 00291 // printf("movementLength don't normalize a zero vector\n"); 00292 } 00293 } 00294 00295 void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* collisionWorld, const btVector3& walkMove) 00296 { 00297 // printf("m_normalizedDirection=%f,%f,%f\n", 00298 // m_normalizedDirection[0],m_normalizedDirection[1],m_normalizedDirection[2]); 00299 // phase 2: forward and strafe 00300 btTransform start, end; 00301 m_targetPosition = m_currentPosition + walkMove; 00302 00303 start.setIdentity (); 00304 end.setIdentity (); 00305 00306 btScalar fraction = 1.0; 00307 btScalar distance2 = (m_currentPosition-m_targetPosition).length2(); 00308 // printf("distance2=%f\n",distance2); 00309 00310 if (m_touchingContact) 00311 { 00312 if (m_normalizedDirection.dot(m_touchingNormal) > btScalar(0.0)) 00313 { 00314 updateTargetPositionBasedOnCollision (m_touchingNormal); 00315 } 00316 } 00317 00318 int maxIter = 10; 00319 00320 while (fraction > btScalar(0.01) && maxIter-- > 0) 00321 { 00322 start.setOrigin (m_currentPosition); 00323 end.setOrigin (m_targetPosition); 00324 btVector3 sweepDirNegative(m_currentPosition - m_targetPosition); 00325 00326 btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, sweepDirNegative, btScalar(0.0)); 00327 callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; 00328 callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; 00329 00330 00331 btScalar margin = m_convexShape->getMargin(); 00332 m_convexShape->setMargin(margin + m_addedMargin); 00333 00334 00335 if (m_useGhostObjectSweepTest) 00336 { 00337 m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); 00338 } else 00339 { 00340 collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); 00341 } 00342 00343 m_convexShape->setMargin(margin); 00344 00345 00346 fraction -= callback.m_closestHitFraction; 00347 00348 if (callback.hasHit()) 00349 { 00350 // we moved only a fraction 00351 btScalar hitDistance; 00352 hitDistance = (callback.m_hitPointWorld - m_currentPosition).length(); 00353 00354 // m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); 00355 00356 updateTargetPositionBasedOnCollision (callback.m_hitNormalWorld); 00357 btVector3 currentDir = m_targetPosition - m_currentPosition; 00358 distance2 = currentDir.length2(); 00359 if (distance2 > SIMD_EPSILON) 00360 { 00361 currentDir.normalize(); 00362 /* See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." */ 00363 if (currentDir.dot(m_normalizedDirection) <= btScalar(0.0)) 00364 { 00365 break; 00366 } 00367 } else 00368 { 00369 // printf("currentDir: don't normalize a zero vector\n"); 00370 break; 00371 } 00372 00373 } else { 00374 // we moved whole way 00375 m_currentPosition = m_targetPosition; 00376 } 00377 00378 // if (callback.m_closestHitFraction == 0.f) 00379 // break; 00380 00381 } 00382 } 00383 00384 void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld, btScalar dt) 00385 { 00386 btTransform start, end; 00387 00388 // phase 3: down 00389 /*btScalar additionalDownStep = (m_wasOnGround && !onGround()) ? m_stepHeight : 0.0; 00390 btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + additionalDownStep); 00391 btScalar downVelocity = (additionalDownStep == 0.0 && m_verticalVelocity<0.0?-m_verticalVelocity:0.0) * dt; 00392 btVector3 gravity_drop = getUpAxisDirections()[m_upAxis] * downVelocity; 00393 m_targetPosition -= (step_drop + gravity_drop);*/ 00394 00395 btScalar downVelocity = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt; 00396 if(downVelocity > 0.0 && downVelocity < m_stepHeight 00397 && (m_wasOnGround || !m_wasJumping)) 00398 { 00399 downVelocity = m_stepHeight; 00400 } 00401 00402 btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity); 00403 m_targetPosition -= step_drop; 00404 00405 start.setIdentity (); 00406 end.setIdentity (); 00407 00408 start.setOrigin (m_currentPosition); 00409 end.setOrigin (m_targetPosition); 00410 00411 btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine); 00412 callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; 00413 callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; 00414 00415 if (m_useGhostObjectSweepTest) 00416 { 00417 m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); 00418 } else 00419 { 00420 collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); 00421 } 00422 00423 if (callback.hasHit()) 00424 { 00425 // we dropped a fraction of the height -> hit floor 00426 m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); 00427 m_verticalVelocity = 0.0; 00428 m_verticalOffset = 0.0; 00429 m_wasJumping = false; 00430 } else { 00431 // we dropped the full height 00432 00433 m_currentPosition = m_targetPosition; 00434 } 00435 } 00436 00437 00438 00439 void btKinematicCharacterController::setWalkDirection 00440 ( 00441 const btVector3& walkDirection 00442 ) 00443 { 00444 m_useWalkDirection = true; 00445 m_walkDirection = walkDirection; 00446 m_normalizedDirection = getNormalizedVector(m_walkDirection); 00447 } 00448 00449 00450 00451 void btKinematicCharacterController::setVelocityForTimeInterval 00452 ( 00453 const btVector3& velocity, 00454 btScalar timeInterval 00455 ) 00456 { 00457 // printf("setVelocity!\n"); 00458 // printf(" interval: %f\n", timeInterval); 00459 // printf(" velocity: (%f, %f, %f)\n", 00460 // velocity.x(), velocity.y(), velocity.z()); 00461 00462 m_useWalkDirection = false; 00463 m_walkDirection = velocity; 00464 m_normalizedDirection = getNormalizedVector(m_walkDirection); 00465 m_velocityTimeInterval = timeInterval; 00466 } 00467 00468 00469 00470 void btKinematicCharacterController::reset () 00471 { 00472 } 00473 00474 void btKinematicCharacterController::warp (const btVector3& origin) 00475 { 00476 btTransform xform; 00477 xform.setIdentity(); 00478 xform.setOrigin (origin); 00479 m_ghostObject->setWorldTransform (xform); 00480 } 00481 00482 00483 void btKinematicCharacterController::preStep ( btCollisionWorld* collisionWorld) 00484 { 00485 00486 int numPenetrationLoops = 0; 00487 m_touchingContact = false; 00488 while (recoverFromPenetration (collisionWorld)) 00489 { 00490 numPenetrationLoops++; 00491 m_touchingContact = true; 00492 if (numPenetrationLoops > 4) 00493 { 00494 //printf("character could not recover from penetration = %d\n", numPenetrationLoops); 00495 break; 00496 } 00497 } 00498 00499 m_currentPosition = m_ghostObject->getWorldTransform().getOrigin(); 00500 m_targetPosition = m_currentPosition; 00501 // printf("m_targetPosition=%f,%f,%f\n",m_targetPosition[0],m_targetPosition[1],m_targetPosition[2]); 00502 00503 00504 } 00505 00506 #include <stdio.h> 00507 00508 void btKinematicCharacterController::playerStep ( btCollisionWorld* collisionWorld, btScalar dt) 00509 { 00510 // printf("playerStep(): "); 00511 // printf(" dt = %f", dt); 00512 00513 // quick check... 00514 if (!m_useWalkDirection && m_velocityTimeInterval <= 0.0) { 00515 // printf("\n"); 00516 return; // no motion 00517 } 00518 00519 m_wasOnGround = onGround(); 00520 00521 // Update fall velocity. 00522 m_verticalVelocity -= m_gravity * dt; 00523 if(m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed) 00524 { 00525 m_verticalVelocity = m_jumpSpeed; 00526 } 00527 if(m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed)) 00528 { 00529 m_verticalVelocity = -btFabs(m_fallSpeed); 00530 } 00531 m_verticalOffset = m_verticalVelocity * dt; 00532 00533 00534 btTransform xform; 00535 xform = m_ghostObject->getWorldTransform (); 00536 00537 // printf("walkDirection(%f,%f,%f)\n",walkDirection[0],walkDirection[1],walkDirection[2]); 00538 // printf("walkSpeed=%f\n",walkSpeed); 00539 00540 stepUp (collisionWorld); 00541 if (m_useWalkDirection) { 00542 stepForwardAndStrafe (collisionWorld, m_walkDirection); 00543 } else { 00544 //printf(" time: %f", m_velocityTimeInterval); 00545 // still have some time left for moving! 00546 btScalar dtMoving = 00547 (dt < m_velocityTimeInterval) ? dt : m_velocityTimeInterval; 00548 m_velocityTimeInterval -= dt; 00549 00550 // how far will we move while we are moving? 00551 btVector3 move = m_walkDirection * dtMoving; 00552 00553 //printf(" dtMoving: %f", dtMoving); 00554 00555 // okay, step 00556 stepForwardAndStrafe(collisionWorld, move); 00557 } 00558 stepDown (collisionWorld, dt); 00559 00560 // printf("\n"); 00561 00562 xform.setOrigin (m_currentPosition); 00563 m_ghostObject->setWorldTransform (xform); 00564 } 00565 00566 void btKinematicCharacterController::setFallSpeed (btScalar fallSpeed) 00567 { 00568 m_fallSpeed = fallSpeed; 00569 } 00570 00571 void btKinematicCharacterController::setJumpSpeed (btScalar jumpSpeed) 00572 { 00573 m_jumpSpeed = jumpSpeed; 00574 } 00575 00576 void btKinematicCharacterController::setMaxJumpHeight (btScalar maxJumpHeight) 00577 { 00578 m_maxJumpHeight = maxJumpHeight; 00579 } 00580 00581 bool btKinematicCharacterController::canJump () const 00582 { 00583 return onGround(); 00584 } 00585 00586 void btKinematicCharacterController::jump () 00587 { 00588 if (!canJump()) 00589 return; 00590 00591 m_verticalVelocity = m_jumpSpeed; 00592 m_wasJumping = true; 00593 00594 #if 0 00595 currently no jumping. 00596 btTransform xform; 00597 m_rigidBody->getMotionState()->getWorldTransform (xform); 00598 btVector3 up = xform.getBasis()[1]; 00599 up.normalize (); 00600 btScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0); 00601 m_rigidBody->applyCentralImpulse (up * magnitude); 00602 #endif 00603 } 00604 00605 void btKinematicCharacterController::setGravity(btScalar gravity) 00606 { 00607 m_gravity = gravity; 00608 } 00609 00610 btScalar btKinematicCharacterController::getGravity() const 00611 { 00612 return m_gravity; 00613 } 00614 00615 void btKinematicCharacterController::setMaxSlope(btScalar slopeRadians) 00616 { 00617 m_maxSlopeRadians = slopeRadians; 00618 m_maxSlopeCosine = btCos(slopeRadians); 00619 } 00620 00621 btScalar btKinematicCharacterController::getMaxSlope() const 00622 { 00623 return m_maxSlopeRadians; 00624 } 00625 00626 bool btKinematicCharacterController::onGround () const 00627 { 00628 return m_verticalVelocity == 0.0 && m_verticalOffset == 0.0; 00629 } 00630 00631 00632 btVector3* btKinematicCharacterController::getUpAxisDirections() 00633 { 00634 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) }; 00635 00636 return sUpAxisDirection; 00637 } 00638 00639 void btKinematicCharacterController::debugDraw(btIDebugDraw* debugDrawer) 00640 { 00641 }