BGE patch #28476: Character object physics type

===============================================
This patch adds a new "Character" BGE physics type which uses Bullet's btKinematicCharacter for simulation instead of full-blown dynamics. It is appropiate for (player-controlled) characters, for which the other physics types often result unexpected results (bouncing off walls, sliding etc.) and for which simple kinematics offers much more precision.

"Character" can be chosen like any other physics type in the "Physics" section of the properties window. Current settings for tweaking are "Step Height" (to make the object automatically climb small steps if it collides with them), "Fall Speed" (the maximum speed that the object can have when falling) and "Jump Speed", which is currently not used.

See http://projects.blender.org/tracker/?func=detail&atid=127&aid=28476&group_id=9
for sample blends and a discussion on the patch: how to use it and what influences the behavior of the character object.

Known problem: there is a crash if the "compound" option is set in the physics panel of the Character object.
This commit is contained in:
2012-05-28 21:36:29 +00:00
parent 4e0492e3bc
commit dfc19a1ff7
21 changed files with 168 additions and 29 deletions

View File

@@ -118,6 +118,7 @@ set(SRC
src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp
src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp
src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp
src/BulletDynamics/Character/btKinematicCharacterController.cpp
src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp
src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp
src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp
@@ -154,7 +155,6 @@ set(SRC
# src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp # src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp
# src/BulletCollision/CollisionShapes/btBox2dShape.cpp # src/BulletCollision/CollisionShapes/btBox2dShape.cpp
# src/BulletCollision/CollisionShapes/btConvex2dShape.cpp # src/BulletCollision/CollisionShapes/btConvex2dShape.cpp
# src/BulletDynamics/Character/btKinematicCharacterController.cpp
# src/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp # src/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp
# src/BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp # src/BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp
@@ -274,6 +274,7 @@ set(SRC
src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h
src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h
src/BulletDynamics/Character/btCharacterControllerInterface.h src/BulletDynamics/Character/btCharacterControllerInterface.h
src/BulletDynamics/Character/btKinematicCharacterController.h
src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h
src/BulletDynamics/ConstraintSolver/btConstraintSolver.h src/BulletDynamics/ConstraintSolver/btConstraintSolver.h
src/BulletDynamics/ConstraintSolver/btContactConstraint.h src/BulletDynamics/ConstraintSolver/btContactConstraint.h
@@ -343,7 +344,6 @@ set(SRC
# src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h # src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h
# src/BulletCollision/CollisionShapes/btBox2dShape.h # src/BulletCollision/CollisionShapes/btBox2dShape.h
# src/BulletCollision/CollisionShapes/btConvex2dShape.h # src/BulletCollision/CollisionShapes/btConvex2dShape.h
# src/BulletDynamics/Character/btKinematicCharacterController.h
# src/BulletDynamics/ConstraintSolver/btHinge2Constraint.h # src/BulletDynamics/ConstraintSolver/btHinge2Constraint.h
# src/BulletDynamics/ConstraintSolver/btUniversalConstraint.h # src/BulletDynamics/ConstraintSolver/btUniversalConstraint.h
) )

View File

@@ -339,7 +339,7 @@ public:
///***************************************** expert/internal use only ************************* ///***************************************** expert/internal use only *************************
void setQuantizationValues(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,btScalar quantizationMargin=btScalar(1.0)); void setQuantizationValues(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,btScalar quantizationMargin=btScalar(1.5));
QuantizedNodeArray& getLeafNodeArray() { return m_quantizedLeafNodes; } QuantizedNodeArray& getLeafNodeArray() { return m_quantizedLeafNodes; }
///buildInternal is expert use only: assumes that setQuantizationValues and LeafNodeArray are initialized ///buildInternal is expert use only: assumes that setQuantizationValues and LeafNodeArray are initialized
void buildInternal(); void buildInternal();

View File

@@ -84,7 +84,7 @@ public:
} else } else
{ {
///need to transform normal into worldspace ///need to transform normal into worldspace
hitNormalWorld = m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal; hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
} }
btScalar dotUp = m_up.dot(hitNormalWorld); btScalar dotUp = m_up.dot(hitNormalWorld);

View File

@@ -23,7 +23,7 @@ elif sys.platform=='darwin':
linearmath_src = env.Glob("LinearMath/*.cpp") linearmath_src = env.Glob("LinearMath/*.cpp")
bulletdyn_src = env.Glob("BulletDynamics/Vehicle/*.cpp") + env.Glob("BulletDynamics/ConstraintSolver/*.cpp") + env.Glob("BulletDynamics/Dynamics/*.cpp") bulletdyn_src = env.Glob("BulletDynamics/Vehicle/*.cpp") + env.Glob("BulletDynamics/ConstraintSolver/*.cpp") + env.Glob("BulletDynamics/Dynamics/*.cpp") + env.Glob("BulletDynamics/Character/*.cpp")
collision_broadphase_src = env.Glob("BulletCollision/BroadphaseCollision/*.cpp") collision_broadphase_src = env.Glob("BulletCollision/BroadphaseCollision/*.cpp")
collision_dispatch_src = env.Glob("BulletCollision/CollisionDispatch/*.cpp") collision_dispatch_src = env.Glob("BulletCollision/CollisionDispatch/*.cpp")

