ShapeFilterTests.cpp 4.3 KB

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