Переглянути джерело

Add some missing functionality

Panagiotis Christopoulos Charitos 10 місяців тому
батько
коміт
4c6daf7c9c

+ 16 - 0
AnKi/Math/Mat.h

@@ -1411,6 +1411,22 @@ public:
 		return out;
 	}
 
+	/// Create a rotation matrix from some direction. http://jcgt.org/published/0006/01/01/
+	static TMat rotationFromDirection(const TVec<T, 3>& zAxis) requires(kSize == 9)
+	{
+		const TVec<T, 3> z = zAxis;
+		const T sign = (z.z() >= T(0)) ? T(1) : -T(1);
+		const T a = -T(1) / (sign + z.z());
+		const T b = z.x() * z.y() * a;
+
+		const TVec<T, 3> x = TVec<T, 3>(T(1) + sign * a * pow(z.x(), T(2)), sign * b, -sign * z.x());
+		const TVec<T, 3> y = TVec<T, 3>(b, sign + a * pow(z.y(), T(2)), -z.y());
+
+		TMat out;
+		out.setColumns(x, y, z);
+		return out;
+	}
+
 	TMat lerp(const TMat& b, T t) const
 	{
 		return ((*this) * (T(1) - t)) + (b * t);

+ 45 - 0
AnKi/Physics2/PhysicsBody.cpp

@@ -9,8 +9,39 @@
 namespace anki {
 namespace v2 {
 
+PhysicsBody::MyGroupFilter PhysicsBody::m_groupFilter;
+
+Bool PhysicsBody::MyGroupFilter::CanCollide(const JPH::CollisionGroup& inGroup1, const JPH::CollisionGroup& inGroup2) const
+{
+	const U64 address1 = (U64(inGroup1.GetGroupID()) << 32_U64) | U64(inGroup1.GetSubGroupID());
+	const U64 address2 = (U64(inGroup2.GetGroupID()) << 32_U64) | U64(inGroup2.GetSubGroupID());
+	ANKI_ASSERT(address1 && address2);
+
+	const PhysicsBody& body1 = *numberToPtr<const PhysicsBody*>(address1);
+	const PhysicsBody& body2 = *numberToPtr<const PhysicsBody*>(address2);
+
+	if(body1.m_collisionFilterCallback == body2.m_collisionFilterCallback && body1.m_collisionFilterCallback)
+	{
+		// Both have the same filter callback and it's not nullptr, use it
+		return body1.m_collisionFilterCallback->collidesWith(body1, body2);
+	}
+	else
+	{
+		return true;
+	}
+}
+
 void PhysicsBody::init(const PhysicsBodyInitInfo& init)
 {
+	if(init.m_layer == PhysicsLayer::kStatic)
+	{
+		ANKI_ASSERT(init.m_mass == 0.0f);
+	}
+	else
+	{
+		ANKI_ASSERT(init.m_mass > 0.0f);
+	}
+
 	PhysicsWorld& world = PhysicsWorld::getSingleton();
 
 	const Vec3 pos = init.m_transform.getOrigin().xyz();
@@ -125,5 +156,19 @@ void PhysicsBody::postPhysicsUpdate()
 	}
 }
 
+void PhysicsBody::setCollisionFilterCallback(PhysicsCollisionFilterCallback* callback)
+{
+	m_collisionFilterCallback = callback;
+	JPH::CollisionGroup collisionGroup;
+
+	if(m_collisionFilterCallback)
+	{
+		const U64 callbackAddress = ptrToNumber(callback);
+		collisionGroup = JPH::CollisionGroup(&m_groupFilter, U32(callbackAddress >> 32_U64), U32(callbackAddress));
+	}
+
+	m_jphBody->SetCollisionGroup(collisionGroup);
+}
+
 } // namespace v2
 } // namespace anki

+ 25 - 0
AnKi/Physics2/PhysicsBody.h

@@ -30,16 +30,30 @@ public:
 	}
 };
 
+/// An interface to process contacts.
+/// @memberof PhysicsBody
+class PhysicsCollisionFilterCallback
+{
+public:
+	virtual Bool collidesWith(const PhysicsBody& body1, const PhysicsBody& body2) = 0;
+};
+
 /// Init info for PhysicsBody.
 class PhysicsBodyInitInfo
 {
 public:
 	PhysicsCollisionShape* m_shape = nullptr;
+
 	F32 m_mass = 0.0f; ///< Zero mass means static object.
+
 	Transform m_transform = Transform::getIdentity();
+
 	F32 m_friction = 0.5f;
+
 	PhysicsLayer m_layer = PhysicsLayer::kStatic;
+
 	Bool m_isTrigger = false;
+
 	void* m_userData = nullptr;
 };
 
