From 960734e87ab41f8c810decfcc037d210e98aad96 Mon Sep 17 00:00:00 2001 From: Turanszki Janos Date: Mon, 28 Dec 2020 17:21:47 +0100 Subject: [PATCH] physics updates #206 #207 physics debug draw editor physics updates --- Editor/Editor.cpp | 11 +- Editor/MeshWindow.cpp | 23 +- Editor/MeshWindow.h | 1 + Editor/ObjectWindow.cpp | 392 ++++++++++++++++++------ Editor/ObjectWindow.h | 11 +- Editor/RendererWindow.cpp | 13 +- Editor/RendererWindow.h | 1 + WickedEngine/ArchiveVersionHistory.txt | 1 + WickedEngine/wiArchive.cpp | 2 +- WickedEngine/wiPhysicsEngine.h | 45 ++- WickedEngine/wiPhysicsEngine_Bullet.cpp | 206 ++++++++++--- WickedEngine/wiScene.h | 24 +- WickedEngine/wiScene_Serializers.cpp | 36 ++- WickedEngine/wiVersion.cpp | 2 +- 14 files changed, 609 insertions(+), 159 deletions(-) diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index fb7dafe6e..236e7b94d 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -337,7 +337,7 @@ void EditorComponent::ResizeLayout() exitButton.SetSize(XMFLOAT2(50, 40)); profilerEnabledCheckBox.SetSize(XMFLOAT2(20, 20)); - profilerEnabledCheckBox.SetPos(XMFLOAT2(screenW - 520, 45)); + profilerEnabledCheckBox.SetPos(XMFLOAT2(screenW - 530, 45)); physicsEnabledCheckBox.SetSize(XMFLOAT2(20, 20)); physicsEnabledCheckBox.SetPos(XMFLOAT2(screenW - 370, 45)); @@ -879,12 +879,12 @@ void EditorComponent::Load() profilerEnabledCheckBox.SetCheck(wiProfiler::IsEnabled()); GetGUI().AddWidget(&profilerEnabledCheckBox); - physicsEnabledCheckBox.Create("Physics Enabled: "); - physicsEnabledCheckBox.SetTooltip("Toggle Physics Engine On/Off"); + physicsEnabledCheckBox.Create("Physics Simulation: "); + physicsEnabledCheckBox.SetTooltip("Toggle Physics Simulation On/Off"); physicsEnabledCheckBox.OnClick([&](wiEventArgs args) { - wiPhysicsEngine::SetEnabled(args.bValue); + wiPhysicsEngine::SetSimulationEnabled(args.bValue); }); - physicsEnabledCheckBox.SetCheck(wiPhysicsEngine::IsEnabled()); + physicsEnabledCheckBox.SetCheck(wiPhysicsEngine::IsSimulationEnabled()); GetGUI().AddWidget(&physicsEnabledCheckBox); cinemaModeCheckBox.Create("Cinema Mode: "); @@ -1597,6 +1597,7 @@ void EditorComponent::Update(float dt) const wiScene::PickResult& picked = translator.selected.back(); assert(picked.entity != INVALID_ENTITY); + objectWnd.SetEntity(picked.entity); for (auto& x : translator.selected) { diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index b9da11c4a..23d479bdf 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -118,6 +118,7 @@ void MeshWindow::Create(EditorComponent* editor) { SoftBodyPhysicsComponent& softbody = scene.softbodies.Create(entity); softbody.friction = frictionSlider.GetValue(); + softbody.restitution = restitutionSlider.GetValue(); softbody.mass = massSlider.GetValue(); } } @@ -132,7 +133,7 @@ void MeshWindow::Create(EditorComponent* editor) }); AddWidget(&softbodyCheckBox); - massSlider.Create(0, 10, 0, 100000, "Mass: "); + massSlider.Create(0, 10, 1, 100000, "Mass: "); massSlider.SetTooltip("Set the mass amount for the physics engine."); massSlider.SetSize(XMFLOAT2(100, hei)); massSlider.SetPos(XMFLOAT2(x, y += step)); @@ -145,7 +146,7 @@ void MeshWindow::Create(EditorComponent* editor) }); AddWidget(&massSlider); - frictionSlider.Create(0, 2, 0, 100000, "Friction: "); + frictionSlider.Create(0, 1, 0.5f, 100000, "Friction: "); frictionSlider.SetTooltip("Set the friction amount for the physics engine."); frictionSlider.SetSize(XMFLOAT2(100, hei)); frictionSlider.SetPos(XMFLOAT2(x, y += step)); @@ -158,6 +159,19 @@ void MeshWindow::Create(EditorComponent* editor) }); AddWidget(&frictionSlider); + restitutionSlider.Create(0, 1, 0, 100000, "Restitution: "); + restitutionSlider.SetTooltip("Set the restitution amount for the physics engine."); + restitutionSlider.SetSize(XMFLOAT2(100, hei)); + restitutionSlider.SetPos(XMFLOAT2(x, y += step)); + restitutionSlider.OnSlide([&](wiEventArgs args) { + SoftBodyPhysicsComponent* physicscomponent = wiScene::GetScene().softbodies.GetComponent(entity); + if (physicscomponent != nullptr) + { + physicscomponent->restitution = args.fValue; + } + }); + AddWidget(&restitutionSlider); + impostorCreateButton.Create("Create Impostor"); impostorCreateButton.SetTooltip("Create an impostor image of the mesh. The mesh will be replaced by this image when far away, to render faster."); impostorCreateButton.SetSize(XMFLOAT2(240, hei)); @@ -525,7 +539,7 @@ void MeshWindow::Create(EditorComponent* editor) morphTargetCombo.SetPos(XMFLOAT2(x + 280, y += step)); morphTargetCombo.OnSelect([&](wiEventArgs args) { MeshComponent* mesh = wiScene::GetScene().meshes.GetComponent(entity); - if (mesh != nullptr && args.iValue < mesh->targets.size()) + if (mesh != nullptr && args.iValue < (int)mesh->targets.size()) { morphTargetSlider.SetValue(mesh->targets[args.iValue].weight); } @@ -539,7 +553,7 @@ void MeshWindow::Create(EditorComponent* editor) morphTargetSlider.SetPos(XMFLOAT2(x + 280, y += step)); morphTargetSlider.OnSlide([&](wiEventArgs args) { MeshComponent* mesh = wiScene::GetScene().meshes.GetComponent(entity); - if (mesh != nullptr && morphTargetCombo.GetSelected() < mesh->targets.size()) + if (mesh != nullptr && morphTargetCombo.GetSelected() < (int)mesh->targets.size()) { mesh->targets[morphTargetCombo.GetSelected()].weight = args.fValue; mesh->SetDirtyMorph(); @@ -635,6 +649,7 @@ void MeshWindow::SetEntity(Entity entity) softbodyCheckBox.SetCheck(true); massSlider.SetValue(physicscomponent->mass); frictionSlider.SetValue(physicscomponent->friction); + restitutionSlider.SetValue(physicscomponent->restitution); } uint8_t selected = morphTargetCombo.GetSelected(); diff --git a/Editor/MeshWindow.h b/Editor/MeshWindow.h index 297eaaa4d..58d39d9c3 100644 --- a/Editor/MeshWindow.h +++ b/Editor/MeshWindow.h @@ -16,6 +16,7 @@ public: wiCheckBox softbodyCheckBox; wiSlider massSlider; wiSlider frictionSlider; + wiSlider restitutionSlider; wiButton impostorCreateButton; wiSlider impostorDistanceSlider; wiSlider tessellationFactorSlider; diff --git a/Editor/ObjectWindow.cpp b/Editor/ObjectWindow.cpp index 4d2436347..8ba79ea3a 100644 --- a/Editor/ObjectWindow.cpp +++ b/Editor/ObjectWindow.cpp @@ -250,7 +250,7 @@ void ObjectWindow::Create(EditorComponent* editor) this->editor = editor; wiWindow::Create("Object Window"); - SetSize(XMFLOAT2(350, 610)); + SetSize(XMFLOAT2(660, 480)); float x = 200; float y = 0; @@ -312,37 +312,247 @@ void ObjectWindow::Create(EditorComponent* editor) AddWidget(&physicsLabel); - - rigidBodyCheckBox.Create("Rigid Body Physics: "); - rigidBodyCheckBox.SetTooltip("Enable rigid body physics simulation."); - rigidBodyCheckBox.SetSize(XMFLOAT2(hei, hei)); - rigidBodyCheckBox.SetPos(XMFLOAT2(x, y += step)); - rigidBodyCheckBox.SetCheck(false); - rigidBodyCheckBox.OnClick([&](wiEventArgs args) - { - Scene& scene = wiScene::GetScene(); - RigidBodyPhysicsComponent* physicscomponent = scene.rigidbodies.GetComponent(entity); - - if (args.bValue) + collisionShapeComboBox.Create("Collision Shape:"); + collisionShapeComboBox.SetSize(XMFLOAT2(100, hei)); + collisionShapeComboBox.SetPos(XMFLOAT2(x, y += step)); + collisionShapeComboBox.AddItem("DISABLED"); + collisionShapeComboBox.AddItem("Box"); + collisionShapeComboBox.AddItem("Sphere"); + collisionShapeComboBox.AddItem("Capsule"); + collisionShapeComboBox.AddItem("Convex Hull"); + collisionShapeComboBox.AddItem("Triangle Mesh"); + collisionShapeComboBox.OnSelect([&](wiEventArgs args) { + if (entity == INVALID_ENTITY) + return; + + Scene& scene = wiScene::GetScene(); + RigidBodyPhysicsComponent* physicscomponent = scene.rigidbodies.GetComponent(entity); + + if (args.iValue == 0) + { + if (physicscomponent != nullptr) + { + scene.rigidbodies.Remove(entity); + } + return; + } + if (physicscomponent == nullptr) { - RigidBodyPhysicsComponent& rigidbody = scene.rigidbodies.Create(entity); - rigidbody.SetKinematic(kinematicCheckBox.GetCheck()); - rigidbody.SetDisableDeactivation(disabledeactivationCheckBox.GetCheck()); - rigidbody.shape = (RigidBodyPhysicsComponent::CollisionShape)collisionShapeComboBox.GetSelected(); + physicscomponent = &scene.rigidbodies.Create(entity); + physicscomponent->SetKinematic(kinematicCheckBox.GetCheck()); + physicscomponent->SetDisableDeactivation(disabledeactivationCheckBox.GetCheck()); + physicscomponent->shape = (RigidBodyPhysicsComponent::CollisionShape)collisionShapeComboBox.GetSelected(); } - } - else - { + if (physicscomponent != nullptr) { - scene.rigidbodies.Remove(entity); - } - } + XSlider.SetEnabled(false); + YSlider.SetEnabled(false); + ZSlider.SetEnabled(false); + XSlider.SetText("-"); + YSlider.SetText("-"); + ZSlider.SetText("-"); - }); - AddWidget(&rigidBodyCheckBox); + switch (args.iValue) + { + case 1: + if (physicscomponent->shape != RigidBodyPhysicsComponent::CollisionShape::BOX) + { + physicscomponent->physicsobject = nullptr; + physicscomponent->shape = RigidBodyPhysicsComponent::CollisionShape::BOX; + } + XSlider.SetEnabled(true); + YSlider.SetEnabled(true); + ZSlider.SetEnabled(true); + XSlider.SetText("Width"); + YSlider.SetText("Height"); + ZSlider.SetText("Depth"); + XSlider.SetValue(physicscomponent->box.halfextents.x); + YSlider.SetValue(physicscomponent->box.halfextents.y); + ZSlider.SetValue(physicscomponent->box.halfextents.z); + break; + case 2: + if (physicscomponent->shape != RigidBodyPhysicsComponent::CollisionShape::SPHERE) + { + physicscomponent->physicsobject = nullptr; + physicscomponent->shape = RigidBodyPhysicsComponent::CollisionShape::SPHERE; + } + XSlider.SetEnabled(true); + XSlider.SetText("Radius"); + YSlider.SetText("-"); + ZSlider.SetText("-"); + XSlider.SetValue(physicscomponent->sphere.radius); + break; + case 3: + if (physicscomponent->shape != RigidBodyPhysicsComponent::CollisionShape::CAPSULE) + { + physicscomponent->physicsobject = nullptr; + physicscomponent->shape = RigidBodyPhysicsComponent::CollisionShape::CAPSULE; + } + XSlider.SetEnabled(true); + YSlider.SetEnabled(true); + XSlider.SetText("Height"); + YSlider.SetText("Radius"); + ZSlider.SetText("-"); + XSlider.SetValue(physicscomponent->capsule.height); + YSlider.SetValue(physicscomponent->capsule.radius); + break; + case 4: + if (physicscomponent->shape != RigidBodyPhysicsComponent::CollisionShape::CONVEX_HULL) + { + physicscomponent->physicsobject = nullptr; + physicscomponent->shape = RigidBodyPhysicsComponent::CollisionShape::CONVEX_HULL; + } + break; + case 5: + if (physicscomponent->shape != RigidBodyPhysicsComponent::CollisionShape::TRIANGLE_MESH) + { + physicscomponent->physicsobject = nullptr; + physicscomponent->shape = RigidBodyPhysicsComponent::CollisionShape::TRIANGLE_MESH; + } + break; + default: + break; + } + } + }); + collisionShapeComboBox.SetSelected(0); + collisionShapeComboBox.SetEnabled(true); + collisionShapeComboBox.SetTooltip("Set rigid body collision shape."); + AddWidget(&collisionShapeComboBox); + + XSlider.Create(0, 10, 1, 100000, "X: "); + XSlider.SetSize(XMFLOAT2(100, hei)); + XSlider.SetPos(XMFLOAT2(x, y += step)); + XSlider.OnSlide([&](wiEventArgs args) { + RigidBodyPhysicsComponent* physicscomponent = wiScene::GetScene().rigidbodies.GetComponent(entity); + if (physicscomponent != nullptr) + { + switch (physicscomponent->shape) + { + default: + case RigidBodyPhysicsComponent::CollisionShape::BOX: + physicscomponent->box.halfextents.x = args.fValue; + break; + case RigidBodyPhysicsComponent::CollisionShape::SPHERE: + physicscomponent->sphere.radius = args.fValue; + break; + case RigidBodyPhysicsComponent::CollisionShape::CAPSULE: + physicscomponent->capsule.height = args.fValue; + break; + } + physicscomponent->physicsobject = nullptr; + } + }); + AddWidget(&XSlider); + + YSlider.Create(0, 10, 1, 100000, "Y: "); + YSlider.SetSize(XMFLOAT2(100, hei)); + YSlider.SetPos(XMFLOAT2(x, y += step)); + YSlider.OnSlide([&](wiEventArgs args) { + RigidBodyPhysicsComponent* physicscomponent = wiScene::GetScene().rigidbodies.GetComponent(entity); + if (physicscomponent != nullptr) + { + switch (physicscomponent->shape) + { + default: + case RigidBodyPhysicsComponent::CollisionShape::BOX: + physicscomponent->box.halfextents.y = args.fValue; + break; + case RigidBodyPhysicsComponent::CollisionShape::CAPSULE: + physicscomponent->capsule.radius = args.fValue; + break; + } + physicscomponent->physicsobject = nullptr; + } + }); + AddWidget(&YSlider); + + ZSlider.Create(0, 10, 1, 100000, "Z: "); + ZSlider.SetSize(XMFLOAT2(100, hei)); + ZSlider.SetPos(XMFLOAT2(x, y += step)); + ZSlider.OnSlide([&](wiEventArgs args) { + RigidBodyPhysicsComponent* physicscomponent = wiScene::GetScene().rigidbodies.GetComponent(entity); + if (physicscomponent != nullptr) + { + switch (physicscomponent->shape) + { + default: + case RigidBodyPhysicsComponent::CollisionShape::BOX: + physicscomponent->box.halfextents.z = args.fValue; + break; + } + physicscomponent->physicsobject = nullptr; + } + }); + AddWidget(&ZSlider); + + massSlider.Create(0, 10, 1, 100000, "Mass: "); + massSlider.SetTooltip("Set the mass amount for the physics engine."); + massSlider.SetSize(XMFLOAT2(100, hei)); + massSlider.SetPos(XMFLOAT2(x, y += step)); + massSlider.OnSlide([&](wiEventArgs args) { + RigidBodyPhysicsComponent* physicscomponent = wiScene::GetScene().rigidbodies.GetComponent(entity); + if (physicscomponent != nullptr) + { + physicscomponent->mass = args.fValue; + } + }); + AddWidget(&massSlider); + + frictionSlider.Create(0, 1, 0.5f, 100000, "Friction: "); + frictionSlider.SetTooltip("Set the friction amount for the physics engine."); + frictionSlider.SetSize(XMFLOAT2(100, hei)); + frictionSlider.SetPos(XMFLOAT2(x, y += step)); + frictionSlider.OnSlide([&](wiEventArgs args) { + RigidBodyPhysicsComponent* physicscomponent = wiScene::GetScene().rigidbodies.GetComponent(entity); + if (physicscomponent != nullptr) + { + physicscomponent->friction = args.fValue; + } + }); + AddWidget(&frictionSlider); + + restitutionSlider.Create(0, 1, 0, 100000, "Restitution: "); + restitutionSlider.SetTooltip("Set the restitution amount for the physics engine."); + restitutionSlider.SetSize(XMFLOAT2(100, hei)); + restitutionSlider.SetPos(XMFLOAT2(x, y += step)); + restitutionSlider.OnSlide([&](wiEventArgs args) { + RigidBodyPhysicsComponent* physicscomponent = wiScene::GetScene().rigidbodies.GetComponent(entity); + if (physicscomponent != nullptr) + { + physicscomponent->restitution = args.fValue; + } + }); + AddWidget(&restitutionSlider); + + lineardampingSlider.Create(0, 1, 0, 100000, "Linear Damping: "); + lineardampingSlider.SetTooltip("Set the linear damping amount for the physics engine."); + lineardampingSlider.SetSize(XMFLOAT2(100, hei)); + lineardampingSlider.SetPos(XMFLOAT2(x, y += step)); + lineardampingSlider.OnSlide([&](wiEventArgs args) { + RigidBodyPhysicsComponent* physicscomponent = wiScene::GetScene().rigidbodies.GetComponent(entity); + if (physicscomponent != nullptr) + { + physicscomponent->damping_linear = args.fValue; + } + }); + AddWidget(&lineardampingSlider); + + angulardampingSlider.Create(0, 1, 0, 100000, "Angular Damping: "); + angulardampingSlider.SetTooltip("Set the mass amount for the physics engine."); + angulardampingSlider.SetSize(XMFLOAT2(100, hei)); + angulardampingSlider.SetPos(XMFLOAT2(x, y += step)); + angulardampingSlider.OnSlide([&](wiEventArgs args) { + RigidBodyPhysicsComponent* physicscomponent = wiScene::GetScene().rigidbodies.GetComponent(entity); + if (physicscomponent != nullptr) + { + physicscomponent->damping_angular = args.fValue; + } + }); + AddWidget(&angulardampingSlider); kinematicCheckBox.Create("Kinematic: "); kinematicCheckBox.SetTooltip("Toggle kinematic behaviour."); @@ -372,46 +582,6 @@ void ObjectWindow::Create(EditorComponent* editor) }); AddWidget(&disabledeactivationCheckBox); - collisionShapeComboBox.Create("Collision Shape:"); - collisionShapeComboBox.SetSize(XMFLOAT2(100, hei)); - collisionShapeComboBox.SetPos(XMFLOAT2(x, y += step)); - collisionShapeComboBox.AddItem("Box"); - collisionShapeComboBox.AddItem("Sphere"); - collisionShapeComboBox.AddItem("Capsule"); - collisionShapeComboBox.AddItem("Convex Hull"); - collisionShapeComboBox.AddItem("Triangle Mesh"); - collisionShapeComboBox.OnSelect([&](wiEventArgs args) - { - RigidBodyPhysicsComponent* physicscomponent = wiScene::GetScene().rigidbodies.GetComponent(entity); - if (physicscomponent != nullptr) - { - switch (args.iValue) - { - case 0: - physicscomponent->shape = RigidBodyPhysicsComponent::CollisionShape::BOX; - break; - case 1: - physicscomponent->shape = RigidBodyPhysicsComponent::CollisionShape::SPHERE; - break; - case 2: - physicscomponent->shape = RigidBodyPhysicsComponent::CollisionShape::CAPSULE; - break; - case 3: - physicscomponent->shape = RigidBodyPhysicsComponent::CollisionShape::CONVEX_HULL; - break; - case 4: - physicscomponent->shape = RigidBodyPhysicsComponent::CollisionShape::TRIANGLE_MESH; - break; - default: - break; - } - } - }); - collisionShapeComboBox.SetSelected(0); - collisionShapeComboBox.SetEnabled(true); - collisionShapeComboBox.SetTooltip("Set rigid body collision shape."); - AddWidget(&collisionShapeComboBox); - y += step; @@ -559,10 +729,10 @@ void ObjectWindow::Create(EditorComponent* editor) }); AddWidget(&clearLightmapButton); - y += step; + y = 10; colorPicker.Create("Object Color", false); - colorPicker.SetPos(XMFLOAT2(20, y += step)); + colorPicker.SetPos(XMFLOAT2(350, y += step)); colorPicker.SetVisible(true); colorPicker.SetEnabled(true); colorPicker.OnColorChanged([&](wiEventArgs args) { @@ -585,6 +755,9 @@ void ObjectWindow::Create(EditorComponent* editor) void ObjectWindow::SetEntity(Entity entity) { + if (this->entity == entity) + return; + this->entity = entity; Scene& scene = wiScene::GetScene(); @@ -603,41 +776,64 @@ void ObjectWindow::SetEntity(Entity entity) ditherSlider.SetValue(object->GetTransparency()); colorPicker.SetPickColor(wiColor::fromFloat4(object->color)); - const RigidBodyPhysicsComponent* physicsComponent = scene.rigidbodies.GetComponent(entity); - - rigidBodyCheckBox.SetCheck(physicsComponent != nullptr); - - if (physicsComponent != nullptr) - { - kinematicCheckBox.SetCheck(physicsComponent->IsKinematic()); - disabledeactivationCheckBox.SetCheck(physicsComponent->IsDisableDeactivation()); - - if (physicsComponent->shape == RigidBodyPhysicsComponent::CollisionShape::BOX) - { - collisionShapeComboBox.SetSelected(0); - } - else if (physicsComponent->shape == RigidBodyPhysicsComponent::CollisionShape::SPHERE) - { - collisionShapeComboBox.SetSelected(1); - } - else if (physicsComponent->shape == RigidBodyPhysicsComponent::CollisionShape::CAPSULE) - { - collisionShapeComboBox.SetSelected(2); - } - else if (physicsComponent->shape == RigidBodyPhysicsComponent::CollisionShape::CONVEX_HULL) - { - collisionShapeComboBox.SetSelected(3); - } - else if (physicsComponent->shape == RigidBodyPhysicsComponent::CollisionShape::TRIANGLE_MESH) - { - collisionShapeComboBox.SetSelected(4); - } - } - } else { SetEnabled(false); } + const TransformComponent* transform = scene.transforms.GetComponent(entity); + const RigidBodyPhysicsComponent* physicsComponent = scene.rigidbodies.GetComponent(entity); + + if (transform != nullptr) + { + kinematicCheckBox.SetEnabled(true); + disabledeactivationCheckBox.SetEnabled(true); + collisionShapeComboBox.SetEnabled(true); + massSlider.SetEnabled(true); + frictionSlider.SetEnabled(true); + restitutionSlider.SetEnabled(true); + lineardampingSlider.SetEnabled(true); + angulardampingSlider.SetEnabled(true); + + if (physicsComponent != nullptr) + { + massSlider.SetValue(physicsComponent->mass); + frictionSlider.SetValue(physicsComponent->friction); + restitutionSlider.SetValue(physicsComponent->restitution); + lineardampingSlider.SetValue(physicsComponent->damping_linear); + angulardampingSlider.SetValue(physicsComponent->damping_angular); + + kinematicCheckBox.SetCheck(physicsComponent->IsKinematic()); + disabledeactivationCheckBox.SetCheck(physicsComponent->IsDisableDeactivation()); + + if (physicsComponent->shape == RigidBodyPhysicsComponent::CollisionShape::BOX) + { + collisionShapeComboBox.SetSelected(1); + } + else if (physicsComponent->shape == RigidBodyPhysicsComponent::CollisionShape::SPHERE) + { + collisionShapeComboBox.SetSelected(2); + } + else if (physicsComponent->shape == RigidBodyPhysicsComponent::CollisionShape::CAPSULE) + { + collisionShapeComboBox.SetSelected(3); + } + else if (physicsComponent->shape == RigidBodyPhysicsComponent::CollisionShape::CONVEX_HULL) + { + collisionShapeComboBox.SetSelected(4); + } + else if (physicsComponent->shape == RigidBodyPhysicsComponent::CollisionShape::TRIANGLE_MESH) + { + collisionShapeComboBox.SetSelected(5); + } + } + else + { + collisionShapeComboBox.SetSelected(0); + kinematicCheckBox.SetCheck(false); + disabledeactivationCheckBox.SetCheck(false); + } + } + } diff --git a/Editor/ObjectWindow.h b/Editor/ObjectWindow.h index bcc830be9..f4a6c8ed4 100644 --- a/Editor/ObjectWindow.h +++ b/Editor/ObjectWindow.h @@ -19,10 +19,17 @@ public: wiColorPicker colorPicker; wiLabel physicsLabel; - wiCheckBox rigidBodyCheckBox; + wiComboBox collisionShapeComboBox; + wiSlider XSlider; + wiSlider YSlider; + wiSlider ZSlider; + wiSlider massSlider; + wiSlider frictionSlider; + wiSlider restitutionSlider; + wiSlider lineardampingSlider; + wiSlider angulardampingSlider; wiCheckBox disabledeactivationCheckBox; wiCheckBox kinematicCheckBox; - wiComboBox collisionShapeComboBox; wiSlider lightmapResolutionSlider; wiComboBox lightmapSourceUVSetComboBox; diff --git a/Editor/RendererWindow.cpp b/Editor/RendererWindow.cpp index f13cf81be..3f9238b68 100644 --- a/Editor/RendererWindow.cpp +++ b/Editor/RendererWindow.cpp @@ -2,6 +2,7 @@ #include "RendererWindow.h" #include "RenderPath3D.h" #include "Editor.h" +#include "wiPhysicsEngine.h" void RendererWindow::Create(EditorComponent* editor) @@ -466,8 +467,18 @@ void RendererWindow::Create(EditorComponent* editor) // Visualizer toggles: x = 540, y = 5; + physicsDebugCheckBox.Create("Physics visualizer: "); + physicsDebugCheckBox.SetTooltip("Visualize the physics world"); + physicsDebugCheckBox.SetPos(XMFLOAT2(x, y += step)); + physicsDebugCheckBox.SetSize(XMFLOAT2(itemheight, itemheight)); + physicsDebugCheckBox.OnClick([](wiEventArgs args) { + wiPhysicsEngine::SetDebugDrawEnabled(args.bValue); + }); + physicsDebugCheckBox.SetCheck(wiPhysicsEngine::IsDebugDrawEnabled()); + AddWidget(&physicsDebugCheckBox); + partitionBoxesCheckBox.Create("SPTree visualizer: "); - partitionBoxesCheckBox.SetTooltip("Visualize the world space partitioning tree as boxes"); + partitionBoxesCheckBox.SetTooltip("Visualize the scene bounding boxes"); partitionBoxesCheckBox.SetScriptTip("SetDebugPartitionTreeEnabled(bool enabled)"); partitionBoxesCheckBox.SetPos(XMFLOAT2(x, y += step)); partitionBoxesCheckBox.SetSize(XMFLOAT2(itemheight, itemheight)); diff --git a/Editor/RendererWindow.h b/Editor/RendererWindow.h index c3dc60caa..b30ebefa6 100644 --- a/Editor/RendererWindow.h +++ b/Editor/RendererWindow.h @@ -35,6 +35,7 @@ public: wiSlider voxelRadianceConeTracingSlider; wiSlider voxelRadianceRayStepSizeSlider; wiSlider voxelRadianceMaxDistanceSlider; + wiCheckBox physicsDebugCheckBox; wiCheckBox partitionBoxesCheckBox; wiCheckBox boneLinesCheckBox; wiCheckBox debugEmittersCheckBox; diff --git a/WickedEngine/ArchiveVersionHistory.txt b/WickedEngine/ArchiveVersionHistory.txt index 5f6879f71..d97bfe12d 100644 --- a/WickedEngine/ArchiveVersionHistory.txt +++ b/WickedEngine/ArchiveVersionHistory.txt @@ -1,5 +1,6 @@ This file contains changelog of wiArchive versions +57: serialized RigidBodyPhysicsComponent::damping_angular and SoftBodyPhysicsComponent::restitution 56: serialized Material specularColor (specular-glossiness workflow) 55: removed area lights 54: MaterialComponent::subsurfaceScattering color instead of profile diff --git a/WickedEngine/wiArchive.cpp b/WickedEngine/wiArchive.cpp index 411be1c75..38aba5069 100644 --- a/WickedEngine/wiArchive.cpp +++ b/WickedEngine/wiArchive.cpp @@ -6,7 +6,7 @@ using namespace std; // this should always be only INCREMENTED and only if a new serialization is implemeted somewhere! -uint64_t __archiveVersion = 56; +uint64_t __archiveVersion = 57; // this is the version number of which below the archive is not compatible with the current version uint64_t __archiveVersionBarrier = 22; diff --git a/WickedEngine/wiPhysicsEngine.h b/WickedEngine/wiPhysicsEngine.h index 9db7b3d51..cf6b3c633 100644 --- a/WickedEngine/wiPhysicsEngine.h +++ b/WickedEngine/wiPhysicsEngine.h @@ -5,14 +5,57 @@ namespace wiPhysicsEngine { + // Initializes the physics engine void Initialize(); - bool IsEnabled(); + // Enable/disable the physics engine all together void SetEnabled(bool value); + bool IsEnabled(); + // Enable/disable the physics simulation. + // Physics engine state will be updated but not simulated + void SetSimulationEnabled(bool value); + bool IsSimulationEnabled(); + + // Enable/disable debug drawing of physics object + void SetDebugDrawEnabled(bool value); + bool IsDebugDrawEnabled(); + + // Set the accuracy of the simulation + // This value corresponds to maximum simulation step count + // Higher values will be slower but more accurate + // Default is 10 + void SetAccuracy(int value); + int GetAccuracy(); + + // Update the physics state, run simulation, etc. void RunPhysicsUpdateSystem( wiJobSystem::context& ctx, wiScene::Scene& scene, float dt ); + + // Apply force at body center + void ApplyForce( + const wiScene::RigidBodyPhysicsComponent& physicscomponent, + const XMFLOAT3& force + ); + // Apply force at body local position + void ApplyForceAt( + const wiScene::RigidBodyPhysicsComponent& physicscomponent, + const XMFLOAT3& force, + const XMFLOAT3& at + ); + + // Apply impulse at body center + void ApplyBodyImpulse( + const wiScene::RigidBodyPhysicsComponent& physicscomponent, + const XMFLOAT3& impulse + ); + // Apply impulse at body local position + void ApplyImpulseAt( + const wiScene::RigidBodyPhysicsComponent& physicscomponent, + const XMFLOAT3& impulse, + const XMFLOAT3& at + ); } diff --git a/WickedEngine/wiPhysicsEngine_Bullet.cpp b/WickedEngine/wiPhysicsEngine_Bullet.cpp index d737804c9..8d9e1129e 100644 --- a/WickedEngine/wiPhysicsEngine_Bullet.cpp +++ b/WickedEngine/wiPhysicsEngine_Bullet.cpp @@ -3,6 +3,7 @@ #include "wiProfiler.h" #include "wiBackLog.h" #include "wiJobSystem.h" +#include "wiRenderer.h" #include "btBulletDynamicsCommon.h" #include "BulletSoftBody/btSoftBodyHelpers.h" @@ -21,32 +22,53 @@ using namespace wiScene; namespace wiPhysicsEngine { bool ENABLED = true; + bool SIMULATION_ENABLED = true; + bool DEBUGDRAW_ENABLED = false; + int ACCURACY = 10; std::mutex physicsLock; btVector3 gravity(0, -10, 0); int softbodyIterationCount = 5; - std::unique_ptr collisionConfiguration; + btSoftBodyRigidBodyCollisionConfiguration collisionConfiguration; + btDbvtBroadphase overlappingPairCache; + btSequentialImpulseConstraintSolver solver; std::unique_ptr dispatcher; - std::unique_ptr overlappingPairCache; - std::unique_ptr solver; std::unique_ptr dynamicsWorld; + class DebugDraw : public btIDebugDraw + { + void drawLine(const btVector3& from, const btVector3& to, const btVector3& color) override + { + wiRenderer::RenderableLine line; + line.start = XMFLOAT3(from.x(), from.y(), from.z()); + line.end = XMFLOAT3(to.x(), to.y(), to.z()); + line.color_start = line.color_end = XMFLOAT4(color.x(), color.y(), color.z(), 1.0f); + wiRenderer::DrawLine(line); + } + void drawContactPoint(const btVector3& PointOnB, const btVector3& normalOnB, btScalar distance, int lifeTime, const btVector3& color) override + { + } + void reportErrorWarning(const char* warningString) override + { + wiBackLog::post(warningString); + } + void draw3dText(const btVector3& location, const char* textString) override + { + } + void setDebugMode(int debugMode) override + { + } + int getDebugMode() const override + { + return DBG_DrawWireframe; + } + }; + DebugDraw debugDraw; void Initialize() { - // collision configuration contains default setup for memory, collision setup. Advanced users can create their own configuration. - collisionConfiguration = std::make_unique(); - - // use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded) - dispatcher = std::make_unique(collisionConfiguration.get()); - - // btDbvtBroadphase is a good general purpose broadphase. You can also try out btAxis3Sweep. - overlappingPairCache = std::make_unique(); - - // the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded) - solver = std::make_unique(); - - dynamicsWorld = std::make_unique(dispatcher.get(), overlappingPairCache.get(), solver.get(), collisionConfiguration.get()); + dispatcher = std::make_unique(&collisionConfiguration); + dynamicsWorld = std::make_unique(dispatcher.get(), &overlappingPairCache, &solver, &collisionConfiguration); dynamicsWorld->getSolverInfo().m_solverMode |= SOLVER_RANDMIZE_ORDER; dynamicsWorld->getDispatchInfo().m_enableSatConvex = true; @@ -63,58 +85,79 @@ namespace wiPhysicsEngine softWorldInfo.m_gravity.setValue(gravity.x(), gravity.y(), gravity.z()); softWorldInfo.m_sparsesdf.Initialize(); + softRigidWorld->setDebugDrawer(&debugDraw); + wiBackLog::post("wiPhysicsEngine_Bullet Initialized"); } bool IsEnabled() { return ENABLED; } void SetEnabled(bool value) { ENABLED = value; } - void AddRigidBody(Entity entity, wiScene::RigidBodyPhysicsComponent& physicscomponent, const wiScene::MeshComponent& mesh, const wiScene::TransformComponent& transform) - { - btVector3 S(transform.scale_local.x, transform.scale_local.y, transform.scale_local.z); + bool IsSimulationEnabled() { return SIMULATION_ENABLED; } + void SetSimulationEnabled(bool value) { SIMULATION_ENABLED = value; } + bool IsDebugDrawEnabled() { return DEBUGDRAW_ENABLED; } + void SetDebugDrawEnabled(bool value) { DEBUGDRAW_ENABLED = value; } + + int GetAccuracy() { return ACCURACY; } + void SetAccuracy(int value) { ACCURACY = value; } + + void AddRigidBody(Entity entity, wiScene::RigidBodyPhysicsComponent& physicscomponent, const wiScene::TransformComponent& transform, const wiScene::MeshComponent* mesh) + { btCollisionShape* shape = nullptr; switch (physicscomponent.shape) { case RigidBodyPhysicsComponent::CollisionShape::BOX: - shape = new btBoxShape(S); - break; + { + shape = new btBoxShape(btVector3(physicscomponent.box.halfextents.x, physicscomponent.box.halfextents.y, physicscomponent.box.halfextents.z)); + } + break; case RigidBodyPhysicsComponent::CollisionShape::SPHERE: - shape = new btSphereShape(btScalar(S.x())); - break; + { + shape = new btSphereShape(btScalar(physicscomponent.sphere.radius)); + } + break; case RigidBodyPhysicsComponent::CollisionShape::CAPSULE: - shape = new btCapsuleShape(btScalar(S.x()), btScalar(S.y())); + shape = new btCapsuleShape(btScalar(physicscomponent.capsule.radius), btScalar(physicscomponent.capsule.height)); break; case RigidBodyPhysicsComponent::CollisionShape::CONVEX_HULL: + if(mesh != nullptr) { shape = new btConvexHullShape(); - for (auto& pos : mesh.vertex_positions) + for (auto& pos : mesh->vertex_positions) { ((btConvexHullShape*)shape)->addPoint(btVector3(pos.x, pos.y, pos.z)); } + btVector3 S(transform.scale_local.x, transform.scale_local.y, transform.scale_local.z); shape->setLocalScaling(S); } + else + { + wiBackLog::post("Convex Hull physics requested, but no MeshComponent provided!"); + assert(0); + } break; case RigidBodyPhysicsComponent::CollisionShape::TRIANGLE_MESH: + if(mesh != nullptr) { - int totalVerts = (int)mesh.vertex_positions.size(); - int totalTriangles = (int)mesh.indices.size() / 3; + int totalVerts = (int)mesh->vertex_positions.size(); + int totalTriangles = (int)mesh->indices.size() / 3; btVector3* btVerts = new btVector3[totalVerts]; size_t i = 0; - for (auto& pos : mesh.vertex_positions) + for (auto& pos : mesh->vertex_positions) { btVerts[i++] = btVector3(pos.x, pos.y, pos.z); } - int* btInd = new int[mesh.indices.size()]; + int* btInd = new int[mesh->indices.size()]; i = 0; - for (auto& ind : mesh.indices) + for (auto& ind : mesh->indices) { btInd[i++] = ind; } @@ -133,8 +176,14 @@ namespace wiPhysicsEngine bool useQuantizedAabbCompression = true; shape = new btBvhTriangleMeshShape(indexVertexArrays, useQuantizedAabbCompression); + btVector3 S(transform.scale_local.x, transform.scale_local.y, transform.scale_local.z); shape->setLocalScaling(S); } + else + { + wiBackLog::post("Triangle Mesh physics requested, but no MeshComponent provided!"); + assert(0); + } break; } @@ -290,9 +339,7 @@ namespace wiPhysicsEngine ) { if (!IsEnabled() || dt <= 0) - { return; - } auto range = wiProfiler::BeginRangeCPU("Physics"); @@ -307,10 +354,14 @@ namespace wiPhysicsEngine if (physicscomponent.physicsobject == nullptr) { TransformComponent& transform = *scene.transforms.GetComponent(entity); - const ObjectComponent& object = *scene.objects.GetComponent(entity); - const MeshComponent& mesh = *scene.meshes.GetComponent(object.meshID); + const ObjectComponent* object = scene.objects.GetComponent(entity); + const MeshComponent* mesh = nullptr; + if (object != nullptr) + { + mesh = scene.meshes.GetComponent(object->meshID); + } physicsLock.lock(); - AddRigidBody(entity, physicscomponent, mesh, transform); + AddRigidBody(entity, physicscomponent, transform, mesh); physicsLock.unlock(); } @@ -329,8 +380,15 @@ namespace wiPhysicsEngine } rigidbody->setActivationState(activationState); + rigidbody->setDamping( + physicscomponent.damping_linear, + physicscomponent.damping_angular + ); + rigidbody->setFriction(physicscomponent.friction); + rigidbody->setRestitution(physicscomponent.restitution); + // For kinematic object, system updates physics state, else the physics updates system state: - if (physicscomponent.IsKinematic()) + if (physicscomponent.IsKinematic() || !IsSimulationEnabled()) { TransformComponent& transform = *scene.transforms.GetComponent(entity); @@ -345,6 +403,12 @@ namespace wiPhysicsEngine physicsTransform.setRotation(R); motionState->setWorldTransform(physicsTransform); + if (!IsSimulationEnabled()) + { + // This is a more direct way of manipulating rigid body: + rigidbody->setWorldTransform(physicsTransform); + } + btCollisionShape* shape = rigidbody->getCollisionShape(); XMFLOAT3 scale = transform.GetScale(); btVector3 S(scale.x, scale.y, scale.z); @@ -384,6 +448,9 @@ namespace wiPhysicsEngine softbody->m_cfg.kDF = physicscomponent.friction; softbody->setWindVelocity(wind); + softbody->setFriction(physicscomponent.friction); + softbody->setRestitution(physicscomponent.restitution); + // This is different from rigid bodies, because soft body is a per mesh component (no TransformComponent). World matrix is propagated down from single mesh instance (ObjectUpdateSystem). XMMATRIX worldMatrix = XMLoadFloat4x4(&physicscomponent.worldMatrix); @@ -409,7 +476,10 @@ namespace wiPhysicsEngine wiJobSystem::Wait(ctx); // Perform internal simulation step: - dynamicsWorld->stepSimulation(dt, 10); + if (IsSimulationEnabled()) + { + dynamicsWorld->stepSimulation(dt, ACCURACY); + } // Feedback physics engine state to system: for (int i = 0; i < dynamicsWorld->getCollisionObjectArray().size(); ++i) @@ -421,7 +491,7 @@ namespace wiPhysicsEngine if (rigidbody != nullptr) { RigidBodyPhysicsComponent* physicscomponent = scene.rigidbodies.GetComponent(entity); - if (physicscomponent == nullptr) + if (physicscomponent == nullptr || physicscomponent->physicsobject != rigidbody) { dynamicsWorld->removeRigidBody(rigidbody); i--; @@ -429,7 +499,7 @@ namespace wiPhysicsEngine } // Feedback non-kinematic objects to system: - if(!physicscomponent->IsKinematic()) + if (IsSimulationEnabled() && !physicscomponent->IsKinematic()) { TransformComponent& transform = *scene.transforms.GetComponent(entity); @@ -452,7 +522,7 @@ namespace wiPhysicsEngine if (softbody != nullptr) { SoftBodyPhysicsComponent* physicscomponent = scene.softbodies.GetComponent(entity); - if (physicscomponent == nullptr) + if (physicscomponent == nullptr || physicscomponent->physicsobject != softbody) { ((btSoftRigidDynamicsWorld*)dynamicsWorld.get())->removeSoftBody(softbody); i--; @@ -561,6 +631,62 @@ namespace wiPhysicsEngine } } + if (IsDebugDrawEnabled()) + { + dynamicsWorld->debugDrawWorld(); + } + wiProfiler::EndRange(range); // Physics } + + + + void ApplyForce( + const wiScene::RigidBodyPhysicsComponent& physicscomponent, + const XMFLOAT3& force + ) + { + if (physicscomponent.physicsobject != nullptr) + { + btRigidBody* rigidbody = (btRigidBody*)physicscomponent.physicsobject; + rigidbody->applyCentralForce(btVector3(force.x, force.y, force.z)); + } + } + void ApplyForceAt( + const wiScene::RigidBodyPhysicsComponent& physicscomponent, + const XMFLOAT3& force, + const XMFLOAT3& at + ) + { + if (physicscomponent.physicsobject != nullptr) + { + btRigidBody* rigidbody = (btRigidBody*)physicscomponent.physicsobject; + rigidbody->applyForce(btVector3(force.x, force.y, force.z), btVector3(at.x, at.y, at.z)); + } + } + + void ApplyImpulse( + const wiScene::RigidBodyPhysicsComponent& physicscomponent, + const XMFLOAT3& impulse + ) + { + if (physicscomponent.physicsobject != nullptr) + { + btRigidBody* rigidbody = (btRigidBody*)physicscomponent.physicsobject; + rigidbody->applyCentralImpulse(btVector3(impulse.x, impulse.y, impulse.z)); + } + } + void ApplyImpulseAt( + const wiScene::RigidBodyPhysicsComponent& physicscomponent, + const XMFLOAT3& impulse, + const XMFLOAT3& at + ) + { + if (physicscomponent.physicsobject != nullptr) + { + btRigidBody* rigidbody = (btRigidBody*)physicscomponent.physicsobject; + rigidbody->applyImpulse(btVector3(impulse.x, impulse.y, impulse.z), btVector3(at.x, at.y, at.z)); + } + } + } diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index 7e9fcf96b..302d8125c 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -656,9 +656,24 @@ namespace wiScene }; CollisionShape shape; float mass = 1.0f; - float friction = 1.0f; - float restitution = 1.0f; - float damping = 1.0f; + float friction = 0.5f; + float restitution = 0.0f; + float damping_linear = 0.0f; + float damping_angular = 0.0f; + + struct BoxParams + { + XMFLOAT3 halfextents = XMFLOAT3(1, 1, 1); + } box; + struct SphereParams + { + float radius = 1; + } sphere; + struct CapsuleParams + { + float radius = 1; + float height = 1; + } capsule; // Non-serialized attributes: void* physicsobject = nullptr; @@ -684,7 +699,8 @@ namespace wiScene uint32_t _flags = DISABLE_DEACTIVATION; float mass = 1.0f; - float friction = 1.0f; + float friction = 0.5f; + float restitution = 0.0f; std::vector physicsToGraphicsVertexMapping; // maps graphics vertex index to physics vertex index of the same position std::vector graphicsToPhysicsVertexMapping; // maps a physics vertex index to first graphics vertex index of the same position std::vector weights; // weight per physics vertex controlling the mass. (0: disable weight (no physics, only animation), 1: default weight) diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index f34475388..99ef85b96 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -485,7 +485,19 @@ namespace wiScene archive >> mass; archive >> friction; archive >> restitution; - archive >> damping; + archive >> damping_linear; + + if (archive.GetVersion() >= 57) + { + archive >> damping_angular; + } + else + { + // these were previously untested: + friction = 0.5f; + restitution = 0.0f; + damping_linear = 0; + } } else { @@ -494,7 +506,12 @@ namespace wiScene archive << mass; archive << friction; archive << restitution; - archive << damping; + archive << damping_linear; + + if (archive.GetVersion() >= 57) + { + archive << damping_angular; + } } } void SoftBodyPhysicsComponent::Serialize(wiArchive& archive, EntitySerializer& seri) @@ -514,6 +531,16 @@ namespace wiScene archive >> temp; } + if (archive.GetVersion() >= 57) + { + archive >> restitution; + } + else + { + // these were previously untested: + friction = 0.5f; + } + _flags &= ~SAFE_TO_REGISTER; } else @@ -524,6 +551,11 @@ namespace wiScene archive << physicsToGraphicsVertexMapping; archive << graphicsToPhysicsVertexMapping; archive << weights; + + if (archive.GetVersion() >= 57) + { + archive << restitution; + } } } void ArmatureComponent::Serialize(wiArchive& archive, EntitySerializer& seri) diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 9c0c8d25e..2603ee1b8 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates, breaking compatibility changes const int minor = 51; // minor bug fixes, alterations, refactors, updates - const int revision = 34; + const int revision = 35; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);