View File

@@ -49,7 +49,12 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel):
physics_type = game.physics_type physics_type = game.physics_type
if physics_type in {'DYNAMIC', 'RIGID_BODY'}: if physics_type == 'CHARACTER':
layout.prop(game, "step_height", slider=True)
layout.prop(game, "jump_speed")
layout.prop(game, "fall_speed")
elif physics_type in {'DYNAMIC', 'RIGID_BODY'}:
split = layout.split() split = layout.split()
col = split.column() col = split.column()
@@ -192,7 +197,7 @@ class PHYSICS_PT_game_collision_bounds(PhysicsButtonsPanel, Panel):
def poll(cls, context): def poll(cls, context):
game = context.object.game game = context.object.game
rd = context.scene.render rd = context.scene.render
return (game.physics_type in {'DYNAMIC', 'RIGID_BODY', 'SENSOR', 'SOFT_BODY', 'STATIC'}) and (rd.engine in cls.COMPAT_ENGINES) return (game.physics_type in {'DYNAMIC', 'RIGID_BODY', 'SENSOR', 'SOFT_BODY', 'STATIC', 'CHARACTER'}) and (rd.engine in cls.COMPAT_ENGINES)
def draw_header(self, context): def draw_header(self, context):
game = context.active_object.game game = context.active_object.game

View File

@@ -835,6 +835,9 @@ Object *BKE_object_add_only_object(int type, const char *name)
/* ob->pad3 == Contact Processing Threshold */ /* ob->pad3 == Contact Processing Threshold */
ob->m_contactProcessingThreshold = 1.0f; ob->m_contactProcessingThreshold = 1.0f;
ob->obstacleRad = 1.0f; ob->obstacleRad = 1.0f;
ob->step_height = 0.15f;
ob->jump_speed = 10.0f;
ob->fall_speed = 55.0f;
/* NT fluid sim defaults */ /* NT fluid sim defaults */
ob->fluidsimSettings = NULL; ob->fluidsimSettings = NULL;

View File

