فهرست منبع

Finalizing C++ MeshCollider implementation
Slight refactor for rigidbodies and colliders keep track of each other

BearishSun 10 سال پیش
والد
کامیت
24bdaebae7
37فایلهای تغییر یافته به همراه691 افزوده شده و 149 حذف شده
  1. 5 0
      BansheeCore/BansheeCore.vcxproj
  2. 15 0
      BansheeCore/BansheeCore.vcxproj.filters
  3. 19 2
      BansheeCore/Include/BsCCollider.h
  4. 62 0
      BansheeCore/Include/BsCMeshCollider.h
  5. 47 0
      BansheeCore/Include/BsCMeshColliderRTTI.h
  6. 3 0
      BansheeCore/Include/BsCPlaneCollider.h
  7. 11 2
      BansheeCore/Include/BsCRigidbody.h
  8. 9 3
      BansheeCore/Include/BsCollider.h
  9. 4 1
      BansheeCore/Include/BsCorePrerequisites.h
  10. 3 4
      BansheeCore/Include/BsFCollider.h
  11. 36 0
      BansheeCore/Include/BsMeshCollider.h
  12. 1 0
      BansheeCore/Include/BsPhysics.h
  13. 6 8
      BansheeCore/Include/BsRigidbody.h
  14. 38 10
      BansheeCore/Source/BsCCollider.cpp
  15. 69 0
      BansheeCore/Source/BsCMeshCollider.cpp
  16. 7 0
      BansheeCore/Source/BsCPlaneCollider.cpp
  17. 59 12
      BansheeCore/Source/BsCRigidbody.cpp
  18. 17 10
      BansheeCore/Source/BsCollider.cpp
  19. 1 18
      BansheeCore/Source/BsFCollider.cpp
  20. 29 0
      BansheeCore/Source/BsMeshCollider.cpp
  21. 0 27
      BansheeCore/Source/BsRigidbody.cpp
  22. 2 0
      BansheePhysX/BansheePhysX.vcxproj
  23. 6 0
      BansheePhysX/BansheePhysX.vcxproj.filters
  24. 3 2
      BansheePhysX/Include/BsFPhysXCollider.h
  25. 1 0
      BansheePhysX/Include/BsPhysX.h
  26. 5 0
      BansheePhysX/Include/BsPhysXBoxCollider.h
  27. 7 0
      BansheePhysX/Include/BsPhysXCapsuleCollider.h
  28. 25 0
      BansheePhysX/Include/BsPhysXMeshCollider.h
  29. 5 1
      BansheePhysX/Include/BsPhysXRigidbody.h
  30. 5 0
      BansheePhysX/Include/BsPhysXSphereCollider.h
  31. 29 32
      BansheePhysX/Source/BsFPhysXCollider.cpp
  32. 6 0
      BansheePhysX/Source/BsPhysX.cpp
  33. 17 4
      BansheePhysX/Source/BsPhysXBoxCollider.cpp
  34. 20 8
      BansheePhysX/Source/BsPhysXCapsuleCollider.cpp
  35. 71 0
      BansheePhysX/Source/BsPhysXMeshCollider.cpp
  36. 31 1
      BansheePhysX/Source/BsPhysXRigidbody.cpp
  37. 17 4
      BansheePhysX/Source/BsPhysXSphereCollider.cpp

+ 5 - 0
BansheeCore/BansheeCore.vcxproj

@@ -304,6 +304,8 @@
     <ClInclude Include="Include\BsCCapsuleColliderRTTI.h" />
     <ClInclude Include="Include\BsCCollider.h" />
     <ClInclude Include="Include\BsCColliderRTTI.h" />
+    <ClInclude Include="Include\BsCMeshCollider.h" />
+    <ClInclude Include="Include\BsCMeshColliderRTTI.h" />
     <ClInclude Include="Include\BsCollider.h" />
     <ClInclude Include="Include\BsCollision.h" />
     <ClInclude Include="Include\BsCoreObjectCore.h" />
@@ -318,6 +320,7 @@
     <ClInclude Include="Include\BsIconUtility.h" />
     <ClInclude Include="Include\BsMaterialParams.h" />
     <ClInclude Include="Include\BsMaterialParamsRTTI.h" />
+    <ClInclude Include="Include\BsMeshCollider.h" />
     <ClInclude Include="Include\BsMeshImportOptions.h" />
     <ClInclude Include="Include\BsMeshImportOptionsRTTI.h" />
     <ClInclude Include="Include\BsMeshRTTI.h" />
@@ -491,6 +494,7 @@
     <ClCompile Include="Source\BsCBoxCollider.cpp" />
     <ClCompile Include="Source\BsCCapsuleCollider.cpp" />
     <ClCompile Include="Source\BsCCollider.cpp" />
+    <ClCompile Include="Source\BsCMeshCollider.cpp" />
     <ClCompile Include="Source\BsCollider.cpp" />
     <ClCompile Include="Source\BsCoreObjectCore.cpp" />
     <ClCompile Include="Source\BsCoreThread.cpp" />
@@ -502,6 +506,7 @@
     <ClCompile Include="Source\BsIconUtility.cpp" />
     <ClCompile Include="Source\BsIResourceListener.cpp" />
     <ClCompile Include="Source\BsMaterialParam.cpp" />
+    <ClCompile Include="Source\BsMeshCollider.cpp" />
     <ClCompile Include="Source\BsMeshImportOptions.cpp" />
     <ClCompile Include="Source\BsMeshUtility.cpp" />
     <ClCompile Include="Source\BsPhysics.cpp" />

+ 15 - 0
BansheeCore/BansheeCore.vcxproj.filters

@@ -671,6 +671,15 @@
     <ClInclude Include="Source\BsPhysicsMeshRTTI.h">
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsMeshCollider.h">
+      <Filter>Header Files\Physics</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsCMeshCollider.h">
+      <Filter>Header Files\Components</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsCMeshColliderRTTI.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsCoreApplication.cpp">
@@ -1054,5 +1063,11 @@
     <ClCompile Include="Source\BsPhysicsMesh.cpp">
       <Filter>Source Files\Physics</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsMeshCollider.cpp">
+      <Filter>Source Files\Physics</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsCMeshCollider.cpp">
+      <Filter>Source Files\Components</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 19 - 2
BansheeCore/Include/BsCCollider.h

@@ -72,15 +72,17 @@ namespace BansheeEngine
 
 		/** @cond INTERNAL */
 
-		/** Changes the rigidbody parent of the collider. Meant to be called from the Rigidbody itself. */
-		void _setRigidbody(const HRigidbody& rigidbody);
+		/** Returns the Collider implementation wrapped by this component. */
+		SPtr<Collider> _getInternal() const { return mInternal; }
 
 		/** @endcond */
+
 		/************************************************************************/
 		/* 						COMPONENT OVERRIDES                      		*/
 		/************************************************************************/
 	protected:
 		friend class SceneObject;
