Просмотр исходного кода

Bugfix: ContactListener OnContactValidate was reporting contacts relative to some unknown quantity (#351)

Added an inBaseOffset parameter that should be added to the contact point positions to get to world space.
Jorrit Rouwe 2 лет назад
Родитель
Сommit
4286114828

+ 1 - 1
HelloWorld/HelloWorld.cpp

@@ -159,7 +159,7 @@ class MyContactListener : public ContactListener
 {
 public:
 	// See: ContactListener
-	virtual ValidateResult	OnContactValidate(const Body &inBody1, const Body &inBody2, const CollideShapeResult &inCollisionResult) override
+	virtual ValidateResult	OnContactValidate(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult) override
 	{
 		cout << "Contact validate callback" << endl;
 

+ 3 - 2
Jolt/Physics/Collision/ContactListener.h

@@ -69,8 +69,9 @@ public:
 	/// This is a rather expensive time to reject a contact point since a lot of the collision detection has happened already, make sure you
 	/// filter out the majority of undesired body pairs through the ObjectLayerPairFilter that is registered on the PhysicsSystem.
 	/// Note that this callback is called when all bodies are locked, so don't use any locking functions!
-	/// The order of body 1 and 2 is undefined, but when one of the two bodies is dynamic it will be body 1
-	virtual ValidateResult	OnContactValidate(const Body &inBody1, const Body &inBody2, const CollideShapeResult &inCollisionResult) { return ValidateResult::AcceptAllContactsForThisBodyPair; }
+	/// The order of body 1 and 2 is undefined, but when one of the two bodies is dynamic it will be body 1.
+	/// The collision result (inCollisionResult) is reported relative to inBaseOffset.
+	virtual ValidateResult	OnContactValidate(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult) { return ValidateResult::AcceptAllContactsForThisBodyPair; }
 
 	/// Called whenever a new contact point is detected.
 	/// Note that this callback is called when all bodies are locked, so don't use any locking functions!

+ 2 - 2
Jolt/Physics/Constraints/ContactConstraintManager.h

@@ -57,12 +57,12 @@ public:
 	uint32						GetMaxConstraints() const											{ return mMaxConstraints; }
 
 	/// Check with the listener if inBody1 and inBody2 could collide, returns false if not
-	inline ValidateResult		ValidateContactPoint(const Body &inBody1, const Body &inBody2, const CollideShapeResult &inCollisionResult) const	
+	inline ValidateResult		ValidateContactPoint(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult) const	
 	{ 
 		if (mContactListener == nullptr) 
 			return ValidateResult::AcceptAllContactsForThisBodyPair; 
 
-		return mContactListener->OnContactValidate(inBody1, inBody2, inCollisionResult); 
+		return mContactListener->OnContactValidate(inBody1, inBody2, inBaseOffset, inCollisionResult); 
 	}
 
 	/// Sets up the constraint buffer. Should be called before starting collision detection.

+ 4 - 3
Jolt/Physics/PhysicsSystem.cpp

@@ -1017,7 +1017,7 @@ void PhysicsSystem::ProcessBodyPair(ContactAllocator &ioContactAllocator, const
 					// Test if we want to accept this hit
 					if (mValidateBodyPair)
 					{
-						switch (mSystem->mContactManager.ValidateContactPoint(*mBody1, *mBody2, inResult))
+						switch (mSystem->mContactManager.ValidateContactPoint(*mBody1, *mBody2, mBody1->GetCenterOfMassPosition(), inResult))
 						{
 						case ValidateResult::AcceptContact:
 							// We're just accepting this one, nothing to do
@@ -1140,7 +1140,7 @@ void PhysicsSystem::ProcessBodyPair(ContactAllocator &ioContactAllocator, const
 					// Test if we want to accept this hit
 					if (mValidateBodyPair)
 					{
-						switch (mSystem->mContactManager.ValidateContactPoint(*mBody1, *mBody2, inResult))
+						switch (mSystem->mContactManager.ValidateContactPoint(*mBody1, *mBody2, mBody1->GetCenterOfMassPosition(), inResult))
 						{
 						case ValidateResult::AcceptContact:
 							// We're just accepting this one, nothing to do
@@ -1647,7 +1647,8 @@ void PhysicsSystem::JobFindCCDContacts(const PhysicsUpdateContext *ioContext, Ph
 							if (mValidateBodyPair)
 							{
 								// Validate the contact result
-								ValidateResult validate_result = mContactConstraintManager.ValidateContactPoint(mBodyManager.GetBody(mCCDBody.mBodyID1), body2, inResult);
+								const Body &body1 = mBodyManager.GetBody(mCCDBody.mBodyID1);
+								ValidateResult validate_result = mContactConstraintManager.ValidateContactPoint(body1, body2, body1.GetCenterOfMassPosition(), inResult); // Note that the center of mass of body 1 is the start of the sweep and is used as base offset below
 								switch (validate_result)
 								{
 								case ValidateResult::AcceptContact:

+ 1 - 1
Samples/Tests/General/ContactListenerTest.cpp

@@ -55,7 +55,7 @@ void ContactListenerTest::Initialize()
 	mBody[3] = &body4;
 }
 
-ValidateResult ContactListenerTest::OnContactValidate(const Body &inBody1, const Body &inBody2, const CollideShapeResult &inCollisionResult)
+ValidateResult ContactListenerTest::OnContactValidate(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult)
 {
 	// Body 1 and 2 should never collide
 	return ((&inBody1 == mBody[0] && &inBody2 == mBody[1]) || (&inBody1 == mBody[1] && &inBody2 == mBody[0]))? ValidateResult::RejectAllContactsForThisBodyPair : ValidateResult::AcceptAllContactsForThisBodyPair;

+ 1 - 1
Samples/Tests/General/ContactListenerTest.h

@@ -19,7 +19,7 @@ public:
 	virtual ContactListener *GetContactListener() override		{ return this; }
 
 	// See: ContactListener
-	virtual ValidateResult	OnContactValidate(const Body &inBody1, const Body &inBody2, const CollideShapeResult &inCollisionResult) override;
+	virtual ValidateResult	OnContactValidate(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult) override;
 	virtual void			OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override;
 
 private:

+ 7 - 3
Samples/Utils/ContactListenerImpl.cpp

@@ -6,9 +6,10 @@
 #include <Utils/ContactListenerImpl.h>
 #include <Renderer/DebugRendererImp.h>
 #include <Jolt/Physics/Body/Body.h>
+#include <Jolt/Physics/Collision/CollideShape.h>
 #include <Jolt/Core/QuickSort.h>
 
-ValidateResult ContactListenerImpl::OnContactValidate(const Body &inBody1, const Body &inBody2, const CollideShapeResult &inCollisionResult)
+ValidateResult ContactListenerImpl::OnContactValidate(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult)
 {
 	// Expect body 1 to be dynamic (or one of the bodies must be a sensor)
 	if (!inBody1.IsDynamic() && !inBody1.IsSensor() && !inBody2.IsSensor())
@@ -16,9 +17,12 @@ ValidateResult ContactListenerImpl::OnContactValidate(const Body &inBody1, const
 
 	ValidateResult result;
 	if (mNext != nullptr)
-		result = mNext->OnContactValidate(inBody1, inBody2, inCollisionResult);
+		result = mNext->OnContactValidate(inBody1, inBody2, inBaseOffset, inCollisionResult);
 	else
-		result = ContactListener::OnContactValidate(inBody1, inBody2, inCollisionResult);
+		result = ContactListener::OnContactValidate(inBody1, inBody2, inBaseOffset, inCollisionResult);
+
+	RVec3 contact_point = inBaseOffset + inCollisionResult.mContactPointOn1;
+	DebugRenderer::sInstance->DrawArrow(contact_point, contact_point + -inCollisionResult.mPenetrationAxis.NormalizedOr(Vec3::sZero()), Color::sBlue, 0.05f);
 
 	Trace("Validate %d and %d result %d", inBody1.GetID().GetIndex(), inBody2.GetID().GetIndex(), (int)result);
 

+ 1 - 1
Samples/Utils/ContactListenerImpl.h

@@ -13,7 +13,7 @@ class ContactListenerImpl : public ContactListener
 {
 public:
 	// See: ContactListener
-	virtual ValidateResult	OnContactValidate(const Body &inBody1, const Body &inBody2, const CollideShapeResult &inCollisionResult) override;
+	virtual ValidateResult	OnContactValidate(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult) override;
 	virtual void			OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override;
 	virtual void			OnContactPersisted(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override;
 	virtual void			OnContactRemoved(const SubShapeIDPair &inSubShapePair) override;

+ 1 - 1
UnitTests/LoggingContactListener.h

@@ -27,7 +27,7 @@ public:
 		ContactManifold				mManifold;
 	};
 
-	virtual ValidateResult			OnContactValidate(const Body &inBody1, const Body &inBody2, const CollideShapeResult &inCollisionResult) override
+	virtual ValidateResult			OnContactValidate(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult) override
 	{
 		// Check contract that body 1 is dynamic or that body2 is not dynamic
 		bool contract = inBody1.IsDynamic() || !inBody2.IsDynamic();