Index: source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp =================================================================== --- source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp (r‚vision 13929) +++ source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp (copie de travail) @@ -206,6 +206,8 @@ case PHY_STATIC_RESPONSE: sumoRespClass = PHY_STATIC_RESPONSE; break; + case PHY_BROADPH_RESPONSE: + return; default: assert(0); return; Index: source/gameengine/Physics/Bullet/CcdPhysicsController.cpp =================================================================== --- source/gameengine/Physics/Bullet/CcdPhysicsController.cpp (r‚vision 13929) +++ source/gameengine/Physics/Bullet/CcdPhysicsController.cpp (copie de travail) @@ -36,6 +36,7 @@ btVector3 startVel(0,0,0);//-10000); + CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci) :m_cci(ci) { @@ -119,17 +120,20 @@ m_cci.m_linearDamping,m_cci.m_angularDamping, m_cci.m_friction,m_cci.m_restitution); - - // // init the rigidbody properly // //setMassProps this also sets collisionFlags //convert collision flags! - + //special case: a near/radar sensor controller should not be defined static or it will + //generate loads of static-static collision messages on the console + if ((m_cci.m_collisionFilterGroup & CcdConstructionInfo::SensorFilter) != 0) + { + // reset the flags that have been set so far + m_body->setCollisionFlags(0); + } m_body->setCollisionFlags(m_body->getCollisionFlags() | m_cci.m_collisionFlags); - m_body->setGravity( m_cci.m_gravity); m_body->setDamping(m_cci.m_linearDamping, m_cci.m_angularDamping); @@ -141,12 +145,14 @@ if (m_cci.m_physicsEnv) m_cci.m_physicsEnv->removeCcdPhysicsController(this); - delete m_MotionState; + if (m_MotionState) + delete m_MotionState; if (m_bulletMotionState) delete m_bulletMotionState; delete m_body; } + /** SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding') */ Index: source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp =================================================================== --- source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp (r‚vision 13929) +++ source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp (copie de travail) @@ -251,7 +251,23 @@ }; #endif //NEW_BULLET_VEHICLE_SUPPORT +class CcdOverlapFilterCallBack : public btOverlapFilterCallback +{ +private: + class CcdPhysicsEnvironment* m_physEnv; +public: + CcdOverlapFilterCallBack(CcdPhysicsEnvironment* env) : + m_physEnv(env) + { + } + virtual ~CcdOverlapFilterCallBack() + { + } + // return true when pairs need collision + virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const; +}; + void CcdPhysicsEnvironment::setDebugDrawer(btIDebugDraw* debugDrawer) { if (debugDrawer && m_dynamicsWorld) @@ -302,7 +318,11 @@ m_ccdMode(0), m_solverType(-1), m_profileTimings(0), -m_enableSatCollisionDetection(false) +m_enableSatCollisionDetection(false), +m_solver(NULL), +m_ownPairCache(NULL), +m_ownDispatcher(NULL), +m_filterCallback(NULL) { for (int i=0;isetOverlapFilterCallback(m_filterCallback); setSolverType(1);//issues with quickstep and memory allocations - - m_dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,pairCache,new btSequentialImpulseConstraintSolver()); + m_dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,pairCache,m_solver); m_debugDrawer = 0; m_gravity = btVector3(0.f,-10.f,0.f); m_dynamicsWorld->setGravity(m_gravity); @@ -346,7 +370,8 @@ body->setGravity( m_gravity ); m_controllers.push_back(ctrl); - m_dynamicsWorld->addRigidBody(body); + //use explicit group/filter for finer control over collision in bullet => near/radar sensor + m_dynamicsWorld->addRigidBody(body, ctrl->GetCollisionFilterGroup(), ctrl->GetCollisionFilterMask()); if (body->isStaticOrKinematicObject()) { body->setActivationState(ISLAND_SLEEPING); @@ -778,7 +803,20 @@ delete m_dynamicsWorld; + if (NULL != m_ownPairCache) + delete m_ownPairCache; + if (NULL != m_ownDispatcher) + delete m_ownDispatcher; + + if (NULL != m_solver) + delete m_solver; + + if (NULL != m_debugDrawer) + delete m_debugDrawer; + + if (NULL != m_filterCallback) + delete m_filterCallback; } @@ -841,9 +879,10 @@ { addCcdPhysicsController(ctrl1); } + //Collision filter/mask is now set at the time of the creation of the controller //force collision detection with everything, including static objects (might hurt performance!) - ctrl1->GetRigidBody()->getBroadphaseHandle()->m_collisionFilterMask = btBroadphaseProxy::AllFilter; - ctrl1->GetRigidBody()->getBroadphaseHandle()->m_collisionFilterGroup = btBroadphaseProxy::AllFilter; + //ctrl1->GetRigidBody()->getBroadphaseHandle()->m_collisionFilterMask = btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::SensorTrigger; + //ctrl1->GetRigidBody()->getBroadphaseHandle()->m_collisionFilterGroup = btBroadphaseProxy::SensorTrigger; //todo: make this 'sensor'! requestCollisionCallback(ctrl); @@ -962,11 +1001,49 @@ } +// This call back is called before a pair is added in the cache +// Handy to remove objects that must be ignored by sensors +bool CcdOverlapFilterCallBack::needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const +{ + btCollisionObject *colObj0, *colObj1; + CcdPhysicsController *sensorCtrl, *objCtrl; + bool collides; + // first check the filters + collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0; + collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask); + if (!collides) + return false; + // additional check for sensor object + if (proxy0->m_collisionFilterGroup & btBroadphaseProxy::SensorTrigger) + { + // this is a sensor object, the other one can't be a sensor object because + // they exclude each other in the above test + assert(!(proxy1->m_collisionFilterGroup & btBroadphaseProxy::SensorTrigger)); + colObj0 = (btCollisionObject*)proxy0->m_clientObject; + colObj1 = (btCollisionObject*)proxy1->m_clientObject; + } + else if (proxy1->m_collisionFilterGroup & btBroadphaseProxy::SensorTrigger) + { + colObj0 = (btCollisionObject*)proxy1->m_clientObject; + colObj1 = (btCollisionObject*)proxy0->m_clientObject; + } + else + { + return true; + } + if (!colObj0 || !colObj1) + return false; + sensorCtrl = static_cast(colObj0->getUserPointer()); + objCtrl = static_cast(colObj1->getUserPointer()); + if (m_physEnv->m_triggerCallbacks[PHY_BROADPH_RESPONSE]) + { + return m_physEnv->m_triggerCallbacks[PHY_BROADPH_RESPONSE](m_physEnv->m_triggerCallbacksUserPtrs[PHY_BROADPH_RESPONSE], sensorCtrl, objCtrl, 0); + } + return true; +} - - #ifdef NEW_BULLET_VEHICLE_SUPPORT //complex constraint for vehicles @@ -998,12 +1075,19 @@ { CcdConstructionInfo cinfo; + // memory leak! The shape is not deleted by Bullet and we cannot add it to the KX_Scene.m_shapes list cinfo.m_collisionShape = new btSphereShape(radius); cinfo.m_MotionState = 0; cinfo.m_physicsEnv = this; - cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE | btCollisionObject::CF_KINEMATIC_OBJECT; + // declare this object as Dyamic rather then static!! + // The reason as it is designed to detect all type of object, including static object + // It would cause static-static message to be printed on the console otherwise + cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE/* | btCollisionObject::CF_KINEMATIC_OBJECT*/; DefaultMotionState* motionState = new DefaultMotionState(); cinfo.m_MotionState = motionState; + // we will add later the possibility to select the filter from option + cinfo.m_collisionFilterMask = CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter; + cinfo.m_collisionFilterGroup = CcdConstructionInfo::SensorFilter; motionState->m_worldTransform.setIdentity(); motionState->m_worldTransform.setOrigin(btVector3(position[0],position[1],position[2])); @@ -1275,12 +1359,18 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::CreateConeController(float coneradius,float coneheight) { CcdConstructionInfo cinfo; + //This is a memory leak: Bullet does not delete the shape and it cannot be added to + //the KX_Scene.m_shapes list -- too bad but that's not a lot of data cinfo.m_collisionShape = new btConeShape(coneradius,coneheight); cinfo.m_MotionState = 0; cinfo.m_physicsEnv = this; cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE; DefaultMotionState* motionState = new DefaultMotionState(); cinfo.m_MotionState = motionState; + + // we will add later the possibility to select the filter from option + cinfo.m_collisionFilterMask = CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter; + cinfo.m_collisionFilterGroup = CcdConstructionInfo::SensorFilter; motionState->m_worldTransform.setIdentity(); // motionState->m_worldTransform.setOrigin(btVector3(position[0],position[1],position[2])); Index: source/gameengine/Physics/Bullet/CcdPhysicsController.h =================================================================== --- source/gameengine/Physics/Bullet/CcdPhysicsController.h (r‚vision 13929) +++ source/gameengine/Physics/Bullet/CcdPhysicsController.h (copie de travail) @@ -46,7 +46,8 @@ StaticFilter = 2, KinematicFilter = 4, DebrisFilter = 8, - AllFilter = DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter, + SensorFilter = 16, + AllFilter = DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorFilter, }; @@ -61,6 +62,7 @@ m_collisionFlags(0), m_collisionFilterGroup(DefaultFilter), m_collisionFilterMask(AllFilter), + m_collisionShape(0), m_MotionState(0), m_physicsEnv(0), m_inertiaFactor(1.f) @@ -85,9 +87,8 @@ short int m_collisionFilterGroup; short int m_collisionFilterMask; - - btCollisionShape* m_collisionShape; - class PHY_IMotionState* m_MotionState; + class btCollisionShape* m_collisionShape; + class PHY_IMotionState* m_MotionState; CcdPhysicsEnvironment* m_physicsEnv; //needed for self-replication float m_inertiaFactor;//tweak the inertia (hooked up to Blender 'formfactor' @@ -96,11 +97,12 @@ class btRigidBody; + ///CcdPhysicsController is a physics object that supports continuous collision detection and time of impact based physics resolution. class CcdPhysicsController : public PHY_IPhysicsController { btRigidBody* m_body; - class PHY_IMotionState* m_MotionState; + class PHY_IMotionState* m_MotionState; btMotionState* m_bulletMotionState; @@ -215,7 +217,11 @@ return m_MotionState; } - + class CcdPhysicsEnvironment* GetPhysicsEnvironment() + { + return m_cci.m_physicsEnv; + } + }; Index: source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h =================================================================== --- source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h (r‚vision 13929) +++ source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h (copie de travail) @@ -42,6 +42,7 @@ class btOverlappingPairCache; class btIDebugDraw; class PHY_IVehicle; +class CcdOverlapFilterCallBack; /// CcdPhysicsEnvironment is an experimental mainloop for physics simulation using optional continuous collision detection. /// Physics Environment takes care of stepping the simulation and is a container for physics entities. @@ -49,9 +50,8 @@ /// A derived class may be able to 'construct' entities by loading and/or converting class CcdPhysicsEnvironment : public PHY_IPhysicsEnvironment { + friend CcdOverlapFilterCallBack; btVector3 m_gravity; - - protected: btIDebugDraw* m_debugDrawer; @@ -166,7 +166,7 @@ virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user); virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl); virtual void removeCollisionCallback(PHY_IPhysicsController* ctrl); - + //These two methods are used *solely* to create controllers for Near/Radar sensor! Don't use for anything else virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position); virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight); @@ -229,10 +229,22 @@ std::vector m_wrapperVehicles; - class btDynamicsWorld* m_dynamicsWorld; + //use explicit btDiscreteDynamicsWorld* so that we have access to + //btDiscreteDynamicsWorld::addRigidBody(body,filter,group) + //so that we can set the body collision filter/group at the time of creation + //and not afterwards (breaks the collision system for radar/near sensor) + //Ideally we would like to have access to this function from the btDynamicsWorld interface + //class btDynamicsWorld* m_dynamicsWorld; + class btDiscreteDynamicsWorld* m_dynamicsWorld; class btConstraintSolver* m_solver; + class btOverlappingPairCache* m_ownPairCache; + + class CcdOverlapFilterCallBack* m_filterCallback; + + class btDispatcher* m_ownDispatcher; + bool m_scalingPropagated; Index: source/gameengine/Physics/common/PHY_DynamicTypes.h =================================================================== --- source/gameengine/Physics/common/PHY_DynamicTypes.h (r‚vision 13929) +++ source/gameengine/Physics/common/PHY_DynamicTypes.h (copie de travail) @@ -19,7 +19,6 @@ -class PHY_ResponseTable; class PHY_Shape; @@ -40,10 +39,11 @@ typedef enum { PHY_FH_RESPONSE, - PHY_SENSOR_RESPONSE, /* Touch Sensors */ + PHY_SENSOR_RESPONSE, /* Touch Sensors */ PHY_CAMERA_RESPONSE, /* Visibility Culling */ PHY_OBJECT_RESPONSE, /* Object Dynamic Geometry Response */ PHY_STATIC_RESPONSE, /* Static Geometry Response */ + PHY_BROADPH_RESPONSE, /* broadphase Response */ PHY_NUM_RESPONSE }; Index: source/gameengine/Physics/common/PHY_IPhysicsController.h =================================================================== --- source/gameengine/Physics/common/PHY_IPhysicsController.h (r‚vision 13929) +++ source/gameengine/Physics/common/PHY_IPhysicsController.h (copie de travail) @@ -85,7 +85,6 @@ // dyna's that are rigidbody are free in orientation, dyna's with non-rigidbody are restricted virtual void setRigidBody(bool rigid)=0; - // clientinfo for raycasts for example virtual void* getNewClientInfo()=0; virtual void setNewClientInfo(void* clientinfo)=0; Index: source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h =================================================================== --- source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h (r‚vision 13929) +++ source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h (copie de travail) @@ -107,6 +107,7 @@ virtual void removeSensor(PHY_IPhysicsController* ctrl)=0; virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user)=0; virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl)=0; + //These two methods are *solely* used to create controllers for sensor! Don't use for anything else virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position) =0; virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight)=0; Index: source/gameengine/Ketsji/KX_NearSensor.cpp =================================================================== --- source/gameengine/Ketsji/KX_NearSensor.cpp (r‚vision 13929) +++ source/gameengine/Ketsji/KX_NearSensor.cpp (copie de travail) @@ -191,8 +191,37 @@ return result; } +// this function is called at broad phase stage to check if the two controller +// need to interact at all. It is used for Near/Radar sensor that don't need to +// check collision with object not included in filter +bool KX_NearSensor::BroadPhaseFilterCollision(void*obj1,void*obj2) +{ + KX_GameObject* parent = static_cast(GetParent()); + + // need the mapping from PHY_IPhysicsController to gameobjects now + assert(obj1==m_physCtrl && obj2); + KX_ClientObjectInfo* client_info = static_cast((static_cast(obj2))->getNewClientInfo()); + KX_GameObject* gameobj = ( client_info ? + client_info->m_gameobject : + NULL); + + if (gameobj && (gameobj != parent)) + { + // only take valid colliders + if (client_info->m_type == KX_ClientObjectInfo::ACTOR) + { + if ((m_touchedpropname.Length() == 0) || + (gameobj->GetProperty(m_touchedpropname))) + { + return true; + } + } + } + return false; +} + bool KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData * coll_data) { // KX_TouchEventManager* toucheventmgr = static_cast(m_eventmgr); @@ -208,20 +237,22 @@ client_info->m_gameobject : NULL); - if (gameobj && (gameobj != parent)) + // these checks are done already in BroadPhaseFilterCollision() + if (gameobj /*&& (gameobj != parent)*/) { if (!m_colliders->SearchValue(gameobj)) m_colliders->Add(gameobj->AddRef()); // only take valid colliders - if (client_info->m_type == KX_ClientObjectInfo::ACTOR) - { - if ((m_touchedpropname.Length() == 0) || - (gameobj->GetProperty(m_touchedpropname))) - { + // These checks are done already in BroadPhaseFilterCollision() + //if (client_info->m_type == KX_ClientObjectInfo::ACTOR) + //{ + // if ((m_touchedpropname.Length() == 0) || + // (gameobj->GetProperty(m_touchedpropname))) + // { m_bTriggered = true; m_hitObject = gameobj; - } - } + // } + //} } return DT_CONTINUE; Index: source/gameengine/Ketsji/KX_NearSensor.h =================================================================== --- source/gameengine/Ketsji/KX_NearSensor.h (r‚vision 13929) +++ source/gameengine/Ketsji/KX_NearSensor.h (copie de travail) @@ -77,6 +77,7 @@ virtual void ReParent(SCA_IObject* parent); virtual bool NewHandleCollision(void* obj1,void* obj2, const PHY_CollData * coll_data); + virtual bool BroadPhaseFilterCollision(void*obj1,void*obj2); virtual void RegisterSumo(KX_TouchEventManager *touchman); virtual PyObject* _getattr(const STR_String& attr); Index: source/gameengine/Ketsji/KX_TouchEventManager.cpp =================================================================== --- source/gameengine/Ketsji/KX_TouchEventManager.cpp (r‚vision 13929) +++ source/gameengine/Ketsji/KX_TouchEventManager.cpp (copie de travail) @@ -54,6 +54,7 @@ m_physEnv->addTouchCallback(PHY_OBJECT_RESPONSE, KX_TouchEventManager::newCollisionResponse, this); m_physEnv->addTouchCallback(PHY_SENSOR_RESPONSE, KX_TouchEventManager::newCollisionResponse, this); + m_physEnv->addTouchCallback(PHY_BROADPH_RESPONSE, KX_TouchEventManager::newBroadphaseResponse, this); } @@ -79,6 +80,26 @@ return false; } +bool KX_TouchEventManager::newBroadphaseResponse(void *client_data, + void *object1, + void *object2, + const PHY_CollData *coll_data) +{ + PHY_IPhysicsController* ctrl = static_cast(object1); + KX_ClientObjectInfo* info = (ctrl) ? static_cast(ctrl->getNewClientInfo()) : NULL; + // This call back should only be called for controllers of Near and Radar sensor + if (info && + info->m_sensors.size() == 1 && + (info->m_type == KX_ClientObjectInfo::NEAR || + info->m_type == KX_ClientObjectInfo::RADAR)) + { + // only one sensor for this type of object + KX_TouchSensor* touchsensor = static_cast(*info->m_sensors.begin()); + return touchsensor->BroadPhaseFilterCollision(object1,object2); + } + return true; +} + void KX_TouchEventManager::RegisterSensor(SCA_ISensor* sensor) { KX_TouchSensor* touchsensor = static_cast(sensor); Index: source/gameengine/Ketsji/KX_TouchSensor.h =================================================================== --- source/gameengine/Ketsji/KX_TouchSensor.h (r‚vision 13929) +++ source/gameengine/Ketsji/KX_TouchSensor.h (copie de travail) @@ -57,8 +57,6 @@ class SCA_EventManager* m_eventmgr; class PHY_IPhysicsController* m_physCtrl; - class PHY_ResponseTable* m_responstTable; - class PHY_PhysicsController* m_responsObject; bool m_bCollision; bool m_bTriggered; @@ -86,7 +84,11 @@ virtual bool NewHandleCollision(void*obj1,void*obj2,const PHY_CollData* colldata); - PHY_PhysicsController* GetPhysicsController() { return m_responsObject;} + // Allows to do pre-filtering and save computation time + // obj1 = sensor physical controller, obj2 = physical controller of second object + // return value = true if collision should be checked on pair of object + virtual bool BroadPhaseFilterCollision(void*obj1,void*obj2) { return true; } + virtual bool IsPositiveTrigger() { Index: source/gameengine/Ketsji/KX_TouchEventManager.h =================================================================== --- source/gameengine/Ketsji/KX_TouchEventManager.h (r‚vision 13929) +++ source/gameengine/Ketsji/KX_TouchEventManager.h (copie de travail) @@ -56,7 +56,12 @@ void *object1, void *object2, const PHY_CollData *coll_data); - + + static bool newBroadphaseResponse(void *client_data, + void *object1, + void *object2, + const PHY_CollData *coll_data); + virtual bool NewHandleCollision(void* obj1,void* obj2, const PHY_CollData * coll_data); Index: source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp =================================================================== --- source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp (r‚vision 13929) +++ source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp (copie de travail) @@ -1123,8 +1131,12 @@ ci.m_angularDamping = 1.f - shapeprops->m_ang_drag; //need a bit of damping, else system doesn't behave well ci.m_inertiaFactor = shapeprops->m_inertia/0.4f;//defaults to 0.4, don't want to change behaviour - + ci.m_collisionFilterGroup = (isbulletdyna) ? short(CcdConstructionInfo::DefaultFilter) : short(CcdConstructionInfo::StaticFilter); + ci.m_collisionFilterMask = (isbulletdyna) ? short(CcdConstructionInfo::AllFilter) : short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::StaticFilter); + KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,isbulletdyna); if (objprop->m_in_active_layer)