+		friend class CRigidbody;
 
 		/** @copydoc Component::onInitialized() */
 		void onInitialized() override;
@@ -104,6 +106,21 @@ namespace BansheeEngine
 		/** Creates the internal representation of the Collider and restores the values saved by the Component. */
 		virtual void restoreInternal();
 
+		/** 
+		 * Checks is the provided rigidbody a valid parent for this collider. 
+		 *
+		 * @note This is required because certain colliders are limited in how they can be used. */
+		virtual bool isValidParent(const HRigidbody& parent) const { return true; }
+
+		/**
+		 * Changes the rigidbody parent of the collider. Meant to be called from the Rigidbody itself. 
+		 *
+		 * @param rigidbody	New rigidbody to assign as the parent to the collider.
+		 * @param internal	If true the rigidbody will just be changed internally, but parent rigidbody will not be
+		 *                  notified.
+		 */
+		void setRigidbody(const HRigidbody& rigidbody, bool internal = false);
+
 		/** 
 		 * Updates the transform of the internal Collider representation from the transform of the component's Scene Object.
 		 */

+ 62 - 0
BansheeCore/Include/BsCMeshCollider.h

@@ -0,0 +1,62 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsMeshCollider.h"
+#include "BsCCollider.h"
+
+namespace BansheeEngine 
+{
+	/** @addtogroup Components-Core
+	 *  @{
+	 */
+
+	/**
+	 * @copydoc	MeshCollider
+	 *
+	 * Wraps MeshCollider as a Component.
+	 */
+    class BS_CORE_EXPORT CMeshCollider : public CCollider
+    {
+    public:
+		CMeshCollider(const HSceneObject& parent);
+
+		/** @copydoc MeshCollider::setMesh */
+		void setMesh(const HPhysicsMesh& mesh);
+
+		/** @copydoc MeshCollider::getMesh */
+		HPhysicsMesh getMesh() const { return mMesh; }
+
+	    /**	Returns the mesh collider that this component wraps. */
+		SPtr<MeshCollider> _getInternal() const { return std::static_pointer_cast<MeshCollider>(mInternal); }
+
+		/************************************************************************/
+		/* 						COMPONENT OVERRIDES                      		*/
+		/************************************************************************/
+	protected:
+		friend class SceneObject;
+
+		/** @copydoc CCollider::createInternal */
+		SPtr<Collider> createInternal() override;
+
+		/** @copydoc CPlaneCollider::isValidParent */
+		bool isValidParent(const HRigidbody& parent) const override;
+
+    protected:
+		HPhysicsMesh mMesh;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class CMeshColliderRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		RTTITypeBase* getRTTI() const override;
+
+	protected:
+		CMeshCollider() {} // Serialization only
+     };
+
+	 /** @} */
+}

+ 47 - 0
BansheeCore/Include/BsCMeshColliderRTTI.h

@@ -0,0 +1,47 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsRTTIType.h"
+#include "BsCMeshCollider.h"
+#include "BsGameObjectRTTI.h"
+
+namespace BansheeEngine
+{
+	/** @cond RTTI */
+	/** @addtogroup RTTI-Impl-Core
+	 *  @{
+	 */
+
+	class BS_CORE_EXPORT CMeshColliderRTTI : public RTTIType<CMeshCollider, CCollider, CMeshColliderRTTI>
+	{
+	private:
+		BS_REFL_MEMBER(mMesh)
+
+	public:
+		CMeshColliderRTTI()
+		{
+			BS_ADD_REFL_FIELD(mMesh, 0);
+		}
+
+		const String& getRTTIName() override
+		{
+			static String name = "CMeshCollider";
+			return name;
+		}
+
+		UINT32 getRTTIId() override
+		{
+			return TID_CMeshCollider;
+		}
+
+		std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return GameObjectRTTI::createGameObject<CMeshCollider>();
+		}
+	};
+
+	/** @} */
+	/** @endcond */
+}

+ 3 - 0
BansheeCore/Include/BsCPlaneCollider.h

@@ -46,6 +46,9 @@ namespace BansheeEngine
 		/** @copydoc CCollider::createInternal */
 		SPtr<Collider> createInternal() override;
 
+		/** @copydoc CPlaneCollider::isValidParent */
+		bool isValidParent(const HRigidbody& parent) const override;
+
     protected:
 		Vector3 mNormal = Vector3::UNIT_Y;
 		float mDistance = 0.0f;

+ 11 - 2
BansheeCore/Include/BsCRigidbody.h

@@ -158,14 +158,22 @@ namespace BansheeEngine
 
 		/** @endcond */
 	protected:
+		friend class CCollider;
+
 		/** 
 		 * Searches child scene objects for Collider components and attaches them to the rigidbody. Make sure to call
 		 * clearChildColliders() if you need to clear old colliders first. 
 		 */
-		void updateChildColliders();
+		void updateColliders();
 
 		/** Unregisters all child colliders from the Rigidbody. */
-		void clearChildColliders();
+		void clearColliders();
+
+		/** Registers a new collider with the Rigidbody. */
+		void addCollider(const HCollider& collider);
+
+		/** Unregisters the collider from the Rigidbody. */
+		void removeCollider(const HCollider& collider);
 
 		/** Checks if the rigidbody is nested under another rigidbody, and throws out a warning if so. */
 		void checkForNestedRigibody();
@@ -201,6 +209,7 @@ namespace BansheeEngine
 		void onTransformChanged(TransformChangedFlags flags) override;
 
 		SPtr<Rigidbody> mInternal;
+		Vector<HCollider> mChildren;
 
 		UINT32 mPositionSolverCount = 4;
 		UINT32 mVelocitySolverCount = 1;

+ 9 - 3
BansheeCore/Include/BsCollider.h

@@ -18,15 +18,18 @@ namespace BansheeEngine
 		inline Quaternion getRotation() const;
 		inline void setTransform(const Vector3& pos, const Quaternion& rot);
 
+		virtual void setScale(const Vector3& scale);
+		inline Vector3 getScale() const;
+
 		inline void setIsTrigger(bool value);
 		inline bool getIsTrigger() const;
 
+		inline void setRigidbody(const SPtr<Rigidbody>& value);
+		SPtr<Rigidbody> getRigidbody() const { return mRigidbody; }
+
 		inline void setMass(float mass);
 		inline float getMass() const;
 
-		inline void setRigidbody(const SPtr<Rigidbody>& rigidbody);
-		inline SPtr<Rigidbody> getRigidbody() const;
-
 		inline void setMaterial(const HPhysicsMaterial& material);
 		inline HPhysicsMaterial getMaterial() const;
 
@@ -43,7 +46,10 @@ namespace BansheeEngine
 		Event<void(const CollisionData&)> onCollisionStay;
 		Event<void(const CollisionData&)> onCollisionEnd;
 
+		FCollider* _getInternal() const { return mInternal; }
 	protected:
 		FCollider* mInternal = nullptr;
