|
@@ -439,6 +439,80 @@ TEST_SUITE("SensorTests")
|
|
|
CHECK_APPROX_EQUAL(dynamic2.GetPosition(), RVec3(2, -1.5f - 3.0f * c.GetDeltaTime(), 0), 1.0e-4f);
|
|
|
}
|
|
|
|
|
|
+ TEST_CASE("TestContactListenerMakesSensorCCD")
|
|
|
+ {
|
|
|
+ PhysicsTestContext c;
|
|
|
+ c.ZeroGravity();
|
|
|
+
|
|
|
+ const float cPenetrationSlop = c.GetSystem()->GetPhysicsSettings().mPenetrationSlop;
|
|
|
+
|
|
|
+ class SensorOverridingListener : public LoggingContactListener
|
|
|
+ {
|
|
|
+ public:
|
|
|
+ virtual void OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override
|
|
|
+ {
|
|
|
+ LoggingContactListener::OnContactAdded(inBody1, inBody2, inManifold, ioSettings);
|
|
|
+
|
|
|
+ JPH_ASSERT(ioSettings.mIsSensor == false);
|
|
|
+ if (inBody1.GetID() == mBodyThatBecomesSensor || inBody2.GetID() == mBodyThatBecomesSensor)
|
|
|
+ ioSettings.mIsSensor = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void OnContactPersisted(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override
|
|
|
+ {
|
|
|
+ LoggingContactListener::OnContactPersisted(inBody1, inBody2, inManifold, ioSettings);
|
|
|
+
|
|
|
+ JPH_ASSERT(ioSettings.mIsSensor == false);
|
|
|
+ if (inBody1.GetID() == mBodyThatBecomesSensor || inBody2.GetID() == mBodyThatBecomesSensor)
|
|
|
+ ioSettings.mIsSensor = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ BodyID mBodyThatBecomesSensor;
|
|
|
+ };
|
|
|
+
|
|
|
+ // Register listener
|
|
|
+ SensorOverridingListener listener;
|
|
|
+ c.GetSystem()->SetContactListener(&listener);
|
|
|
+
|
|
|
+ // Body that blocks the path
|
|
|
+ BodyID static_id = c.GetBodyInterface().CreateAndAddBody(BodyCreationSettings(new BoxShape(Vec3(0.1f, 10, 10)), RVec3::sZero(), Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING), EActivation::DontActivate);
|
|
|
+
|
|
|
+ // Dynamic body moving to the static object that will do a normal CCD collision
|
|
|
+ RVec3 dynamic1_pos(-0.5f, 2, 0);
|
|
|
+ Vec3 initial_velocity(500, 0, 0);
|
|
|
+ Body &dynamic1 = c.CreateBox(dynamic1_pos, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::LinearCast, Layers::MOVING, Vec3::sReplicate(0.1f));
|
|
|
+ dynamic1.SetAllowSleeping(false);
|
|
|
+ dynamic1.SetLinearVelocity(initial_velocity);
|
|
|
+ dynamic1.SetRestitution(1.0f);
|
|
|
+
|
|
|
+ // Dynamic body moving through the static object that will become a sensor an thus pass through
|
|
|
+ RVec3 dynamic2_pos(-0.5f, -2, 0);
|
|
|
+ Body &dynamic2 = c.CreateBox(dynamic2_pos, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::LinearCast, Layers::MOVING, Vec3::sReplicate(0.1f));
|
|
|
+ dynamic2.SetAllowSleeping(false);
|
|
|
+ dynamic2.SetLinearVelocity(initial_velocity);
|
|
|
+ dynamic2.SetRestitution(1.0f);
|
|
|
+ listener.mBodyThatBecomesSensor = dynamic2.GetID();
|
|
|
+
|
|
|
+ // After a single step the we should have contact added callbacks for both bodies
|
|
|
+ c.SimulateSingleStep();
|
|
|
+ CHECK(listener.Contains(EType::Add, dynamic1.GetID(), static_id));
|
|
|
+ CHECK(listener.Contains(EType::Add, dynamic2.GetID(), static_id));
|
|
|
+ listener.Clear();
|
|
|
+ CHECK_APPROX_EQUAL(dynamic1.GetPosition(), dynamic1_pos + RVec3(0.3f + cPenetrationSlop, 0, 0), 1.0e-4f); // Dynamic 1 should have moved to the surface of the static body
|
|
|
+ CHECK_APPROX_EQUAL(dynamic2.GetPosition(), dynamic2_pos + initial_velocity * c.GetDeltaTime(), 1.0e-4f); // Dynamic 2 should have passed through the static body because it became a sensor
|
|
|
+
|
|
|
+ // The next step the sensor should have its contact removed and the CCD body should have its contact persisted because it starts penetrating
|
|
|
+ c.SimulateSingleStep();
|
|
|
+ CHECK(listener.Contains(EType::Persist, dynamic1.GetID(), static_id));
|
|
|
+ CHECK(listener.Contains(EType::Remove, dynamic2.GetID(), static_id));
|
|
|
+ listener.Clear();
|
|
|
+
|
|
|
+ // The next step all contacts have been removed
|
|
|
+ c.SimulateSingleStep();
|
|
|
+ CHECK(listener.Contains(EType::Remove, dynamic1.GetID(), static_id));
|
|
|
+ listener.Clear();
|
|
|
+ }
|
|
|
+
|
|
|
TEST_CASE("TestSensorVsSubShapes")
|
|
|
{
|
|
|
PhysicsTestContext c;
|