added swing-twist constraint and constraint debug size control

This commit is contained in:
Turánszki János
2025-04-07 08:50:14 +02:00
parent e57cc107a6
commit 1b3f322f83
11 changed files with 177 additions and 23 deletions
Binary file not shown.
+115 -21
View File
@@ -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);
}
}
+5
View File
@@ -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;
+1
View File
@@ -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);
+1
View File
@@ -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);
+4
View File
@@ -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
+26
View File
@@ -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;
+1 -1
View File
@@ -63,7 +63,7 @@ namespace wi::scene
wi::ecs::ComponentManager<wi::VoxelGrid>& voxel_grids = componentLibrary.Register<wi::VoxelGrid>("wi::scene::Scene::voxel_grids");
wi::ecs::ComponentManager<MetadataComponent>& metadatas = componentLibrary.Register<MetadataComponent>("wi::scene::Scene::metadatas");
wi::ecs::ComponentManager<CharacterComponent>& characters = componentLibrary.Register<CharacterComponent>("wi::scene::Scene::characters");
wi::ecs::ComponentManager<PhysicsConstraintComponent>& constraints = componentLibrary.Register<PhysicsConstraintComponent>("wi::scene::Scene::constraints", 1); // version = 1
wi::ecs::ComponentManager<PhysicsConstraintComponent>& constraints = componentLibrary.Register<PhysicsConstraintComponent>("wi::scene::Scene::constraints", 2); // version = 2
// Non-serialized attributes:
float dt = 0;
+9
View File
@@ -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<void> physicsobject = nullptr; // You can set to null to recreate the physics object the next time phsyics system will be running.
+14
View File
@@ -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)
+1 -1
View File
@@ -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);