@@ -204,6 +204,12 @@ typedef struct Object {
float min_vel; /* clamp the maximum velocity 0.0 is disabled */ float min_vel; /* clamp the maximum velocity 0.0 is disabled */
float m_contactProcessingThreshold; float m_contactProcessingThreshold;
float obstacleRad; float obstacleRad;
/* "Character" physics properties */
float step_height;
float jump_speed;
float fall_speed;
char pad1[4];
short rotmode; /* rotation mode - uses defines set out in DNA_action_types.h for PoseChannel rotations... */ short rotmode; /* rotation mode - uses defines set out in DNA_action_types.h for PoseChannel rotations... */
@@ -483,6 +489,7 @@ typedef struct DupliObject {
#define OB_SENSOR 0x80000 #define OB_SENSOR 0x80000
#define OB_NAVMESH 0x100000 #define OB_NAVMESH 0x100000
#define OB_HASOBSTACLE 0x200000 #define OB_HASOBSTACLE 0x200000
#define OB_CHARACTER 0x400000
/* ob->gameflag2 */ /* ob->gameflag2 */
#define OB_NEVER_DO_ACTIVITY_CULLING 1 #define OB_NEVER_DO_ACTIVITY_CULLING 1
@@ -504,6 +511,7 @@ typedef struct DupliObject {
#define OB_BODY_TYPE_OCCLUDER 5 #define OB_BODY_TYPE_OCCLUDER 5
#define OB_BODY_TYPE_SENSOR 6 #define OB_BODY_TYPE_SENSOR 6
#define OB_BODY_TYPE_NAVMESH 7 #define OB_BODY_TYPE_NAVMESH 7
#define OB_BODY_TYPE_CHARACTER 8
/* ob->scavisflag */ /* ob->scavisflag */
#define OB_VIS_SENS 1 #define OB_VIS_SENS 1

View File

@@ -891,6 +891,9 @@ static int rna_GameObjectSettings_physics_type_get(PointerRNA *ptr)
ob->body_type = OB_BODY_TYPE_NO_COLLISION; ob->body_type = OB_BODY_TYPE_NO_COLLISION;
} }
} }
else if (ob->gameflag & OB_CHARACTER) {
ob->body_type = OB_BODY_TYPE_CHARACTER;
}
else if (ob->gameflag & OB_SENSOR) { else if (ob->gameflag & OB_SENSOR) {
ob->body_type = OB_BODY_TYPE_SENSOR; ob->body_type = OB_BODY_TYPE_SENSOR;
} }
@@ -922,16 +925,16 @@ static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
switch (ob->body_type) { switch (ob->body_type) {
case OB_BODY_TYPE_SENSOR: case OB_BODY_TYPE_SENSOR:
ob->gameflag |= OB_SENSOR | OB_COLLISION | OB_GHOST; ob->gameflag |= OB_SENSOR | OB_COLLISION | OB_GHOST;
ob->gameflag &= ~(OB_OCCLUDER | OB_DYNAMIC | OB_RIGID_BODY | OB_SOFT_BODY | OB_ACTOR | ob->gameflag &= ~(OB_OCCLUDER | OB_CHARACTER | OB_DYNAMIC | OB_RIGID_BODY | OB_SOFT_BODY | OB_ACTOR |
OB_ANISOTROPIC_FRICTION | OB_DO_FH | OB_ROT_FH | OB_COLLISION_RESPONSE | OB_NAVMESH); OB_ANISOTROPIC_FRICTION | OB_DO_FH | OB_ROT_FH | OB_COLLISION_RESPONSE | OB_NAVMESH);
break; break;
case OB_BODY_TYPE_OCCLUDER: case OB_BODY_TYPE_OCCLUDER:
ob->gameflag |= OB_OCCLUDER; ob->gameflag |= OB_OCCLUDER;
ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_DYNAMIC | OB_NAVMESH); ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_CHARACTER | OB_DYNAMIC | OB_NAVMESH);
break; break;
case OB_BODY_TYPE_NAVMESH: case OB_BODY_TYPE_NAVMESH:
ob->gameflag |= OB_NAVMESH; ob->gameflag |= OB_NAVMESH;
ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_DYNAMIC | OB_OCCLUDER); ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_CHARACTER | OB_DYNAMIC | OB_OCCLUDER);
if (ob->type == OB_MESH) { if (ob->type == OB_MESH) {
/* could be moved into mesh UI but for now ensure mesh data layer */ /* could be moved into mesh UI but for now ensure mesh data layer */
@@ -940,24 +943,29 @@ static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
break; break;
case OB_BODY_TYPE_NO_COLLISION: case OB_BODY_TYPE_NO_COLLISION:
ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_OCCLUDER | OB_DYNAMIC | OB_NAVMESH); ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_CHARACTER | OB_OCCLUDER | OB_DYNAMIC | OB_NAVMESH);
break; break;
case OB_BODY_TYPE_CHARACTER:
ob->gameflag |= OB_COLLISION | OB_GHOST | OB_CHARACTER;
ob->gameflag &= ~(OB_SENSOR | OB_OCCLUDER | OB_DYNAMIC | OB_RIGID_BODY | OB_SOFT_BODY | OB_ACTOR
| OB_ANISOTROPIC_FRICTION | OB_DO_FH | OB_ROT_FH | OB_COLLISION_RESPONSE | OB_NAVMESH);
break;
case OB_BODY_TYPE_STATIC: case OB_BODY_TYPE_STATIC:
ob->gameflag |= OB_COLLISION; ob->gameflag |= OB_COLLISION;
ob->gameflag &= ~(OB_DYNAMIC | OB_RIGID_BODY | OB_SOFT_BODY | OB_OCCLUDER | OB_SENSOR | OB_NAVMESH); ob->gameflag &= ~(OB_DYNAMIC | OB_RIGID_BODY | OB_SOFT_BODY | OB_OCCLUDER | OB_CHARACTER | OB_SENSOR | OB_NAVMESH);
break; break;
case OB_BODY_TYPE_DYNAMIC: case OB_BODY_TYPE_DYNAMIC:
ob->gameflag |= OB_COLLISION | OB_DYNAMIC | OB_ACTOR; ob->gameflag |= OB_COLLISION | OB_DYNAMIC | OB_ACTOR;
ob->gameflag &= ~(OB_RIGID_BODY | OB_SOFT_BODY | OB_OCCLUDER | OB_SENSOR | OB_NAVMESH); ob->gameflag &= ~(OB_RIGID_BODY | OB_SOFT_BODY | OB_OCCLUDER | OB_CHARACTER | OB_SENSOR | OB_NAVMESH);
break; break;
case OB_BODY_TYPE_RIGID: case OB_BODY_TYPE_RIGID:
ob->gameflag |= OB_COLLISION | OB_DYNAMIC | OB_RIGID_BODY | OB_ACTOR; ob->gameflag |= OB_COLLISION | OB_DYNAMIC | OB_RIGID_BODY | OB_ACTOR;
ob->gameflag &= ~(OB_SOFT_BODY | OB_OCCLUDER | OB_SENSOR | OB_NAVMESH); ob->gameflag &= ~(OB_SOFT_BODY | OB_OCCLUDER | OB_CHARACTER | OB_SENSOR | OB_NAVMESH);
break; break;
default: default:
case OB_BODY_TYPE_SOFT: case OB_BODY_TYPE_SOFT:
ob->gameflag |= OB_COLLISION | OB_DYNAMIC | OB_SOFT_BODY | OB_ACTOR; ob->gameflag |= OB_COLLISION | OB_DYNAMIC | OB_SOFT_BODY | OB_ACTOR;
ob->gameflag &= ~(OB_RIGID_BODY | OB_OCCLUDER | OB_SENSOR | OB_NAVMESH); ob->gameflag &= ~(OB_RIGID_BODY | OB_OCCLUDER | OB_CHARACTER | OB_SENSOR | OB_NAVMESH);
/* assume triangle mesh, if no bounds chosen for soft body */ /* assume triangle mesh, if no bounds chosen for soft body */
if ((ob->gameflag & OB_BOUNDS) && (ob->boundtype < OB_BOUND_TRIANGLE_MESH)) { if ((ob->gameflag & OB_BOUNDS) && (ob->boundtype < OB_BOUND_TRIANGLE_MESH)) {
@@ -1436,6 +1444,7 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
"Collision Sensor, detects static and dynamic objects but not the other " "Collision Sensor, detects static and dynamic objects but not the other "
"collision sensor objects"}, "collision sensor objects"},
{OB_BODY_TYPE_NAVMESH, "NAVMESH", 0, "Navigation Mesh", "Navigation mesh"}, {OB_BODY_TYPE_NAVMESH, "NAVMESH", 0, "Navigation Mesh", "Navigation mesh"},
{OB_BODY_TYPE_CHARACTER, "CHARACTER", 0, "Character", "Simple kinematic physics appropiate for game characters"},
{0, NULL, 0, NULL, NULL} {0, NULL, 0, NULL, NULL}
}; };
@@ -1529,6 +1538,22 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "max_vel"); RNA_def_property_float_sdna(prop, NULL, "max_vel");
RNA_def_property_range(prop, 0.0, 1000.0); RNA_def_property_range(prop, 0.0, 1000.0);
RNA_def_property_ui_text(prop, "Velocity Max", "Clamp velocity to this maximum speed"); RNA_def_property_ui_text(prop, "Velocity Max", "Clamp velocity to this maximum speed");
prop= RNA_def_property(srna, "step_height", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "step_height");
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_ui_text(prop, "Step Height", "Maximum height of steps the character can run over");
prop= RNA_def_property(srna, "jump_speed", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "jump_speed");
RNA_def_property_range(prop, 0.0, 1000.0);
RNA_def_property_ui_text(prop, "Jump Force", "Upward velocity applied to the character when jumping (with the Motion actuator)");
prop= RNA_def_property(srna, "fall_speed", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "fall_speed");
RNA_def_property_range(prop, 0.0, 1000.0);
RNA_def_property_ui_text(prop, "Fall Speed Max", "Maximum speed at which the character will fall");
/* lock position */ /* lock position */
prop = RNA_def_property(srna, "lock_location_x", PROP_BOOLEAN, PROP_NONE); prop = RNA_def_property(srna, "lock_location_x", PROP_BOOLEAN, PROP_NONE);

