Преглед изворни кода

Added CCD
Added flags for ignoring collision callbacks for better performance

BearishSun пре 9 година
родитељ
комит
39db4c5d63

+ 10 - 0
BansheeCore/Include/BsCCollider.h

@@ -59,6 +59,12 @@ namespace BansheeEngine
 		/** @copydoc Collider::getLayer */
 		UINT64 getLayer() const { return mLayer; }
 
+		/** @copydoc Collider::setCollisionReportMode */
+		inline void setCollisionReportMode(CollisionReportMode mode);
+
+		/** @copydoc Collider::getCollisionReportMode */
+		CollisionReportMode getCollisionReportMode() const { return mCollisionReportMode; }
+
 		/** @copydoc Collider::getRigidbody */
 		HRigidbody getRigidbody() const { return mParent; }
 
@@ -137,6 +143,9 @@ namespace BansheeEngine
 		 */
 		void updateTransform();
 
+		/** Applies the collision report mode to the internal collider depending on the current state. */
+		void updateCollisionReportMode();
+
 		/** Searches the parent scene object hierarchy to find a parent Rigidbody component. */
 		void updateParentRigidbody();
 
@@ -152,6 +161,7 @@ namespace BansheeEngine
 		SPtr<Collider> mInternal;
 
 		UINT64 mLayer = 1;
+		CollisionReportMode mCollisionReportMode = CollisionReportMode::None;
 		float mRestOffset = 0.0f;
 		float mContactOffset = 0.0f;
 		HPhysicsMaterial mMaterial;

+ 2 - 0
BansheeCore/Include/BsCColliderRTTI.h

@@ -23,6 +23,7 @@ namespace BansheeEngine
 		BS_PLAIN_MEMBER(mIsTrigger)
 		BS_PLAIN_MEMBER(mLocalPosition)
 		BS_PLAIN_MEMBER(mLocalRotation)
+		BS_PLAIN_MEMBER(mCollisionReportMode)
 
 	public:
 		CColliderRTTI()
@@ -35,6 +36,7 @@ namespace BansheeEngine
 			BS_ADD_PLAIN_FIELD(mIsTrigger, 5);
 			BS_ADD_PLAIN_FIELD(mLocalPosition, 6);
 			BS_ADD_PLAIN_FIELD(mLocalRotation, 7);
+			BS_ADD_PLAIN_FIELD(mCollisionReportMode, 8);
 		}
 
 		const String& getRTTIName() override

+ 15 - 0
BansheeCore/Include/BsCRigidbody.h

@@ -120,6 +120,19 @@ namespace BansheeEngine
 		/** @copydoc Rigidbody::getVelocitySolverCount */
 		UINT32 getVelocitySolverCount() const { return mVelocitySolverCount; }
 
+		/** @copydoc Rigidbody::setInterpolationMode */
+		void setInterpolationMode(Rigidbody::InterpolationMode value);
+
+		/** @copydoc Rigidbody::getInterpolationMode */
+		Rigidbody::InterpolationMode getInterpolationMode(Rigidbody::InterpolationMode value) const 
+			{ return mInterpolationMode; }
+
+		/** Sets a value that determines which (if any) collision events are reported. */
+		inline void setCollisionReportMode(CollisionReportMode mode);
+
+		/** Gets a value that determines which (if any) collision events are reported. */
+		CollisionReportMode getCollisionReportMode() const { return mCollisionReportMode; }
+
 		/** @copydoc Rigidbody::setFlags */
 		inline void setFlags(Rigidbody::Flag flags);
 
@@ -224,6 +237,8 @@ namespace BansheeEngine
 		UINT32 mPositionSolverCount = 4;
 		UINT32 mVelocitySolverCount = 1;
 		Rigidbody::Flag mFlags = (Rigidbody::Flag)((UINT32)Rigidbody::Flag::AutoTensors | (UINT32)Rigidbody::Flag::AutoMass);
+		Rigidbody::InterpolationMode mInterpolationMode = Rigidbody::InterpolationMode::None;
+		CollisionReportMode mCollisionReportMode = CollisionReportMode::None;
 		Vector3 mCMassPosition;
 		Quaternion mCMassRotation;
 		Vector3 mIntertiaTensor;

+ 5 - 0
BansheeCore/Include/BsCRigidbodyRTTI.h