+		SPtr<Rigidbody> mRigidbody;
+		Vector3 mScale = Vector3::ONE;
 	};
 }

+ 4 - 1
BansheeCore/Include/BsCorePrerequisites.h

@@ -244,12 +244,14 @@ namespace BansheeEngine
 	class SphereCollider;
 	class PlaneCollider;
 	class CapsuleCollider;
+	class MeshCollider;
 	class CCollider;
 	class CRigidbody;
 	class CBoxCollider;
 	class CSphereCollider;
 	class CPlaneCollider;
 	class CCapsuleCollider;
+	class CMeshCollider;
 	// Asset import
 	class SpecificImporter;
 	class Importer;
@@ -430,7 +432,8 @@ namespace BansheeEngine
 		TID_CCapsuleCollider = 1096,
 		TID_CPlaneCollider = 1097,
 		TID_CRigidbody = 1098,
-		TID_PhysicsMesh = 1099
+		TID_PhysicsMesh = 1099,
+		TID_CMeshCollider = 1100
 	};
 }
 

+ 3 - 4
BansheeCore/Include/BsFCollider.h

@@ -20,13 +20,13 @@ namespace BansheeEngine
 		virtual void setIsTrigger(bool value) = 0;
 		virtual bool getIsTrigger() const = 0;
 
+		virtual void setIsStatic(bool value) = 0;
+		virtual bool getIsStatic() const = 0;
+
 		// Not used for triggers, only relevant if parent rigidbody uses child mass
 		virtual void setMass(float mass) { mMass = mass; }
 		virtual float getMass() const { return mMass; }
 
-		virtual void setRigidbody(const SPtr<Rigidbody>& rigidbody);
-		virtual SPtr<Rigidbody> getRigidbody() const { return mRigidbody; }
-
 		virtual void setMaterial(const HPhysicsMaterial& material);
 		virtual HPhysicsMaterial getMaterial() const { return mMaterial; }
 
@@ -42,7 +42,6 @@ namespace BansheeEngine
 		UINT64 mLayer = 1;
 		float mMass = 1.0f;
 
-		SPtr<Rigidbody> mRigidbody;
 		HPhysicsMaterial mMaterial;
 	};
 }

+ 36 - 0
BansheeCore/Include/BsMeshCollider.h

@@ -0,0 +1,36 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsCollider.h"
+#include "BsIResourceListener.h"
+
+namespace BansheeEngine
+{
+	class BS_CORE_EXPORT MeshCollider : public Collider, public IResourceListener
+	{
+	public:
+		MeshCollider();
+
+		void setMesh(const HPhysicsMesh& mesh) { mMesh = mesh; onMeshChanged();  markListenerResourcesDirty(); }
+		HPhysicsMesh getMesh() const { return mMesh; }
+
+		static SPtr<MeshCollider> create(const Vector3& position = Vector3::ZERO, 
+			const Quaternion& rotation = Quaternion::IDENTITY);
+
+	protected:
+		/** @copydoc IResourceListener::getListenerResources */
+		void getListenerResources(Vector<HResource>& resources) override;
+
+		/** @copydoc IResourceListener::notifyResourceLoaded */
+		void notifyResourceLoaded(const HResource& resource) override;
+
+		/** @copydoc IResourceListener::notifyResourceChanged */
+		void notifyResourceChanged(const HResource& resource) override;
+
+		virtual void onMeshChanged() { }
+
+		HPhysicsMesh mMesh;
+	};
+}

+ 1 - 0
BansheeCore/Include/BsPhysics.h

@@ -28,6 +28,7 @@ namespace BansheeEngine
 		virtual SPtr<PlaneCollider> createPlaneCollider(const Vector3& position, const Quaternion& rotation) = 0;
 		virtual SPtr<CapsuleCollider> createCapsuleCollider(float radius, float halfHeight,
 			const Vector3& position, const Quaternion& rotation) = 0;
+		virtual SPtr<MeshCollider> createMeshCollider(const Vector3& position, const Quaternion& rotation) = 0;
 
 		void toggleCollision(UINT64 groupA, UINT64 groupB, bool enabled);
 		bool isCollisionEnabled(UINT64 groupA, UINT64 groupB) const;

+ 6 - 8
BansheeCore/Include/BsRigidbody.h

@@ -87,7 +87,7 @@ namespace BansheeEngine
 		virtual void setVelocitySolverCount(UINT32 count) = 0;
 		virtual UINT32 getVelocitySolverCount() const = 0;
 
-		virtual void setFlags(Flag flags);
+		virtual void setFlags(Flag flags) { mFlags = flags; }
 		virtual Flag getFlags() const { return mFlags; }
 
 		virtual void addForce(const Vector3& force, ForceMode mode = ForceMode::Force) = 0;
@@ -97,28 +97,26 @@ namespace BansheeEngine
 
 		virtual Vector3 getVelocityAtPoint(const Vector3& point) const = 0;
 
+		virtual void addCollider(FCollider* collider) = 0;
+		virtual void removeCollider(FCollider* collider) = 0;
+		virtual void removeColliders() = 0;
+		virtual void updateMassDistribution() { }
+
 		static SPtr<Rigidbody> create(const HSceneObject& linkedSO);
 
 		Event<void(const CollisionData&)> onCollisionBegin;
 		Event<void(const CollisionData&)> onCollisionStay;
 		Event<void(const CollisionData&)> onCollisionEnd;
 
-		virtual void _updateMassDistribution() { }
-
 		void _setPriority(UINT32 priority);
 		void _setPhysicsId(UINT32 id) { mPhysicsId = id; }
 		void _setTransform(const Vector3& position, const Quaternion& rotation);
-		void _detachColliders();
 	protected:
 		friend class FCollider;
 
-		virtual void addCollider(FCollider* collider);
-		virtual void removeCollider(FCollider* collider);
-
 		Flag mFlags = Flag::None;
 		UINT32 mPriority = 0;
 		UINT32 mPhysicsId = 0;
 		HSceneObject mLinkedSO;
-		Vector<FCollider*> mColliders;
 	};
 }

+ 38 - 10
BansheeCore/Source/BsCCollider.cpp

@@ -89,12 +89,20 @@ namespace BansheeEngine
 
 	void CCollider::onDestroyed()
 	{
+		if (mParent != nullptr)
+			mParent->removeCollider(mThisHandle);
+
+		mParent = nullptr;
+
 		// This should release the last reference and destroy the internal collider
 		mInternal = nullptr;
 	}
 
 	void CCollider::onDisabled()
 	{
+		if (mParent != nullptr)
+			mParent->removeCollider(mThisHandle);
+
 		mParent = nullptr;
 
 		// This should release the last reference and destroy the internal collider
@@ -123,7 +131,7 @@ namespace BansheeEngine
 			updateTransform();
 	}
 