View File

@@ -489,7 +489,7 @@ void PyC_SetHomePath(const char *py_path_bundle)
/* cmake/MSVC debug build crashes without this, why only /* cmake/MSVC debug build crashes without this, why only
* in this case is unknown.. */ * in this case is unknown.. */
{ {
BLI_setenv("PYTHONPATH", py_path_bundle); /*BLI_setenv("PYTHONPATH", py_path_bundle)*/;
} }
#endif #endif
#endif #endif

View File

@@ -1346,6 +1346,11 @@ static PHY_ShapeProps *CreateShapePropsFromBlenderObject(struct Object* blendero
shapeProps->m_clamp_vel_min = blenderobject->min_vel; shapeProps->m_clamp_vel_min = blenderobject->min_vel;
shapeProps->m_clamp_vel_max = blenderobject->max_vel; shapeProps->m_clamp_vel_max = blenderobject->max_vel;
// Character physics properties
shapeProps->m_step_height = blenderobject->step_height;
shapeProps->m_jump_speed = blenderobject->jump_speed;
shapeProps->m_fall_speed = blenderobject->fall_speed;
return shapeProps; return shapeProps;
} }
@@ -1638,6 +1643,7 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj,
objprop.m_dyna = (blenderobject->gameflag & OB_DYNAMIC) != 0; objprop.m_dyna = (blenderobject->gameflag & OB_DYNAMIC) != 0;
objprop.m_softbody = (blenderobject->gameflag & OB_SOFT_BODY) != 0; objprop.m_softbody = (blenderobject->gameflag & OB_SOFT_BODY) != 0;
objprop.m_angular_rigidbody = (blenderobject->gameflag & OB_RIGID_BODY) != 0; objprop.m_angular_rigidbody = (blenderobject->gameflag & OB_RIGID_BODY) != 0;
objprop.m_character = (blenderobject->gameflag & OB_CHARACTER) != 0;
///contact processing threshold is only for rigid bodies and static geometry, not 'dynamic' ///contact processing threshold is only for rigid bodies and static geometry, not 'dynamic'
if (objprop.m_angular_rigidbody || !objprop.m_dyna ) if (objprop.m_angular_rigidbody || !objprop.m_dyna )
@@ -1754,6 +1760,11 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj,
objprop.m_boundclass = KX_BOUNDMESH; objprop.m_boundclass = KX_BOUNDMESH;
} }
if ((blenderobject->gameflag & OB_CHARACTER) && !(blenderobject->gameflag & OB_BOUNDS))
{
objprop.m_boundclass = KX_BOUNDSPHERE;
}
KX_BoxBounds bb; KX_BoxBounds bb;
DerivedMesh* dm = NULL; DerivedMesh* dm = NULL;
if (gameobj->GetDeformer()) if (gameobj->GetDeformer())

