Browse Source

Add preliminary support for joints

Panagiotis Christopoulos Charitos 7 years ago
parent
commit
dfe79e92bc

+ 1 - 0
samples/physics_playground/Main.cpp

@@ -21,6 +21,7 @@ Error MyApp::sampleExtraInit()
 	ANKI_CHECK(getResourceManager().loadResource("assets/scene.lua", script));
 	ANKI_CHECK(getScriptManager().evalString(script->getSource()));
 
+	// Create the player
 	SceneNode& cam = getSceneGraph().getActiveCameraNode();
 	cam.getComponent<MoveComponent>().setLocalTransform(
 		Transform(Vec4(0.0, 0.0, 5.0, 0.0), Mat3x4::getIdentity(), 1.0));

+ 4 - 0
src/anki/Physics.h

@@ -6,5 +6,9 @@
 #pragma once
 
 #include <anki/physics/PhysicsWorld.h>
+#include <anki/physics/PhysicsBody.h>
+#include <anki/physics/PhysicsCollisionShape.h>
+#include <anki/physics/PhysicsJoint.h>
+#include <anki/physics/PhysicsPlayerController.h>
 
 /// @defgroup physics Physics subsystem

+ 1 - 0
src/anki/Scene.h

@@ -36,3 +36,4 @@
 #include <anki/scene/components/SpatialComponent.h>
 #include <anki/scene/components/ReflectionProxyComponent.h>
 #include <anki/scene/components/FrustumComponent.h>
+#include <anki/scene/components/JointComponent.h>

+ 2 - 0
src/anki/physics/Common.h

@@ -34,6 +34,7 @@ class PhysicsWorld;
 class PhysicsCollisionShape;
 class PhysicsBody;
 class PhysicsPlayerController;
+class PhysicsJoint;
 
 /// @addtogroup physics
 /// @{
@@ -52,6 +53,7 @@ using PhysicsPtr = IntrusivePtr<T, PhysicsPtrDeleter>;
 using PhysicsCollisionShapePtr = PhysicsPtr<PhysicsCollisionShape>;
 using PhysicsBodyPtr = PhysicsPtr<PhysicsBody>;
 using PhysicsPlayerControllerPtr = PhysicsPtr<PhysicsPlayerController>;
+using PhysicsJointPtr = PhysicsPtr<PhysicsJoint>;
 
 /// Material types.
 enum class PhysicsMaterialBit : U16

+ 7 - 0
src/anki/physics/PhysicsBody.h

@@ -76,6 +76,13 @@ public:
 		m_body->applyForce(toBt(force), toBt(relPos));
 	}
 
+anki_internal:
+	btRigidBody* getBtBody() const
+	{
+		ANKI_ASSERT(m_body);
+		return m_body;
+	}
+
 private:
 	class MotionState;
 

+ 2 - 0
src/anki/physics/PhysicsDrawer.cpp