-	void CCollider::_setRigidbody(const HRigidbody& rigidbody)
+	void CCollider::setRigidbody(const HRigidbody& rigidbody, bool internal)
 	{
 		SPtr<Rigidbody> rigidBodyPtr;
 
@@ -132,7 +140,20 @@ namespace BansheeEngine
 
 		if (mInternal == nullptr)
 		{
-			mInternal->setRigidbody(rigidBodyPtr);
+			if (rigidbody == mParent)
+				return;
+
+			if (!internal)
+			{
+				if (mParent != nullptr)
+					mParent->removeCollider(mThisHandle);
+
+				mInternal->setRigidbody(rigidBodyPtr);
+
+				if (rigidbody != nullptr)
+					rigidbody->addCollider(mThisHandle);
+			}
+
 			mParent = rigidbody;
 		}
 	}
@@ -157,29 +178,36 @@ namespace BansheeEngine
 		mInternal->setLayer(mLayer);
 
 		updateParentRigidbody();
-
-		if (mParent != nullptr)
-			mInternal->setRigidbody(mParent->_getInternal());
-
 		updateTransform();
 	}
 
 	void CCollider::updateParentRigidbody()
 	{
-		mParent = nullptr;
-
 		if (mIsTrigger)
+		{
+			setRigidbody(HRigidbody());
 			return;
+		}
 
 		HSceneObject currentSO = SO();
 		while (currentSO != nullptr)
 		{
-			mParent = currentSO->getComponent<CRigidbody>();
-			if (mParent != nullptr)
+			HRigidbody parent = currentSO->getComponent<CRigidbody>();
+			if (parent != nullptr)
+			{
+				if(currentSO->getActive() && isValidParent(parent))
+					setRigidbody(parent);
+				else
+					setRigidbody(HRigidbody());
+
 				return;
+			}
 
 			currentSO = currentSO->getParent();
 		}
+
+		// Not found
+		setRigidbody(HRigidbody());
 	}
 
 	void CCollider::updateTransform()

+ 69 - 0
BansheeCore/Source/BsCMeshCollider.cpp

@@ -0,0 +1,69 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsCMeshCollider.h"
+#include "BsSceneObject.h"
+#include "BsCRigidbody.h"
+#include "BsPhysicsMesh.h"
+#include "BsCMeshColliderRTTI.h"
+
+namespace BansheeEngine
+{
+	CMeshCollider::CMeshCollider(const HSceneObject& parent)
+		: CCollider(parent)
+	{
+		setName("MeshCollider");
+	}
+
+	void CMeshCollider::setMesh(const HPhysicsMesh& mesh)
+	{
+		if (mMesh == mesh)
+			return;
+
+		if(getIsTrigger() && mesh->getType() == PhysicsMeshType::Triangle)
+		{
+			LOGWRN("Triangle meshes are not supported on Trigger colliders.");
+			return;
+		}
+
+		mMesh = mesh;
+
+		if (mInternal != nullptr)
+		{
+			_getInternal()->setMesh(mesh);
+
+			if (mParent != nullptr)
+			{
+				// If triangle mesh its possible the parent can no longer use this collider (they're not supported for 
+				// non-kinematic rigidbodies)
+				if (mMesh.isLoaded() && mMesh->getType() == PhysicsMeshType::Triangle)
+					updateParentRigidbody();
+				else
+					mParent->_updateMassDistribution();
+			}
+		}
+	}
+
+	SPtr<Collider> CMeshCollider::createInternal()
+	{
+		SPtr<MeshCollider> collider = MeshCollider::create(SO()->getWorldPosition(), SO()->getWorldRotation());
+		collider->setMesh(mMesh);
+
+		return collider;
+	}
+
+	bool CMeshCollider::isValidParent(const HRigidbody& parent) const
+	{
+		// Triangle mesh colliders cannot be used for non-kinematic rigidbodies
+		return !mMesh.isLoaded() || mMesh->getType() == PhysicsMeshType::Convex || parent->getIsKinematic();
+	}
+
+	RTTITypeBase* CMeshCollider::getRTTIStatic()
+	{
+		return CMeshColliderRTTI::instance();
+	}
+
+	RTTITypeBase* CMeshCollider::getRTTI() const
+	{
+		return CMeshCollider::getRTTIStatic();
+	}
+}

+ 7 - 0
BansheeCore/Source/BsCPlaneCollider.cpp

@@ -2,6 +2,7 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsCPlaneCollider.h"
 #include "BsSceneObject.h"
+#include "BsCRigidbody.h"
 #include "BsCPlaneColliderRTTI.h"
 
 namespace BansheeEngine
@@ -44,6 +45,12 @@ namespace BansheeEngine
 		return PlaneCollider::create(SO()->getWorldPosition(), SO()->getWorldRotation());
 	}
 
+	bool CPlaneCollider::isValidParent(const HRigidbody& parent) const
+	{
+		// Planes cannot be added to non-kinematic rigidbodies
+		return parent->getIsKinematic();
+	}
+
 	RTTITypeBase* CPlaneCollider::getRTTIStatic()
 	{
 		return CPlaneColliderRTTI::instance();

+ 59 - 12
BansheeCore/Source/BsCRigidbody.cpp

@@ -3,6 +3,8 @@
 #include "BsCRigidbody.h"
 #include "BsSceneObject.h"
 #include "BsCCollider.h"
+#include "BsCMeshCollider.h"
+#include "BsPhysicsMesh.h"
 #include "BsCRigidbodyRTTI.h"
 
 using namespace std::placeholders;
@@ -37,10 +39,18 @@ namespace BansheeEngine
 
 	void CRigidbody::setIsKinematic(bool kinematic)
 	{
+		if (mIsKinematic == kinematic)
+			return;
+
 		mIsKinematic = kinematic;
 		
 		if (mInternal != nullptr)
+		{
 			mInternal->setIsKinematic(kinematic);
+
+			clearColliders();
+			updateColliders();
+		}
 	}
 
 	bool CRigidbody::isSleeping() const
@@ -193,7 +203,10 @@ namespace BansheeEngine
 		mFlags = flags;
 
 		if (mInternal != nullptr)
+		{
 			mInternal->setFlags(flags);
+			mInternal->updateMassDistribution();
+		}
 	}
 
 	void CRigidbody::addForce(const Vector3& force, ForceMode mode)
@@ -225,10 +238,10 @@ namespace BansheeEngine
 	void CRigidbody::_updateMassDistribution()
 	{
 		if (mInternal != nullptr)
-			return mInternal->_updateMassDistribution();
+			return mInternal->updateMassDistribution();
 	}
 