View File

@@ -20,8 +20,8 @@
#include "BulletSoftBody/btSoftBody.h" #include "BulletSoftBody/btSoftBody.h"
KX_BulletPhysicsController::KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna, bool sensor, bool compound) KX_BulletPhysicsController::KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna, bool sensor, bool character, bool compound)
: KX_IPhysicsController(dyna,sensor,compound,(PHY_IPhysicsController*)this), : KX_IPhysicsController(dyna,sensor,character,compound,(PHY_IPhysicsController*)this),
CcdPhysicsController(ci), CcdPhysicsController(ci),
m_savedCollisionFlags(0), m_savedCollisionFlags(0),
m_savedCollisionFilterGroup(0), m_savedCollisionFilterGroup(0),
@@ -472,7 +472,7 @@ SG_Controller* KX_BulletPhysicsController::GetReplica(class SG_Node* destnode)
void KX_BulletPhysicsController::SetSumoTransform(bool nondynaonly) void KX_BulletPhysicsController::SetSumoTransform(bool nondynaonly)
{ {
if (!m_bDyna && !m_bSensor) if (!m_bDyna && !m_bSensor && !m_bCharacter)
{ {
btCollisionObject* object = GetRigidBody(); btCollisionObject* object = GetRigidBody();
object->setActivationState(ACTIVE_TAG); object->setActivationState(ACTIVE_TAG);

View File

@@ -26,7 +26,7 @@ private:
public: public:
#ifdef USE_BULLET #ifdef USE_BULLET
KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna, bool sensor, bool compound); KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna, bool sensor, bool character, bool compound);
virtual ~KX_BulletPhysicsController (); virtual ~KX_BulletPhysicsController ();
#endif #endif
/////////////////////////////////// ///////////////////////////////////

View File

@@ -72,6 +72,7 @@ struct KX_ObjectProperties
class KX_GameObject* m_dynamic_parent; class KX_GameObject* m_dynamic_parent;
bool m_isactor; bool m_isactor;
bool m_sensor; bool m_sensor;
bool m_character;
bool m_concave; bool m_concave;
bool m_isdeformable; bool m_isdeformable;
bool m_disableSleeping; bool m_disableSleeping;

View File

@@ -100,6 +100,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
bool isbulletdyna = false; bool isbulletdyna = false;
bool isbulletsensor = false; bool isbulletsensor = false;
bool isbulletchar = false;
bool useGimpact = false; bool useGimpact = false;
CcdConstructionInfo ci; CcdConstructionInfo ci;
class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode()); class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
@@ -122,9 +123,13 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
ci.m_clamp_vel_min = shapeprops->m_clamp_vel_min; ci.m_clamp_vel_min = shapeprops->m_clamp_vel_min;
ci.m_clamp_vel_max = shapeprops->m_clamp_vel_max; ci.m_clamp_vel_max = shapeprops->m_clamp_vel_max;
ci.m_margin = objprop->m_margin; ci.m_margin = objprop->m_margin;
ci.m_stepHeight = objprop->m_character ? shapeprops->m_step_height : 0.f;
ci.m_jumpSpeed = objprop->m_character ? shapeprops->m_jump_speed : 0.f;
ci.m_fallSpeed = objprop->m_character ? shapeprops->m_fall_speed : 0.f;
shapeInfo->m_radius = objprop->m_radius; shapeInfo->m_radius = objprop->m_radius;
isbulletdyna = objprop->m_dyna; isbulletdyna = objprop->m_dyna;
isbulletsensor = objprop->m_sensor; isbulletsensor = objprop->m_sensor;
isbulletchar = objprop->m_character;
useGimpact = ((isbulletdyna || isbulletsensor) && !objprop->m_softbody); useGimpact = ((isbulletdyna || isbulletsensor) && !objprop->m_softbody);
ci.m_localInertiaTensor = btVector3(ci.m_mass/3.f,ci.m_mass/3.f,ci.m_mass/3.f); ci.m_localInertiaTensor = btVector3(ci.m_mass/3.f,ci.m_mass/3.f,ci.m_mass/3.f);
@@ -400,21 +405,24 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
//////////////////// ////////////////////
ci.m_collisionFilterGroup = ci.m_collisionFilterGroup =
(isbulletsensor) ? short(CcdConstructionInfo::SensorFilter) : (isbulletsensor) ? short(CcdConstructionInfo::SensorFilter) :
(isbulletdyna) ? short(CcdConstructionInfo::DefaultFilter) : (isbulletdyna) ? short(CcdConstructionInfo::DefaultFilter) :
(isbulletchar) ? short(CcdConstructionInfo::CharacterFilter) :
short(CcdConstructionInfo::StaticFilter); short(CcdConstructionInfo::StaticFilter);
ci.m_collisionFilterMask = ci.m_collisionFilterMask =
(isbulletsensor) ? short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter) : (isbulletsensor) ? short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter) :
(isbulletdyna) ? short(CcdConstructionInfo::AllFilter) : (isbulletdyna) ? short(CcdConstructionInfo::AllFilter) :
(isbulletchar) ? short(CcdConstructionInfo::AllFilter) :
short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::StaticFilter); short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::StaticFilter);
ci.m_bRigid = objprop->m_dyna && objprop->m_angular_rigidbody; ci.m_bRigid = objprop->m_dyna && objprop->m_angular_rigidbody;
ci.m_contactProcessingThreshold = objprop->m_contactProcessingThreshold;//todo: expose this in advanced settings, just like margin, default to 10000 or so ci.m_contactProcessingThreshold = objprop->m_contactProcessingThreshold;//todo: expose this in advanced settings, just like margin, default to 10000 or so
ci.m_bSoft = objprop->m_softbody; ci.m_bSoft = objprop->m_softbody;
ci.m_bSensor = isbulletsensor; ci.m_bSensor = isbulletsensor;
ci.m_bCharacter = isbulletchar;
ci.m_bGimpact = useGimpact; ci.m_bGimpact = useGimpact;
MT_Vector3 scaling = gameobj->NodeGetWorldScaling(); MT_Vector3 scaling = gameobj->NodeGetWorldScaling();
ci.m_scaling.setValue(scaling[0], scaling[1], scaling[2]); ci.m_scaling.setValue(scaling[0], scaling[1], scaling[2]);
KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,isbulletdyna,isbulletsensor,objprop->m_hasCompoundChildren); KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,isbulletdyna,isbulletsensor,isbulletchar,objprop->m_hasCompoundChildren);
// shapeInfo is reference counted, decrement now as we don't use it anymore // shapeInfo is reference counted, decrement now as we don't use it anymore
if (shapeInfo) if (shapeInfo)
shapeInfo->Release(); shapeInfo->Release();