@@ -11,6 +11,8 @@ namespace anki
 
 void PhysicsDrawer::drawWorld(const PhysicsWorld& world)
 {
+	auto lock = world.lockWorld();
+
 	btDynamicsWorld& btWorld = *world.getBtWorld();
 
 	btWorld.setDebugDrawer(&m_debugDraw);

+ 37 - 0
src/anki/physics/PhysicsJoint.cpp

@@ -0,0 +1,37 @@
+// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/physics/PhysicsJoint.h>
+#include <anki/physics/PhysicsBody.h>
+#include <anki/physics/PhysicsWorld.h>
+
+namespace anki
+{
+
+PhysicsJoint::PhysicsJoint(PhysicsWorld* world)
+	: PhysicsObject(PhysicsObjectType::JOINT, world)
+{
+}
+
+PhysicsJoint::~PhysicsJoint()
+{
+	if(m_joint)
+	{
+		getWorld().getBtWorld()->removeConstraint(m_joint);
+		getAllocator().deleteInstance(m_joint);
+	}
+}
+
+PhysicsPoint2PointJoint::PhysicsPoint2PointJoint(PhysicsWorld* world, PhysicsBodyPtr bodyA, const Vec3& relPos)
+	: PhysicsJoint(world)
+{
+	m_bodyA = bodyA;
+	m_joint = getAllocator().newInstance<btPoint2PointConstraint>(*m_bodyA->getBtBody(), toBt(relPos));
+	m_joint->setUserConstraintPtr(static_cast<PhysicsJoint*>(this));
+
+	getWorld().getBtWorld()->addConstraint(m_joint);
+}
+
+} // end namespace anki

+ 38 - 0
src/anki/physics/PhysicsJoint.h

@@ -0,0 +1,38 @@
+// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/physics/PhysicsObject.h>
+
+namespace anki
+{
+
+/// @addtogroup physics
+/// @{
+
+class PhysicsJoint : public PhysicsObject
+{
+public:
+	PhysicsJoint(PhysicsWorld* world);
+
+	~PhysicsJoint();
+
+protected:
+	btTypedConstraint* m_joint = nullptr;
+	PhysicsBodyPtr m_bodyA;
+	PhysicsBodyPtr m_bodyB;
+};
+
+class PhysicsPoint2PointJoint : public PhysicsJoint
+{
+public:
+	PhysicsPoint2PointJoint(PhysicsWorld* world, PhysicsBodyPtr bodyA, const Vec3& relPos);
+
+	PhysicsPoint2PointJoint(PhysicsWorld* world, PhysicsBodyPtr bodyA, PhysicsBodyPtr bodyB);
+};
+/// @}
+
+} // end namespace anki

+ 16 - 5
src/anki/physics/PhysicsPlayerController.cpp

@@ -12,9 +12,9 @@ namespace anki
 PhysicsPlayerController::PhysicsPlayerController(PhysicsWorld* world, const PhysicsPlayerControllerInitInfo& init)
 	: PhysicsObject(PhysicsObjectType::PLAYER_CONTROLLER, world)
 {
-	btTransform trf = toBt(Transform(init.m_position.xyz0(), Mat3x4::getIdentity(), 1.0f));
+	const btTransform trf = toBt(Transform(init.m_position.xyz0(), Mat3x4::getIdentity(), 1.0f));
 
-	m_convexShape = getAllocator().newInstance<btCapsuleShapeZ>(init.m_outerRadius, init.m_height);
+	m_convexShape = getAllocator().newInstance<btCapsuleShape>(init.m_outerRadius, init.m_height);
 
 	m_ghostObject = getAllocator().newInstance<btPairCachingGhostObject>();
 	m_ghostObject->setWorldTransform(trf);
@@ -24,10 +24,15 @@ PhysicsPlayerController::PhysicsPlayerController(PhysicsWorld* world, const Phys
 	m_controller = getAllocator().newInstance<btKinematicCharacterController>(
 		m_ghostObject, m_convexShape, init.m_stepHeight, btVector3(0, 1, 0));
 
-	getWorld().getBtWorld()->addCollisionObject(m_ghostObject,
+	btDynamicsWorld* btworld = getWorld().getBtWorld();
+
+	btworld->addCollisionObject(m_ghostObject,
 		btBroadphaseProxy::CharacterFilter,
 		btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter);
-	getWorld().getBtWorld()->addAction(m_controller);
+	btworld->addAction(m_controller);
+
+	// Need to call this else the player is upside down
+	moveToPosition(init.m_position);
 }
 
 PhysicsPlayerController::~PhysicsPlayerController()
@@ -42,7 +47,13 @@ PhysicsPlayerController::~PhysicsPlayerController()
 
 void PhysicsPlayerController::moveToPosition(const Vec4& position)
 {
-	m_ghostObject->setWorldTransform(toBt(Transform(position, Mat3x4::getIdentity(), 1.0f)));
+	ANKI_LOCK_PHYS_WORLD();
+
+	getWorld().getBtWorld()->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(
+		m_ghostObject->getBroadphaseHandle(), getWorld().getBtWorld()->getDispatcher());
+
+	m_controller->reset(getWorld().getBtWorld());
+	m_controller->warp(toBt(position.xyz()));
 }
 
 } // end namespace anki

+ 10 - 1
src/anki/physics/PhysicsWorld.h

@@ -27,6 +27,7 @@ public:
 	PhysicsPtr<T> newInstance(TArgs&&... args)
 	{
 		PhysicsPtr<T> out;
+		LockGuard<Mutex> lock(m_mtx);
 		T* ptr = m_alloc.template newInstance<T>(this, std::forward<TArgs>(args)...);
 		out.reset(ptr);
 		return out;
@@ -58,6 +59,11 @@ anki_internal:
 		return 0.04;
 	}
 
+	ANKI_USE_RESULT LockGuard<Mutex> lockWorld() const
+	{
+		return LockGuard<Mutex>(m_mtx);
+	}
+
 private:
 	HeapAllocator<U8> m_alloc;
 
@@ -69,7 +75,7 @@ private:
 	btSequentialImpulseConstraintSolver* m_solver = nullptr;
 	btDiscreteDynamicsWorld* m_world = nullptr;
 
-	Mutex m_mtx;
+	mutable Mutex m_mtx;
 	List<PhysicsObject*> m_forDeletion;
 
 	template<typename T, typename... TArgs>
@@ -77,6 +83,9 @@ private:
 
 	void cleanupMarkedForDeletion();
 };
+
+/// Lock the bullet physics world.
+#define ANKI_LOCK_PHYS_WORLD() auto lock = getWorld().lockWorld()
 /// @}
 
 } // end namespace anki