-	void CRigidbody::updateChildColliders()
+	void CRigidbody::updateColliders()
 	{
 		Stack<HSceneObject> todo;
 		todo.push(SO());
@@ -243,7 +256,15 @@ namespace BansheeEngine
 				Vector<HCollider> colliders = currentSO->getComponents<CCollider>();
 				
 				for (auto& entry : colliders)
-					entry->_setRigidbody(mThisHandle);
+				{
+					if (!entry->isValidParent(mThisHandle))
+						continue;
+
+					entry->setRigidbody(mThisHandle, true);
+
+					mChildren.push_back(entry);
+					mInternal->addCollider(entry->_getInternal()->_getInternal());
+				}
 			}
 
 			UINT32 childCount = currentSO->getNumChildren();
@@ -259,12 +280,38 @@ namespace BansheeEngine
 		}
 	}
 
-	void CRigidbody::clearChildColliders()
+	void CRigidbody::clearColliders()
+	{
+		for (auto& collider : mChildren)
+			collider->setRigidbody(HRigidbody(), true);
+
+		mChildren.clear();
+
+		if (mInternal != nullptr)
+			mInternal->removeColliders();
+	}
+
+	void CRigidbody::addCollider(const HCollider& collider)
+	{
+		if (mInternal == nullptr)
+			return;
+
+		mChildren.push_back(collider);
+		mInternal->addCollider(collider->_getInternal()->_getInternal());
+	}
+
+	void CRigidbody::removeCollider(const HCollider& collider)
 	{
 		if (mInternal == nullptr)
 			return;
 
-		mInternal->_detachColliders();
+		auto iterFind = std::find(mChildren.begin(), mChildren.end(), collider);
+
+		if(iterFind != mChildren.end())
+		{
+			mInternal->removeCollider(collider->_getInternal()->_getInternal());
+			mChildren.erase(iterFind);
+		}
 	}
 
 	void CRigidbody::checkForNestedRigibody()
@@ -306,13 +353,13 @@ namespace BansheeEngine
 
 	void CRigidbody::onDestroyed()
 	{
-		clearChildColliders();
+		clearColliders();
 		mInternal = nullptr;
 	}
 
 	void CRigidbody::onDisabled()
 	{
-		clearChildColliders();
+		clearColliders();
 		mInternal = nullptr;
 	}
 
@@ -320,7 +367,7 @@ namespace BansheeEngine
 	{
 		mInternal = Rigidbody::create(SO());
 
-		updateChildColliders();
+		updateColliders();
 
 #if BS_DEBUG_MODE
 		checkForNestedRigibody();
@@ -353,7 +400,7 @@ namespace BansheeEngine
 			if (((UINT32)mFlags & (UINT32)Rigidbody::Flag::AutoMass) == 0)
 				mInternal->setMass(mMass);
 
-			mInternal->_updateMassDistribution();
+			mInternal->updateMassDistribution();
 		}
 	}
 
@@ -364,11 +411,11 @@ namespace BansheeEngine
 
 		if((flags & TCF_Parent) != 0)
 		{
-			clearChildColliders();
-			updateChildColliders();
+			clearColliders();
+			updateColliders();
 
 			if (((UINT32)mFlags & (UINT32)Rigidbody::Flag::AutoTensors) != 0)
-				mInternal->_updateMassDistribution();
+				mInternal->updateMassDistribution();
 
 #if BS_DEBUG_MODE
 			checkForNestedRigibody();

+ 17 - 10
BansheeCore/Source/BsCollider.cpp

@@ -18,19 +18,19 @@ namespace BansheeEngine
 		mInternal->setTransform(pos, rot);
 	}
 
-	void Collider::setIsTrigger(bool value)
+	void Collider::setScale(const Vector3& scale)
 	{
-		mInternal->setIsTrigger(value);
+		mScale = scale;
 	}
 
-	void Collider::setMass(float mass)
+	Vector3 Collider::getScale() const
 	{
-		mInternal->setMass(mass);
+		return mScale;
 	}
 
-	float Collider::getMass() const
+	void Collider::setIsTrigger(bool value)
 	{
-		return mInternal->getMass();
+		mInternal->setIsTrigger(value);
 	}
 
 	bool Collider::getIsTrigger() const
@@ -38,14 +38,21 @@ namespace BansheeEngine
 		return mInternal->getIsTrigger();
 	}
 
-	void Collider::setRigidbody(const SPtr<Rigidbody>& rigidbody)
+	void Collider::setRigidbody(const SPtr<Rigidbody>& value)
 	{
-		mInternal->setRigidbody(rigidbody);
+		mInternal->setIsStatic(value == nullptr);
+
+		mRigidbody = value;
+	}
+
+	void Collider::setMass(float mass)
+	{
+		mInternal->setMass(mass);
 	}
 
-	SPtr<Rigidbody> Collider::getRigidbody() const
+	float Collider::getMass() const
 	{
-		return mInternal->getRigidbody();
+		return mInternal->getMass();
 	}
 
 	void Collider::setMaterial(const HPhysicsMaterial& material)

+ 1 - 18
BansheeCore/Source/BsFCollider.cpp