@@ -30,6 +30,9 @@ namespace BansheeEngine
 		BS_PLAIN_MEMBER(mSleepThreshold);
 		BS_PLAIN_MEMBER(mUseGravity);
 		BS_PLAIN_MEMBER(mIsKinematic);
+		BS_PLAIN_MEMBER(mInterpolationMode);
+		BS_PLAIN_MEMBER(mCollisionReportMode);
+
 	public:
 		CRigidbodyRTTI()
 		{
@@ -46,6 +49,8 @@ namespace BansheeEngine
 			BS_ADD_PLAIN_FIELD(mSleepThreshold, 10);
 			BS_ADD_PLAIN_FIELD(mUseGravity, 11);
 			BS_ADD_PLAIN_FIELD(mIsKinematic, 12);
+			BS_ADD_PLAIN_FIELD(mInterpolationMode, 13);
+			BS_ADD_PLAIN_FIELD(mCollisionReportMode, 14);
 		}
 
 		const String& getRTTIName() override

+ 6 - 0
BansheeCore/Include/BsCollider.h

@@ -42,6 +42,12 @@ namespace BansheeEngine
 		inline void setLayer(UINT64 layer);
 		inline UINT64 getLayer() const;
 
+		/** Sets a value that determines which (if any) collision events are reported. */
+		inline void setCollisionReportMode(CollisionReportMode mode);
+
+		/** Gets a value that determines which (if any) collision events are reported. */
+		inline CollisionReportMode getCollisionReportMode() const;
+
 		/** 
 		 * Checks does the ray hit this collider. 
 		 *

+ 10 - 4
BansheeCore/Include/BsFCollider.h

@@ -3,6 +3,7 @@
 #pragma once
 
 #include "BsCorePrerequisites.h"
+#include "BsPhysicsCommon.h"
 #include "BsVector3.h"
 #include "BsQuaternion.h"
 
@@ -52,12 +53,17 @@ namespace BansheeEngine
 		/** Returns shepe's rest offset in meters. See setRestOffset() to learn what contact offset is. */
 		virtual float getRestOffset() const = 0;
 
-		virtual void setLayer(UINT64 layer);
-		virtual UINT64 getLayer() const { return mLayer; }
+		virtual void setLayer(UINT64 layer) = 0;
+		virtual UINT64 getLayer() const = 0;
+
+		virtual void setCollisionReportMode(CollisionReportMode mode);
+		virtual CollisionReportMode getCollisionReportMode() const = 0;
+
+		/** Enables continous collision detect for this collider. Only valid if the collider is a part of a rigidbody. */
+		virtual void _setCCD(bool enabled) = 0;
 	protected:
-		UINT64 mLayer = 1;
 		float mMass = 1.0f;
-
+		
 		HPhysicsMaterial mMaterial;
 	};
 }

+ 7 - 2
BansheeCore/Include/BsPhysics.h

@@ -35,7 +35,12 @@ namespace BansheeEngine
 		 *
 		 * @see Physics::getMaxTesselationEdgeLength
 		 */
-		CCT_Tesselation = 1<<2
+		CCT_Tesselation = 1<<2,
+		/** 
+		 * Enables continous collision detection. This will prevent fast-moving objects from tunneling through each other.
+		 * You must also enable CCD for individual Rigidbodies. This option can have a significant performance impact.
+		 */
+		CCD_Enable = 1<<3
 	};
 
 	/** @copydoc CharacterCollisionFlag */
@@ -511,6 +516,6 @@ namespace BansheeEngine
 		Vector3 gravity = Vector3(0.0f, -9.81f, 0.0f);
 		bool initCooking = true; // TODO: Disable this for Game build
 		float timeStep = 1.0f / 60.0f;
-		PhysicsFlags flags = PhysicsFlag::CCT_OverlapRecovery | PhysicsFlag::CCT_PreciseSweeps;
+		PhysicsFlags flags = PhysicsFlag::CCT_OverlapRecovery | PhysicsFlag::CCT_PreciseSweeps || PhysicsFlag::CCD_Enable;
 	};
 }

+ 12 - 0
BansheeCore/Include/BsPhysicsCommon.h

@@ -47,6 +47,18 @@ namespace BansheeEngine
 		void* ownerData = nullptr; /**< Data managed by the owner. */
 	};
 