View File

@@ -33,10 +33,11 @@
#include "PHY_DynamicTypes.h" #include "PHY_DynamicTypes.h"
KX_IPhysicsController::KX_IPhysicsController(bool dyna, bool sensor, bool compound, void* userdata) KX_IPhysicsController::KX_IPhysicsController(bool dyna, bool sensor, bool character, bool compound, void* userdata)
: m_bDyna(dyna), : m_bDyna(dyna),
m_bSensor(sensor), m_bSensor(sensor),
m_bCharacter(character),
m_bCompound(compound), m_bCompound(compound),
m_suspendDynamics(false), m_suspendDynamics(false),
m_userdata(userdata) m_userdata(userdata)

View File

@@ -53,11 +53,12 @@ class KX_IPhysicsController : public SG_Controller
protected: protected:
bool m_bDyna; bool m_bDyna;
bool m_bSensor; bool m_bSensor;
bool m_bCharacter;
bool m_bCompound; bool m_bCompound;
bool m_suspendDynamics; bool m_suspendDynamics;
void* m_userdata; void* m_userdata;
public: public:
KX_IPhysicsController(bool dyna,bool sensor,bool compound, void* userdata); KX_IPhysicsController(bool dyna,bool sensor,bool character,bool compound, void* userdata);
virtual ~KX_IPhysicsController(); virtual ~KX_IPhysicsController();
@@ -109,6 +110,10 @@ public:
m_bSensor = isSensor; m_bSensor = isSensor;
} }
void SetCharacter(bool isCharacter) {
m_bCharacter = isCharacter;
}
bool IsDyna(void) { bool IsDyna(void) {
return m_bDyna; return m_bDyna;
} }
@@ -117,6 +122,10 @@ public:
return m_bSensor; return m_bSensor;
} }
bool IsCharacter(void) {
return m_bCharacter;
}
bool IsCompound(void) { bool IsCompound(void) {
return m_bCompound; return m_bCompound;
} }

View File

