VehicleStressTest.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2023 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <TestFramework.h>
  5. #include <Tests/Vehicle/VehicleStressTest.h>
  6. #include <Jolt/Physics/Collision/Shape/BoxShape.h>
  7. #include <Jolt/Physics/Vehicle/WheeledVehicleController.h>
  8. #include <Jolt/Physics/Body/BodyCreationSettings.h>
  9. #include <Layers.h>
  10. #include <Renderer/DebugRendererImp.h>
  11. JPH_IMPLEMENT_RTTI_VIRTUAL(VehicleStressTest)
  12. {
  13. JPH_ADD_BASE_CLASS(VehicleStressTest, VehicleTest)
  14. }
  15. VehicleStressTest::~VehicleStressTest()
  16. {
  17. for (Ref<VehicleConstraint> &c : mVehicles)
  18. mPhysicsSystem->RemoveStepListener(c);
  19. }
  20. void VehicleStressTest::Initialize()
  21. {
  22. CreateMeshTerrain();
  23. // Create walls so the vehicles don't fall off
  24. mBodyInterface->CreateAndAddBody(BodyCreationSettings(new BoxShape(Vec3(50.0f, 5.0f, 0.5f)), RVec3(0, 0, -50), Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING), EActivation::DontActivate);
  25. mBodyInterface->CreateAndAddBody(BodyCreationSettings(new BoxShape(Vec3(50.0f, 5.0f, 0.5f)), RVec3(0, 0, 50), Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING), EActivation::DontActivate);
  26. mBodyInterface->CreateAndAddBody(BodyCreationSettings(new BoxShape(Vec3(0.5f, 5.0f, 50.0f)), RVec3(-50, 0, 0), Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING), EActivation::DontActivate);
  27. mBodyInterface->CreateAndAddBody(BodyCreationSettings(new BoxShape(Vec3(0.5f, 5.0f, 50.0f)), RVec3(50, 0, 0), Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING), EActivation::DontActivate);
  28. const float wheel_radius = 0.3f;
  29. const float wheel_width = 0.1f;
  30. const float half_vehicle_length = 2.0f;
  31. const float half_vehicle_width = 0.9f;
  32. const float half_vehicle_height = 0.2f;
  33. const float max_steering_angle = DegreesToRadians(30.0f);
  34. // Create vehicle body
  35. RefConst<Shape> car_shape = new BoxShape(Vec3(half_vehicle_width, half_vehicle_height, half_vehicle_length));
  36. BodyCreationSettings car_body_settings(car_shape, RVec3::sZero(), Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING);
  37. car_body_settings.mOverrideMassProperties = EOverrideMassProperties::CalculateInertia;
  38. car_body_settings.mMassPropertiesOverride.mMass = 1500.0f;
  39. // Create vehicle constraint
  40. VehicleConstraintSettings vehicle;
  41. // Wheels, left front
  42. WheelSettingsWV *w1 = new WheelSettingsWV;
  43. w1->mPosition = Vec3(half_vehicle_width, -0.9f * half_vehicle_height, half_vehicle_length - 2.0f * wheel_radius);
  44. w1->mMaxSteerAngle = max_steering_angle;
  45. w1->mMaxHandBrakeTorque = 0.0f; // Front wheel doesn't have hand brake
  46. // Right front
  47. WheelSettingsWV *w2 = new WheelSettingsWV;
  48. w2->mPosition = Vec3(-half_vehicle_width, -0.9f * half_vehicle_height, half_vehicle_length - 2.0f * wheel_radius);
  49. w2->mMaxSteerAngle = max_steering_angle;
  50. w2->mMaxHandBrakeTorque = 0.0f; // Front wheel doesn't have hand brake
  51. // Left rear
  52. WheelSettingsWV *w3 = new WheelSettingsWV;
  53. w3->mPosition = Vec3(half_vehicle_width, -0.9f * half_vehicle_height, -half_vehicle_length + 2.0f * wheel_radius);
  54. w3->mMaxSteerAngle = 0.0f;
  55. // Right rear
  56. WheelSettingsWV *w4 = new WheelSettingsWV;
  57. w4->mPosition = Vec3(-half_vehicle_width, -0.9f * half_vehicle_height, -half_vehicle_length + 2.0f * wheel_radius);
  58. w4->mMaxSteerAngle = 0.0f;
  59. vehicle.mWheels = { w1, w2, w3, w4 };
  60. for (WheelSettings *w : vehicle.mWheels)
  61. {
  62. w->mRadius = wheel_radius;
  63. w->mWidth = wheel_width;
  64. }
  65. // Controller
  66. WheeledVehicleControllerSettings *controller = new WheeledVehicleControllerSettings;
  67. vehicle.mController = controller;
  68. vehicle.mMaxPitchRollAngle = DegreesToRadians(60.0f);
  69. // Differential
  70. controller->mDifferentials.resize(1);
  71. controller->mDifferentials[0].mLeftWheel = 0;
  72. controller->mDifferentials[0].mRightWheel = 1;
  73. for (int x = 0; x < 15; ++x)
  74. for (int y = 0; y < 15; ++y)
  75. {
  76. // Create body
  77. car_body_settings.mPosition = RVec3(-28.0f + x * 4.0f, 2.0f, -35.0f + y * 5.0f);
  78. Body *car_body = mBodyInterface->CreateBody(car_body_settings);
  79. mBodyInterface->AddBody(car_body->GetID(), EActivation::Activate);
  80. // Create constraint
  81. VehicleConstraint *c = new VehicleConstraint(*car_body, vehicle);
  82. c->SetNumStepsBetweenCollisionTestActive(2); // Only test collision every other step to speed up simulation
  83. c->SetNumStepsBetweenCollisionTestInactive(0); // Disable collision testing when inactive
  84. // Set the collision tester
  85. VehicleCollisionTester *tester = new VehicleCollisionTesterRay(Layers::MOVING);
  86. c->SetVehicleCollisionTester(tester);
  87. // Add the vehicle
  88. mPhysicsSystem->AddConstraint(c);
  89. mPhysicsSystem->AddStepListener(c);
  90. mVehicles.push_back(c);
  91. }
  92. }
  93. void VehicleStressTest::ProcessInput(const ProcessInputParams &inParams)
  94. {
  95. // Determine acceleration and brake
  96. mForward = 0.0f;
  97. if (inParams.mKeyboard->IsKeyPressed(DIK_UP))
  98. mForward = 1.0f;
  99. else if (inParams.mKeyboard->IsKeyPressed(DIK_DOWN))
  100. mForward = -1.0f;
  101. // Steering
  102. mRight = 0.0f;
  103. if (inParams.mKeyboard->IsKeyPressed(DIK_LEFT))
  104. mRight = -1.0f;
  105. else if (inParams.mKeyboard->IsKeyPressed(DIK_RIGHT))
  106. mRight = 1.0f;
  107. // Hand brake will cancel gas pedal
  108. mHandBrake = 0.0f;
  109. if (inParams.mKeyboard->IsKeyPressed(DIK_Z))
  110. {
  111. mForward = 0.0f;
  112. mHandBrake = 1.0f;
  113. }
  114. }
  115. void VehicleStressTest::PrePhysicsUpdate(const PreUpdateParams &inParams)
  116. {
  117. for (VehicleConstraint *c : mVehicles)
  118. {
  119. // On user input, assure that the car is active
  120. if (mRight != 0.0f || mForward != 0.0f)
  121. mBodyInterface->ActivateBody(c->GetVehicleBody()->GetID());
  122. // Pass the input on to the constraint
  123. WheeledVehicleController *controller = static_cast<WheeledVehicleController *>(c->GetController());
  124. controller->SetDriverInput(mForward, mRight, 0.0f, mHandBrake);
  125. // Draw our wheels (this needs to be done in the pre update since we draw the bodies too in the state before the step)
  126. for (uint w = 0; w < 4; ++w)
  127. {
  128. const WheelSettings *settings = c->GetWheels()[w]->GetSettings();
  129. RMat44 wheel_transform = c->GetWheelWorldTransform(w, Vec3::sAxisY(), Vec3::sAxisX()); // The cylinder we draw is aligned with Y so we specify that as rotational axis
  130. mDebugRenderer->DrawCylinder(wheel_transform, 0.5f * settings->mWidth, settings->mRadius, Color::sGreen);
  131. }
  132. }
  133. }
  134. void VehicleStressTest::SaveInputState(StateRecorder &inStream) const
  135. {
  136. inStream.Write(mForward);
  137. inStream.Write(mRight);
  138. inStream.Write(mHandBrake);
  139. }
  140. void VehicleStressTest::RestoreInputState(StateRecorder &inStream)
  141. {
  142. inStream.Read(mForward);
  143. inStream.Read(mRight);
  144. inStream.Read(mHandBrake);
  145. }