+	/** Determines which collision events will be reported by physics objects. */
+	enum class CollisionReportMode
+	{
+		None, /**< No collision events will be triggered. */
+		Report, /**< Collision events will be triggered when object enters and/or leaves collision. */
+		/** 
+		 * Collision events will be triggered when object enters and/or leaves collision, but also every frame the object
+		 * remains in collision. 
+		 */
+		ReportPersistent, 
+	};
+
 	/** Hit information from a physics query. */
 	struct PhysicsQueryHit
 	{

+ 36 - 0
BansheeCore/Include/BsRigidbody.h

@@ -47,6 +47,35 @@ namespace BansheeEngine
 			AutoTensors = 0x01,
 			/** Calculate mass distribution from child shapes (colliders). Only relevant when auto-tensors is on. */
 			AutoMass = 0x02,
+			/** 
+			 * Enables continous collision detection. This can prevent fast moving bodies from tunneling through each other.
+			 * This must also be enabled globally in Physics otherwise the flag will be ignored.
+			 */
+			CCD = 0x04
+		};
+
+		/** Determines interpolation mode for a rigidbody transform during physics simulation. */
+		enum class InterpolationMode
+		{
+			/** 
+			 * No interpolation is performed, physics transform is copied straight to the rigidbody when physics tick is 
+			 * done. 
+			 */
+			None, 
+			/** 
+			 * Physics transfrom from the most recent tick is saved and slowly interpolated to during the following render 
+			 * frames. This can improve smoothness of the visible movement at framerates higher than the physics simulation 
+			 * but will introduce a delay of one physics tick to all such objects. This can create slight inconsistencies as
+			 * non-interpolated objects will have no such delay, as well as cause input lag due to the delayed reaction.
+			 */
+			Interpolate, 
+			/** 
+			 * Physics transform movement will be extrapolated from the last physics simulation tick. This will improve
+			 * smoothness of visible movement at framerates higher than the physics simulation. Unlike Interpolate it will
+			 * not introduce an input delay, but will introduce an error as the exact position/rotation of the objects is
+			 * extrapolated from the last frame's movement and velocities. 
+			 */
+			Extrapolate
 		};
 
 		/** 
@@ -206,6 +235,12 @@ namespace BansheeEngine
 		/** Gets the number of iterations to use when solving for velocity. */
 		virtual UINT32 getVelocitySolverCount() const = 0;
 
+		/** Sets interpolation mode that controls how is the rigidbody transfrom updated from the physics simulation. */
+		virtual void setInterpolationMode(InterpolationMode value) { mInterpolationMode = value; }
+
+		/** Gets interpolation mode that controls how is the rigidbody transfrom updated from the physics simulation. */
+		virtual InterpolationMode getInterpolationMode(InterpolationMode value) const { return mInterpolationMode; }
+
 		/** Sets flags that control the behaviour of the rigidbody. */
 		virtual void setFlags(Flag flags) { mFlags = flags; }
 
@@ -318,6 +353,7 @@ namespace BansheeEngine
 		friend class FCollider;
 
 		Flag mFlags = Flag::None;
+		InterpolationMode mInterpolationMode = InterpolationMode::None;
 		PhysicsObjectOwner mOwner;
 		UINT32 mPriority = 0;
 		UINT32 mPhysicsId = 0;

+ 33 - 16
BansheeCore/Source/BsCCollider.cpp

@@ -82,6 +82,14 @@ namespace BansheeEngine
 			mInternal->setLayer(layer);
 	}
 
+	void CCollider::setCollisionReportMode(CollisionReportMode mode)
+	{
+		mCollisionReportMode = mode;
+
+		if (mInternal != nullptr)
+			updateCollisionReportMode();
+	}
+
 	void CCollider::onInitialized()
 	{
 
@@ -121,29 +129,27 @@ namespace BansheeEngine
 
 	void CCollider::setRigidbody(const HRigidbody& rigidbody, bool internal)
 	{
-		Rigidbody* rigidBodyPtr;
-
-		if (rigidbody != nullptr)
-			rigidBodyPtr = rigidbody->_getInternal();
+		if (rigidbody == mParent)
+			return;
 
-		if (mInternal == nullptr)
+		if (mInternal != nullptr && !internal)
 		{
-			if (rigidbody == mParent)
-				return;
+			if (mParent != nullptr)
+				mParent->removeCollider(mThisHandle);
 
-			if (!internal)
-			{
-				if (mParent != nullptr)
-					mParent->removeCollider(mThisHandle);
+			Rigidbody* rigidBodyPtr = nullptr;
 
-				mInternal->setRigidbody(rigidBodyPtr);
+			if (rigidbody != nullptr)
+				rigidBodyPtr = rigidbody->_getInternal();
 
-				if (rigidbody != nullptr)
-					rigidbody->addCollider(mThisHandle);
-			}
+			mInternal->setRigidbody(rigidBodyPtr);
 
-			mParent = rigidbody;
+			if (rigidbody != nullptr)
+				rigidbody->addCollider(mThisHandle);
 		}
+
+		mParent = rigidbody;
+		updateCollisionReportMode();
 	}
 
 	bool CCollider::rayCast(const Ray& ray, PhysicsQueryHit& hit, float maxDist) const
@@ -184,6 +190,7 @@ namespace BansheeEngine
 
 		updateParentRigidbody();
 		updateTransform();
+		updateCollisionReportMode();
 	}
 
 	void CCollider::destroyInternal()
