瀏覽代碼

Added global physics option and initialization structure

BearishSun 9 年之前
父節點
當前提交
33033c5265

+ 1 - 1
BansheeCore/Include/BsCharacterController.h

@@ -25,7 +25,7 @@ namespace BansheeEngine
 		PreventAndSlide /**< Character will be prevented from going further, but also slide down the slope. */
 	};
 
-	/** Reports in which directions is the character colliding with other objects */
+	/** Reports in which directions is the character colliding with other objects. */
 	enum class CharacterCollisionFlag
 	{
 		Sides = 0x1, /**< Character is colliding with its sides. */

+ 67 - 1
BansheeCore/Include/BsPhysics.h

@@ -9,10 +9,41 @@
 
 namespace BansheeEngine
 {
+	struct PHYSICS_INIT_DESC;
+
+	/** Flags for controlling physics behaviour globally. */
+	enum class PhysicsFlag
+	{
+		/** 
+		 * Automatically recovers character controllers that are interpenetrating geometry. This can happen if a controller
+		 * is spawned or teleported into geometry, its size/rotation is changed so it penetrates geometry, or simply
+		 * because of numerical imprecision.
+		 */
+		CCT_OverlapRecovery = 1<<0,
+		/**
+		 * Performs more accurate sweeps when moving the character controller, making it less likely to interpenetrate
+		 * geometry. When overlap recovery is turned on you can consider turning this off as it can compensate for the
+		 * less precise sweeps.
+		 */
+		CCT_PreciseSweeps = 1<<1,
+		/**
+		 * Large triangles can cause problems with character controller collision. If this option is enabled the triangles
+		 * larger than a certain size will be automatically tesselated into smaller triangles, in order to help with
+		 * precision.
+		 *
+		 * @see Physics::getMaxTesselationEdgeLength
+		 */
+		CCT_Tesselation = 1<<2
+	};
+
+	/** @copydoc CharacterCollisionFlag */
+	typedef Flags<PhysicsFlag> PhysicsFlags;
+	BS_FLAGS_OPERATORS(PhysicsFlag)
+
 	class BS_CORE_EXPORT Physics : public Module<Physics>
 	{
 	public:
-		Physics();
+		Physics(const PHYSICS_INIT_DESC& init);
 		virtual ~Physics() { }
 
 		virtual void update() = 0;
@@ -40,6 +71,30 @@ namespace BansheeEngine
 		/** @copydoc CharacterController::create */
 		virtual SPtr<CharacterController> createCharacterController(const CHAR_CONTROLLER_DESC& desc) = 0;
 
+		virtual bool hasFlag(PhysicsFlags flag) const { return mFlags & flag; }
+		virtual void setFlag(PhysicsFlags flag, bool enabled) { if (enabled) mFlags |= flag; else mFlags &= ~flag; }
+
+		virtual Vector3 getGravity() const = 0;
+		virtual void setGravity(const Vector3& gravity) = 0;
+
+		virtual UINT32 addBroadPhaseRegion(const AABox& region) = 0;
+		virtual void removeBroadPhaseRegion(UINT32 handle) = 0;
+		virtual void clearBroadPhaseRegions() = 0;
+
+		/** 
+		 * Returns a maximum edge length before a triangle is tesselated. 
+		 *
+		 * @see PhysicsFlags::CCT_Tesselation
+		 */
+		virtual float getMaxTesselationEdgeLength() const = 0;
+
+		/** 
+		 * Sets a maximum edge length before a triangle is tesselated. 
+		 *
+		 * @see PhysicsFlags::CCT_Tesselation
+		 */
+		virtual void setMaxTesselationEdgeLength(float length) = 0;
+
 		void toggleCollision(UINT64 groupA, UINT64 groupB, bool enabled);
 		bool isCollisionEnabled(UINT64 groupA, UINT64 groupB) const;
 
@@ -57,6 +112,7 @@ namespace BansheeEngine
 		bool mCollisionMap[CollisionMapSize][CollisionMapSize];
 
 		bool mUpdateInProgress = false;
+		PhysicsFlags mFlags;
 		Vector<Vector<Rigidbody*>> mRigidbodies; // TODO: Unused for now, but keeping it here just in case I change the design. Remove later.
 
 		const static UINT32 MAX_PRIORITY = 128;
@@ -64,4 +120,14 @@ namespace BansheeEngine
 
 	/** Provides easier access to Physics. */
 	BS_CORE_EXPORT Physics& gPhysics();
+
+	struct PHYSICS_INIT_DESC
+	{
+		float typicalLength = 1.0f;
+		float typicalSpeed = 9.81f;
+		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;
+	};
 }

+ 2 - 2
BansheeCore/Include/BsPhysicsManager.h

@@ -12,14 +12,14 @@ namespace BansheeEngine
 	public:
 		virtual ~PhysicsFactory() { }
 
-		virtual void startUp() = 0;
+		virtual void startUp(bool cooking) = 0;
 		virtual void shutDown() = 0;
 	};
 
 	class BS_CORE_EXPORT PhysicsManager : public Module<PhysicsManager>
 	{
 	public:
-		PhysicsManager(const String& pluginName);
+		PhysicsManager(const String& pluginName, bool cooking);
 		~PhysicsManager();
 
 	private:

+ 1 - 1
BansheeCore/Source/BsCoreApplication.cpp

@@ -151,7 +151,7 @@ namespace BansheeEngine
 		MaterialManager::startUp();
 		FontManager::startUp();
 		Importer::startUp();
-		PhysicsManager::startUp(mStartUpDesc.physics);
+		PhysicsManager::startUp(mStartUpDesc.physics, isEditor());
 
 		for (auto& importerName : mStartUpDesc.importers)
 			loadPlugin(importerName);

+ 1 - 1
BansheeCore/Source/BsPhysics.cpp

@@ -5,7 +5,7 @@
 
 namespace BansheeEngine
 {
-	Physics::Physics()
+	Physics::Physics(const PHYSICS_INIT_DESC& init)
 	{
 		memset(mCollisionMap, 1, CollisionMapSize * CollisionMapSize * sizeof(bool));
 	}

+ 2 - 2
BansheeCore/Source/BsPhysicsManager.cpp

@@ -6,7 +6,7 @@
 
 namespace BansheeEngine
 {
-	PhysicsManager::PhysicsManager(const String& pluginName)
+	PhysicsManager::PhysicsManager(const String& pluginName, bool cooking)
 		:mPlugin(nullptr), mFactory(nullptr)
 	{
 		mPlugin = DynLibManager::instance().load(pluginName);
@@ -19,7 +19,7 @@ namespace BansheeEngine
 			mFactory = loadPluginFunc();
 
 			if (mFactory != nullptr)
-				mFactory->startUp();
+				mFactory->startUp(cooking);
 		}
 	}
 

+ 16 - 1
BansheePhysX/Include/BsPhysX.h

@@ -42,7 +42,7 @@ namespace BansheeEngine
 		};
 
 	public:
-		PhysX();
+		PhysX(const PHYSICS_INIT_DESC& input);
 		~PhysX();
 
 		void update() override;
@@ -69,6 +69,18 @@ namespace BansheeEngine
 		/** @copydoc Physics::createCharacterController*/
 		SPtr<CharacterController> createCharacterController(const CHAR_CONTROLLER_DESC& desc) override;
 
+		void setFlag(PhysicsFlags flags, bool enabled) override;
+
+		Vector3 getGravity() const override;
+		void setGravity(const Vector3& gravity) override;
+
+		float getMaxTesselationEdgeLength() const override { return mTesselationLength; }
+		void setMaxTesselationEdgeLength(float length) override;
+
+		UINT32 addBroadPhaseRegion(const AABox& region) override;
+		void removeBroadPhaseRegion(UINT32 regionId) override;
+		void clearBroadPhaseRegions() override;
+
 		void _reportContactEvent(const ContactEvent& event);
 		void _reportTriggerEvent(const TriggerEvent& event);
 		void _reportJointBreakEvent(const JointBreakEvent& event);
@@ -86,10 +98,13 @@ namespace BansheeEngine
 
 		float mSimulationStep = 1.0f/60.0f;
 		float mLastSimulationTime = 0.0f;
+		float mTesselationLength = 3.0f;
+		UINT32 mNextRegionIdx = 1;
 
 		Vector<TriggerEvent> mTriggerEvents;
 		Vector<ContactEvent> mContactEvents;
 		Vector<JointBreakEvent> mJointBreakEvents;
+		UnorderedMap<UINT32, UINT32> mBroadPhaseRegionHandles;
 
 		physx::PxFoundation* mFoundation = nullptr;
 		physx::PxPhysics* mPhysics = nullptr;

+ 4 - 4
BansheePhysX/Include/BsPhysXCharacterController.h

@@ -10,10 +10,10 @@
 namespace BansheeEngine
 {
 	/** PhysX specific implementation if a CharacterController. */
-	class BS_PHYSX_EXPORT PhysXCharacterController : public CharacterController
-												   , physx::PxUserControllerHitReport
-		                                           , physx::PxQueryFilterCallback
-												   , physx::PxControllerFilterCallback
+	class PhysXCharacterController : public CharacterController
+								   , physx::PxUserControllerHitReport
+		                           , physx::PxQueryFilterCallback
+								   , physx::PxControllerFilterCallback
 	{
 	public:
 		PhysXCharacterController(physx::PxControllerManager* manager, const CHAR_CONTROLLER_DESC& desc);

+ 85 - 17
BansheePhysX/Source/BsPhysX.cpp

@@ -18,20 +18,12 @@
 #include "BsTaskScheduler.h"
 #include "BsTime.h"
 #include "Bsvector3.h"
+#include "BsAABox.h"
 
 using namespace physx;
 
 namespace BansheeEngine
 {
-	struct PHYSICS_INIT_DESC
-	{
-		float typicalLength = 1.0f;
-		float typicalSpeed = 9.81f;
-		Vector3 gravity = Vector3(0.0f, -9.81f, 0.0f);
-		bool initCooking = true; // TODO: Disable this for Game build
-		float timeStep = 1.0f / 60.0f;
-	};
-
 	class PhysXAllocator : public PxAllocatorCallback
 	{
 	public:
@@ -276,6 +268,18 @@ namespace BansheeEngine
 		}
 	};
 
+	class PhysXBroadPhaseCallback : public PxBroadPhaseCallback
+	{
+		void onObjectOutOfBounds(PxShape& shape, PxActor& actor) override
+		{
+			Collider* collider = (Collider*)shape.userData;
+			if (collider != nullptr)
+				LOGWRN("Physics object out of bounds. Consider increasing broadphase region!");
+		}
+
+		void onObjectOutOfBounds(PxAggregate& aggregate) override { /* Do nothing */ }
+	};
+
 	PxFilterFlags PhysXFilterShader(PxFilterObjectAttributes attr0, PxFilterData data0, PxFilterObjectAttributes attr1, 
 		PxFilterData data1, PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
 	{
@@ -300,11 +304,11 @@ namespace BansheeEngine
 	static PhysXErrorCallback gPhysXErrorHandler;
 	static PhysXCPUDispatcher gPhysXCPUDispatcher;
 	static PhysXEventCallback gPhysXEventCallback;
+	static PhysXBroadPhaseCallback gPhysXBroadphaseCallback;
 
-	PhysX::PhysX()
+	PhysX::PhysX(const PHYSICS_INIT_DESC& input)
+		:Physics(input)
 	{
-		PHYSICS_INIT_DESC input; // TODO - Make this an input parameter.
-
 		mScale.length = input.typicalLength;
 		mScale.speed = input.typicalSpeed;
 
@@ -327,8 +331,14 @@ namespace BansheeEngine
 		sceneDesc.cpuDispatcher = &gPhysXCPUDispatcher;
 		sceneDesc.filterShader = PhysXFilterShader;
 		sceneDesc.simulationEventCallback = &gPhysXEventCallback;
+		sceneDesc.broadPhaseCallback = &gPhysXBroadphaseCallback;
+
+		// Optionally: eENABLE_CCD, eENABLE_KINEMATIC_STATIC_PAIRS, eENABLE_KINEMATIC_PAIRS, eENABLE_PCM
 		sceneDesc.flags = PxSceneFlag::eENABLE_ACTIVETRANSFORMS;
 
+		// Optionally: eMBP
+		sceneDesc.broadPhaseType = PxBroadPhaseType::eSAP;
+
 		mScene = mPhysics->createScene(sceneDesc);
 
 		// Character controller
@@ -538,11 +548,6 @@ namespace BansheeEngine
 		return bs_shared_ptr_new<PhysXMeshCollider>(mPhysics, position, rotation);
 	}
 
-	SPtr<CharacterController> PhysX::createCharacterController(const CHAR_CONTROLLER_DESC& desc)
-	{
-		return bs_shared_ptr_new<PhysXCharacterController>(mCharManager, desc);
-	}
-
 	SPtr<FixedJoint> PhysX::createFixedJoint()
 	{
 		return bs_shared_ptr_new<PhysXFixedJoint>(mPhysics);
@@ -573,6 +578,69 @@ namespace BansheeEngine
 		return bs_shared_ptr_new<PhysXD6Joint>(mPhysics);
 	}
 
+	SPtr<CharacterController> PhysX::createCharacterController(const CHAR_CONTROLLER_DESC& desc)
+	{
+		return bs_shared_ptr_new<PhysXCharacterController>(mCharManager, desc);
+	}
+
+	void PhysX::setFlag(PhysicsFlags flag, bool enabled)
+	{
+		Physics::setFlag(flag, enabled);
+
+		mCharManager->setOverlapRecoveryModule(mFlags.isSet(PhysicsFlag::CCT_OverlapRecovery));
+		mCharManager->setPreciseSweeps(mFlags.isSet(PhysicsFlag::CCT_PreciseSweeps));
+		mCharManager->setTessellation(mFlags.isSet(PhysicsFlag::CCT_Tesselation), mTesselationLength);
+	}
+
+	Vector3 PhysX::getGravity() const
+	{
+		return fromPxVector(mScene->getGravity());
+	}
+
+	void PhysX::setGravity(const Vector3& gravity)
+	{
+		mScene->setGravity(toPxVector(gravity));
+	}
+
+	void PhysX::setMaxTesselationEdgeLength(float length)
+	{
+		mTesselationLength = length;
+
+		mCharManager->setTessellation(mFlags.isSet(PhysicsFlag::CCT_Tesselation), mTesselationLength);
+	}
+
+	UINT32 PhysX::addBroadPhaseRegion(const AABox& region)
+	{
+		UINT32 id = mNextRegionIdx++;
+
+		PxBroadPhaseRegion pxRegion;
+		pxRegion.bounds = PxBounds3(toPxVector(region.getMin()), toPxVector(region.getMax()));
+		pxRegion.userData = (void*)(UINT64)id;
+
+		UINT32 handle = mScene->addBroadPhaseRegion(pxRegion, true);
+		mBroadPhaseRegionHandles[id] = handle;
+
+		return handle;
+	}
+
+	void PhysX::removeBroadPhaseRegion(UINT32 regionId)
+	{
+		auto iterFind = mBroadPhaseRegionHandles.find(regionId);
+		if (iterFind == mBroadPhaseRegionHandles.end())
+			return;
+
+		mScene->removeBroadPhaseRegion(iterFind->second);
+		mBroadPhaseRegionHandles.erase(iterFind);
+	}
+
+	void PhysX::clearBroadPhaseRegions()
+	{
+		for(auto& entry : mBroadPhaseRegionHandles)
+			mScene->removeBroadPhaseRegion(entry.second);
+
+		mBroadPhaseRegionHandles.clear();
+	}
+
 	PhysX& gPhysX()
 	{
 		return static_cast<PhysX&>(PhysX::instance());

+ 5 - 2
BansheePhysX/Source/BsPhysXPlugin.cpp

@@ -7,9 +7,12 @@ namespace BansheeEngine
 	class BS_PHYSX_EXPORT PhysXFactory : public PhysicsFactory
 	{
 	public:
-		void startUp() override
+		void startUp(bool cooking) override
 		{
-			Physics::startUp<PhysX>();
+			PHYSICS_INIT_DESC desc;
+			desc.initCooking = cooking;
+
+			Physics::startUp<PhysX>(desc);
 		}
 
 		void shutDown() override

+ 4 - 4
BansheeUtility/Include/BsFlags.h

@@ -224,10 +224,10 @@ namespace BansheeEngine
 
 #define BS_FLAGS_OPERATORS(Enum) BS_FLAGS_OPERATORS_EXT(Enum, UINT32)
 
-#define BS_FLAGS_OPERATORS_EXT(Enum, Storage)                                                            \
-		Flags<Enum, Storage> operator|(Enum a, Enum b) { Flags<Enum, Storage> r(a); r |= b; return r; } \
-		Flags<Enum, Storage> operator&(Enum a, Enum b) { Flags<Enum, Storage> r(a); r &= b; return r; } \
-		Flags<Enum, Storage> operator~(Enum a) { return ~Flags<Enum, Storage>(a); }
+#define BS_FLAGS_OPERATORS_EXT(Enum, Storage)																   \
+		inline Flags<Enum, Storage> operator|(Enum a, Enum b) { Flags<Enum, Storage> r(a); r |= b; return r; } \
+		inline Flags<Enum, Storage> operator&(Enum a, Enum b) { Flags<Enum, Storage> r(a); r &= b; return r; } \
+		inline Flags<Enum, Storage> operator~(Enum a) { return ~Flags<Enum, Storage>(a); }
 
 	 /** @} */
 }