VehicleConstraintTest.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <TestFramework.h>
  4. #include <Tests/Vehicle/VehicleConstraintTest.h>
  5. #include <Physics/Collision/Shape/BoxShape.h>
  6. #include <Physics/Collision/Shape/OffsetCenterOfMassShape.h>
  7. #include <Physics/Vehicle/WheeledVehicleController.h>
  8. #include <Physics/Body/BodyCreationSettings.h>
  9. #include <Application/DebugUI.h>
  10. #include <Layers.h>
  11. #include <Renderer/DebugRendererImp.h>
  12. JPH_IMPLEMENT_RTTI_VIRTUAL(VehicleConstraintTest)
  13. {
  14. JPH_ADD_BASE_CLASS(VehicleConstraintTest, VehicleTest)
  15. }
  16. int VehicleConstraintTest::sCollisionMode = 1;
  17. VehicleConstraintTest::~VehicleConstraintTest()
  18. {
  19. mPhysicsSystem->RemoveStepListener(mVehicleConstraint);
  20. }
  21. void VehicleConstraintTest::Initialize()
  22. {
  23. VehicleTest::Initialize();
  24. const float wheel_radius = 0.3f;
  25. const float wheel_width = 0.1f;
  26. const float half_vehicle_length = 2.0f;
  27. const float half_vehicle_width = 0.9f;
  28. const float half_vehicle_height = 0.2f;
  29. const float suspension_min_length = 0.3f;
  30. const float suspension_max_length = 0.5f;
  31. const float suspension_frequency = 1.5f;
  32. const float max_steering_angle = DegreesToRadians(30);
  33. // Create collision testers
  34. mTesters[0] = new VehicleCollisionTesterRay(Layers::MOVING);
  35. mTesters[1] = new VehicleCollisionTesterCastSphere(Layers::MOVING, 0.5f * wheel_width);
  36. // Create vehicle body
  37. Vec3 position(0, 2, 0);
  38. RefConst<Shape> car_shape = OffsetCenterOfMassShapeSettings(Vec3(0, -half_vehicle_height, 0), new BoxShape(Vec3(half_vehicle_width, half_vehicle_height, half_vehicle_length))).Create().Get();
  39. BodyCreationSettings car_body_settings(car_shape, position, Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING);
  40. car_body_settings.mOverrideMassProperties = EOverrideMassProperties::CalculateInertia;
  41. car_body_settings.mMassPropertiesOverride.mMass = 1500.0f;
  42. mCarBody = mBodyInterface->CreateBody(car_body_settings);
  43. mBodyInterface->AddBody(mCarBody->GetID(), EActivation::Activate);
  44. // Create vehicle constraint
  45. VehicleConstraintSettings vehicle;
  46. vehicle.mDrawConstraintSize = 0.1f;
  47. vehicle.mMaxPitchRollAngle = DegreesToRadians(60.0f);
  48. // Wheels
  49. WheelSettingsWV *w1 = new WheelSettingsWV;
  50. w1->mPosition = Vec3(-half_vehicle_width, -0.9f * half_vehicle_height, half_vehicle_length - 2.0f * wheel_radius);
  51. w1->mMaxSteerAngle = max_steering_angle;
  52. w1->mMaxHandBrakeTorque = 0.0f; // Front wheel doesn't have hand brake
  53. WheelSettingsWV *w2 = new WheelSettingsWV;
  54. w2->mPosition = Vec3(half_vehicle_width, -0.9f * half_vehicle_height, half_vehicle_length - 2.0f * wheel_radius);
  55. w2->mMaxSteerAngle = max_steering_angle;
  56. w2->mMaxHandBrakeTorque = 0.0f; // Front wheel doesn't have hand brake
  57. WheelSettingsWV *w3 = new WheelSettingsWV;
  58. w3->mPosition = Vec3(-half_vehicle_width, -0.9f * half_vehicle_height, -half_vehicle_length + 2.0f * wheel_radius);
  59. w3->mMaxSteerAngle = 0.0f;
  60. WheelSettingsWV *w4 = new WheelSettingsWV;
  61. w4->mPosition = Vec3(half_vehicle_width, -0.9f * half_vehicle_height, -half_vehicle_length + 2.0f * wheel_radius);
  62. w4->mMaxSteerAngle = 0.0f;
  63. vehicle.mWheels = { w1, w2, w3, w4 };
  64. for (WheelSettings *w : vehicle.mWheels)
  65. {
  66. w->mRadius = wheel_radius;
  67. w->mWidth = wheel_width;
  68. w->mSuspensionMinLength = suspension_min_length;
  69. w->mSuspensionMaxLength = suspension_max_length;
  70. w->mSuspensionFrequency = suspension_frequency;
  71. }
  72. WheeledVehicleControllerSettings *controller = new WheeledVehicleControllerSettings;
  73. vehicle.mController = controller;
  74. // Differential
  75. controller->mDifferentials.resize(1);
  76. controller->mDifferentials[0].mLeftWheel = 0;
  77. controller->mDifferentials[0].mRightWheel = 1;
  78. // Anti rollbars
  79. vehicle.mAntiRollBars.resize(2);
  80. vehicle.mAntiRollBars[0].mLeftWheel = 0;
  81. vehicle.mAntiRollBars[0].mRightWheel = 1;
  82. vehicle.mAntiRollBars[1].mLeftWheel = 2;
  83. vehicle.mAntiRollBars[1].mRightWheel = 3;
  84. mVehicleConstraint = new VehicleConstraint(*mCarBody, vehicle);
  85. mPhysicsSystem->AddConstraint(mVehicleConstraint);
  86. mPhysicsSystem->AddStepListener(mVehicleConstraint);
  87. }
  88. void VehicleConstraintTest::PrePhysicsUpdate(const PreUpdateParams &inParams)
  89. {
  90. // Determine acceleration and brake
  91. float forward = 0.0f, right = 0.0f, brake = 0.0f, hand_brake = 0.0f;
  92. if (inParams.mKeyboard->IsKeyPressed(DIK_UP))
  93. forward = 1.0f;
  94. else if (inParams.mKeyboard->IsKeyPressed(DIK_DOWN))
  95. forward = -1.0f;
  96. // Check if we're reversing direction
  97. if (mPreviousForward * forward < 0.0f)
  98. {
  99. // Get vehicle velocity in local space to the body of the vehicle
  100. float velocity = (mCarBody->GetRotation().Conjugated() * mCarBody->GetLinearVelocity()).GetZ();
  101. if ((forward > 0.0f && velocity < -0.1f) || (forward < 0.0f && velocity > 0.1f))
  102. {
  103. // Brake while we've not stopped yet
  104. forward = 0.0f;
  105. brake = 1.0f;
  106. }
  107. else
  108. {
  109. // When we've come to a stop, accept the new direction
  110. mPreviousForward = forward;
  111. }
  112. }
  113. // Hand brake will cancel gas pedal
  114. if (inParams.mKeyboard->IsKeyPressed(DIK_Z))
  115. {
  116. forward = 0.0f;
  117. hand_brake = 1.0f;
  118. }
  119. // Steering
  120. if (inParams.mKeyboard->IsKeyPressed(DIK_LEFT))
  121. right = -1.0f;
  122. else if (inParams.mKeyboard->IsKeyPressed(DIK_RIGHT))
  123. right = 1.0f;
  124. // On user input, assure that the car is active
  125. if (right != 0.0f || forward != 0.0f || brake != 0.0f || hand_brake != 0.0f)
  126. mBodyInterface->ActivateBody(mCarBody->GetID());
  127. // Pass the input on to the constraint
  128. static_cast<WheeledVehicleController *>(mVehicleConstraint->GetController())->SetDriverInput(forward, right, brake, hand_brake);
  129. // Set the collision tester
  130. mVehicleConstraint->SetVehicleCollisionTester(mTesters[sCollisionMode]);
  131. // Draw our wheels (this needs to be done in the pre update since we draw the bodies too in the state before the step)
  132. for (uint w = 0; w < 4; ++w)
  133. {
  134. const WheelSettings *settings = mVehicleConstraint->GetWheels()[w]->GetSettings();
  135. Mat44 wheel_transform = mVehicleConstraint->GetWheelWorldTransform(w, Vec3::sAxisY(), Vec3::sAxisX()); // The cyclinder we draw is aligned with Y so we specify that as rotational axis
  136. mDebugRenderer->DrawCylinder(wheel_transform, 0.5f * settings->mWidth, settings->mRadius, Color::sGreen);
  137. }
  138. }
  139. void VehicleConstraintTest::GetInitialCamera(CameraState &ioState) const
  140. {
  141. // Position camera behind car
  142. Vec3 cam_tgt = Vec3(0, 0, 5);
  143. ioState.mPos = Vec3(0, 2.5f, -5);
  144. ioState.mForward = (cam_tgt - ioState.mPos).Normalized();
  145. }
  146. Mat44 VehicleConstraintTest::GetCameraPivot(float inCameraHeading, float inCameraPitch) const
  147. {
  148. // Pivot is center of car and rotates with car around Y axis only
  149. Vec3 fwd = mCarBody->GetRotation().RotateAxisZ();
  150. fwd.SetY(0.0f);
  151. float len = fwd.Length();
  152. if (len != 0.0f)
  153. fwd /= len;
  154. else
  155. fwd = Vec3::sAxisZ();
  156. Vec3 up = Vec3::sAxisY();
  157. Vec3 right = up.Cross(fwd);
  158. return Mat44(Vec4(right, 0), Vec4(up, 0), Vec4(fwd, 0), Vec4(mCarBody->GetPosition(), 1.0f));
  159. }
  160. void VehicleConstraintTest::CreateSettingsMenu(DebugUI *inUI, UIElement *inSubMenu)
  161. {
  162. VehicleTest::CreateSettingsMenu(inUI, inSubMenu);
  163. inUI->CreateComboBox(inSubMenu, "Collision Mode", { "Ray", "Cast Sphere" }, sCollisionMode, [](int inItem) { sCollisionMode = inItem; });
  164. }