@@ -265,6 +272,16 @@ namespace BansheeEngine
 		}
 	}
 
+	void CCollider::updateCollisionReportMode()
+	{
+		CollisionReportMode mode = mCollisionReportMode;
+
+		if (mParent != nullptr)
+			mode = mParent->getCollisionReportMode();
+
+		mInternal->setCollisionReportMode(mode);
+	}
+
 	void CCollider::triggerOnCollisionBegin(const CollisionData& data)
 	{
 		// Const-cast and modify is okay because we're the only object receiving this event

+ 21 - 0
BansheeCore/Source/BsCRigidbody.cpp

@@ -197,6 +197,25 @@ namespace BansheeEngine
 			mInternal->setVelocitySolverCount(count);
 	}
 
+	void CRigidbody::setInterpolationMode(Rigidbody::InterpolationMode value)
+	{
+		mInterpolationMode = value;
+
+		if (mInternal != nullptr)
+			mInternal->setInterpolationMode(value);
+	}
+
+	void CRigidbody::setCollisionReportMode(CollisionReportMode mode)
+	{
+		if (mCollisionReportMode == mode)
+			return;
+
+		mCollisionReportMode = mode;
+
+		for (auto& entry : mChildren)
+			entry->updateCollisionReportMode();
+	}
+
 	void CRigidbody::setFlags(Rigidbody::Flag flags)
 	{
 		mFlags = flags;
@@ -421,6 +440,8 @@ namespace BansheeEngine
 		mInternal->setSleepThreshold(mSleepThreshold);
 		mInternal->setUseGravity(mUseGravity);
 		mInternal->setIsKinematic(mIsKinematic);
+		mInternal->setInterpolationMode(mInterpolationMode);
+		mInternal->setFlags(mFlags);
 
 		if(((UINT32)mFlags & (UINT32)Rigidbody::Flag::AutoTensors) == 0)
 		{

+ 10 - 0
BansheeCore/Source/BsCollider.cpp

@@ -100,6 +100,16 @@ namespace BansheeEngine
 		return mInternal->getLayer();
 	}
 
+	void Collider::setCollisionReportMode(CollisionReportMode mode)
+	{
+		mInternal->setCollisionReportMode(mode);
+	}
+
+	CollisionReportMode Collider::getCollisionReportMode() const
+	{
+		return mInternal->getCollisionReportMode();
+	}
+
 	bool Collider::rayCast(const Ray& ray, PhysicsQueryHit& hit, float maxDist) const
 	{
 		return gPhysics()._rayCast(ray.getOrigin(), ray.getDirection(), *this, hit, maxDist);

+ 2 - 2
BansheeCore/Source/BsFCollider.cpp

@@ -13,8 +13,8 @@ namespace BansheeEngine
 		mMaterial = material;
 	}
 
-	void FCollider::setLayer(UINT64 layer)
+	void FCollider::setCollisionReportMode(CollisionReportMode mode)
 	{
-		mLayer = layer;
+		mCollisionReportMode = mode;
 	}
 }

+ 22 - 4
BansheePhysX/Include/BsFPhysXCollider.h

@@ -56,16 +56,34 @@ namespace BansheeEngine
 		/** @copydoc FCollider::setMaterial */
 		void setMaterial(const HPhysicsMaterial& material) override;
 
+		/** @copydoc FCollider::getLayer */
+		UINT64 getLayer() const override;
+
 		/** @copydoc FCollider::setLayer */
 		void setLayer(UINT64 layer) override;
 