@@ -4,24 +4,7 @@
 namespace BansheeEngine
 {
 	FCollider::~FCollider()
-	{
-		if (mRigidbody != nullptr)
-			mRigidbody->removeCollider(this);
-	}
-
-	void FCollider::setRigidbody(const SPtr<Rigidbody>& rigidbody)
-	{
-		if (mRigidbody == rigidbody)
-			return;
-
-		if (mRigidbody != nullptr)
-			mRigidbody->removeCollider(this);
-
-		mRigidbody = rigidbody;
-
-		if (mRigidbody != nullptr)
-			mRigidbody->addCollider(this);
-	}
+	{ }
 
 	void FCollider::setMaterial(const HPhysicsMaterial& material)
 	{

+ 29 - 0
BansheeCore/Source/BsMeshCollider.cpp

@@ -0,0 +1,29 @@
+#include "BsMeshCollider.h"
+#include "BsPhysics.h"
+
+namespace BansheeEngine
+{
+	MeshCollider::MeshCollider()
+	{ }
+
+	SPtr<MeshCollider> MeshCollider::create(const Vector3& position, const Quaternion& rotation)
+	{
+		return Physics::instance().createMeshCollider(position, rotation);
+	}
+
+	void MeshCollider::getListenerResources(Vector<HResource>& resources)
+	{
+		if(mMesh != nullptr)
+			resources.push_back(mMesh);
+	}
+
+	void MeshCollider::notifyResourceLoaded(const HResource& resource)
+	{
+		onMeshChanged();
+	}
+
+	void MeshCollider::notifyResourceChanged(const HResource& resource)
+	{
+		onMeshChanged();
+	}
+}

+ 0 - 27
BansheeCore/Source/BsRigidbody.cpp

@@ -19,33 +19,6 @@ namespace BansheeEngine
 		gPhysics().unregisterRigidbody(mPhysicsId, mPriority);
 	}
 
-	void Rigidbody::addCollider(FCollider* collider)
-	{
-		mColliders.push_back(collider);
-	}
-
-	void Rigidbody::removeCollider(FCollider* collider)
-	{
-		auto iterFind = std::find(mColliders.begin(), mColliders.end(), collider);
-		if (iterFind != mColliders.end())
-			mColliders.erase(iterFind);
-	}
-
-	void Rigidbody::_detachColliders()
-	{
-		while (mColliders.size() > 0)
-			mColliders[0]->setRigidbody(nullptr);
-	}
-
-	void Rigidbody::setFlags(Flag flags)
-	{
-		if (mFlags == flags)
-			return;
-
-		mFlags = flags;
-		_updateMassDistribution();
-	}
-
 	void Rigidbody::_setPriority(UINT32 priority)
 	{
 		gPhysics().updatePriority(mPhysicsId, mPriority, priority);

+ 2 - 0
BansheePhysX/BansheePhysX.vcxproj

@@ -251,6 +251,7 @@
     <ClCompile Include="Source\BsPhysXCapsuleCollider.cpp" />
     <ClCompile Include="Source\BsPhysXMaterial.cpp" />
     <ClCompile Include="Source\BsPhysXMesh.cpp" />
+    <ClCompile Include="Source\BsPhysXMeshCollider.cpp" />
     <ClCompile Include="Source\BsPhysXPlaneCollider.cpp" />
     <ClCompile Include="Source\BsPhysXPlugin.cpp" />
     <ClCompile Include="Source\BsPhysXRigidbody.cpp" />
@@ -263,6 +264,7 @@
     <ClInclude Include="Include\BsPhysXCapsuleCollider.h" />
     <ClInclude Include="Include\BsPhysXMaterial.h" />
     <ClInclude Include="Include\BsPhysXMesh.h" />
+    <ClInclude Include="Include\BsPhysXMeshCollider.h" />
     <ClInclude Include="Include\BsPhysXMeshRTTI.h" />
     <ClInclude Include="Include\BsPhysXPlaneCollider.h" />
     <ClInclude Include="Include\BsPhysXPrerequisites.h" />

+ 6 - 0
BansheePhysX/BansheePhysX.vcxproj.filters

@@ -44,6 +44,9 @@
     <ClCompile Include="Source\BsPhysXMesh.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsPhysXMeshCollider.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Include\BsPhysXPrerequisites.h">
@@ -79,5 +82,8 @@
     <ClInclude Include="Include\BsPhysXMeshRTTI.h">
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsPhysXMeshCollider.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>

+ 3 - 2
BansheePhysX/Include/BsFPhysXCollider.h

@@ -22,7 +22,8 @@ namespace BansheeEngine
 		void setIsTrigger(bool value) override;
 		bool getIsTrigger() const override;
 
-		void setMass(float mass) override;
+		void setIsStatic(bool value) override;
+		bool getIsStatic() const override;
 
 		/**
 		 * Determines how far apart do two shapes need to be away from each other before the physics runtime starts 
@@ -46,7 +47,6 @@ namespace BansheeEngine
 		/** Returns shepe's rest offset in meters. See setRestOffset() to learn what contact offset is. */
 		float getRestOffset() const override;
 
-		void setRigidbody(const SPtr<Rigidbody>& rigidbody) override;
 		void setMaterial(const HPhysicsMaterial& material) override;
 		void setLayer(UINT64 layer) override;
 
@@ -55,5 +55,6 @@ namespace BansheeEngine
 		physx::PxShape* mShape;
 		physx::PxRigidStatic* mStaticBody;
 		bool mIsTrigger;
+		bool mIsStatic;
 	};
 }

+ 1 - 0
BansheePhysX/Include/BsPhysX.h

@@ -51,6 +51,7 @@ namespace BansheeEngine
 		SPtr<PlaneCollider> createPlaneCollider(const Vector3& position, const Quaternion& rotation) override;
 		SPtr<CapsuleCollider> createCapsuleCollider(float radius, float halfHeight, const Vector3& position, 
 			const Quaternion& rotation) override;
+		SPtr<MeshCollider> createMeshCollider(const Vector3& position, const Quaternion& rotation) override;
 
 		void _reportContactEvent(const ContactEvent& event);
 		void _reportTriggerEvent(const TriggerEvent& event);

+ 5 - 0
BansheePhysX/Include/BsPhysXBoxCollider.h

@@ -15,10 +15,15 @@ namespace BansheeEngine
 			const Vector3& extents);
 		~PhysXBoxCollider();
 
+		void setScale(const Vector3& scale) override;
+
 		void setExtents(const Vector3& extents) override;
 		Vector3 getExtents() const override;
 
 	private:
 		FPhysXCollider* getInternal() const;
+		void applyGeometry();
+
+		Vector3 mExtents;
 	};
 }

+ 7 - 0
BansheePhysX/Include/BsPhysXCapsuleCollider.h

@@ -15,6 +15,9 @@ namespace BansheeEngine
 			float radius, float halfHeight);
 		~PhysXCapsuleCollider();
 
+		/** @copydoc CapsuleCollider::setScale() */
+		void setScale(const Vector3& scale) override;
+
 		/** @copydoc CapsuleCollider::setHalfHeight() */
 		void setHalfHeight(float halfHeight) override;
 
@@ -29,5 +32,9 @@ namespace BansheeEngine
 
 	private:
 		FPhysXCollider* getInternal() const;
+		void applyGeometry();
+
+		float mRadius;
+		float mHalfHeight;
 	};
 }

+ 25 - 0
BansheePhysX/Include/BsPhysXMeshCollider.h

@@ -0,0 +1,25 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPhysXPrerequisites.h"
+#include "BsMeshCollider.h"
+#include "PxPhysics.h"
+
+namespace BansheeEngine
+{
+	class PhysXMeshCollider : public MeshCollider
+	{
+	public:
+		PhysXMeshCollider(physx::PxPhysics* physx, const Vector3& position, const Quaternion& rotation);
+		~PhysXMeshCollider();
+
+		void setScale(const Vector3& scale) override;
+
+	private:
+		FPhysXCollider* getInternal() const;
+
+		void onMeshChanged() override;
+		void applyGeometry();
+	};
+}

+ 5 - 1
BansheePhysX/Include/BsPhysXRigidbody.h

@@ -74,7 +74,11 @@ namespace BansheeEngine
 
 		Vector3 getVelocityAtPoint(const Vector3& point) const override;
 
-		void _updateMassDistribution() override;
+		void addCollider(FCollider* collider) override;
+		void removeCollider(FCollider* collider) override;
+		void removeColliders() override;
+		void updateMassDistribution() override;
+		
 	private:
 		physx::PxRigidDynamic* mInternal;
 	};

+ 5 - 0
BansheePhysX/Include/BsPhysXSphereCollider.h

@@ -14,10 +14,15 @@ namespace BansheeEngine
 		PhysXSphereCollider(physx::PxPhysics* physx, const Vector3& position, const Quaternion& rotation, float radius);
 		~PhysXSphereCollider();
 
