diff --git a/Content/models/constraint_test.wiscene b/Content/models/constraint_test.wiscene index e8c05c61a..e7eefa5dc 100644 Binary files a/Content/models/constraint_test.wiscene and b/Content/models/constraint_test.wiscene differ diff --git a/Editor/ConstraintWindow.cpp b/Editor/ConstraintWindow.cpp index a2f4e6bd1..348ea93ca 100644 --- a/Editor/ConstraintWindow.cpp +++ b/Editor/ConstraintWindow.cpp @@ -50,6 +50,7 @@ void ConstraintWindow::Create(EditorComponent* _editor) typeComboBox.AddItem("Distance", (uint64_t)PhysicsConstraintComponent::Type::Distance); 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.OnSelect([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) @@ -123,7 +124,7 @@ void ConstraintWindow::Create(EditorComponent* _editor) default: break; } - physicscomponent->physicsobject = nullptr; + physicscomponent->SetRefreshParametersNeeded(true); } } }); @@ -148,13 +149,295 @@ void ConstraintWindow::Create(EditorComponent* _editor) default: break; } - physicscomponent->physicsobject = nullptr; + physicscomponent->SetRefreshParametersNeeded(true); } } }); AddWidget(&maxSlider); + + + fixedXButton.Create("Fix X"); + fixedXButton.OnClick([=](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->six_dof.SetFixedX(); + physicscomponent->SetRefreshParametersNeeded(true); + } + } + SetEntity(entity); + }); + AddWidget(&fixedXButton); + + fixedYButton.Create("Fix Y"); + fixedYButton.OnClick([=](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->six_dof.SetFixedY(); + physicscomponent->SetRefreshParametersNeeded(true); + } + } + SetEntity(entity); + }); + AddWidget(&fixedYButton); + + fixedZButton.Create("Fix Z"); + fixedZButton.OnClick([=](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->six_dof.SetFixedZ(); + physicscomponent->SetRefreshParametersNeeded(true); + } + } + SetEntity(entity); + }); + AddWidget(&fixedZButton); + + fixedXRotationButton.Create("Fix Rot X"); + fixedXRotationButton.OnClick([=](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->six_dof.SetFixedRotationX(); + physicscomponent->SetRefreshParametersNeeded(true); + } + } + SetEntity(entity); + }); + AddWidget(&fixedXRotationButton); + + fixedYRotationButton.Create("Fix Rot Y"); + fixedYRotationButton.OnClick([=](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->six_dof.SetFixedRotationY(); + physicscomponent->SetRefreshParametersNeeded(true); + } + } + SetEntity(entity); + }); + AddWidget(&fixedYRotationButton); + + fixedZRotationButton.Create("Fix Rot Z"); + fixedZRotationButton.OnClick([=](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->six_dof.SetFixedRotationZ(); + physicscomponent->SetRefreshParametersNeeded(true); + } + } + SetEntity(entity); + }); + AddWidget(&fixedZRotationButton); + + + minTranslationXSlider.Create(-10, 0, 1, 100000, "Min Translation X: "); + minTranslationXSlider.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->six_dof.minTranslationAxes.x = args.fValue; + physicscomponent->SetRefreshParametersNeeded(true); + } + } + }); + AddWidget(&minTranslationXSlider); + + minTranslationYSlider.Create(-10, 0, 1, 100000, "Min Translation Y: "); + minTranslationYSlider.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->six_dof.minTranslationAxes.y = args.fValue; + physicscomponent->SetRefreshParametersNeeded(true); + } + } + }); + AddWidget(&minTranslationYSlider); + + minTranslationZSlider.Create(-10, 0, 1, 100000, "Min Translation Z: "); + minTranslationZSlider.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->six_dof.minTranslationAxes.z = args.fValue; + physicscomponent->SetRefreshParametersNeeded(true); + } + } + }); + AddWidget(&minTranslationZSlider); + + maxTranslationXSlider.Create(0, 10, 1, 100000, "Max Translation X: "); + maxTranslationXSlider.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->six_dof.maxTranslationAxes.x = args.fValue; + physicscomponent->SetRefreshParametersNeeded(true); + } + } + }); + AddWidget(&maxTranslationXSlider); + + maxTranslationYSlider.Create(0, 10, 1, 100000, "Max Translation Y: "); + maxTranslationYSlider.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->six_dof.maxTranslationAxes.y = args.fValue; + physicscomponent->SetRefreshParametersNeeded(true); + } + } + }); + AddWidget(&maxTranslationYSlider); + + maxTranslationZSlider.Create(0, 10, 1, 100000, "Max Translation Z: "); + maxTranslationZSlider.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->six_dof.maxTranslationAxes.z = args.fValue; + physicscomponent->SetRefreshParametersNeeded(true); + } + } + }); + AddWidget(&maxTranslationZSlider); + + + + minRotationXSlider.Create(-180, 0, 1, 100000, "Min Rotation X: "); + minRotationXSlider.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->six_dof.minRotationAxes.x = wi::math::DegreesToRadians(args.fValue); + physicscomponent->SetRefreshParametersNeeded(true); + } + } + }); + AddWidget(&minRotationXSlider); + + minRotationYSlider.Create(-180, 0, 1, 100000, "Min Rotation Y: "); + minRotationYSlider.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->six_dof.minRotationAxes.y = wi::math::DegreesToRadians(args.fValue); + physicscomponent->SetRefreshParametersNeeded(true); + } + } + }); + AddWidget(&minRotationYSlider); + + minRotationZSlider.Create(-180, 0, 1, 100000, "Min Rotation Z: "); + minRotationZSlider.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->six_dof.minRotationAxes.z = wi::math::DegreesToRadians(args.fValue); + physicscomponent->SetRefreshParametersNeeded(true); + } + } + }); + AddWidget(&minRotationZSlider); + + maxRotationXSlider.Create(0, 180, 1, 100000, "Max Rotation X: "); + maxRotationXSlider.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->six_dof.maxRotationAxes.x = wi::math::DegreesToRadians(args.fValue); + physicscomponent->SetRefreshParametersNeeded(true); + } + } + }); + AddWidget(&maxRotationXSlider); + + maxRotationYSlider.Create(0, 180, 1, 100000, "Max Rotation Y: "); + maxRotationYSlider.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->six_dof.maxRotationAxes.y = wi::math::DegreesToRadians(args.fValue); + physicscomponent->SetRefreshParametersNeeded(true); + } + } + }); + AddWidget(&maxRotationYSlider); + + maxRotationZSlider.Create(0, 180, 1, 100000, "Max Rotation Z: "); + maxRotationZSlider.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->six_dof.maxRotationAxes.z = wi::math::DegreesToRadians(args.fValue); + physicscomponent->SetRefreshParametersNeeded(true); + } + } + }); + AddWidget(&maxRotationZSlider); + + SetMinimized(true); SetVisible(false); @@ -169,8 +452,6 @@ void ConstraintWindow::SetEntity(Entity entity) if (physicsComponent != nullptr) { - if (this->entity == entity) - return; this->entity = entity; typeComboBox.SetSelectedByUserdataWithoutCallback((uint64_t)physicsComponent->type); @@ -218,6 +499,19 @@ void ConstraintWindow::SetEntity(Entity entity) } bodyAComboBox.SetSelectedByUserdataWithoutCallback(physicsComponent->bodyA); bodyBComboBox.SetSelectedByUserdataWithoutCallback(physicsComponent->bodyB); + + minTranslationXSlider.SetValue(physicsComponent->six_dof.minTranslationAxes.x); + minTranslationYSlider.SetValue(physicsComponent->six_dof.minTranslationAxes.y); + minTranslationZSlider.SetValue(physicsComponent->six_dof.minTranslationAxes.z); + maxTranslationXSlider.SetValue(physicsComponent->six_dof.maxTranslationAxes.x); + maxTranslationYSlider.SetValue(physicsComponent->six_dof.maxTranslationAxes.y); + maxTranslationZSlider.SetValue(physicsComponent->six_dof.maxTranslationAxes.z); + minRotationXSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->six_dof.minRotationAxes.x)); + minRotationYSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->six_dof.minRotationAxes.y)); + minRotationZSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->six_dof.minRotationAxes.z)); + maxRotationXSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->six_dof.maxRotationAxes.x)); + maxRotationYSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->six_dof.maxRotationAxes.y)); + maxRotationZSlider.SetValue(wi::math::RadiansToDegrees(physicsComponent->six_dof.maxRotationAxes.z)); } else { @@ -236,7 +530,7 @@ void ConstraintWindow::ResizeLayout() float jump = 20; const float margin_left = 145; - const float margin_right = 40; + float margin_right = 40; auto add = [&](wi::gui::Widget& widget) { if (!widget.IsVisible()) @@ -281,14 +575,113 @@ void ConstraintWindow::ResizeLayout() case PhysicsConstraintComponent::Type::Hinge: minSlider.SetVisible(true); maxSlider.SetVisible(true); + + 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::Cone: minSlider.SetVisible(true); 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; + case PhysicsConstraintComponent::Type::SixDOF: + minSlider.SetVisible(false); + maxSlider.SetVisible(false); + + fixedXButton.SetVisible(true); + fixedYButton.SetVisible(true); + fixedZButton.SetVisible(true); + fixedXRotationButton.SetVisible(true); + fixedYRotationButton.SetVisible(true); + fixedZRotationButton.SetVisible(true); + minTranslationXSlider.SetVisible(true); + minTranslationYSlider.SetVisible(true); + minTranslationZSlider.SetVisible(true); + maxTranslationXSlider.SetVisible(true); + maxTranslationYSlider.SetVisible(true); + maxTranslationZSlider.SetVisible(true); + minRotationXSlider.SetVisible(true); + minRotationYSlider.SetVisible(true); + minRotationZSlider.SetVisible(true); + maxRotationXSlider.SetVisible(true); + maxRotationYSlider.SetVisible(true); + maxRotationZSlider.SetVisible(true); + add_fullwidth(fixedXButton); + add_fullwidth(fixedYButton); + add_fullwidth(fixedZButton); + add_fullwidth(fixedXRotationButton); + add_fullwidth(fixedYRotationButton); + add_fullwidth(fixedZRotationButton); + margin_right = 80; + add(minTranslationXSlider); + add(minTranslationYSlider); + add(minTranslationZSlider); + add(maxTranslationXSlider); + add(maxTranslationYSlider); + add(maxTranslationZSlider); + add(minRotationXSlider); + add(minRotationYSlider); + add(minRotationZSlider); + add(maxRotationXSlider); + add(maxRotationYSlider); + 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; } diff --git a/Editor/ConstraintWindow.h b/Editor/ConstraintWindow.h index 969e916bc..04ba0a643 100644 --- a/Editor/ConstraintWindow.h +++ b/Editor/ConstraintWindow.h @@ -18,6 +18,25 @@ public: wi::gui::Slider minSlider; wi::gui::Slider maxSlider; + wi::gui::Button fixedXButton; + wi::gui::Button fixedYButton; + wi::gui::Button fixedZButton; + wi::gui::Button fixedXRotationButton; + wi::gui::Button fixedYRotationButton; + wi::gui::Button fixedZRotationButton; + wi::gui::Slider minTranslationXSlider; + wi::gui::Slider minTranslationYSlider; + wi::gui::Slider minTranslationZSlider; + wi::gui::Slider maxTranslationXSlider; + wi::gui::Slider maxTranslationYSlider; + wi::gui::Slider maxTranslationZSlider; + wi::gui::Slider minRotationXSlider; + wi::gui::Slider minRotationYSlider; + wi::gui::Slider minRotationZSlider; + wi::gui::Slider maxRotationXSlider; + wi::gui::Slider maxRotationYSlider; + wi::gui::Slider maxRotationZSlider; + void ResizeLayout() override; }; diff --git a/WickedEngine/CommonInclude.h b/WickedEngine/CommonInclude.h index 490b463c6..5d062b7d8 100644 --- a/WickedEngine/CommonInclude.h +++ b/WickedEngine/CommonInclude.h @@ -4,6 +4,7 @@ // This is a helper include file pasted into all engine headers, try to keep it minimal! // Do not include engine features in this file! +#include #include #include diff --git a/WickedEngine/wiGUI.cpp b/WickedEngine/wiGUI.cpp index 9f78c10bb..8eb74e967 100644 --- a/WickedEngine/wiGUI.cpp +++ b/WickedEngine/wiGUI.cpp @@ -1480,9 +1480,20 @@ namespace wi::gui } void TextInputField::SetValue(float newValue) { - std::stringstream ss(""); - ss << newValue; - font.SetText(ss.str()); + if (newValue == FLT_MAX) + { + font.SetText(L"FLT_MAX"); + } + else if (newValue == -FLT_MAX) + { + font.SetText(L"-FLT_MAX"); + } + else + { + std::stringstream ss(""); + ss << newValue; + font.SetText(ss.str()); + } } const std::string TextInputField::GetValue() { @@ -1901,7 +1912,7 @@ namespace wi::gui valueInputField.Create(name + "_endInputField"); valueInputField.SetLocalizationEnabled(LocalizationEnabled::None); valueInputField.SetShadowRadius(0); - valueInputField.SetTooltip("Enter number to modify value even outside slider limits. Enter \"reset\" to reset slider to initial state."); + valueInputField.SetTooltip("Enter number to modify value even outside slider limits. Other inputs:\n - reset : reset slider to initial state.\n - FLT_MAX : float max value\n - -FLT_MAX : negative float max value."); valueInputField.SetValue(end); valueInputField.OnInputAccepted([this, start, end, defaultValue](EventArgs args) { if (args.sValue.compare("reset") == 0) @@ -1912,6 +1923,18 @@ namespace wi::gui args.fValue = this->value; args.iValue = (int)this->value; } + else if (args.sValue.compare("FLT_MAX") == 0) + { + this->value = FLT_MAX; + args.fValue = this->value; + args.iValue = (int)this->value; + } + else if (args.sValue.compare("-FLT_MAX") == 0) + { + this->value = -FLT_MAX; + args.fValue = this->value; + args.iValue = (int)this->value; + } else { this->value = args.fValue; diff --git a/WickedEngine/wiPhysics_Jolt.cpp b/WickedEngine/wiPhysics_Jolt.cpp index c4e2ed561..f000f3858 100644 --- a/WickedEngine/wiPhysics_Jolt.cpp +++ b/WickedEngine/wiPhysics_Jolt.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -1034,6 +1035,27 @@ namespace wi::physics settings.mHalfConeAngle = physicscomponent.cone_constraint.half_cone_angle; physicsobject.constraint = settings.Create(*body1, *body2); } + else if (physicscomponent.type == PhysicsConstraintComponent::Type::SixDOF) + { + SixDOFConstraintSettings settings; + settings.mSpace = EConstraintSpace::WorldSpace; + settings.mPosition1 = settings.mPosition2 = cast(transform.GetPosition()); + settings.mAxisX1 = settings.mAxisX2 = cast(transform.GetRight()).Normalized(); + settings.mAxisY1 = settings.mAxisY2 = cast(transform.GetUp()).Normalized(); + settings.mLimitMin[SixDOFConstraintSettings::EAxis::TranslationX] = physicscomponent.six_dof.minTranslationAxes.x; + settings.mLimitMin[SixDOFConstraintSettings::EAxis::TranslationY] = physicscomponent.six_dof.minTranslationAxes.y; + settings.mLimitMin[SixDOFConstraintSettings::EAxis::TranslationZ] = physicscomponent.six_dof.minTranslationAxes.z; + settings.mLimitMax[SixDOFConstraintSettings::EAxis::TranslationX] = physicscomponent.six_dof.maxTranslationAxes.x; + settings.mLimitMax[SixDOFConstraintSettings::EAxis::TranslationY] = physicscomponent.six_dof.maxTranslationAxes.y; + settings.mLimitMax[SixDOFConstraintSettings::EAxis::TranslationZ] = physicscomponent.six_dof.maxTranslationAxes.z; + settings.mLimitMin[SixDOFConstraintSettings::EAxis::RotationX] = physicscomponent.six_dof.minRotationAxes.x; + settings.mLimitMin[SixDOFConstraintSettings::EAxis::RotationY] = physicscomponent.six_dof.minRotationAxes.y; + settings.mLimitMin[SixDOFConstraintSettings::EAxis::RotationZ] = physicscomponent.six_dof.minRotationAxes.z; + settings.mLimitMax[SixDOFConstraintSettings::EAxis::RotationX] = physicscomponent.six_dof.maxRotationAxes.x; + settings.mLimitMax[SixDOFConstraintSettings::EAxis::RotationY] = physicscomponent.six_dof.maxRotationAxes.y; + settings.mLimitMax[SixDOFConstraintSettings::EAxis::RotationZ] = physicscomponent.six_dof.maxRotationAxes.z; + physicsobject.constraint = settings.Create(*body1, *body2); + } else { wilog("Constraint creation failed: constraint type is not valid!"); @@ -1047,6 +1069,7 @@ namespace wi::physics } physics_scene.physics_system.AddConstraint(physicsobject.constraint); + physicscomponent.SetRefreshParametersNeeded(false); } struct Ragdoll @@ -1934,6 +1957,39 @@ namespace wi::physics return; AddConstraint(scene, entity, physicscomponent, *transform); } + + if (physicscomponent.physicsobject != nullptr && physicscomponent.IsRefreshParametersNeeded()) + { + physicscomponent.SetRefreshParametersNeeded(false); + Constraint& constraint = GetConstraint(physicscomponent); + if (physicscomponent.type == PhysicsConstraintComponent::Type::Fixed) + { + } + else if (physicscomponent.type == PhysicsConstraintComponent::Type::Point) + { + } + else if (physicscomponent.type == PhysicsConstraintComponent::Type::Distance) + { + DistanceConstraint* ptr = ((DistanceConstraint*)constraint.constraint.GetPtr()); + ptr->SetDistance(physicscomponent.distance_constraint.min_distance, physicscomponent.distance_constraint.max_distance); + } + else if (physicscomponent.type == PhysicsConstraintComponent::Type::Hinge) + { + HingeConstraint* ptr = ((HingeConstraint*)constraint.constraint.GetPtr()); + ptr->SetLimits(physicscomponent.hinge_constraint.min_angle, physicscomponent.hinge_constraint.max_angle); + } + else if (physicscomponent.type == PhysicsConstraintComponent::Type::Cone) + { + ConeConstraint* ptr = ((ConeConstraint*)constraint.constraint.GetPtr()); + ptr->SetHalfConeAngle(physicscomponent.cone_constraint.half_cone_angle); + } + else if (physicscomponent.type == PhysicsConstraintComponent::Type::SixDOF) + { + SixDOFConstraint* ptr = ((SixDOFConstraint*)constraint.constraint.GetPtr()); + ptr->SetTranslationLimits(cast(physicscomponent.six_dof.minTranslationAxes), cast(physicscomponent.six_dof.maxTranslationAxes)); + ptr->SetRotationLimits(cast(physicscomponent.six_dof.minRotationAxes), cast(physicscomponent.six_dof.maxRotationAxes)); + } + } }); wi::jobsystem::Wait(ctx); // wait for all creations diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index 60bbdb9e3..0762f3629 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"); + wi::ecs::ComponentManager& constraints = componentLibrary.Register("wi::scene::Scene::constraints", 1); // version = 1 // Non-serialized attributes: float dt = 0; diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index f55516fc6..90d56c3cf 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -531,16 +531,18 @@ namespace wi::scene enum FLAGS { EMPTY = 0, + REFRESH_PARAMETERS_REQUEST = 1 << 0, }; uint32_t _flags = EMPTY; enum class Type { - Fixed, - Point, - Distance, - Hinge, - Cone, + Fixed, // fixed in place completely + Point, // fixed to a point but can rotate around it + Distance, // point constraint within specified distance + 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 } type = Type::Fixed; wi::ecs::Entity bodyA = wi::ecs::INVALID_ENTITY; @@ -554,18 +556,44 @@ namespace wi::scene struct HingeConstraintSettings { - float min_angle = -XM_PI; - float max_angle = XM_PI; + float min_angle = -XM_PI; // radians + float max_angle = XM_PI; // radians } hinge_constraint; // note: hinge axis is UP, normal axis is RIGHT directions of the TransformComponent on this entity struct ConeConstraintSettings { - float half_cone_angle = 0; + float half_cone_angle = 0; // radians } cone_constraint; // note: cone axis is RIGHT of the TransformComponent on this entity + struct SixDOFConstraintSettings + { + XMFLOAT3 minTranslationAxes = XMFLOAT3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + XMFLOAT3 maxTranslationAxes = XMFLOAT3(FLT_MAX, FLT_MAX, FLT_MAX); + XMFLOAT3 minRotationAxes = XMFLOAT3(-XM_PI, -XM_PI, -XM_PI); + XMFLOAT3 maxRotationAxes = XMFLOAT3(XM_PI, XM_PI, XM_PI); + + void SetFixedX() { minTranslationAxes.x = FLT_MAX; maxTranslationAxes.x = -FLT_MAX; } + void SetFreeX() { minTranslationAxes.x = -FLT_MAX; maxTranslationAxes.x = FLT_MAX; } + void SetFixedY() { minTranslationAxes.y = FLT_MAX; maxTranslationAxes.y = -FLT_MAX; } + void SetFreeY() { minTranslationAxes.y = -FLT_MAX; maxTranslationAxes.y = FLT_MAX; } + void SetFixedZ() { minTranslationAxes.z = FLT_MAX; maxTranslationAxes.z = -FLT_MAX; } + void SetFreeZ() { minTranslationAxes.z = -FLT_MAX; maxTranslationAxes.z = FLT_MAX; } + + void SetFixedRotationX() { minRotationAxes.x = XM_PI; maxRotationAxes.x = -XM_PI; } + void SetFreeRotationX() { minRotationAxes.x = -XM_PI; maxRotationAxes.x = XM_PI; } + void SetFixedRotationY() { minRotationAxes.y = XM_PI; maxRotationAxes.y = -XM_PI; } + void SetFreeRotationY() { minRotationAxes.y = -XM_PI; maxRotationAxes.y = XM_PI; } + void SetFixedRotationZ() { minRotationAxes.z = XM_PI; maxRotationAxes.z = -XM_PI; } + void SetFreeRotationZ() { minRotationAxes.z = -XM_PI; maxRotationAxes.z = XM_PI; } + } six_dof; + // 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. + // Request refreshing of constraint settings without recreating the constraint + constexpr void SetRefreshParametersNeeded(bool value = true) { if (value) { _flags |= REFRESH_PARAMETERS_REQUEST; } else { _flags &= ~REFRESH_PARAMETERS_REQUEST; } } + constexpr bool IsRefreshParametersNeeded() const { return _flags & REFRESH_PARAMETERS_REQUEST; } + void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri); }; diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index 65c8c9fc6..cc9283ba2 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -922,6 +922,13 @@ namespace wi::scene archive >> hinge_constraint.min_angle; archive >> hinge_constraint.max_angle; archive >> cone_constraint.half_cone_angle; + if (seri.GetVersion() >= 1) + { + archive >> six_dof.minTranslationAxes; + archive >> six_dof.maxTranslationAxes; + archive >> six_dof.minRotationAxes; + archive >> six_dof.maxRotationAxes; + } } else { @@ -934,6 +941,13 @@ namespace wi::scene archive << hinge_constraint.min_angle; archive << hinge_constraint.max_angle; archive << cone_constraint.half_cone_angle; + if (seri.GetVersion() >= 1) + { + archive << six_dof.minTranslationAxes; + archive << six_dof.maxTranslationAxes; + archive << six_dof.minRotationAxes; + archive << six_dof.maxRotationAxes; + } } } void SoftBodyPhysicsComponent::Serialize(wi::Archive& archive, EntitySerializer& seri)