@@ -79,17 +93,28 @@ public:
 		m_triggerCallbacks = callbacks;
 	}
 
+	void setCollisionFilterCallback(PhysicsCollisionFilterCallback* callback);
+
 	F32 getMass() const
 	{
 		return m_mass;
 	}
 
 private:
+	class MyGroupFilter final : public JPH::GroupFilter
+	{
+	public:
+		Bool CanCollide(const JPH::CollisionGroup& inGroup1, const JPH::CollisionGroup& inGroup2) const override;
+	};
+
+	static MyGroupFilter m_groupFilter;
+
 	JPH::Body* m_jphBody = nullptr;
 	PhysicsCollisionShapePtr m_primaryShape;
 	PhysicsCollisionShapePtr m_scaledShape;
 
 	PhysicsTriggerCallbacks* m_triggerCallbacks = nullptr;
+	PhysicsCollisionFilterCallback* m_collisionFilterCallback = nullptr;
 
 	Transform m_worldTrf;
 	U32 m_worldTrfVersion = 1;

+ 17 - 5
AnKi/Physics2/PhysicsWorld.cpp

@@ -552,19 +552,31 @@ PhysicsJointPtr PhysicsWorld::newJoint(PhysicsBody* body1, PhysicsBody* body2, T
 	return PhysicsJointPtr(&(*it));
 }
 
-PhysicsJointPtr PhysicsWorld::newPointJoint(PhysicsBody* body1, PhysicsBody* body2, Bool pointsInWorldSpace, const Vec3& body1Point,
-											const Vec3& body2Point)
+PhysicsJointPtr PhysicsWorld::newPointJoint(PhysicsBody* body1, PhysicsBody* body2, const Vec3& pivot)
 {
+	ANKI_ASSERT(body1 && body2);
 	JPH::PointConstraintSettings settings;
 	settings.SetEmbedded();
 
-	settings.mSpace = (pointsInWorldSpace) ? JPH::EConstraintSpace::WorldSpace : JPH::EConstraintSpace::LocalToBodyCOM;
-	settings.mPoint1 = toJPH(body1Point);
-	settings.mPoint2 = toJPH(body2Point);
+	settings.mPoint1 = settings.mPoint2 = toJPH(pivot);
 
 	return newJoint<JPH::PointConstraint>(body1, body2, settings);
 }
 
+PhysicsJointPtr PhysicsWorld::newHingeJoint(PhysicsBody* body1, PhysicsBody* body2, const Transform& pivot)
+{
+	ANKI_ASSERT(body1 && body2);
+	JPH::HingeConstraintSettings settings;
+	settings.SetEmbedded();
+
+	settings.mPoint1 = settings.mPoint2 = toJPH(pivot.getOrigin().xyz());
+	settings.mHingeAxis1 = settings.mHingeAxis2 = toJPH(pivot.getRotation().getXAxis());
+
+	settings.mNormalAxis1 = settings.mNormalAxis2 = toJPH(pivot.getRotation().getYAxis());
+
+	return newJoint<JPH::HingeConstraint>(body1, body2, settings);
+}
+
 PhysicsPlayerControllerPtr PhysicsWorld::newPlayerController(const PhysicsPlayerControllerInitInfo& init)
 {
 	PhysicsPlayerController* newChar;

+ 4 - 1
AnKi/Physics2/PhysicsWorld.h

@@ -59,7 +59,10 @@ public:
 
 	PhysicsBodyPtr newPhysicsBody(const PhysicsBodyInitInfo& init);
 
-	PhysicsJointPtr newPointJoint(PhysicsBody* body1, PhysicsBody* body2, Bool pointsInWorldSpace, const Vec3& body1Point, const Vec3& body2Point);
+	PhysicsJointPtr newPointJoint(PhysicsBody* body1, PhysicsBody* body2, const Vec3& pivot);
+
+	/// @param pivot Gives the origin and rotation of the hinge. The hinge rotats in the X axis of the transform.
+	PhysicsJointPtr newHingeJoint(PhysicsBody* body1, PhysicsBody* body2, const Transform& pivot);
 
 	PhysicsPlayerControllerPtr newPlayerController(const PhysicsPlayerControllerInitInfo& init);