Files
CosmicEngine/lib/All/JoltPhysics/Samples/Tests/Constraints/PoweredSwingTwistConstraintTest.cpp

143 lines
7.6 KiB
C++
Raw Permalink Normal View History

// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <TestFramework.h>
#include <Tests/Constraints/PoweredSwingTwistConstraintTest.h>
#include <Jolt/Physics/Collision/Shape/BoxShape.h>
#include <Jolt/Physics/Collision/GroupFilterTable.h>
#include <Jolt/Physics/Body/BodyCreationSettings.h>
#include <Application/DebugUI.h>
#include <Layers.h>
JPH_IMPLEMENT_RTTI_VIRTUAL(PoweredSwingTwistConstraintTest)
{
JPH_ADD_BASE_CLASS(PoweredSwingTwistConstraintTest, Test)
}
Vec3 PoweredSwingTwistConstraintTest::sBodyRotation[] = { Vec3::sZero(), Vec3::sZero() };
void PoweredSwingTwistConstraintTest::Initialize()
{
// Floor
CreateFloor();
// Create group filter
Ref<GroupFilterTable> group_filter = new GroupFilterTable;
float half_box_height = 1.5f;
RefConst<Shape> box = new BoxShape(Vec3(0.25f, half_box_height, 0.5f));
Quat body1_rotation = Quat::sEulerAngles(sBodyRotation[0]);
Quat body2_rotation = Quat::sEulerAngles(sBodyRotation[1]) * body1_rotation;
RVec3 body1_position(0, 20, 0);
Body &body1 = *mBodyInterface->CreateBody(BodyCreationSettings(box, body1_position, body1_rotation, EMotionType::Static, Layers::NON_MOVING));
body1.SetCollisionGroup(CollisionGroup(group_filter, 0, 0));
mBodyInterface->AddBody(body1.GetID(), EActivation::DontActivate);
RVec3 constraint_position = body1_position + body1_rotation * Vec3(0, -half_box_height, 0);
RVec3 body2_position = constraint_position + body2_rotation * Vec3(0, -half_box_height, 0);
Body &body2 = *mBodyInterface->CreateBody(BodyCreationSettings(box, body2_position, body2_rotation, EMotionType::Dynamic, Layers::MOVING));
body2.SetCollisionGroup(CollisionGroup(group_filter, 0, 0));
body2.GetMotionProperties()->SetLinearDamping(0.0f);
body2.GetMotionProperties()->SetAngularDamping(0.0f);
body2.SetAllowSleeping(false);
mBodyInterface->AddBody(body2.GetID(), EActivation::Activate);
Ref<SwingTwistConstraintSettings> settings = new SwingTwistConstraintSettings;
settings->mNormalHalfConeAngle = sNormalHalfConeAngle;
settings->mPlaneHalfConeAngle = sPlaneHalfConeAngle;
settings->mTwistMinAngle = sTwistMinAngle;
settings->mTwistMaxAngle = sTwistMaxAngle;
settings->mPosition1 = settings->mPosition2 = constraint_position;
settings->mTwistAxis1 = settings->mTwistAxis2 = -body1_rotation.RotateAxisY();
settings->mPlaneAxis1 = settings->mPlaneAxis2 = body1_rotation.RotateAxisX();
mConstraint = static_cast<SwingTwistConstraint *>(settings->Create(body1, body2));
mPhysicsSystem->AddConstraint(mConstraint);
// Calculate inertia along the axis of the box, so that the acceleration of the motor / friction are correct for twist
Mat44 body2_inertia = body2.GetMotionProperties()->GetLocalSpaceInverseInertia().Inversed3x3();
mInertiaBody2AsSeenFromConstraint = (body2_inertia * Vec3::sAxisY()).Length();
}
void PoweredSwingTwistConstraintTest::PrePhysicsUpdate(const PreUpdateParams &inParams)
{
// Torque = Inertia * Angular Acceleration (alpha)
mConstraint->SetMaxFrictionTorque(mInertiaBody2AsSeenFromConstraint * sMaxFrictionAngularAcceleration);
mConstraint->SetNormalHalfConeAngle(sNormalHalfConeAngle);
mConstraint->SetPlaneHalfConeAngle(sPlaneHalfConeAngle);
mConstraint->SetTwistMinAngle(sTwistMinAngle);
mConstraint->SetTwistMaxAngle(sTwistMaxAngle);
mConstraint->SetSwingMotorState(sSwingMotorState);
mConstraint->SetTwistMotorState(sTwistMotorState);
mConstraint->SetTargetAngularVelocityCS(sTargetVelocityCS);
mConstraint->SetTargetOrientationCS(Quat::sEulerAngles(sTargetOrientationCS));
MotorSettings &swing = mConstraint->GetSwingMotorSettings();
swing.SetTorqueLimit(mInertiaBody2AsSeenFromConstraint * sMaxAngularAcceleration);
swing.mSpringSettings.mFrequency = sFrequency;
swing.mSpringSettings.mDamping = sDamping;
MotorSettings &twist = mConstraint->GetTwistMotorSettings();
twist.SetTorqueLimit(mInertiaBody2AsSeenFromConstraint * sMaxAngularAcceleration);
twist.mSpringSettings.mFrequency = sFrequency;
twist.mSpringSettings.mDamping = sDamping;
}
void PoweredSwingTwistConstraintTest::GetInitialCamera(CameraState &ioState) const
{
ioState.mPos = RVec3(4, 25, 4);
ioState.mForward = Vec3(-1, -1, -1).Normalized();
}
void PoweredSwingTwistConstraintTest::CreateSettingsMenu(DebugUI *inUI, UIElement *inSubMenu)
{
Array<String> axis_label = { "X", "Y", "Z" };
Array<String> constraint_label = { "Twist", "Plane", "Normal" };
inUI->CreateTextButton(inSubMenu, "Configuration Settings", [this, inUI, axis_label]() {
UIElement *configuration_settings = inUI->CreateMenu();
for (int body = 0; body < 2; ++body)
for (int axis = 0; axis < 3; ++axis)
inUI->CreateSlider(configuration_settings, "Body " + ConvertToString(body + 1) + " Rotation " + axis_label[axis] + " (deg)", RadiansToDegrees(sBodyRotation[body][axis]), -180.0f, 180.0f, 1.0f, [=](float inValue) { sBodyRotation[body].SetComponent(axis, DegreesToRadians(inValue)); });
inUI->CreateTextButton(configuration_settings, "Accept Changes", [this]() { RestartTest(); });
inUI->ShowMenu(configuration_settings);
});
inUI->CreateTextButton(inSubMenu, "Runtime Settings", [=]() {
UIElement *runtime_settings = inUI->CreateMenu();
inUI->CreateSlider(runtime_settings, "Min Twist Angle (deg)", RadiansToDegrees(sTwistMinAngle), -180.0f, 180.0f, 1.0f, [=](float inValue) { sTwistMinAngle = DegreesToRadians(inValue); });
inUI->CreateSlider(runtime_settings, "Max Twist Angle (deg)", RadiansToDegrees(sTwistMaxAngle), -180.0f, 180.0f, 1.0f, [=](float inValue) { sTwistMaxAngle = DegreesToRadians(inValue); });
inUI->CreateSlider(runtime_settings, "Normal Half Cone Angle (deg)", RadiansToDegrees(sNormalHalfConeAngle), 0.0f, 180.0f, 1.0f, [=](float inValue) { sNormalHalfConeAngle = DegreesToRadians(inValue); });
inUI->CreateSlider(runtime_settings, "Plane Half Cone Angle (deg)", RadiansToDegrees(sPlaneHalfConeAngle), 0.0f, 180.0f, 1.0f, [=](float inValue) { sPlaneHalfConeAngle = DegreesToRadians(inValue); });
inUI->CreateComboBox(runtime_settings, "Swing Motor", { "Off", "Velocity", "Position" }, (int)sSwingMotorState, [=](int inItem) { sSwingMotorState = (EMotorState)inItem; });
inUI->CreateComboBox(runtime_settings, "Twist Motor", { "Off", "Velocity", "Position" }, (int)sTwistMotorState, [=](int inItem) { sTwistMotorState = (EMotorState)inItem; });
for (int i = 0; i < 3; ++i)
inUI->CreateSlider(runtime_settings, "Target Angular Velocity " + constraint_label[i] + " (deg/s)", RadiansToDegrees(sTargetVelocityCS[i]), -90.0f, 90.0f, 1.0f, [i](float inValue) { sTargetVelocityCS.SetComponent(i, DegreesToRadians(inValue)); });
for (int i = 0; i < 3; ++i)
inUI->CreateSlider(runtime_settings, "Target Angle " + constraint_label[i] + " (deg)", RadiansToDegrees(sTargetOrientationCS[i]), -180, 180.0f, 1.0f, [i](float inValue) {
sTargetOrientationCS.SetComponent(i, DegreesToRadians(Clamp(inValue, -179.99f, 179.99f))); // +/- 180 degrees is ambiguous, so add a little bit of a margin
});
inUI->CreateSlider(runtime_settings, "Max Angular Acceleration (deg/s^2)", RadiansToDegrees(sMaxAngularAcceleration), 0.0f, 36000.0f, 100.0f, [=](float inValue) { sMaxAngularAcceleration = DegreesToRadians(inValue); });
inUI->CreateSlider(runtime_settings, "Frequency (Hz)", sFrequency, 0.0f, 20.0f, 0.1f, [=](float inValue) { sFrequency = inValue; });
inUI->CreateSlider(runtime_settings, "Damping", sDamping, 0.0f, 2.0f, 0.01f, [=](float inValue) { sDamping = inValue; });
inUI->CreateSlider(runtime_settings, "Max Friction Angular Acceleration (deg/s^2)", RadiansToDegrees(sMaxFrictionAngularAcceleration), 0.0f, 900.0f, 1.0f, [=](float inValue) { sMaxFrictionAngularAcceleration = DegreesToRadians(inValue); });
inUI->ShowMenu(runtime_settings);
});
}