+ 36 - 0
src/anki/scene/components/JointComponent.cpp

@@ -0,0 +1,36 @@
+// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/scene/components/JointComponent.h>
+#include <anki/scene/components/BodyComponent.h>
+#include <anki/scene/SceneGraph.h>
+#include <anki/physics/PhysicsWorld.h>
+
+namespace anki
+{
+
+JointComponent::~JointComponent()
+{
+	m_jointList.destroy(getAllocator());
+}
+
+void JointComponent::newPoint2PointJoint(const Vec3& relPosA)
+{
+	BodyComponent* bodyc = m_node->tryGetComponent<BodyComponent>();
+
+	if(bodyc)
+	{
+		PhysicsJointPtr joint =
+			getSceneGraph().getPhysicsWorld().newInstance<PhysicsPoint2PointJoint>(bodyc->getPhysicsBody(), relPosA);
+
+		m_jointList.pushBack(getAllocator(), joint);
+	}
+	else
+	{
+		ANKI_SCENE_LOGW("Can't create new joint. The node is missing a body component");
+	}
+}
+
+} // end namespace anki

+ 37 - 0
src/anki/scene/components/JointComponent.h

@@ -0,0 +1,37 @@
+// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/scene/components/SceneComponent.h>
+#include <anki/physics/PhysicsJoint.h>
+
+namespace anki
+{
+
+/// @addtogroup scene
+/// @{
+
+/// Contains a list of joints.
+class JointComponent : public SceneComponent
+{
+public:
+	static const SceneComponentType CLASS_TYPE = SceneComponentType::JOINT;
+
+	JointComponent(SceneNode* node)
+		: SceneComponent(SceneComponentType::JOINT, node)
+	{
+	}
+
+	~JointComponent();
+
+	void newPoint2PointJoint(const Vec3& relPosA);
+
+private:
+	List<PhysicsJointPtr> m_jointList;
+};
+/// @}
+
+} // end namespace anki

+ 1 - 0
src/anki/scene/components/SceneComponent.h

@@ -35,6 +35,7 @@ enum class SceneComponentType : U16
 	DECAL,
 	SKIN,
 	SCRIPT,
+	JOINT,
 	PLAYER_CONTROLLER,
 
 	COUNT,

+ 16 - 1
src/anki/util/Thread.h

@@ -161,11 +161,26 @@ public:
 		m_mtx->lock();
 	}
 
+	LockGuard(const LockGuard& b) = delete;
+
+	LockGuard(LockGuard&& b)
+	{
+		m_mtx = b.m_mtx;
+		b.m_mtx = nullptr;
+	}
+
 	~LockGuard()
 	{
-		m_mtx->unlock();
+		if(m_mtx)
+		{
+			m_mtx->unlock();
+		}
 	}
 
+	LockGuard& operator=(LockGuard&& b) = delete;
+
+	LockGuard& operator=(const LockGuard& b) = delete;
+
 private:
 	TMutex* m_mtx;
 };