ShapeFilterTests.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2024 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include "UnitTestFramework.h"
  5. #include "PhysicsTestContext.h"
  6. #include "Layers.h"
  7. #include "LoggingContactListener.h"
  8. #include <Jolt/Physics/Collision/Shape/BoxShape.h>
  9. #include <Jolt/Physics/Collision/Shape/SphereShape.h>
  10. #include <Jolt/Physics/Collision/Shape/StaticCompoundShape.h>
  11. #include <Jolt/Physics/Collision/SimShapeFilter.h>
  12. #include <Jolt/Physics/Body/BodyCreationSettings.h>
  13. TEST_SUITE("ShapeFilterTests")
  14. {
  15. // Tests two spheres in one simulated body, one collides with a static platform, the other doesn't
  16. TEST_CASE("TestSimShapeFilter")
  17. {
  18. // Test once per motion quality type
  19. for (int q = 0; q < 2; ++q)
  20. {
  21. PhysicsTestContext c;
  22. // Log contacts
  23. LoggingContactListener contact_listener;
  24. c.GetSystem()->SetContactListener(&contact_listener);
  25. // Install simulation shape filter
  26. class Filter : public SimShapeFilter
  27. {
  28. public:
  29. virtual bool ShouldCollide(const Body &inBody1, const Shape *inShape1, const SubShapeID &inSubShapeIDOfShape1, const Body &inBody2, const Shape *inShape2, const SubShapeID &inSubShapeIDOfShape2) const override
  30. {
  31. // If the platform is colliding with the compound, filter out collisions where the shape has user data 1
  32. if (inBody1.GetID() == mPlatformID && inBody2.GetID() == mCompoundID)
  33. return inShape2->GetUserData() != 1;
  34. else if (inBody1.GetID() == mCompoundID && inBody2.GetID() == mPlatformID)
  35. return inShape1->GetUserData() != 1;
  36. return true;
  37. }
  38. BodyID mPlatformID;
  39. BodyID mCompoundID;
  40. };
  41. Filter shape_filter;
  42. c.GetSystem()->SetSimShapeFilter(&shape_filter);
  43. // Floor
  44. BodyID floor_id = c.CreateFloor().GetID();
  45. // Platform
  46. BodyInterface &bi = c.GetBodyInterface();
  47. shape_filter.mPlatformID = bi.CreateAndAddBody(BodyCreationSettings(new BoxShape(Vec3(10, 0.5f, 10)), RVec3(0, 3.5f, 0), Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING), EActivation::DontActivate);
  48. // Compound shape that starts above platform
  49. Ref<Shape> sphere = new SphereShape(0.5f);
  50. sphere->SetUserData(1); // Don't want sphere to collide with the platform
  51. Ref<Shape> sphere2 = new SphereShape(0.5f);
  52. Ref<StaticCompoundShapeSettings> compound_settings = new StaticCompoundShapeSettings;
  53. compound_settings->AddShape(Vec3(0, -2, 0), Quat::sIdentity(), sphere);
  54. compound_settings->AddShape(Vec3(0, 2, 0), Quat::sIdentity(), sphere2);
  55. Ref<StaticCompoundShape> compound = StaticCast<StaticCompoundShape>(compound_settings->Create().Get());
  56. BodyCreationSettings bcs(compound, RVec3(0, 7, 0), Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING);
  57. if (q == 1)
  58. {
  59. // For the 2nd iteration activate CCD
  60. bcs.mMotionQuality = EMotionQuality::LinearCast;
  61. bcs.mLinearVelocity = Vec3(0, -50, 0);
  62. }
  63. shape_filter.mCompoundID = bi.CreateAndAddBody(bcs, EActivation::Activate);
  64. // Get sub shape IDs
  65. SubShapeID sphere_id = compound->GetSubShapeIDFromIndex(0, SubShapeIDCreator()).GetID();
  66. SubShapeID sphere2_id = compound->GetSubShapeIDFromIndex(1, SubShapeIDCreator()).GetID();
  67. // Simulate for 2 seconds
  68. c.Simulate(2.0f);
  69. // The compound should now be resting with sphere on the platform and the sphere2 on the floor
  70. CHECK_APPROX_EQUAL(bi.GetPosition(shape_filter.mCompoundID), RVec3(0, 2.5f, 0), 1.01f * c.GetSystem()->GetPhysicsSettings().mPenetrationSlop);
  71. CHECK_APPROX_EQUAL(bi.GetRotation(shape_filter.mCompoundID), Quat::sIdentity());
  72. // Check that sphere2 collided with the platform but sphere did not
  73. CHECK(contact_listener.Contains(LoggingContactListener::EType::Add, shape_filter.mPlatformID, SubShapeID(), shape_filter.mCompoundID, sphere2_id));
  74. CHECK(!contact_listener.Contains(LoggingContactListener::EType::Add, shape_filter.mPlatformID, SubShapeID(), shape_filter.mCompoundID, sphere_id));
  75. // Check that sphere2 didn't collide with the floor but that the sphere did
  76. CHECK(contact_listener.Contains(LoggingContactListener::EType::Add, floor_id, SubShapeID(), shape_filter.mCompoundID, sphere_id));
  77. CHECK(!contact_listener.Contains(LoggingContactListener::EType::Add, floor_id, SubShapeID(), shape_filter.mCompoundID, sphere2_id));
  78. }
  79. }
  80. }