+		/** @copydoc FCollider::getCollisionReportMode */
+		CollisionReportMode getCollisionReportMode() const override;
+
+		/** @copydoc FCollider::setCollisionReportMode */
+		void setCollisionReportMode(CollisionReportMode mode) override;
+
+		/** @copydoc FCollider::_setCCD */
+		void _setCCD(bool enabled) override;
+
 		/** Gets the internal PhysX shape that represents the collider. */
 		physx::PxShape* _getShape() const { return mShape; }
 	protected:
-		physx::PxShape* mShape;
-		physx::PxRigidStatic* mStaticBody;
-		bool mIsTrigger;
-		bool mIsStatic;
+		/** Updates shape filter data from stored values. */
+		void updateFilter();
+
+		physx::PxShape* mShape = nullptr;
+		physx::PxRigidStatic* mStaticBody = nullptr;
+		bool mIsTrigger = false;
+		bool mIsStatic = true;
+		UINT64 mLayer = 1;
+		bool mCCD = false;
+		CollisionReportMode mCollisionReportMode = CollisionReportMode::None;
 	};
 
 	/** @} */

+ 20 - 0
BansheePhysX/Include/BsPhysXPrerequisites.h

@@ -46,38 +46,58 @@ namespace BansheeEngine
 		TID_PhysXMesh = 100000,
 	};
 
+	/** Converts a Banshee vector to a PhysX vector. */
 	inline const physx::PxVec3& toPxVector(const Vector3& input)
 	{
 		return *(physx::PxVec3*)&input;
 	}
 
+	/** Converts a Banshee vector to a PhysX vector. */
 	inline const physx::PxVec4& toPxVector(const Vector4& input)
 	{
 		return *(physx::PxVec4*)&input;
 	}
 
+	/** Converts a Banshee quaternion to a PhysX quaternion. */
 	inline const physx::PxQuat& toPxQuaternion(const Quaternion& input)
 	{
 		return *(physx::PxQuat*)&input;
 	}
 
+	/** Converts a Banshee position/rotation pair to a PhysX transform. */
 	inline physx::PxTransform toPxTransform(const Vector3& pos, const Quaternion& rot)
 	{
 		return physx::PxTransform(toPxVector(pos), toPxQuaternion(rot));
 	}
 
+	/** Converts a PhysX vector to a Banshee vector. */
 	inline const Vector3& fromPxVector(const physx::PxVec3& input)
 	{
 		return *(Vector3*)&input;
 	}
 
+	/** Converts a PhysX vector to a Banshee vector. */
 	inline const Vector4& fromPxVector(const physx::PxVec4& input)
 	{
 		return *(Vector4*)&input;
 	}
 
+	/** Converts a PhysX quaternion to a Banshee quaternion. */
 	inline const Quaternion& fromPxQuaternion(const physx::PxQuat& input)
 	{
 		return *(Quaternion*)&input;
 	}
+
+	/** Flags used on PhysX shape filters. */
+	enum class PhysXObjectFilterFlag
+	{
+		NoReport = 1 << 0, /**< Don't report collision events. */
+		ReportBasic = 1 << 1, /**< Report start/begin collision events. */
+		ReportAll = 1 << 2, /**< Report start/begin, as well as persistant collision events. */
+		CCD = 1 << 3 /**< Use continous collision detection for this shape. */
+	};
+
+	/** @copydoc ObjectFilterFlag */
+	typedef Flags<PhysXObjectFilterFlag> PhysXObjectFilterFlags;
+	BS_FLAGS_OPERATORS(PhysXObjectFilterFlag)
 }

+ 3 - 0
BansheePhysX/Include/BsPhysXRigidbody.h

@@ -126,6 +126,9 @@ namespace BansheeEngine
 		/** @copydoc Rigidbody::getVelocitySolverCount */
 		UINT32 getVelocitySolverCount() const override;
 
+		/** @copydoc Rigidbody::setFlags */
+		void setFlags(Flag flags) override;
+
 		/** @copydoc Rigidbody::addForce */
 		void addForce(const Vector3& force, ForceMode mode = ForceMode::Force) override;
 

+ 49 - 9
BansheePhysX/Source/BsFPhysXCollider.cpp