@@ -2267,7 +2267,10 @@ KX_PYMETHODDEF_DOC(KX_Scene, addObject,
!ConvertPythonToGameObject(pyother, &other, false, "scene.addObject(object, other, time): KX_Scene (second argument)") ) !ConvertPythonToGameObject(pyother, &other, false, "scene.addObject(object, other, time): KX_Scene (second argument)") )
return NULL; return NULL;
if (!m_inactivelist->SearchValue(ob)) {
PyErr_Format(PyExc_ValueError, "scene.addObject(object, other, time): KX_Scene (second argument): object does not belong to scene");
return NULL;
}
SCA_IObject* replica = AddReplicaObject((SCA_IObject*)ob, other, time); SCA_IObject* replica = AddReplicaObject((SCA_IObject*)ob, other, time);
// release here because AddReplicaObject AddRef's // release here because AddReplicaObject AddRef's

View File

@@ -22,6 +22,7 @@ subject to the following restrictions:
#include "CcdPhysicsController.h" #include "CcdPhysicsController.h"
#include "btBulletDynamicsCommon.h" #include "btBulletDynamicsCommon.h"
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" #include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h"
#include "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h" #include "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h"
@@ -88,7 +89,7 @@ CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci)
m_shapeInfo->AddRef(); m_shapeInfo->AddRef();
m_bulletMotionState = 0; m_bulletMotionState = 0;
m_characterController = 0;
CreateRigidbody(); CreateRigidbody();
@@ -151,6 +152,24 @@ public:
}; };
class BlenderBulletCharacterController : public btKinematicCharacterController
{
private:
btMotionState* m_motionState;
public:
BlenderBulletCharacterController(btMotionState *motionState, btPairCachingGhostObject *ghost, btConvexShape* shape, float stepHeight)
: btKinematicCharacterController(ghost,shape,stepHeight,2),
m_motionState(motionState)
{
}
virtual void updateAction(btCollisionWorld *collisionWorld, btScalar dt)
{
btKinematicCharacterController::updateAction(collisionWorld,dt);
m_motionState->setWorldTransform(getGhostObject()->getWorldTransform());
}
};
btRigidBody* CcdPhysicsController::GetRigidBody() btRigidBody* CcdPhysicsController::GetRigidBody()
{ {
@@ -164,6 +183,10 @@ btSoftBody* CcdPhysicsController::GetSoftBody()
{ {
return btSoftBody::upcast(m_object); return btSoftBody::upcast(m_object);
} }
btKinematicCharacterController* CcdPhysicsController::GetCharacterController()
{
return m_characterController;
}
#include "BulletSoftBody/btSoftBodyHelpers.h" #include "BulletSoftBody/btSoftBodyHelpers.h"
@@ -425,6 +448,29 @@ bool CcdPhysicsController::CreateSoftbody()
return true; return true;
} }
bool CcdPhysicsController::CreateCharacterController()
{
if (!m_cci.m_bCharacter)
return false;
m_object = new btPairCachingGhostObject();
m_object->setCollisionShape(m_collisionShape);
m_object->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);
btTransform trans;
m_bulletMotionState->getWorldTransform(trans);
m_object->setWorldTransform(trans);
m_characterController = new BlenderBulletCharacterController(m_bulletMotionState,(btPairCachingGhostObject*)m_object,(btConvexShape*)m_collisionShape,m_cci.m_stepHeight);
PHY__Vector3 gravity;
m_cci.m_physicsEnv->getGravity(gravity);
m_characterController->setGravity(-gravity.m_vec[2]); // need positive gravity
m_characterController->setJumpSpeed(m_cci.m_jumpSpeed);
m_characterController->setFallSpeed(m_cci.m_fallSpeed);
return true;
}
void CcdPhysicsController::CreateRigidbody() void CcdPhysicsController::CreateRigidbody()
{ {
@@ -433,7 +479,7 @@ void CcdPhysicsController::CreateRigidbody()
m_bulletMotionState = new BlenderBulletMotionState(m_MotionState); m_bulletMotionState = new BlenderBulletMotionState(m_MotionState);
///either create a btCollisionObject, btRigidBody or btSoftBody ///either create a btCollisionObject, btRigidBody or btSoftBody
if (CreateSoftbody()) if (CreateSoftbody() || CreateCharacterController())
// soft body created, done // soft body created, done
return; return;

View File

@@ -29,6 +29,7 @@ subject to the following restrictions:
/// PHY_IPhysicsController is the abstract simplified Interface to a physical object. /// PHY_IPhysicsController is the abstract simplified Interface to a physical object.
/// It contains the IMotionState and IDeformableMesh Interfaces. /// It contains the IMotionState and IDeformableMesh Interfaces.
#include "btBulletDynamicsCommon.h" #include "btBulletDynamicsCommon.h"
#include "BulletDynamics/Character/btKinematicCharacterController.h"
#include "LinearMath/btTransform.h" #include "LinearMath/btTransform.h"
#include "PHY_IMotionState.h" #include "PHY_IMotionState.h"
@@ -221,7 +222,8 @@ struct CcdConstructionInfo
KinematicFilter = 4, KinematicFilter = 4,
DebrisFilter = 8, DebrisFilter = 8,
SensorFilter = 16, SensorFilter = 16,
AllFilter = DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorFilter, CharacterFilter = 32,
AllFilter = DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorFilter | CharacterFilter,
}; };
@@ -301,6 +303,10 @@ struct CcdConstructionInfo
btScalar m_margin; btScalar m_margin;
//////////////////// ////////////////////
float m_stepHeight;
float m_jumpSpeed;
float m_fallSpeed;
int m_gamesoftFlag; int m_gamesoftFlag;
float m_soft_linStiff; /* linear stiffness 0..1 */ float m_soft_linStiff; /* linear stiffness 0..1 */
float m_soft_angStiff; /* angular stiffness 0..1 */ float m_soft_angStiff; /* angular stiffness 0..1 */
@@ -343,6 +349,7 @@ struct CcdConstructionInfo
bool m_bRigid; bool m_bRigid;
bool m_bSoft; bool m_bSoft;
bool m_bSensor; bool m_bSensor;
bool m_bCharacter;
bool m_bGimpact; // use Gimpact for mesh body bool m_bGimpact; // use Gimpact for mesh body
///optional use of collision group/mask: ///optional use of collision group/mask:
@@ -391,6 +398,7 @@ class CcdPhysicsController : public PHY_IPhysicsController
{ {
protected: protected:
btCollisionObject* m_object; btCollisionObject* m_object;
btKinematicCharacterController* m_characterController;
class PHY_IMotionState* m_MotionState; class PHY_IMotionState* m_MotionState;
@@ -417,6 +425,7 @@ protected:
void CreateRigidbody(); void CreateRigidbody();
bool CreateSoftbody(); bool CreateSoftbody();
bool CreateCharacterController();
bool Register() { bool Register() {
return (m_registerCount++ == 0) ? true : false; return (m_registerCount++ == 0) ? true : false;
@@ -453,6 +462,7 @@ protected:
btRigidBody* GetRigidBody(); btRigidBody* GetRigidBody();
btCollisionObject* GetCollisionObject(); btCollisionObject* GetCollisionObject();
btSoftBody* GetSoftBody(); btSoftBody* GetSoftBody();
btKinematicCharacterController* GetCharacterController();
CcdShapeConstructionInfo* GetShapeInfo() { return m_shapeInfo; } CcdShapeConstructionInfo* GetShapeInfo() { return m_shapeInfo; }

View File

@@ -26,6 +26,7 @@ subject to the following restrictions:
#include <algorithm> #include <algorithm>
#include "btBulletDynamicsCommon.h" #include "btBulletDynamicsCommon.h"
#include "LinearMath/btIDebugDraw.h" #include "LinearMath/btIDebugDraw.h"
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
#include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h" #include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h"
#include "BulletSoftBody/btSoftRigidDynamicsWorld.h" #include "BulletSoftBody/btSoftRigidDynamicsWorld.h"
#include "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h" #include "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h"
@@ -369,6 +370,7 @@ m_scalingPropagated(false)
m_filterCallback = new CcdOverlapFilterCallBack(this); m_filterCallback = new CcdOverlapFilterCallBack(this);
m_broadphase->getOverlappingPairCache()->setOverlapFilterCallback(m_filterCallback); m_broadphase->getOverlappingPairCache()->setOverlapFilterCallback(m_filterCallback);
m_broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
setSolverType(1);//issues with quickstep and memory allocations setSolverType(1);//issues with quickstep and memory allocations
// m_dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,m_broadphase,m_solver,m_collisionConfiguration); // m_dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
@@ -406,7 +408,11 @@ void CcdPhysicsEnvironment::addCcdPhysicsController(CcdPhysicsController* ctrl)
{ {
if (obj->getCollisionShape()) if (obj->getCollisionShape())
{ {
m_dynamicsWorld->addCollisionObject(obj,ctrl->GetCollisionFilterGroup(), ctrl->GetCollisionFilterMask()); m_dynamicsWorld->addCollisionObject(obj, ctrl->GetCollisionFilterGroup(), ctrl->GetCollisionFilterMask());
}
if (ctrl->GetCharacterController())
{
m_dynamicsWorld->addAction(ctrl->GetCharacterController());
} }
} }
} }

View File

@@ -46,6 +46,9 @@ struct PHY_ShapeProps {
bool m_do_anisotropic; // Should I do anisotropic friction? bool m_do_anisotropic; // Should I do anisotropic friction?
bool m_do_fh; // Should the object have a linear Fh spring? bool m_do_fh; // Should the object have a linear Fh spring?
bool m_do_rot_fh; // Should the object have an angular Fh spring? bool m_do_rot_fh; // Should the object have an angular Fh spring?
MT_Scalar m_step_height; // Max height of climbable steps (Character)
MT_Scalar m_jump_speed; // Velocity of jumps (Character)
MT_Scalar m_fall_speed; // Max velocity of falling (Character)
}; };