Changeset 1819
- Timestamp:
- Aug 25, 2012, 7:21:55 PM (11 years ago)
- Location:
- trunk/test
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/test/BtPhysTest.cpp
r1803 r1819 105 105 if (idx != 1) 106 106 { 107 vec3 axis = vec3(.0f);108 axis[2 - idx] = 1;109 NewRotation = quat::rotate(90.f, axis);107 vec3 NewAxis = vec3(.0f); 108 NewAxis[2 - idx] = 1; 109 NewRotation = quat::rotate(90.f, NewAxis); 110 110 } 111 111 -
trunk/test/Physics/Include/BulletCharacterController.h
r1802 r1819 25 25 #endif 26 26 27 #define USE_LOL_CTRLR_CHARAC 28 27 29 namespace lol 28 30 { … … 31 33 { 32 34 33 #if 035 #ifdef USE_LOL_CTRLR_CHARAC 34 36 #ifdef HAVE_PHYS_USE_BULLET 35 37 … … 37 39 ///It uses a ghost object and convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations. 38 40 ///Interaction between btKinematicCharacterController and dynamic rigid bodies needs to be explicity implemented by the user. 39 class BulletKinematicCharacterController : public bt CharacterControllerInterface41 class BulletKinematicCharacterController : public btActionInterface 40 42 { 43 public: 44 BulletKinematicCharacterController(btPairCachingGhostObject* NewGhostObject, btConvexShape* NewConvexShape, float NewStepHeight, int NewUpAxis=1) 45 { 46 m_convex_shape = NewConvexShape; 47 m_up_axis = NewUpAxis; 48 m_ghost_object = NewGhostObject; 49 m_step_height = NewStepHeight; 50 51 m_added_margin = 0.02f; 52 m_walk_direction = vec3(.0f, .0f, .0f); 53 m_do_gobject_sweep_test = true; 54 m_turn_angle = .0f; 55 m_use_walk_direction = false; // Should remove walk direction, this doesn't work correctly. 56 m_velocity_time_interval = .0f; 57 m_vertical_velocity = .0f; 58 m_vertical_offset = .0f; 59 m_gravity = 9.8f * 3.f; // 3G acceleration. 60 m_fall_speed = 55.f; // Terminal velocity of a sky diver in m/s. 61 m_jump_speed = 10.f; // ? 62 m_was_on_ground = false; 63 m_was_jumping = false; 64 SetMaxSlope(45.f); 65 } 66 ~BulletKinematicCharacterController() { } 67 41 68 protected: 42 69 43 btScalar m_halfHeight; 44 45 btPairCachingGhostObject* m_ghostObject; 46 btConvexShape* m_convexShape;//is also in m_ghostObject, but it needs to be convex, so we store it here to avoid upcast 47 48 btScalar m_verticalVelocity; 49 btScalar m_verticalOffset; 50 btScalar m_fallSpeed; 51 btScalar m_jumpSpeed; 52 btScalar m_maxJumpHeight; 53 btScalar m_maxSlopeRadians; // Slope angle that is set (used for returning the exact value) 54 btScalar m_maxSlopeCosine; // Cosine equivalent of m_maxSlopeRadians (calculated once when set, for optimization) 55 btScalar m_gravity; 56 57 btScalar m_turnAngle; 58 59 btScalar m_stepHeight; 60 61 btScalar m_addedMargin;//@todo: remove this and fix the code 62 63 ///this is the desired walk direction, set by the user 64 btVector3 m_walkDirection; 65 btVector3 m_normalizedDirection; 70 static vec3* GetUpAxisDirections() 71 { 72 static vec3 sUpAxisDirection[3] = { vec3(1.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, 0.0f, 1.0f) }; 73 74 return sUpAxisDirection; 75 } 76 77 //-------------------------- 78 //CONVENIENCE FUNCTIONS 79 //-- 80 81 //Returns the reflection Direction of a ray going 'Direction' hitting a surface with Normal 'Normal' from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html 82 vec3 GetReflectedDir(const vec3& Direction, const vec3& Normal) 83 { 84 return Direction - (2.f * dot(Direction, Normal) * Normal); 85 } 86 //Returns the portion of 'direction' that is parallel to 'normal' 87 vec3 ProjectDirOnNorm(const vec3& Direction, const vec3& Normal) 88 { 89 return Normal * dot(Direction, Normal); 90 } 91 //Returns the portion of 'Direction' that is perpindicular to 'Normal' 92 vec3 ProjectDirOnNormPerpindicular(const vec3& Direction, const vec3& Normal) 93 { 94 return Direction - ProjectDirOnNorm(Direction, Normal); 95 } 96 //Returns Ghost Object. -duh- 97 btPairCachingGhostObject* GetGhostObject() 98 { 99 return m_ghost_object; 100 } 101 102 //"Real" war functions 103 bool RecoverFromPenetration(btCollisionWorld* CollisionWorld); 104 void UpdateTargetOnHit(const vec3& hit_normal, float TangentMag = .0f, float NormalMag = 1.f); 105 void StepUp(btCollisionWorld* CollisionWorld); 106 void StepForwardAndStrafe(btCollisionWorld* CollisionWorld, const vec3& MoveStep); 107 void StepDown(btCollisionWorld* CollisionWorld, float DeltaTime); 108 109 public: 110 ///btActionInterface interface : KEEP IN camelCase 111 virtual void updateAction(btCollisionWorld* CollisionWorld, float deltaTime) 112 { 113 PreStep(CollisionWorld); 114 PlayerStep(CollisionWorld, deltaTime); 115 } 116 117 //not in the interface, but called above 118 void PreStep(btCollisionWorld* CollisionWorld); 119 void PlayerStep(btCollisionWorld* CollisionWorld, float DeltaTime); 120 121 ///btActionInterface interface : KEEP IN camelCase 122 void debugDraw(btIDebugDraw* debugDrawer) { } 123 124 void SetUpAxis(int NewAxis) 125 { 126 if (NewAxis < 0) 127 NewAxis = 0; 128 if (NewAxis > 2) 129 NewAxis = 2; 130 m_up_axis = NewAxis; 131 } 132 133 //!!!!!! SHOULD DITCH THAT !!!!!! 134 //This should probably be called setPositionIncrementPerSimulatorStep. 135 //This is neither a Direction nor a velocity, but the amount to 136 //increment the position each simulation iteration, regardless 137 //of DeltaTime. 138 //This call will Reset any velocity set by SetVelocityForTimeInterval(). 139 virtual void SetWalkDirection(const vec3& walkDirection) 140 { 141 m_use_walk_direction = true; 142 m_walk_direction = walkDirection; 143 m_normalized_direction = normalize(m_walk_direction); 144 } 145 146 //Caller provides a velocity with which the character should MoveStep for 147 //the given time period. After the time period, velocity is Reset 148 //to zero. 149 //This call will Reset any walk Direction set by SetWalkDirection(). 150 //Negative time intervals will result in no motion. 151 virtual void SetVelocityForTimeInterval(const vec3& velocity, float timeInterval) 152 { 153 m_use_walk_direction = false; 154 m_walk_direction = velocity; 155 m_normalized_direction = normalize(m_walk_direction); 156 m_velocity_time_interval = timeInterval; 157 } 158 159 //Usefulness ? 160 void Reset() { } 161 void Warp(const vec3& NewOrigin) 162 { 163 btTransform NewTransform; 164 NewTransform.setIdentity(); 165 NewTransform.setOrigin(LOL2BTU_VEC3(NewOrigin)); 166 m_ghost_object->setWorldTransform(NewTransform); 167 } 168 169 //External Setup 170 //-- 171 172 void SetFallSpeed(float NewFallSpeed) { m_fall_speed = NewFallSpeed; } 173 void SetJumpSpeed(float NewJumpSpeed) { m_jump_speed = NewJumpSpeed; } 174 void SetMaxJumpHeight(float NewMaxJumpHeight) { m_max_jump_height = NewMaxJumpHeight; } 175 176 //Jump logic will go in EasyCC 177 bool CanJump() const { return OnGround(); } 178 void Jump(); 179 180 //NewGravity functions 181 void SetGravity(float NewGravity) { m_gravity = NewGravity; } 182 float GetGravity() const { return m_gravity; } 183 184 //The max slope determines the maximum angle that the controller can walk up. 185 //The slope angle is measured in radians. 186 void SetMaxSlope(float NewSlopeRadians) { m_max_slope_radians = NewSlopeRadians; m_max_slope_cosine = lol::cos(NewSlopeRadians); } 187 float GetMaxSlope() const { return m_max_slope_radians; } 188 189 void SetUseGhostSweepTest(bool UseGObjectSweepTest) { m_do_gobject_sweep_test = UseGObjectSweepTest; } 190 191 bool OnGround() const { return m_vertical_velocity == .0f && m_vertical_offset == .0f; } 192 193 private: 194 195 btPairCachingGhostObject* m_ghost_object; 196 btConvexShape* m_convex_shape; //is also in m_ghost_object, but it needs to be convex, so we store it here to avoid upcast 197 198 //keep track of the contact manifolds 199 btManifoldArray m_manifold_array; 200 201 float m_half_height; 202 float m_velocity_time_interval; 203 float m_vertical_velocity; 204 float m_vertical_offset; 205 float m_fall_speed; 206 float m_jump_speed; 207 float m_max_jump_height; 208 float m_max_slope_radians; // Slope angle that is set (used for returning the exact value) 209 float m_max_slope_cosine; // Cosine equivalent of m_max_slope_radians (calculated once when set, for optimization) 210 float m_gravity; 211 float m_turn_angle; 212 float m_step_height; 213 float m_added_margin;//@todo: remove this and fix the code 214 215 ///this is the desired walk Direction, set by the user 216 vec3 m_walk_direction; 217 vec3 m_normalized_direction; 66 218 67 219 //some internal variables 68 btVector3 m_currentPosition; 69 btScalar m_currentStepOffset; 70 btVector3 m_targetPosition; 71 72 ///keep track of the contact manifolds 73 btManifoldArray m_manifoldArray; 74 75 bool m_touchingContact; 76 btVector3 m_touchingNormal; 77 78 bool m_wasOnGround; 79 bool m_wasJumping; 80 bool m_useGhostObjectSweepTest; 81 bool m_useWalkDirection; 82 btScalar m_velocityTimeInterval; 83 int m_upAxis; 84 85 static btVector3* getUpAxisDirections(); 86 87 btVector3 computeReflectionDirection (const btVector3& direction, const btVector3& normal); 88 btVector3 parallelComponent (const btVector3& direction, const btVector3& normal); 89 btVector3 perpindicularComponent (const btVector3& direction, const btVector3& normal); 90 91 bool recoverFromPenetration ( btCollisionWorld* collisionWorld); 92 void stepUp (btCollisionWorld* collisionWorld); 93 void updateTargetPositionBasedOnCollision (const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0)); 94 void stepForwardAndStrafe (btCollisionWorld* collisionWorld, const btVector3& walkMove); 95 void stepDown (btCollisionWorld* collisionWorld, btScalar dt); 96 public: 97 BulletKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, int upAxis = 1); 98 ~BulletKinematicCharacterController (); 99 100 101 ///btActionInterface interface 102 virtual void updateAction( btCollisionWorld* collisionWorld,btScalar deltaTime) 103 { 104 preStep ( collisionWorld); 105 playerStep (collisionWorld, deltaTime); 106 } 107 108 ///btActionInterface interface 109 void debugDraw(btIDebugDraw* debugDrawer); 110 111 void setUpAxis (int axis) 112 { 113 if (axis < 0) 114 axis = 0; 115 if (axis > 2) 116 axis = 2; 117 m_upAxis = axis; 118 } 119 120 /// This should probably be called setPositionIncrementPerSimulatorStep. 121 /// This is neither a direction nor a velocity, but the amount to 122 /// increment the position each simulation iteration, regardless 123 /// of dt. 124 /// This call will reset any velocity set by setVelocityForTimeInterval(). 125 virtual void setWalkDirection(const btVector3& walkDirection); 126 127 /// Caller provides a velocity with which the character should move for 128 /// the given time period. After the time period, velocity is reset 129 /// to zero. 130 /// This call will reset any walk direction set by setWalkDirection(). 131 /// Negative time intervals will result in no motion. 132 virtual void setVelocityForTimeInterval(const btVector3& velocity, 133 btScalar timeInterval); 134 135 void reset (); 136 void warp (const btVector3& origin); 137 138 void preStep ( btCollisionWorld* collisionWorld); 139 void playerStep ( btCollisionWorld* collisionWorld, btScalar dt); 140 141 void setFallSpeed (btScalar fallSpeed); 142 void setJumpSpeed (btScalar jumpSpeed); 143 void setMaxJumpHeight (btScalar maxJumpHeight); 144 bool canJump () const; 145 146 void jump (); 147 148 void setGravity(btScalar gravity); 149 btScalar getGravity() const; 150 151 /// The max slope determines the maximum angle that the controller can walk up. 152 /// The slope angle is measured in radians. 153 void setMaxSlope(btScalar slopeRadians); 154 btScalar getMaxSlope() const; 155 156 btPairCachingGhostObject* getGhostObject(); 157 void setUseGhostSweepTest(bool useGhostObjectSweepTest) 158 { 159 m_useGhostObjectSweepTest = useGhostObjectSweepTest; 160 } 161 162 bool onGround () const; 220 vec3 m_current_position; 221 float m_current_step_offset; 222 vec3 m_target_position; 223 224 vec3 m_touching_normal; 225 bool m_touching_contact; 226 227 bool m_was_on_ground; 228 bool m_was_jumping; 229 bool m_do_gobject_sweep_test; 230 bool m_use_walk_direction; 231 int m_up_axis; 163 232 }; 164 233 165 234 #endif // HAVE_PHYS_USE_BULLET 166 #endif // 0235 #endif // USE_LOL_CTRLR_CHARAC 167 236 168 237 } /* namespace phys */ -
trunk/test/Physics/Include/EasyCharacterController.h
r1795 r1819 24 24 #include "core.h" 25 25 #include "EasyPhysics.h" 26 #include "BulletCharacterController.h" 26 27 #include <BulletDynamics/Character/btKinematicCharacterController.h> 27 28 #endif … … 83 84 84 85 btPairCachingGhostObject* m_pair_caching_object; 85 btKinematicCharacterController* m_character; 86 //btKinematicCharacterController* m_character; 87 BulletKinematicCharacterController* m_character; 86 88 87 89 float m_step_height; -
trunk/test/Physics/Include/EasyPhysics.h
r1782 r1819 23 23 #include <bullet/btBulletCollisionCommon.h> 24 24 #include <bullet/BulletCollision/CollisionDispatch/btGhostObject.h> 25 #endif 25 #endif //HAVE_PHYS_USE_BULLET 26 26 27 27 namespace lol … … 157 157 158 158 //Base/Attachment logic 159 Array<EasyPhysic*> m_based_physic_list; //List of objects based on this : this object moves, its based object movewith it.159 Array<EasyPhysic*> m_based_physic_list; //List of objects based on this : this object moves, its based object MoveStep with it. 160 160 EasyPhysic* m_base_physic; //Base for this object : The base moves, the object moves with it. 161 161 bool m_base_lock_location; //when this is TRUE, location moves with rotation change. -
trunk/test/Physics/Include/LolPhysics.h
r1782 r1819 119 119 } 120 120 121 //R eap-Off of the btKinematicClosestNotMeRayResultCallback122 class LolClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback121 //Rip-Off of the btKinematicClosestNotMeRayResultCallback 122 class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback 123 123 { 124 124 public: 125 LolClosestNotMeRayResultCallback(btCollisionObject* Me, const btVector3& rayFromWorld, const btVector3& rayToWorld) :125 ClosestNotMeRayResultCallback(btCollisionObject* Me, const btVector3& rayFromWorld, const btVector3& rayToWorld) : 126 126 btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld) 127 127 { … … 169 169 { 170 170 if (SourceCaster) 171 BtRayResult_Closest = new LolClosestNotMeRayResultCallback(SourceCaster->m_collision_object, LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo));171 BtRayResult_Closest = new ClosestNotMeRayResultCallback(SourceCaster->m_collision_object, LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo)); 172 172 else 173 173 BtRayResult_Closest = new btCollisionWorld::ClosestRayResultCallback(LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo)); -
trunk/test/Physics/Src/BulletCharacterController.cpp
r1802 r1819 15 15 #endif 16 16 17 #define USE_LOL_CTRLR_CHARAC 18 19 #ifdef HAVE_PHYS_USE_BULLET 20 #include "core.h" 21 #include <stdio.h> 17 22 #include "../Include/LolBtPhysicsIntegration.h" 18 23 #include "../Include/LolPhysics.h" … … 26 31 //#include "BulletCollision/CollisionDispatch/btCollisionWorld.h" 27 32 //#include "LinearMath/btDefaultMotionState.h" 33 #endif //HAVE_PHYS_USE_BULLET 28 34 29 35 … … 31 37 { 32 38 33 34 35 36 #if 039 namespace phys 40 { 41 42 #ifdef USE_LOL_CTRLR_CHARAC 37 43 #ifdef HAVE_PHYS_USE_BULLET 38 44 39 // static helper method 40 static btVector3 41 getNormalizedVector(const btVector3& v) 42 { 43 btVector3 n = v.normalized(); 44 if (n.length() < SIMD_EPSILON) { 45 n.setValue(0, 0, 0); 46 } 47 return n; 48 } 49 50 51 ///@todo Interact with dynamic objects, 52 ///Ride kinematicly animated platforms properly 53 ///More realistic (or maybe just a config option) falling 54 /// -> Should integrate falling velocity manually and use that in stepDown() 55 ///Support jumping 56 ///Support ducking 57 class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback 45 //SweepCallback used for Swweep Tests. 46 class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback 58 47 { 59 48 public: 60 btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) 61 { 62 m_me = me; 63 } 64 65 virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) 66 { 67 if (rayResult.m_collisionObject == m_me) 68 return 1.0; 69 70 return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace); 49 ClosestNotMeConvexResultCallback(btCollisionObject* NewMe, const vec3& NewUp, float MinSlopeDot) : 50 btCollisionWorld::ClosestConvexResultCallback(LOL2BTU_VEC3(vec3(.0f)), LOL2BTU_VEC3(vec3(.0f))), 51 m_me(NewMe), 52 m_up(NewUp), 53 m_min_slope_dot(MinSlopeDot) { } 54 55 virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& ConvexResult, bool NormalInWorld) 56 { 57 //We hit ourselves, FAIL 58 if (ConvexResult.m_hitCollisionObject == m_me) 59 return btScalar(1.f); 60 61 vec3 WorldHitNomal(.0f); 62 if (NormalInWorld) 63 WorldHitNomal = BT2LOL_VEC3(ConvexResult.m_hitNormalLocal); 64 else //need to transform Normal into worldspace 65 { 66 btVector3 TmpWorldHitNormal = ConvexResult.m_hitCollisionObject->getWorldTransform().getBasis() * ConvexResult.m_hitNormalLocal; 67 WorldHitNomal = BT2LOL_VEC3(TmpWorldHitNormal); 68 } 69 70 float DotUp = dot(m_up, WorldHitNomal); 71 //We hit below the accepted slope_dot, FAIL 72 if (DotUp < m_min_slope_dot) 73 return btScalar(1.f); 74 75 //Continue to next. 76 return ClosestConvexResultCallback::addSingleResult(ConvexResult, NormalInWorld); 71 77 } 72 78 protected: 73 btCollisionObject* m_me; 79 btCollisionObject* m_me; 80 const vec3 m_up; 81 float m_min_slope_dot; 74 82 }; 75 83 76 class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback 77 { 78 public: 79 btKinematicClosestNotMeConvexResultCallback (btCollisionObject* me, const btVector3& up, btScalar minSlopeDot) 80 : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) 81 , m_me(me) 82 , m_up(up) 83 , m_minSlopeDot(minSlopeDot) 84 { 85 } 86 87 virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) 88 { 89 if (convexResult.m_hitCollisionObject == m_me) 90 return btScalar(1.0); 91 92 btVector3 hitNormalWorld; 93 if (normalInWorldSpace) 84 //When called, will try to remove Character controller from its collision. 85 bool BulletKinematicCharacterController::RecoverFromPenetration(btCollisionWorld* CollisionWorld) 86 { 87 bool HasPenetration = false; 88 89 //Retrieve all pair with us colliding. 90 CollisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghost_object->getOverlappingPairCache(), CollisionWorld->getDispatchInfo(), CollisionWorld->getDispatcher()); 91 m_current_position = BT2LOLU_VEC3(m_ghost_object->getWorldTransform().getOrigin()); 92 93 float MaxPen = .0f; 94 for (int i = 0; i < m_ghost_object->getOverlappingPairCache()->getNumOverlappingPairs(); i++) 95 { 96 m_manifold_array.resize(0); 97 98 //this is the equivalent of the "Touch algorithm". Maybe refactor ? 99 btBroadphasePair* CollisionPair = &m_ghost_object->getOverlappingPairCache()->getOverlappingPairArray()[i]; 100 if (CollisionPair->m_algorithm) 101 CollisionPair->m_algorithm->getAllContactManifolds(m_manifold_array); 102 103 for (int j = 0; j < m_manifold_array.size(); ++j) 94 104 { 95 hitNormalWorld = convexResult.m_hitNormalLocal; 96 } else 97 { 98 ///need to transform normal into worldspace 99 hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal; 100 } 101 102 btScalar dotUp = m_up.dot(hitNormalWorld); 103 if (dotUp < m_minSlopeDot) { 104 return btScalar(1.0); 105 } 106 107 return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace); 108 } 109 protected: 110 btCollisionObject* m_me; 111 const btVector3 m_up; 112 btScalar m_minSlopeDot; 113 }; 114 115 /* 116 * Returns the reflection direction of a ray going 'direction' hitting a surface with normal 'normal' 117 * 118 * from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html 119 */ 120 btVector3 BulletKinematicCharacterController::computeReflectionDirection (const btVector3& direction, const btVector3& normal) 121 { 122 return direction - (btScalar(2.0) * direction.dot(normal)) * normal; 123 } 124 125 /* 126 * Returns the portion of 'direction' that is parallel to 'normal' 127 */ 128 btVector3 BulletKinematicCharacterController::parallelComponent (const btVector3& direction, const btVector3& normal) 129 { 130 btScalar magnitude = direction.dot(normal); 131 return normal * magnitude; 132 } 133 134 /* 135 * Returns the portion of 'direction' that is perpindicular to 'normal' 136 */ 137 btVector3 BulletKinematicCharacterController::perpindicularComponent (const btVector3& direction, const btVector3& normal) 138 { 139 return direction - parallelComponent(direction, normal); 140 } 141 142 BulletKinematicCharacterController::BulletKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, int upAxis) 143 { 144 m_upAxis = upAxis; 145 m_addedMargin = 0.02; 146 m_walkDirection.setValue(0,0,0); 147 m_useGhostObjectSweepTest = true; 148 m_ghostObject = ghostObject; 149 m_stepHeight = stepHeight; 150 m_turnAngle = btScalar(0.0); 151 m_convexShape=convexShape; 152 m_useWalkDirection = true; // use walk direction by default, legacy behavior 153 m_velocityTimeInterval = 0.0; 154 m_verticalVelocity = 0.0; 155 m_verticalOffset = 0.0; 156 m_gravity = 9.8 * 3 ; // 3G acceleration. 157 m_fallSpeed = 55.0; // Terminal velocity of a sky diver in m/s. 158 m_jumpSpeed = 10.0; // ? 159 m_wasOnGround = false; 160 m_wasJumping = false; 161 setMaxSlope(btRadians(45.0)); 162 } 163 164 BulletKinematicCharacterController::~BulletKinematicCharacterController () 165 { 166 } 167 168 btPairCachingGhostObject* BulletKinematicCharacterController::getGhostObject() 169 { 170 return m_ghostObject; 171 } 172 173 bool BulletKinematicCharacterController::recoverFromPenetration ( btCollisionWorld* collisionWorld) 174 { 175 176 bool penetration = false; 177 178 collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher()); 179 180 m_currentPosition = m_ghostObject->getWorldTransform().getOrigin(); 181 182 btScalar maxPen = btScalar(0.0); 183 for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++) 184 { 185 m_manifoldArray.resize(0); 186 187 btBroadphasePair* collisionPair = &m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i]; 188 189 if (collisionPair->m_algorithm) 190 collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray); 191 192 193 for (int j=0;j<m_manifoldArray.size();j++) 194 { 195 btPersistentManifold* manifold = m_manifoldArray[j]; 196 btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0); 197 for (int p=0;p<manifold->getNumContacts();p++) 105 btPersistentManifold* CurMfold = m_manifold_array[j]; 106 //Normal direction differs if we're Body0 107 float DirSign = CurMfold->getBody0() == m_ghost_object ? -1.f : 1.f; 108 109 for (int k = 0; k < CurMfold->getNumContacts(); k++) 198 110 { 199 const btManifoldPoint&pt = manifold->getContactPoint(p); 200 201 btScalar dist = pt.getDistance(); 202 203 if (dist < 0.0) 111 const btManifoldPoint& MfPoint = CurMfold->getContactPoint(k); 112 float Dist = MfPoint.getDistance(); 113 if (Dist < .0f) 204 114 { 205 if ( dist < maxPen)115 if (Dist < MaxPen) 206 116 { 207 maxPen = dist; 208 m_touchingNormal = pt.m_normalWorldOnB * directionSign;//?? 209 117 MaxPen = Dist; 118 m_touching_normal = BT2LOL_VEC3(MfPoint.m_normalWorldOnB) * DirSign; 210 119 } 211 m_currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2); 212 penetration = true; 213 } else { 214 //printf("touching %f\n", dist); 120 m_current_position += BT2LOL_VEC3(MfPoint.m_normalWorldOnB) * DirSign * Dist * .2f; 121 HasPenetration = true; 215 122 } 216 123 } 217 218 //manifold->clearManifold();219 124 } 220 125 } 221 btTransform newTrans = m_ghostObject->getWorldTransform(); 222 newTrans.setOrigin(m_currentPosition); 223 m_ghostObject->setWorldTransform(newTrans); 224 // printf("m_touchingNormal = %f,%f,%f\n",m_touchingNormal[0],m_touchingNormal[1],m_touchingNormal[2]); 225 return penetration; 226 } 227 228 void BulletKinematicCharacterController::stepUp ( btCollisionWorld* world) 126 127 btTransform GObjMx = m_ghost_object->getWorldTransform(); 128 GObjMx.setOrigin(LOL2BTU_VEC3(m_current_position)); 129 m_ghost_object->setWorldTransform(GObjMx); 130 131 return HasPenetration; 132 } 133 134 //When the Controller hits a wall, we modify the target so the controller will MoveStep along the wall. 135 void BulletKinematicCharacterController::UpdateTargetOnHit(const vec3& HitNormal, float TangentMag, float NormalMag) 136 { 137 vec3 Movedir = m_target_position - m_current_position; 138 float MoveLength = (float)length(Movedir); 139 140 if (MoveLength > SIMD_EPSILON) 141 { 142 Movedir = normalize(Movedir); 143 144 vec3 ReflectDir = normalize(GetReflectedDir(Movedir, HitNormal)); 145 vec3 ParallelDir = ProjectDirOnNorm(ReflectDir, HitNormal); 146 vec3 PerpindicularDir = ProjectDirOnNormPerpindicular(ReflectDir, HitNormal); 147 148 m_target_position = m_current_position; 149 150 if (NormalMag != .0f) 151 m_target_position += PerpindicularDir * NormalMag * MoveLength; 152 } 153 } 154 155 //Handles the Step-Up : Currently taking into account Stair step & Jump. 156 void BulletKinematicCharacterController::StepUp(btCollisionWorld* world) 229 157 { 230 158 // phase 1: up 231 btTransform start, end; 232 m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_stepHeight + (m_verticalOffset > 0.f?m_verticalOffset:0.f)); 233 234 start.setIdentity (); 235 end.setIdentity (); 236 237 /* FIXME: Handle penetration properly */ 238 start.setOrigin (m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_convexShape->getMargin() + m_addedMargin)); 239 end.setOrigin (m_targetPosition); 240 241 btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, -getUpAxisDirections()[m_upAxis], btScalar(0.7071)); 242 callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; 243 callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; 159 vec3 UpDir = GetUpAxisDirections()[m_up_axis]; 160 btTransform SweepStart, SweepEnd; 161 SweepStart.setIdentity(); 162 SweepEnd.setIdentity(); 163 164 m_target_position = m_current_position + UpDir * (m_step_height + (m_vertical_offset > 0.f ? m_vertical_offset : 0.f)); 165 166 /* FIXME: Handle HasPenetration properly */ 167 SweepStart.setOrigin(LOL2BTU_VEC3(m_current_position + UpDir * (m_convex_shape->getMargin() + m_added_margin))); 168 SweepEnd.setOrigin(LOL2BTU_VEC3(m_target_position)); 169 170 ClosestNotMeConvexResultCallback SweepCallback(m_ghost_object, -UpDir, float(0.7071)); 171 SweepCallback.m_collisionFilterGroup = GetGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; 172 SweepCallback.m_collisionFilterMask = GetGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; 244 173 245 if (m_useGhostObjectSweepTest) 246 { 247 m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration); 248 } 174 if (m_do_gobject_sweep_test) 175 m_ghost_object->convexSweepTest(m_convex_shape, SweepStart, SweepEnd, SweepCallback, world->getDispatchInfo().m_allowedCcdPenetration); 249 176 else 250 { 251 world->convexSweepTest (m_convexShape, start, end, callback); 252 } 177 world->convexSweepTest(m_convex_shape, SweepStart, SweepEnd, SweepCallback); 253 178 254 if ( callback.hasHit())179 if (SweepCallback.hasHit()) 255 180 { 256 181 // Only modify the position if the hit was a slope and not a wall or ceiling. 257 if( callback.m_hitNormalWorld.dot(getUpAxisDirections()[m_upAxis]) > 0.0)182 if(SweepCallback.m_hitNormalWorld.dot(LOL2BTU_VEC3(UpDir)) > .0f) 258 183 { 259 // we moved up only a fraction of the step height 260 m_currentStepOffset = m_stepHeight * callback.m_closestHitFraction; 261 m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); 184 // we moved up only a Fraction of the step height 185 m_current_step_offset = m_step_height * SweepCallback.m_closestHitFraction; 186 btVector3 InterpolPos; //TODO : REPLACE BY INTERPOLATE3/LERP(VEC3) 187 InterpolPos.setInterpolate3(LOL2BTU_VEC3(m_current_position), LOL2BTU_VEC3(m_target_position), SweepCallback.m_closestHitFraction); 188 m_current_position = BT2LOLU_VEC3(InterpolPos); 262 189 } 263 m_verticalVelocity = 0.0; 264 m_verticalOffset = 0.0; 265 } else { 266 m_currentStepOffset = m_stepHeight; 267 m_currentPosition = m_targetPosition; 268 } 269 } 270 271 void BulletKinematicCharacterController::updateTargetPositionBasedOnCollision (const btVector3& hitNormal, btScalar tangentMag, btScalar normalMag) 272 { 273 btVector3 movementDirection = m_targetPosition - m_currentPosition; 274 btScalar movementLength = movementDirection.length(); 275 if (movementLength>SIMD_EPSILON) 276 { 277 movementDirection.normalize(); 278 279 btVector3 reflectDir = computeReflectionDirection (movementDirection, hitNormal); 280 reflectDir.normalize(); 281 282 btVector3 parallelDir, perpindicularDir; 283 284 parallelDir = parallelComponent (reflectDir, hitNormal); 285 perpindicularDir = perpindicularComponent (reflectDir, hitNormal); 286 287 m_targetPosition = m_currentPosition; 288 if (0)//tangentMag != 0.0) 289 { 290 btVector3 parComponent = parallelDir * btScalar (tangentMag*movementLength); 291 // printf("parComponent=%f,%f,%f\n",parComponent[0],parComponent[1],parComponent[2]); 292 m_targetPosition += parComponent; 190 m_vertical_velocity = .0f; 191 m_vertical_offset = .0f; 192 } 193 else 194 { 195 m_current_step_offset = m_step_height; 196 m_current_position = m_target_position; 197 } 198 } 199 200 //Handles the actual Movement. It actually moves in the 3 dimensions, function name is confusing. 201 void BulletKinematicCharacterController::StepForwardAndStrafe(btCollisionWorld* CollisionWorld, const vec3& MoveStep) 202 { 203 // phase 2: forward and strafe 204 m_target_position = m_current_position + MoveStep; 205 btTransform SweepStart, SweepEnd; 206 SweepStart.setIdentity(); 207 SweepEnd.setIdentity(); 208 209 float Fraction = 1.f; 210 float SqDist = .0f; 211 212 if (m_touching_contact && dot(m_normalized_direction, m_touching_normal) > .0f) 213 UpdateTargetOnHit(m_touching_normal); 214 215 //Let's loop on movement, until Movement fraction if below 0.01, which means we've reached our destination. 216 //Or until we'tried 10 times. 217 int MaxMoveLoop = 10; 218 while (Fraction > .01f && MaxMoveLoop-- > 0) 219 { 220 SweepStart.setOrigin(LOL2BTU_VEC3(m_current_position)); 221 SweepEnd.setOrigin(LOL2BTU_VEC3(m_target_position)); 222 vec3 SweepDirNeg(m_current_position - m_target_position); 223 224 ClosestNotMeConvexResultCallback SweepCallback(m_ghost_object, SweepDirNeg, .0f); 225 SweepCallback.m_collisionFilterGroup = GetGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; 226 SweepCallback.m_collisionFilterMask = GetGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; 227 228 //The sweep test is done with an added margin, so we use it and then discard it 229 float SavedMargin = m_convex_shape->getMargin(); 230 m_convex_shape->setMargin(SavedMargin + m_added_margin); //Apply Added Margin 231 if (m_do_gobject_sweep_test) 232 m_ghost_object->convexSweepTest (m_convex_shape, SweepStart, SweepEnd, SweepCallback, CollisionWorld->getDispatchInfo().m_allowedCcdPenetration); 233 else 234 CollisionWorld->convexSweepTest (m_convex_shape, SweepStart, SweepEnd, SweepCallback, CollisionWorld->getDispatchInfo().m_allowedCcdPenetration); 235 m_convex_shape->setMargin(SavedMargin); //Restore saved margin 236 237 Fraction -= SweepCallback.m_closestHitFraction; 238 239 if (SweepCallback.hasHit()) 240 { 241 //We moved only a Fraction 242 float HitDist = (float)length(BT2LOLU_VEC3(SweepCallback.m_hitPointWorld) - m_current_position); 243 244 UpdateTargetOnHit(BT2LOL_VEC3(SweepCallback.m_hitNormalWorld)); 245 vec3 NewDir = m_target_position - m_current_position; 246 SqDist = sqlength(NewDir); 247 if (SqDist > SIMD_EPSILON) 248 { 249 NewDir = normalize(NewDir); 250 //See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." 251 if (dot(NewDir, m_normalized_direction) <= .0f) 252 break; 253 } 254 else 255 break; 293 256 } 294 295 if (normalMag != 0.0) 296 { 297 btVector3 perpComponent = perpindicularDir * btScalar (normalMag*movementLength); 298 // printf("perpComponent=%f,%f,%f\n",perpComponent[0],perpComponent[1],perpComponent[2]); 299 m_targetPosition += perpComponent; 300 } 301 } else 302 { 303 // printf("movementLength don't normalize a zero vector\n"); 304 } 305 } 306 307 void BulletKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* collisionWorld, const btVector3& walkMove) 308 { 309 // printf("m_normalizedDirection=%f,%f,%f\n", 310 // m_normalizedDirection[0],m_normalizedDirection[1],m_normalizedDirection[2]); 311 // phase 2: forward and strafe 312 btTransform start, end; 313 m_targetPosition = m_currentPosition + walkMove; 314 315 start.setIdentity (); 316 end.setIdentity (); 257 else //We moved whole way 258 m_current_position = m_target_position; 259 } 260 } 261 262 //Handles the Step-down : We go back on the ground at the end of the MoveStep. 263 void BulletKinematicCharacterController::StepDown(btCollisionWorld* CollisionWorld, float DeltaTime) 264 { 265 // phase 3: down 266 vec3 UpDir = GetUpAxisDirections()[m_up_axis]; 267 btTransform SweepStart, SweepEnd; 268 SweepStart.setIdentity(); 269 SweepEnd.setIdentity(); 270 271 float DownVel = (m_vertical_velocity < 0.f ? -m_vertical_velocity : 0.f) * DeltaTime; 272 if (DownVel > .0f && DownVel < m_step_height && (m_was_on_ground || !m_was_jumping)) 273 DownVel = m_step_height; 274 275 vec3 StepDrop = UpDir * (m_current_step_offset + DownVel); 276 m_target_position -= StepDrop; 277 278 SweepStart.setOrigin(LOL2BTU_VEC3(m_current_position)); 279 SweepEnd.setOrigin(LOL2BTU_VEC3(m_target_position)); 280 281 ClosestNotMeConvexResultCallback SweepCallback(m_ghost_object, UpDir, m_max_slope_cosine); 282 SweepCallback.m_collisionFilterGroup = GetGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; 283 SweepCallback.m_collisionFilterMask = GetGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; 317 284 318 btScalar fraction = 1.0; 319 btScalar distance2 = (m_currentPosition-m_targetPosition).length2(); 320 // printf("distance2=%f\n",distance2); 321 322 if (m_touchingContact) 323 { 324 if (m_normalizedDirection.dot(m_touchingNormal) > btScalar(0.0)) 325 { 326 updateTargetPositionBasedOnCollision (m_touchingNormal); 327 } 328 } 329 330 int maxIter = 10; 331 332 while (fraction > btScalar(0.01) && maxIter-- > 0) 333 { 334 start.setOrigin (m_currentPosition); 335 end.setOrigin (m_targetPosition); 336 btVector3 sweepDirNegative(m_currentPosition - m_targetPosition); 337 338 btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, sweepDirNegative, btScalar(0.0)); 339 callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; 340 callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; 341 342 343 btScalar margin = m_convexShape->getMargin(); 344 m_convexShape->setMargin(margin + m_addedMargin); 345 346 347 if (m_useGhostObjectSweepTest) 348 { 349 m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); 350 } else 351 { 352 collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); 353 } 354 355 m_convexShape->setMargin(margin); 356 357 358 fraction -= callback.m_closestHitFraction; 359 360 if (callback.hasHit()) 361 { 362 // we moved only a fraction 363 btScalar hitDistance; 364 hitDistance = (callback.m_hitPointWorld - m_currentPosition).length(); 365 366 // m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); 367 368 updateTargetPositionBasedOnCollision (callback.m_hitNormalWorld); 369 btVector3 currentDir = m_targetPosition - m_currentPosition; 370 distance2 = currentDir.length2(); 371 if (distance2 > SIMD_EPSILON) 372 { 373 currentDir.normalize(); 374 /* See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." */ 375 if (currentDir.dot(m_normalizedDirection) <= btScalar(0.0)) 376 { 377 break; 378 } 379 } else 380 { 381 // printf("currentDir: don't normalize a zero vector\n"); 382 break; 383 } 384 385 } else { 386 // we moved whole way 387 m_currentPosition = m_targetPosition; 388 } 389 390 // if (callback.m_closestHitFraction == 0.f) 391 // break; 392 393 } 394 } 395 396 void BulletKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld, btScalar dt) 397 { 398 btTransform start, end; 399 400 // phase 3: down 401 /*btScalar additionalDownStep = (m_wasOnGround && !onGround()) ? m_stepHeight : 0.0; 402 btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + additionalDownStep); 403 btScalar downVelocity = (additionalDownStep == 0.0 && m_verticalVelocity<0.0?-m_verticalVelocity:0.0) * dt; 404 btVector3 gravity_drop = getUpAxisDirections()[m_upAxis] * downVelocity; 405 m_targetPosition -= (step_drop + gravity_drop);*/ 406 407 btScalar downVelocity = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt; 408 if(downVelocity > 0.0 && downVelocity < m_stepHeight 409 && (m_wasOnGround || !m_wasJumping)) 410 { 411 downVelocity = m_stepHeight; 412 } 413 414 btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity); 415 m_targetPosition -= step_drop; 416 417 start.setIdentity (); 418 end.setIdentity (); 419 420 start.setOrigin (m_currentPosition); 421 end.setOrigin (m_targetPosition); 422 423 btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine); 424 callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; 425 callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; 426 427 if (m_useGhostObjectSweepTest) 428 { 429 m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); 430 } else 431 { 432 collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); 433 } 434 435 if (callback.hasHit()) 436 { 437 // we dropped a fraction of the height -> hit floor 438 m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); 439 m_verticalVelocity = 0.0; 440 m_verticalOffset = 0.0; 441 m_wasJumping = false; 442 } else { 443 // we dropped the full height 444 445 m_currentPosition = m_targetPosition; 446 } 447 } 448 449 450 451 void BulletKinematicCharacterController::setWalkDirection 452 ( 453 const btVector3& walkDirection 454 ) 455 { 456 m_useWalkDirection = true; 457 m_walkDirection = walkDirection; 458 m_normalizedDirection = getNormalizedVector(m_walkDirection); 459 } 460 461 462 463 void BulletKinematicCharacterController::setVelocityForTimeInterval 464 ( 465 const btVector3& velocity, 466 btScalar timeInterval 467 ) 468 { 469 // printf("setVelocity!\n"); 470 // printf(" interval: %f\n", timeInterval); 471 // printf(" velocity: (%f, %f, %f)\n", 472 // velocity.x(), velocity.y(), velocity.z()); 473 474 m_useWalkDirection = false; 475 m_walkDirection = velocity; 476 m_normalizedDirection = getNormalizedVector(m_walkDirection); 477 m_velocityTimeInterval = timeInterval; 478 } 479 480 481 482 void BulletKinematicCharacterController::reset () 483 { 484 } 485 486 void BulletKinematicCharacterController::warp (const btVector3& origin) 487 { 488 btTransform xform; 489 xform.setIdentity(); 490 xform.setOrigin (origin); 491 m_ghostObject->setWorldTransform (xform); 492 } 493 494 495 void BulletKinematicCharacterController::preStep ( btCollisionWorld* collisionWorld) 496 { 497 498 int numPenetrationLoops = 0; 499 m_touchingContact = false; 500 while (recoverFromPenetration (collisionWorld)) 501 { 502 numPenetrationLoops++; 503 m_touchingContact = true; 504 if (numPenetrationLoops > 4) 505 { 506 //printf("character could not recover from penetration = %d\n", numPenetrationLoops); 285 if (m_do_gobject_sweep_test) 286 m_ghost_object->convexSweepTest(m_convex_shape, SweepStart, SweepEnd, SweepCallback, CollisionWorld->getDispatchInfo().m_allowedCcdPenetration); 287 else 288 CollisionWorld->convexSweepTest(m_convex_shape, SweepStart, SweepEnd, SweepCallback, CollisionWorld->getDispatchInfo().m_allowedCcdPenetration); 289 290 if (SweepCallback.hasHit()) 291 { 292 // we dropped a Fraction of the height -> hit floor 293 btVector3 InterpolPos; //TODO : REPLACE BY INTERPOLATE3/LERP(VEC3) 294 InterpolPos.setInterpolate3(LOL2BTU_VEC3(m_current_position), LOL2BTU_VEC3(m_target_position), SweepCallback.m_closestHitFraction); 295 m_current_position = BT2LOLU_VEC3(InterpolPos); 296 m_vertical_velocity = .0f; 297 m_vertical_offset = .0f; 298 m_was_jumping = false; 299 } 300 else // we dropped the full height 301 m_current_position = m_target_position; 302 } 303 304 //The PreStepis done in order to recover from any HasPenetration. 305 void BulletKinematicCharacterController::PreStep(btCollisionWorld* CollisionWorld) 306 { 307 int MaxPenetrationLoop = 0; 308 m_touching_contact = false; 309 310 while (RecoverFromPenetration(CollisionWorld)) 311 { 312 MaxPenetrationLoop++; 313 m_touching_contact = true; 314 if (MaxPenetrationLoop > 4) 507 315 break; 508 } 509 } 510 511 m_currentPosition = m_ghostObject->getWorldTransform().getOrigin(); 512 m_targetPosition = m_currentPosition; 513 // printf("m_targetPosition=%f,%f,%f\n",m_targetPosition[0],m_targetPosition[1],m_targetPosition[2]); 514 515 516 } 517 518 #include <stdio.h> 519 520 void BulletKinematicCharacterController::playerStep ( btCollisionWorld* collisionWorld, btScalar dt) 521 { 522 // printf("playerStep(): "); 523 // printf(" dt = %f", dt); 524 316 } 317 318 m_current_position = BT2LOLU_VEC3(m_ghost_object->getWorldTransform().getOrigin()); 319 m_target_position = m_current_position; 320 } 321 322 //And so we step : 323 //StepUpfirst, then movement, then StepDownon the ground. 324 void BulletKinematicCharacterController::PlayerStep(btCollisionWorld* CollisionWorld, float DeltaTime) 325 { 525 326 // quick check... 526 if (!m_useWalkDirection && m_velocityTimeInterval <= 0.0) { 527 // printf("\n"); 327 if (!m_use_walk_direction && m_velocity_time_interval <= .0f) 528 328 return; // no motion 529 } 530 531 m_wasOnGround = onGround(); 329 330 m_was_on_ground = OnGround(); 532 331 533 332 // Update fall velocity. 534 m_verticalVelocity -= m_gravity * dt; 535 if(m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed) 536 { 537 m_verticalVelocity = m_jumpSpeed; 538 } 539 if(m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed)) 540 { 541 m_verticalVelocity = -btFabs(m_fallSpeed); 542 } 543 m_verticalOffset = m_verticalVelocity * dt; 544 545 546 btTransform xform; 547 xform = m_ghostObject->getWorldTransform (); 548 549 // printf("walkDirection(%f,%f,%f)\n",walkDirection[0],walkDirection[1],walkDirection[2]); 550 // printf("walkSpeed=%f\n",walkSpeed); 551 552 stepUp (collisionWorld); 553 if (m_useWalkDirection) { 554 stepForwardAndStrafe (collisionWorld, m_walkDirection); 555 } else { 556 //printf(" time: %f", m_velocityTimeInterval); 557 // still have some time left for moving! 558 btScalar dtMoving = 559 (dt < m_velocityTimeInterval) ? dt : m_velocityTimeInterval; 560 m_velocityTimeInterval -= dt; 561 562 // how far will we move while we are moving? 563 btVector3 move = m_walkDirection * dtMoving; 564 565 //printf(" dtMoving: %f", dtMoving); 566 567 // okay, step 568 stepForwardAndStrafe(collisionWorld, move); 569 } 570 stepDown (collisionWorld, dt); 571 572 // printf("\n"); 573 574 xform.setOrigin (m_currentPosition); 575 m_ghostObject->setWorldTransform (xform); 576 } 577 578 void BulletKinematicCharacterController::setFallSpeed (btScalar fallSpeed) 579 { 580 m_fallSpeed = fallSpeed; 581 } 582 583 void BulletKinematicCharacterController::setJumpSpeed (btScalar jumpSpeed) 584 { 585 m_jumpSpeed = jumpSpeed; 586 } 587 588 void BulletKinematicCharacterController::setMaxJumpHeight (btScalar maxJumpHeight) 589 { 590 m_maxJumpHeight = maxJumpHeight; 591 } 592 593 bool BulletKinematicCharacterController::canJump () const 594 { 595 return onGround(); 596 } 597 598 void BulletKinematicCharacterController::jump () 599 { 600 if (!canJump()) 333 m_vertical_velocity -= m_gravity * DeltaTime; 334 if(m_vertical_velocity > .0f && m_vertical_velocity > m_jump_speed) 335 m_vertical_velocity = m_jump_speed; 336 337 if(m_vertical_velocity < .0f && btFabs(m_vertical_velocity) > btFabs(m_fall_speed)) 338 m_vertical_velocity = -btFabs(m_fall_speed); 339 m_vertical_offset = m_vertical_velocity * DeltaTime; 340 341 btTransform NewTransform; 342 NewTransform = m_ghost_object->getWorldTransform(); 343 344 vec3 MoveStep(.0f); 345 if (m_use_walk_direction) 346 MoveStep = m_walk_direction; 347 else 348 { 349 //Still have some time left for moving! 350 float dtMoving = (DeltaTime < m_velocity_time_interval) ? DeltaTime : m_velocity_time_interval; 351 m_velocity_time_interval -= DeltaTime; 352 353 // how far will we MoveStep while we are moving? 354 MoveStep = m_walk_direction * dtMoving; 355 } 356 357 //Okay, step ! 358 StepUp(CollisionWorld); 359 StepForwardAndStrafe(CollisionWorld, MoveStep); 360 StepDown(CollisionWorld, DeltaTime); 361 362 //Movement finished, update World transform 363 NewTransform.setOrigin(LOL2BTU_VEC3(m_current_position)); 364 m_ghost_object->setWorldTransform(NewTransform); 365 } 366 367 //should MoveStep Jump logic in EasyCC 368 void BulletKinematicCharacterController::Jump() 369 { 370 if (!CanJump()) 601 371 return; 602 372 603 m_verticalVelocity = m_jumpSpeed; 604 m_wasJumping = true; 605 606 #if 0 607 currently no jumping. 608 btTransform xform; 609 m_rigidBody->getMotionState()->getWorldTransform (xform); 610 btVector3 up = xform.getBasis()[1]; 611 up.normalize (); 612 btScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0); 613 m_rigidBody->applyCentralImpulse (up * magnitude); 614 #endif 615 } 616 617 void BulletKinematicCharacterController::setGravity(btScalar gravity) 618 { 619 m_gravity = gravity; 620 } 621 622 btScalar BulletKinematicCharacterController::getGravity() const 623 { 624 return m_gravity; 625 } 626 627 void BulletKinematicCharacterController::setMaxSlope(btScalar slopeRadians) 628 { 629 m_maxSlopeRadians = slopeRadians; 630 m_maxSlopeCosine = btCos(slopeRadians); 631 } 632 633 btScalar BulletKinematicCharacterController::getMaxSlope() const 634 { 635 return m_maxSlopeRadians; 636 } 637 638 bool BulletKinematicCharacterController::onGround () const 639 { 640 return m_verticalVelocity == 0.0 && m_verticalOffset == 0.0; 641 } 642 643 644 btVector3* BulletKinematicCharacterController::getUpAxisDirections() 645 { 646 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) }; 647 648 return sUpAxisDirection; 649 } 650 651 void BulletKinematicCharacterController::debugDraw(btIDebugDraw* debugDrawer) 652 { 653 } 654 373 m_vertical_velocity = m_jump_speed; 374 m_was_jumping = true; 375 } 655 376 656 377 #endif // HAVE_PHYS_USE_BULLET 657 #endif // 0378 #endif // USE_LOL_CTRLR_CHARAC 658 379 659 380 } /* namespace phys */ -
trunk/test/Physics/Src/EasyCharacterController.cpp
r1795 r1819 62 62 delete m_character; 63 63 64 m_character = new btKinematicCharacterController(m_pair_caching_object, m_convex_shape, m_step_height, m_up_axis); 64 //m_character = new btKinematicCharacterController(m_pair_caching_object, m_convex_shape, m_step_height, m_up_axis); 65 m_character = new BulletKinematicCharacterController(m_pair_caching_object, m_convex_shape, m_step_height, m_up_axis); 65 66 66 67 //Deactivate Character controller basic behaviour. … … 93 94 void EasyCharacterController::Jump() 94 95 { 95 m_character-> jump();96 m_character->Jump(); 96 97 } 97 98 … … 141 142 int IterationsNb = (int)(seconds / m_owner_simulation->m_timestep); 142 143 float NewSeconds = IterationsNb * m_owner_simulation->m_timestep; 143 m_character-> setVelocityForTimeInterval(LOL2BT_VEC3(LOL2BT_UNIT * (m_base_cached_movement + m_frame_cached_movement)) / NewSeconds, NewSeconds);144 m_character->SetVelocityForTimeInterval((m_base_cached_movement + m_frame_cached_movement) / NewSeconds, NewSeconds); 144 145 m_base_cached_movement = vec3(.0f); 145 146 }
Note: See TracChangeset
for help on using the changeset viewer.