@@ -10,20 +10,15 @@ using namespace physx;
 namespace BansheeEngine
 {
 	FPhysXCollider::FPhysXCollider(PxShape* shape)
-		:mShape(shape), mStaticBody(nullptr), mIsTrigger(false), mIsStatic(true)
+		:mShape(shape)
 	{
-		UINT64 layer = 1;
-
-		PxFilterData data;
-		memcpy(&data.word0, &layer, sizeof(layer));
-		mShape->setSimulationFilterData(data);
-		mShape->setQueryFilterData(data);
-
 		mStaticBody = gPhysX().getPhysX()->createRigidStatic(PxTransform());
 		mStaticBody->attachShape(*mShape);
 
 		PxScene* scene = gPhysX().getScene();
 		scene->addActor(*mStaticBody);
+
+		updateFilter();
 	}
 
 	FPhysXCollider::~FPhysXCollider()
@@ -139,11 +134,56 @@ namespace BansheeEngine
 		mShape->setMaterials(materials, sizeof(materials));
 	}
 
+	UINT64 FPhysXCollider::getLayer() const
+	{
+		return mLayer;
+	}
+
 	void FPhysXCollider::setLayer(UINT64 layer)
+	{
+		mLayer = layer;
+		updateFilter();
+	}
+
+	CollisionReportMode FPhysXCollider::getCollisionReportMode() const
+	{
+		return mCollisionReportMode;
+	}
+
+	void FPhysXCollider::setCollisionReportMode(CollisionReportMode mode)
+	{
+		mCollisionReportMode = mode;
+		updateFilter();
+	}
+
+	void FPhysXCollider::_setCCD(bool enabled)
+	{
+		mCCD = enabled;
+		updateFilter();
+	}
+
+	void FPhysXCollider::updateFilter()
 	{
 		PxFilterData data;
-		memcpy(&data.word0, &layer, sizeof(layer));
+		memcpy(&data.word0, &mLayer, sizeof(mLayer));
 		mShape->setSimulationFilterData(data);
 		mShape->setQueryFilterData(data);
+
+		PhysXObjectFilterFlags flags;
+
+		switch(mCollisionReportMode)
+		{
+		case CollisionReportMode::None:
+			flags |= PhysXObjectFilterFlag::NoReport;
+		case CollisionReportMode::Report:
+			flags |= PhysXObjectFilterFlag::ReportBasic;
+		case CollisionReportMode::ReportPersistent:
+			flags |= PhysXObjectFilterFlag::ReportAll;
+		}
+
+		if (mCCD)
+			flags |= PhysXObjectFilterFlag::CCD;
+
+		data.word2 = flags;
 	}
 }

+ 69 - 21
BansheePhysX/Source/BsPhysX.cpp

@@ -128,24 +128,46 @@ namespace BansheeEngine
 			for (PxU32 i = 0; i < count; i++)
 			{
 				const PxTriggerPair& pair = pairs[i];
-
+				
 				PhysX::ContactEventType type;
 				bool ignoreContact = false;
-				switch ((UINT32)pair.status)
+				PhysXObjectFilterFlags flags = PhysXObjectFilterFlags(pair.triggerShape->getSimulationFilterData().word2);
+
+				if (flags.isSet(PhysXObjectFilterFlag::ReportAll))
 				{
-				case PxPairFlag::eNOTIFY_TOUCH_FOUND:
-					type = PhysX::ContactEventType::ContactBegin;
-					break;
-				case PxPairFlag::eNOTIFY_TOUCH_PERSISTS:
-					type = PhysX::ContactEventType::ContactStay;
-					break;
-				case PxPairFlag::eNOTIFY_TOUCH_LOST:
-					type = PhysX::ContactEventType::ContactEnd;
-					break;
-				default:
-					ignoreContact = true;
-					break;
+					switch ((UINT32)pair.status)
+					{
+					case PxPairFlag::eNOTIFY_TOUCH_FOUND:
+						type = PhysX::ContactEventType::ContactBegin;
+						break;
+					case PxPairFlag::eNOTIFY_TOUCH_PERSISTS:
+						type = PhysX::ContactEventType::ContactStay;
+						break;
+					case PxPairFlag::eNOTIFY_TOUCH_LOST:
+						type = PhysX::ContactEventType::ContactEnd;
+						break;
+					default:
+						ignoreContact = true;
+						break;
+					}
 				}
+				else if (flags.isSet(PhysXObjectFilterFlag::ReportBasic))
+				{
+					switch ((UINT32)pair.status)
+					{
+					case PxPairFlag::eNOTIFY_TOUCH_FOUND:
+						type = PhysX::ContactEventType::ContactBegin;
+						break;
+					case PxPairFlag::eNOTIFY_TOUCH_LOST:
+						type = PhysX::ContactEventType::ContactEnd;
+						break;
+					default:
+						ignoreContact = true;
+						break;
+					}
+				}
+				else
+					ignoreContact = true;
 
 				if (ignoreContact)
 					continue;
@@ -187,8 +209,6 @@ namespace BansheeEngine
 					continue;
 
 				PhysX::ContactEvent event;
-				event.colliderA = (Collider*)pair.shapes[0]->userData;
-				event.colliderB = (Collider*)pair.shapes[1]->userData;
 				event.type = type;
 
 				PxU32 contactCount = pair.contactCount;
@@ -229,6 +249,9 @@ namespace BansheeEngine
 					}
 				}
 