+		void setScale(const Vector3& scale) override;
+
 		void setRadius(float radius) override;
 		float getRadius() const override;
 
 	private:
 		FPhysXCollider* getInternal() const;
+		void applyGeometry();
+
+		float mRadius;
 	};
 }

+ 29 - 32
BansheePhysX/Source/BsFPhysXCollider.cpp

@@ -10,7 +10,7 @@ using namespace physx;
 namespace BansheeEngine
 {
 	FPhysXCollider::FPhysXCollider(PxShape* shape)
-		:mShape(shape), mStaticBody(nullptr), mIsTrigger(false)
+		:mShape(shape), mStaticBody(nullptr), mIsTrigger(false), mIsStatic(true)
 	{
 		mStaticBody = gPhysX().getPhysX()->createRigidStatic(PxTransform());
 		mStaticBody->attachShape(*mShape);
@@ -65,17 +65,39 @@ namespace BansheeEngine
 		return (UINT32)(mShape->getFlags() & PxShapeFlag::eTRIGGER_SHAPE) != 0;
 	}
 
-	void FPhysXCollider::setContactOffset(float value)
+	void FPhysXCollider::setIsStatic(bool value)
 	{
-		mShape->setContactOffset(value);
+		if (mIsStatic == value)
+			return;
+
+		if (mStaticBody != nullptr)
+		{
+			mStaticBody->detachShape(*mShape);
+
+			mStaticBody->release();
+			mStaticBody = nullptr;
+		}
+
+		mIsStatic = value;
+
+		if (mIsStatic)
+		{
+			mStaticBody = gPhysX().getPhysX()->createRigidStatic(PxTransform());
+			mStaticBody->attachShape(*mShape);
+
+			PxScene* scene = gPhysX().getScene();
+			scene->addActor(*mStaticBody);
+		}
 	}
 
-	void FPhysXCollider::setMass(float mass)
+	bool FPhysXCollider::getIsStatic() const
 	{
-		FCollider::setMass(mass);
+		return mIsStatic;
+	}
 
-		if (mRigidbody != nullptr)
-			mRigidbody->_updateMassDistribution(); // Note: Perhaps I can just mark mass distribution as dirty and recalculate it delayed, in case a lot of colliders change
+	void FPhysXCollider::setContactOffset(float value)
+	{
+		mShape->setContactOffset(value);
 	}
 
 	float FPhysXCollider::getContactOffset() const
@@ -93,31 +115,6 @@ namespace BansheeEngine
 		return mShape->getRestOffset();
 	}
 
-	void FPhysXCollider::setRigidbody(const SPtr<Rigidbody>& rigidbody)
-	{
-		if (mRigidbody == rigidbody)
-			return;
-
-		if(mStaticBody != nullptr)
-		{
-			mStaticBody->detachShape(*mShape);
-
-			mStaticBody->release();
-			mStaticBody = nullptr;
-		}
-
-		FCollider::setRigidbody(rigidbody);
-
-		if(rigidbody == nullptr)
-		{
-			mStaticBody = gPhysX().getPhysX()->createRigidStatic(PxTransform());
-			mStaticBody->attachShape(*mShape);
-
-			PxScene* scene = gPhysX().getScene();
-			scene->addActor(*mStaticBody);
-		}
-	}
-
 	void FPhysXCollider::setMaterial(const HPhysicsMaterial& material)
 	{
 		FCollider::setMaterial(material);

+ 6 - 0
BansheePhysX/Source/BsPhysX.cpp

@@ -7,6 +7,7 @@
 #include "BsPhysXSphereCollider.h"
 #include "BsPhysXPlaneCollider.h"
 #include "BsPhysXCapsuleCollider.h"
+#include "BsPhysXMeshCollider.h"
 #include "BsTaskScheduler.h"
 #include "BsTime.h"
 #include "Bsvector3.h"
@@ -495,6 +496,11 @@ namespace BansheeEngine
 		return bs_shared_ptr_new<PhysXCapsuleCollider>(mPhysics, position, rotation, radius, halfHeight);
 	}
 
