From 1b3f322f83766bf97c1228cf475d4e23eda7ad5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Mon, 7 Apr 2025 08:50:14 +0200 Subject: [PATCH] added swing-twist constraint and constraint debug size control --- Content/models/constraint_test.wiscene | Bin 43345 -> 43082 bytes Editor/ConstraintWindow.cpp | 136 +++++++++++++++++++++---- Editor/ConstraintWindow.h | 5 + Editor/GeneralWindow.cpp | 1 + Editor/RigidBodyWindow.cpp | 1 + WickedEngine/wiPhysics.h | 4 + WickedEngine/wiPhysics_Jolt.cpp | 26 +++++ WickedEngine/wiScene.h | 2 +- WickedEngine/wiScene_Components.h | 9 ++ WickedEngine/wiScene_Serializers.cpp | 14 +++ WickedEngine/wiVersion.cpp | 2 +- 11 files changed, 177 insertions(+), 23 deletions(-) diff --git a/Content/models/constraint_test.wiscene b/Content/models/constraint_test.wiscene index e7eefa5dc0585730b664d3c80347fdb135b80102..024f4f318035a8fbb0fb4a5984a67585e066a6d1 100644 GIT binary patch delta 20824 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 M4w-9(NOURZUvXKtR{#J2 delta 23833 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 diff --git a/Editor/ConstraintWindow.cpp b/Editor/ConstraintWindow.cpp index 348ea93ca..9ab7d63dc 100644 --- a/Editor/ConstraintWindow.cpp +++ b/Editor/ConstraintWindow.cpp @@ -30,6 +30,23 @@ void ConstraintWindow::Create(EditorComponent* _editor) infoLabel.SetText("Constraints can be added to bind one or two rigid bodies. If only one body is specified, then it will be bound to the constraint's location. If two bodies are specified, they will be bound together with the constraint acting as the pivot between them at the time of binding."); AddWidget(&infoLabel); + physicsDebugCheckBox.Create(ICON_EYE " Physics visualizer: "); + physicsDebugCheckBox.SetTooltip("Visualize the physics world"); + physicsDebugCheckBox.OnClick([=](wi::gui::EventArgs args) { + wi::physics::SetDebugDrawEnabled(args.bValue); + editor->generalWnd.physicsDebugCheckBox.SetCheck(args.bValue); + editor->componentsWnd.rigidWnd.physicsDebugCheckBox.SetCheck(args.bValue); + }); + physicsDebugCheckBox.SetCheck(wi::physics::IsDebugDrawEnabled()); + AddWidget(&physicsDebugCheckBox); + + constraintDebugSlider.Create(0, 10, 1, 100, "Debug size: "); + constraintDebugSlider.SetValue(wi::physics::GetConstraintDebugSize()); + constraintDebugSlider.OnSlide([](wi::gui::EventArgs args) { + wi::physics::SetConstraintDebugSize(args.fValue); + }); + AddWidget(&constraintDebugSlider); + rebindButton.Create("Rebind Constraint"); rebindButton.OnClick([this](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); @@ -51,6 +68,7 @@ void ConstraintWindow::Create(EditorComponent* _editor) typeComboBox.AddItem("Hinge", (uint64_t)PhysicsConstraintComponent::Type::Hinge); typeComboBox.AddItem("Cone", (uint64_t)PhysicsConstraintComponent::Type::Cone); typeComboBox.AddItem("Six DOF", (uint64_t)PhysicsConstraintComponent::Type::SixDOF); + typeComboBox.AddItem("Swing Twist", (uint64_t)PhysicsConstraintComponent::Type::SwingTwist); typeComboBox.OnSelect([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -121,6 +139,9 @@ void ConstraintWindow::Create(EditorComponent* _editor) case PhysicsConstraintComponent::Type::Cone: physicscomponent->cone_constraint.half_cone_angle = wi::math::DegreesToRadians(args.fValue); break; + case PhysicsConstraintComponent::Type::SwingTwist: + physicscomponent->swing_twist.min_twist_angle = wi::math::DegreesToRadians(args.fValue); + break; default: break; } @@ -146,6 +167,9 @@ void ConstraintWindow::Create(EditorComponent* _editor) case PhysicsConstraintComponent::Type::Hinge: physicscomponent->hinge_constraint.max_angle = wi::math::DegreesToRadians(args.fValue); break; + case PhysicsConstraintComponent::Type::SwingTwist: + physicscomponent->swing_twist.max_twist_angle = wi::math::DegreesToRadians(args.fValue); + break; default: break; } @@ -157,6 +181,38 @@ void ConstraintWindow::Create(EditorComponent* _editor) + normalConeSlider.Create(0, 90, 1, 90, "Normal Angle: "); + normalConeSlider.OnSlide([&](wi::gui::EventArgs args) { + wi::scene::Scene& scene = editor->GetCurrentScene(); + for (auto& x : editor->translator.selected) + { + PhysicsConstraintComponent* physicscomponent = scene.constraints.GetComponent(x.entity); + if (physicscomponent != nullptr) + { + physicscomponent->swing_twist.normal_half_cone_angle = wi::math::DegreesToRadians(args.fValue); + physicscomponent->SetRefreshParametersNeeded(true); + } + } + }); + AddWidget(&normalConeSlider); + + planeConeSlider.Create(0, 90, 1, 90, "Plane Angle: "); + planeConeSlider.OnSlide([&](wi::gui::EventArgs args) { + wi::scene::Scene& scene = editor->GetCurrentScene(); + for (auto& x : editor->translator.selected) + { + PhysicsConstraintComponent* physicscomponent = scene.constraints.GetComponent(x.entity); + if (physicscomponent != nullptr) + { + physicscomponent->swing_twist.plane_half_cone_angle = wi::math::DegreesToRadians(args.fValue); + physicscomponent->SetRefreshParametersNeeded(true); + } + } + }); + AddWidget(&planeConeSlider); + + + fixedXButton.Create("Fix X"); fixedXButton.OnClick([=](wi::gui::EventArgs args) { @@ -479,6 +535,16 @@ void ConstraintWindow::SetEntity(Entity entity) minSlider.SetRange(0, 90); minSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->cone_constraint.half_cone_angle)); break; + case PhysicsConstraintComponent::Type::SwingTwist: + minSlider.SetText("Min twist angle: "); + maxSlider.SetText("Max twist angle: "); + minSlider.SetRange(-180, 0); + maxSlider.SetRange(0, 180); + minSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->swing_twist.min_twist_angle)); + maxSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->swing_twist.max_twist_angle)); + normalConeSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->swing_twist.normal_half_cone_angle)); + planeConeSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->swing_twist.plane_half_cone_angle)); + break; default: break; } @@ -569,6 +635,7 @@ void ConstraintWindow::ResizeLayout() const PhysicsConstraintComponent* physicsComponent = scene.constraints.GetComponent(entity); if (physicsComponent != nullptr) { + switch (physicsComponent->type) { case PhysicsConstraintComponent::Type::Distance: @@ -576,6 +643,34 @@ void ConstraintWindow::ResizeLayout() minSlider.SetVisible(true); maxSlider.SetVisible(true); + normalConeSlider.SetVisible(false); + planeConeSlider.SetVisible(false); + + fixedXButton.SetVisible(false); + fixedYButton.SetVisible(false); + fixedZButton.SetVisible(false); + fixedXRotationButton.SetVisible(false); + fixedYRotationButton.SetVisible(false); + fixedZRotationButton.SetVisible(false); + minTranslationXSlider.SetVisible(false); + minTranslationYSlider.SetVisible(false); + minTranslationZSlider.SetVisible(false); + maxTranslationXSlider.SetVisible(false); + maxTranslationYSlider.SetVisible(false); + maxTranslationZSlider.SetVisible(false); + minRotationXSlider.SetVisible(false); + minRotationYSlider.SetVisible(false); + minRotationZSlider.SetVisible(false); + maxRotationXSlider.SetVisible(false); + maxRotationYSlider.SetVisible(false); + maxRotationZSlider.SetVisible(false); + break; + case PhysicsConstraintComponent::Type::SwingTwist: + minSlider.SetVisible(true); + maxSlider.SetVisible(true); + normalConeSlider.SetVisible(true); + planeConeSlider.SetVisible(true); + fixedXButton.SetVisible(false); fixedYButton.SetVisible(false); fixedZButton.SetVisible(false); @@ -599,6 +694,9 @@ void ConstraintWindow::ResizeLayout() minSlider.SetVisible(true); maxSlider.SetVisible(false); + normalConeSlider.SetVisible(false); + planeConeSlider.SetVisible(false); + fixedXButton.SetVisible(false); fixedYButton.SetVisible(false); fixedZButton.SetVisible(false); @@ -622,6 +720,9 @@ void ConstraintWindow::ResizeLayout() minSlider.SetVisible(false); maxSlider.SetVisible(false); + normalConeSlider.SetVisible(false); + planeConeSlider.SetVisible(false); + fixedXButton.SetVisible(true); fixedYButton.SetVisible(true); fixedZButton.SetVisible(true); @@ -661,30 +762,20 @@ void ConstraintWindow::ResizeLayout() add(maxRotationZSlider); break; default: - minSlider.SetVisible(false); - maxSlider.SetVisible(false); - - fixedXButton.SetVisible(false); - fixedYButton.SetVisible(false); - fixedZButton.SetVisible(false); - fixedXRotationButton.SetVisible(false); - fixedYRotationButton.SetVisible(false); - fixedZRotationButton.SetVisible(false); - minTranslationXSlider.SetVisible(false); - minTranslationYSlider.SetVisible(false); - minTranslationZSlider.SetVisible(false); - maxTranslationXSlider.SetVisible(false); - maxTranslationYSlider.SetVisible(false); - maxTranslationZSlider.SetVisible(false); - minRotationXSlider.SetVisible(false); - minRotationYSlider.SetVisible(false); - minRotationZSlider.SetVisible(false); - maxRotationXSlider.SetVisible(false); - maxRotationYSlider.SetVisible(false); - maxRotationZSlider.SetVisible(false); break; } + margin_right = 40; + + if (normalConeSlider.IsVisible()) + { + add(normalConeSlider); + } + if (planeConeSlider.IsVisible()) + { + add(planeConeSlider); + } + if (minSlider.IsVisible()) { add(minSlider); @@ -693,5 +784,8 @@ void ConstraintWindow::ResizeLayout() { add(maxSlider); } + + add_right(physicsDebugCheckBox); + add(constraintDebugSlider); } } diff --git a/Editor/ConstraintWindow.h b/Editor/ConstraintWindow.h index 04ba0a643..f94e556af 100644 --- a/Editor/ConstraintWindow.h +++ b/Editor/ConstraintWindow.h @@ -11,6 +11,8 @@ public: void SetEntity(wi::ecs::Entity entity); wi::gui::Label infoLabel; + wi::gui::CheckBox physicsDebugCheckBox; + wi::gui::Slider constraintDebugSlider; wi::gui::Button rebindButton; wi::gui::ComboBox typeComboBox; wi::gui::ComboBox bodyAComboBox; @@ -18,6 +20,9 @@ public: wi::gui::Slider minSlider; wi::gui::Slider maxSlider; + wi::gui::Slider normalConeSlider; + wi::gui::Slider planeConeSlider; + wi::gui::Button fixedXButton; wi::gui::Button fixedYButton; wi::gui::Button fixedZButton; diff --git a/Editor/GeneralWindow.cpp b/Editor/GeneralWindow.cpp index 138fcbd8c..78ae88d11 100644 --- a/Editor/GeneralWindow.cpp +++ b/Editor/GeneralWindow.cpp @@ -33,6 +33,7 @@ void GeneralWindow::Create(EditorComponent* _editor) physicsDebugCheckBox.OnClick([=](wi::gui::EventArgs args) { wi::physics::SetDebugDrawEnabled(args.bValue); editor->componentsWnd.rigidWnd.physicsDebugCheckBox.SetCheck(args.bValue); + editor->componentsWnd.constraintWnd.physicsDebugCheckBox.SetCheck(args.bValue); }); physicsDebugCheckBox.SetCheck(wi::physics::IsDebugDrawEnabled()); AddWidget(&physicsDebugCheckBox); diff --git a/Editor/RigidBodyWindow.cpp b/Editor/RigidBodyWindow.cpp index 970dceb7c..794202678 100644 --- a/Editor/RigidBodyWindow.cpp +++ b/Editor/RigidBodyWindow.cpp @@ -355,6 +355,7 @@ void RigidBodyWindow::Create(EditorComponent* _editor) physicsDebugCheckBox.OnClick([=](wi::gui::EventArgs args) { wi::physics::SetDebugDrawEnabled(args.bValue); editor->generalWnd.physicsDebugCheckBox.SetCheck(args.bValue); + editor->componentsWnd.constraintWnd.physicsDebugCheckBox.SetCheck(args.bValue); }); physicsDebugCheckBox.SetCheck(wi::physics::IsDebugDrawEnabled()); AddWidget(&physicsDebugCheckBox); diff --git a/WickedEngine/wiPhysics.h b/WickedEngine/wiPhysics.h index 1e1e39ed8..8f78258c6 100644 --- a/WickedEngine/wiPhysics.h +++ b/WickedEngine/wiPhysics.h @@ -30,6 +30,10 @@ namespace wi::physics void SetDebugDrawEnabled(bool value); bool IsDebugDrawEnabled(); + // Adjust constraint debugging sizes + void SetConstraintDebugSize(float value); + float GetConstraintDebugSize(); + // Set the accuracy of the simulation // This value corresponds to maximum simulation step count // Higher values will be slower but more accurate diff --git a/WickedEngine/wiPhysics_Jolt.cpp b/WickedEngine/wiPhysics_Jolt.cpp index 07cd692aa..f04d46c88 100644 --- a/WickedEngine/wiPhysics_Jolt.cpp +++ b/WickedEngine/wiPhysics_Jolt.cpp @@ -81,6 +81,7 @@ namespace wi::physics bool ENABLED = true; bool SIMULATION_ENABLED = true; bool DEBUGDRAW_ENABLED = false; + float CONSTRAINT_DEBUGSIZE = 1; int ACCURACY = 4; int softbodyIterationCount = 6; float TIMESTEP = 1.0f / 60.0f; @@ -1056,6 +1057,19 @@ namespace wi::physics settings.mLimitMax[SixDOFConstraintSettings::EAxis::RotationZ] = physicscomponent.six_dof.maxRotationAxes.z; physicsobject.constraint = settings.Create(*body1, *body2); } + else if (physicscomponent.type == PhysicsConstraintComponent::Type::SwingTwist) + { + SwingTwistConstraintSettings settings; + settings.mSpace = EConstraintSpace::WorldSpace; + settings.mPosition1 = settings.mPosition2 = cast(transform.GetPosition()); + settings.mTwistAxis1 = settings.mTwistAxis2 = cast(transform.GetRight()).Normalized(); + settings.mPlaneAxis1 = settings.mPlaneAxis2 = cast(transform.GetUp()).Normalized(); + settings.mNormalHalfConeAngle = physicscomponent.swing_twist.normal_half_cone_angle; + settings.mPlaneHalfConeAngle = physicscomponent.swing_twist.plane_half_cone_angle; + settings.mTwistMinAngle = physicscomponent.swing_twist.min_twist_angle; + settings.mTwistMaxAngle = physicscomponent.swing_twist.max_twist_angle; + physicsobject.constraint = settings.Create(*body1, *body2); + } else { wilog("Constraint creation failed: constraint type is not valid!"); @@ -1812,6 +1826,9 @@ namespace wi::physics bool IsDebugDrawEnabled() { return DEBUGDRAW_ENABLED; } void SetDebugDrawEnabled(bool value) { DEBUGDRAW_ENABLED = value; } + void SetConstraintDebugSize(float value) { CONSTRAINT_DEBUGSIZE = value; } + float GetConstraintDebugSize() { return CONSTRAINT_DEBUGSIZE; } + int GetAccuracy() { return ACCURACY; } void SetAccuracy(int value) { ACCURACY = value; } @@ -1989,6 +2006,14 @@ namespace wi::physics ptr->SetTranslationLimits(cast(physicscomponent.six_dof.minTranslationAxes), cast(physicscomponent.six_dof.maxTranslationAxes)); ptr->SetRotationLimits(cast(physicscomponent.six_dof.minRotationAxes), cast(physicscomponent.six_dof.maxRotationAxes)); } + else if (physicscomponent.type == PhysicsConstraintComponent::Type::SwingTwist) + { + SwingTwistConstraint* ptr = ((SwingTwistConstraint*)constraint.constraint.GetPtr()); + ptr->SetNormalHalfConeAngle(physicscomponent.swing_twist.normal_half_cone_angle); + ptr->SetPlaneHalfConeAngle(physicscomponent.swing_twist.plane_half_cone_angle); + ptr->SetTwistMinAngle(physicscomponent.swing_twist.min_twist_angle); + ptr->SetTwistMaxAngle(physicscomponent.swing_twist.max_twist_angle); + } } }); @@ -2345,6 +2370,7 @@ namespace wi::physics if (physicscomponent.physicsobject == nullptr) return; Constraint& constraint = GetConstraint(physicscomponent); + constraint.constraint->SetDrawConstraintSize(CONSTRAINT_DEBUGSIZE); if (constraint.body1_self.IsInvalid() && constraint.body2_self.IsInvalid()) return; diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index 0762f3629..437d9b129 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -63,7 +63,7 @@ namespace wi::scene wi::ecs::ComponentManager& voxel_grids = componentLibrary.Register("wi::scene::Scene::voxel_grids"); wi::ecs::ComponentManager& metadatas = componentLibrary.Register("wi::scene::Scene::metadatas"); wi::ecs::ComponentManager& characters = componentLibrary.Register("wi::scene::Scene::characters"); - wi::ecs::ComponentManager& constraints = componentLibrary.Register("wi::scene::Scene::constraints", 1); // version = 1 + wi::ecs::ComponentManager& constraints = componentLibrary.Register("wi::scene::Scene::constraints", 2); // version = 2 // Non-serialized attributes: float dt = 0; diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index 90d56c3cf..58ca3076f 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -543,6 +543,7 @@ namespace wi::scene Hinge, // rotation around a point on the UP axis of the contraint transform Cone, // constrain to a cone shape specified by the cone angle SixDOF, // manual specification of axes movement and rotation limits + SwingTwist, // cone + rotational limits } type = Type::Fixed; wi::ecs::Entity bodyA = wi::ecs::INVALID_ENTITY; @@ -587,6 +588,14 @@ namespace wi::scene void SetFreeRotationZ() { minRotationAxes.z = -XM_PI; maxRotationAxes.z = XM_PI; } } six_dof; + struct SwingTwistConstraintSettings + { + float normal_half_cone_angle = 0; // radians + float plane_half_cone_angle = 0; // radians + float min_twist_angle = 0; // radians [-PI, PI] + float max_twist_angle = 0; // radians [-PI, PI] + } swing_twist; + // Non-serialized attributes: std::shared_ptr physicsobject = nullptr; // You can set to null to recreate the physics object the next time phsyics system will be running. diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index cc9283ba2..9e62f2dfb 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -929,6 +929,13 @@ namespace wi::scene archive >> six_dof.minRotationAxes; archive >> six_dof.maxRotationAxes; } + if (seri.GetVersion() >= 2) + { + archive >> swing_twist.normal_half_cone_angle; + archive >> swing_twist.plane_half_cone_angle; + archive >> swing_twist.min_twist_angle; + archive >> swing_twist.max_twist_angle; + } } else { @@ -948,6 +955,13 @@ namespace wi::scene archive << six_dof.minRotationAxes; archive << six_dof.maxRotationAxes; } + if (seri.GetVersion() >= 2) + { + archive << swing_twist.normal_half_cone_angle; + archive << swing_twist.plane_half_cone_angle; + archive << swing_twist.min_twist_angle; + archive << swing_twist.max_twist_angle; + } } } void SoftBodyPhysicsComponent::Serialize(wi::Archive& archive, EntitySerializer& seri) diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 1421ac3bb..8f9bcba33 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 732; + const int revision = 733; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);