+				event.colliderA = (Collider*)pair.shapes[0]->userData;
+				event.colliderB = (Collider*)pair.shapes[1]->userData;
+
 				gPhysX()._reportContactEvent(event);
 			}
 		}
@@ -287,9 +310,17 @@ namespace BansheeEngine
 	PxFilterFlags PhysXFilterShader(PxFilterObjectAttributes attr0, PxFilterData data0, PxFilterObjectAttributes attr1, 
 		PxFilterData data1, PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
 	{
+		PhysXObjectFilterFlags flags0 = PhysXObjectFilterFlags(data0.word2);
+		PhysXObjectFilterFlags flags1 = PhysXObjectFilterFlags(data1.word2);
+
+		if (flags0.isSet(PhysXObjectFilterFlag::ReportAll) || flags1.isSet(PhysXObjectFilterFlag::ReportAll))
+			pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND | PxPairFlag::eNOTIFY_TOUCH_LOST | PxPairFlag::eNOTIFY_TOUCH_PERSISTS;
+		else if (flags0.isSet(PhysXObjectFilterFlag::ReportBasic) || flags1.isSet(PhysXObjectFilterFlag::ReportBasic))
+			pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND | PxPairFlag::eNOTIFY_TOUCH_LOST;
+
 		if (PxFilterObjectIsTrigger(attr0) || PxFilterObjectIsTrigger(attr1))
 		{
-			pairFlags = PxPairFlag::eTRIGGER_DEFAULT;
+			pairFlags |= PxPairFlag::eDETECT_DISCRETE_CONTACT;
 			return PxFilterFlags();
 		}
 
@@ -300,7 +331,10 @@ namespace BansheeEngine
 		if (!canCollide)
 			return PxFilterFlag::eSUPPRESS;
 
-		pairFlags = PxPairFlag::eCONTACT_DEFAULT;
+		if (flags0.isSet(PhysXObjectFilterFlag::CCD) || flags1.isSet(PhysXObjectFilterFlag::CCD))
+			pairFlags |= PxPairFlag::eDETECT_CCD_CONTACT;
+
+		pairFlags |= PxPairFlag::eSOLVE_CONTACT | PxPairFlag::eDETECT_DISCRETE_CONTACT;
 		return PxFilterFlags();
 	}
 
@@ -430,9 +464,12 @@ namespace BansheeEngine
 		sceneDesc.simulationEventCallback = &gPhysXEventCallback;
 		sceneDesc.broadPhaseCallback = &gPhysXBroadphaseCallback;
 
-		// Optionally: eENABLE_CCD, eENABLE_KINEMATIC_STATIC_PAIRS, eENABLE_KINEMATIC_PAIRS, eENABLE_PCM
+		// Optionally: eENABLE_KINEMATIC_STATIC_PAIRS, eENABLE_KINEMATIC_PAIRS, eENABLE_PCM
 		sceneDesc.flags = PxSceneFlag::eENABLE_ACTIVETRANSFORMS;
 
+		if (input.flags.isSet(PhysicsFlag::CCD_Enable))
+			sceneDesc.flags |= PxSceneFlag::eENABLE_CCD;
+
 		// Optionally: eMBP
 		sceneDesc.broadPhaseType = PxBroadPhaseType::eSAP;
 
@@ -604,8 +641,19 @@ namespace BansheeEngine
 
 		for (auto& entry : mContactEvents)
 		{
-			notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
-			notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
+			CollisionReportMode reportModeA = entry.colliderA->getCollisionReportMode();
+
+			if (reportModeA == CollisionReportMode::ReportPersistent)
+				notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
+			else if (reportModeA == CollisionReportMode::Report && entry.type != ContactEventType::ContactStay)
+				notifyContact(entry.colliderA, entry.colliderB, entry.type, entry.points, true);
+
+			CollisionReportMode reportModeB = entry.colliderB->getCollisionReportMode();
+
+			if (reportModeB == CollisionReportMode::ReportPersistent)
+				notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
+			else if (reportModeB == CollisionReportMode::Report && entry.type != ContactEventType::ContactStay)
+				notifyContact(entry.colliderB, entry.colliderA, entry.type, entry.points, false);
 		}
 
 		for(auto& entry : mJointBreakEvents)

+ 41 - 0
BansheePhysX/Source/BsPhysXRigidbody.cpp

@@ -2,6 +2,7 @@
 #include "BsCollider.h"
 #include "BsFPhysXCollider.h"
 #include "BsSceneObject.h"
+#include "BsPhysics.h"
 #include "PxRigidDynamic.h"
 #include "PxScene.h"
 #include "extensions\PxRigidBodyExt.h"
@@ -270,6 +271,37 @@ namespace BansheeEngine
 		return velCount;
 	}
 
