DistanceConstraintTests.cpp 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2023 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include "UnitTestFramework.h"
  5. #include "PhysicsTestContext.h"
  6. #include <Jolt/Physics/Constraints/DistanceConstraint.h>
  7. #include "Layers.h"
  8. TEST_SUITE("DistanceConstraintTests")
  9. {
  10. // Test if the distance constraint can be used to create a spring
  11. TEST_CASE("TestDistanceSpring")
  12. {
  13. // Configuration of the spring
  14. const RVec3 cInitialPosition(10, 0, 0);
  15. const float cFrequency = 2.0f;
  16. const float cDamping = 0.1f;
  17. for (int mode = 0; mode < 2; ++mode)
  18. {
  19. // Create a sphere
  20. PhysicsTestContext context;
  21. context.ZeroGravity();
  22. Body &body = context.CreateSphere(cInitialPosition, 0.5f, EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING);
  23. body.GetMotionProperties()->SetLinearDamping(0.0f);
  24. // Calculate stiffness and damping of spring
  25. float m = 1.0f / body.GetMotionProperties()->GetInverseMass();
  26. float omega = 2.0f * JPH_PI * cFrequency;
  27. float k = m * Square(omega);
  28. float c = 2.0f * m * cDamping * omega;
  29. // Create spring
  30. DistanceConstraintSettings constraint;
  31. constraint.mPoint2 = cInitialPosition;
  32. if (mode == 0)
  33. {
  34. // First iteration use stiffness and damping
  35. constraint.mLimitsSpringSettings.mMode = ESpringMode::StiffnessAndDamping;
  36. constraint.mLimitsSpringSettings.mStiffness = k;
  37. constraint.mLimitsSpringSettings.mDamping = c;
  38. }
  39. else
  40. {
  41. // Second iteration use frequency and damping
  42. constraint.mLimitsSpringSettings.mMode = ESpringMode::FrequencyAndDamping;
  43. constraint.mLimitsSpringSettings.mFrequency = cFrequency;
  44. constraint.mLimitsSpringSettings.mDamping = cDamping;
  45. }
  46. constraint.mMinDistance = constraint.mMaxDistance = 0.0f;
  47. context.CreateConstraint<DistanceConstraint>(Body::sFixedToWorld, body, constraint);
  48. // Simulate spring
  49. Real x = cInitialPosition.GetX();
  50. float v = 0.0f;
  51. float dt = context.GetDeltaTime();
  52. for (int i = 0; i < 120; ++i)
  53. {
  54. // Using the equations from page 32 of Soft Constraints: Reinventing The Spring - Erin Catto - GDC 2011 for an implicit euler spring damper
  55. v = (v - dt * k / m * float(x)) / (1.0f + dt * c / m + Square(dt) * k / m);
  56. x += v * dt;
  57. // Run physics simulation
  58. context.SimulateSingleStep();
  59. // Test if simulation matches prediction
  60. CHECK_APPROX_EQUAL(x, body.GetPosition().GetX(), 5.0e-6_r);
  61. CHECK(body.GetPosition().GetY() == 0);
  62. CHECK(body.GetPosition().GetZ() == 0);
  63. }
  64. }
  65. }
  66. }