diff --git a/Source/Engine/Physics/Colliders/CharacterController.cpp b/Source/Engine/Physics/Colliders/CharacterController.cpp index 288d32d56..c57c0f395 100644 --- a/Source/Engine/Physics/Colliders/CharacterController.cpp +++ b/Source/Engine/Physics/Colliders/CharacterController.cpp @@ -173,6 +173,7 @@ CharacterController::CollisionFlags CharacterController::Move(const Vector3& dis filters.mFilterData = (PxFilterData*)&_filterData; filters.mFilterCallback = Physics::GetCharacterQueryFilterCallback(); filters.mFilterFlags = PxQueryFlag::eDYNAMIC | PxQueryFlag::eSTATIC | PxQueryFlag::ePREFILTER; + filters.mCCTFilterCallback = Physics::GetCharacterControllerFilterCallback(); result = (CollisionFlags)(byte)_controller->move(C2P(displacement), _minMoveDistance, deltaTime, filters); _lastFlags = result; diff --git a/Source/Engine/Physics/Physics.Queries.cpp b/Source/Engine/Physics/Physics.Queries.cpp index bb6940db5..f7986397e 100644 --- a/Source/Engine/Physics/Physics.Queries.cpp +++ b/Source/Engine/Physics/Physics.Queries.cpp @@ -6,6 +6,8 @@ #include "Actors/PhysicsColliderActor.h" #include #include +#include +#include // Temporary result buffer size #define HIT_BUFFER_SIZE 128 @@ -217,6 +219,52 @@ public: } }; +class CharacterControllerFilter : public PxControllerFilterCallback +{ +private: + + PxShape* getShape(const PxController& controller) + { + PxRigidDynamic* actor = controller.getActor(); + + // Early out if no actor or no shapes + if (!actor || actor->getNbShapes() < 1) + return nullptr; + + // Get first shape only. + PxShape* shape = nullptr; + actor->getShapes(&shape, 1); + + return shape; + } + +public: + + bool filter(const PxController& a, const PxController& b) override + { + // Early out to avoid crashing + PxShape* shapeA = getShape(a); + if (!shapeA) + return false; + + PxShape* shapeB = getShape(b); + if (!shapeB) + return false; + + // Let triggers through + if (PxFilterObjectIsTrigger(shapeB->getFlags())) + return false; + + // Trigger the contact callback for pairs (A,B) where the filtermask of A contains the ID of B and vice versa + const PxFilterData shapeFilterA = shapeA->getQueryFilterData(); + const PxFilterData shapeFilterB = shapeB->getQueryFilterData(); + if (shapeFilterA.word0 & shapeFilterB.word1) + return true; + + return false; + } +}; + PxQueryFilterCallback* Physics::GetQueryFilterCallback() { static QueryFilter Filter; @@ -229,6 +277,12 @@ PxQueryFilterCallback* Physics::GetCharacterQueryFilterCallback() return &Filter; } +PxControllerFilterCallback* Physics::GetCharacterControllerFilterCallback() +{ + static CharacterControllerFilter Filter; + return &Filter; +} + bool Physics::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) { // Prepare data diff --git a/Source/Engine/Physics/Physics.h b/Source/Engine/Physics/Physics.h index 96048b829..6eb38dcd6 100644 --- a/Source/Engine/Physics/Physics.h +++ b/Source/Engine/Physics/Physics.h @@ -112,6 +112,11 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(Physics); /// static PxQueryFilterCallback* GetCharacterQueryFilterCallback(); + /// + /// Gets the default controller filter callback used for the character controller collisions detection. + /// + static PxControllerFilterCallback* GetCharacterControllerFilterCallback(); + /// /// Gets the default physical material. /// diff --git a/Source/Engine/Physics/Types.h b/Source/Engine/Physics/Types.h index 6465dd900..614322488 100644 --- a/Source/Engine/Physics/Types.h +++ b/Source/Engine/Physics/Types.h @@ -39,6 +39,7 @@ namespace physx class PxController; class PxCapsuleController; class PxQueryFilterCallback; + class PxControllerFilterCallback; class PxHeightField; struct PxFilterData; struct PxRaycastHit;