+	void PhysXRigidbody::setFlags(Flag flags)
+	{
+		bool ccdEnabledOld = mInternal->getRigidBodyFlags() & PxRigidBodyFlag::eENABLE_CCD;
+		bool ccdEnabledNew = ((UINT32)flags & (UINT32)Flag::CCD) != 0;
+		
+		if(ccdEnabledOld != ccdEnabledNew)
+		{
+			if(ccdEnabledNew)
+			{
+				if (!gPhysics().hasFlag(PhysicsFlag::CCD_Enable))
+					LOGWRN("Enabling CCD on a Rigidbody but CCD is not enabled globally.");
+			}
+
+			mInternal->setRigidBodyFlag(PxRigidBodyFlag::eENABLE_CCD, ccdEnabledNew);
+
+			// Enable/disable CCD on shapes so the filter can handle them properly
+			UINT32 numShapes = mInternal->getNbShapes();
+			PxShape** shapes = (PxShape**)bs_stack_alloc(sizeof(PxShape*) * numShapes);
+
+			mInternal->getShapes(shapes, sizeof(PxShape*) * numShapes);
+
+			for (UINT32 i = 0; i < numShapes; i++)
+			{
+				Collider* collider = (Collider*)shapes[i]->userData;
+				collider->_getInternal()->_setCCD(ccdEnabledNew);
+			}
+		}
+
+		Rigidbody::setFlags(flags);
+	}
+
 	void PhysXRigidbody::addForce(const Vector3& force, ForceMode mode)
 	{
 		mInternal->addForce(toPxVector(force), toPxForceMode(mode));
@@ -342,6 +374,8 @@ namespace BansheeEngine
 			return;
 
 		FPhysXCollider* physxCollider = static_cast<FPhysXCollider*>(collider);
+		physxCollider->_setCCD(((UINT32)mFlags & (UINT32)Flag::CCD) != 0);
+
 		mInternal->attachShape(*physxCollider->_getShape());
 	}
 
@@ -351,6 +385,8 @@ namespace BansheeEngine
 			return;
 
 		FPhysXCollider* physxCollider = static_cast<FPhysXCollider*>(collider);
+		physxCollider->_setCCD(false);
+
 		mInternal->detachShape(*physxCollider->_getShape());
 	}
 
@@ -362,6 +398,11 @@ namespace BansheeEngine
 		mInternal->getShapes(shapes, sizeof(PxShape*) * numShapes);
 
 		for (UINT32 i = 0; i < numShapes; i++)
+		{
+			Collider* collider = (Collider*)shapes[i]->userData;
+			collider->_getInternal()->_setCCD(false);
+
 			mInternal->detachShape(*shapes[i]);
+		}
 	}
 }

+ 1 - 1
README.md

@@ -14,7 +14,7 @@ For engine developers it aims to provide a high quality foundation to build and
 
 * [Features](Documentation/GitHub/features.md)
 * [Roadmap](Documentation/GitHub/roadmap.md)
-* [Install](Documentation/GitHub/install.md)
+* [Download](Documentation/GitHub/install.md)
 * [Compiling](Documentation/GitHub/compiling.md)
 * [Documentation](Documentation/GitHub/documentation.md)
 * [License](Documentation/GitHub/license.md)