+	SPtr<MeshCollider> PhysX::createMeshCollider(const Vector3& position, const Quaternion& rotation)
+	{
+		return bs_shared_ptr_new<PhysXMeshCollider>(mPhysics, position, rotation);
+	}
+
 	PhysX& gPhysX()
 	{
 		return static_cast<PhysX&>(PhysX::instance());

+ 17 - 4
BansheePhysX/Source/BsPhysXBoxCollider.cpp

@@ -9,6 +9,7 @@ namespace BansheeEngine
 {
 	PhysXBoxCollider::PhysXBoxCollider(PxPhysics* physx, const Vector3& position, const Quaternion& rotation, 
 		const Vector3& extents)
+		:mExtents(extents)
 	{
 		PxBoxGeometry geometry(extents.x, extents.y, extents.z);
 
@@ -24,16 +25,28 @@ namespace BansheeEngine
 		bs_delete(mInternal);
 	}
 
-	void PhysXBoxCollider::setExtents(const Vector3& extents)
+	void PhysXBoxCollider::setScale(const Vector3& scale)
 	{
-		PxBoxGeometry geometry(extents.x, extents.y, extents.z);
+		BoxCollider::setScale(scale);
+		applyGeometry();
+	}
 
-		getInternal()->_getShape()->setGeometry(geometry);
+	void PhysXBoxCollider::setExtents(const Vector3& extents)
+	{
+		mExtents = extents;
+		applyGeometry();
 	}
 
 	Vector3 PhysXBoxCollider::getExtents() const
 	{
-		return fromPxVector(getInternal()->_getShape()->getGeometry().box().halfExtents);
+		return mExtents;
+	}
+
+	void PhysXBoxCollider::applyGeometry()
+	{
+		PxBoxGeometry geometry(mExtents.x * mScale.x, mExtents.y * mScale.y, mExtents.z * mScale.z);
+
+		getInternal()->_getShape()->setGeometry(geometry);
 	}
 
 	FPhysXCollider* PhysXBoxCollider::getInternal() const

+ 20 - 8
BansheePhysX/Source/BsPhysXCapsuleCollider.cpp

@@ -9,6 +9,7 @@ namespace BansheeEngine
 {
 	PhysXCapsuleCollider::PhysXCapsuleCollider(PxPhysics* physx, const Vector3& position, const Quaternion& rotation,
 		float radius, float halfHeight)
+		:mRadius(radius), mHalfHeight(halfHeight)
 	{
 		PxCapsuleGeometry geometry(radius, halfHeight);
 
@@ -24,28 +25,39 @@ namespace BansheeEngine
 		bs_delete(mInternal);
 	}
 
-	void PhysXCapsuleCollider::setHalfHeight(float halfHeight)
+	void PhysXCapsuleCollider::setScale(const Vector3& scale)
 	{
-		PxCapsuleGeometry geometry(getRadius(), halfHeight);
+		CapsuleCollider::setScale(scale);
+		applyGeometry();
+	}
 
-		getInternal()->_getShape()->setGeometry(geometry);
+	void PhysXCapsuleCollider::setHalfHeight(float halfHeight)
+	{
+		mHalfHeight = halfHeight;
+		applyGeometry();
 	}
 
 	float PhysXCapsuleCollider::getHalfHeight() const
 	{
-		return getInternal()->_getShape()->getGeometry().capsule().halfHeight;
+		return mHalfHeight;
 	}
 
 	void PhysXCapsuleCollider::setRadius(float radius)
 	{
-		PxCapsuleGeometry geometry(radius, getHalfHeight());
-
-		getInternal()->_getShape()->setGeometry(geometry);
+		mRadius = radius;
+		applyGeometry();
 	}
 
 	float PhysXCapsuleCollider::getRadius() const
 	{
-		return getInternal()->_getShape()->getGeometry().capsule().radius;
+		return mRadius;
+	}
+
+	void PhysXCapsuleCollider::applyGeometry()
+	{
+		PxCapsuleGeometry geometry(mRadius * std::max(mScale.x, mScale.z), mHalfHeight * mScale.y);
+
+		getInternal()->_getShape()->setGeometry(geometry);
 	}
 
 	FPhysXCollider* PhysXCapsuleCollider::getInternal() const

+ 71 - 0
BansheePhysX/Source/BsPhysXMeshCollider.cpp

@@ -0,0 +1,71 @@
+#include "BsPhysXMeshCollider.h"
+#include "BsPhysX.h"
+#include "PxPhysics.h"
+#include "BsFPhysXCollider.h"
+#include "BsPhysXMesh.h"
+
+using namespace physx;
+
+namespace BansheeEngine
+{
+	PhysXMeshCollider::PhysXMeshCollider(PxPhysics* physx, const Vector3& position, const Quaternion& rotation)
+	{
+		PxConvexMeshGeometry geometry;
+
+		PxShape* shape = physx->createShape(geometry, *gPhysX().getDefaultMaterial(), true);
+		shape->setLocalPose(toPxTransform(position, rotation));
+		shape->userData = this;
+
+		mInternal = bs_new<FPhysXCollider>(shape);
+	}
+
+	PhysXMeshCollider::~PhysXMeshCollider()
+	{
+		bs_delete(mInternal);
+	}
+
+	void PhysXMeshCollider::setScale(const Vector3& scale)
+	{
+		MeshCollider::setScale(scale);
+		applyGeometry();
+	}
+
+	void PhysXMeshCollider::onMeshChanged()
+	{
+		applyGeometry();
+	}
+
+	void PhysXMeshCollider::applyGeometry()
+	{
+		if (!mMesh.isLoaded())
+		{
+			PxConvexMeshGeometry geometry;
+			getInternal()->_getShape()->setGeometry(geometry);
+			return;
+		}
+
+		SPtr<PhysXMesh> physxMesh = std::static_pointer_cast<PhysXMesh>(mMesh.getInternalPtr());
+
+		if (physxMesh->getType() == PhysicsMeshType::Convex)
+		{
+			PxConvexMeshGeometry geometry;
+			geometry.scale = PxMeshScale(toPxVector(getScale()), PxIdentity);
+			geometry.convexMesh = physxMesh->_getConvex();
+
+			getInternal()->_getShape()->setGeometry(geometry);
+		}
+		else // Triangle
+		{
+			PxTriangleMeshGeometry geometry;
+			geometry.scale = PxMeshScale(toPxVector(getScale()), PxIdentity);
+			geometry.triangleMesh = physxMesh->_getTriangle();
+
+			getInternal()->_getShape()->setGeometry(geometry);
+		}
+	}
+
+	FPhysXCollider* PhysXMeshCollider::getInternal() const
+	{
+		return static_cast<FPhysXCollider*>(mInternal);
+	}
+}

+ 31 - 1
BansheePhysX/Source/BsPhysXRigidbody.cpp

@@ -1,5 +1,6 @@
 #include "BsPhysXRigidbody.h"
 #include "BsCollider.h"
+#include "BsFPhysXCollider.h"
 #include "BsSceneObject.h"
 #include "PxRigidDynamic.h"
 #include "PxScene.h"
@@ -308,7 +309,7 @@ namespace BansheeEngine
 		return fromPxVector(velocity);
 	}
 
-	void PhysXRigidbody::_updateMassDistribution() 
+	void PhysXRigidbody::updateMassDistribution() 
 	{
 		if (((UINT32)mFlags & (UINT32)Flag::AutoTensors) == 0)
 			return;
@@ -334,4 +335,33 @@ namespace BansheeEngine
 			bs_stack_free(shapes);
 		}
 	}
+
+	void PhysXRigidbody::addCollider(FCollider* collider)
+	{
+		if (collider == nullptr)
+			return;
+
+		FPhysXCollider* physxCollider = static_cast<FPhysXCollider*>(collider);
+		mInternal->attachShape(*physxCollider->_getShape());
+	}
+
+	void PhysXRigidbody::removeCollider(FCollider* collider)
+	{
+		if (collider == nullptr)
+			return;
+
+		FPhysXCollider* physxCollider = static_cast<FPhysXCollider*>(collider);
+		mInternal->detachShape(*physxCollider->_getShape());
+	}
+
+	void PhysXRigidbody::removeColliders()
+	{
+		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++)
+			mInternal->detachShape(*shapes[i]);
+	}
 }

+ 17 - 4
BansheePhysX/Source/BsPhysXSphereCollider.cpp

@@ -9,6 +9,7 @@ namespace BansheeEngine
 {
 	PhysXSphereCollider::PhysXSphereCollider(PxPhysics* physx, const Vector3& position, const Quaternion& rotation,
 		float radius)
+		:mRadius(radius)
 	{
 		PxSphereGeometry geometry(radius);
 
@@ -24,16 +25,28 @@ namespace BansheeEngine
 		bs_delete(mInternal);
 	}
 
-	void PhysXSphereCollider::setRadius(float radius)
+	void PhysXSphereCollider::setScale(const Vector3& scale)
 	{
-		PxSphereGeometry geometry(radius);
+		SphereCollider::setScale(scale);
+		applyGeometry();
+	}
 
-		getInternal()->_getShape()->setGeometry(geometry);
+	void PhysXSphereCollider::setRadius(float radius)
+	{
+		mRadius = radius;
+		applyGeometry();
 	}
 
 	float PhysXSphereCollider::getRadius() const
 	{
-		return getInternal()->_getShape()->getGeometry().sphere().radius;
+		return mRadius;
+	}
+
+	void PhysXSphereCollider::applyGeometry()
+	{
+		PxSphereGeometry geometry(mRadius * std::max(std::max(mScale.x, mScale.y), mScale.z));
+
+		getInternal()->_getShape()->setGeometry(geometry);
 	}
 
 	FPhysXCollider* PhysXSphereCollider::getInternal() const