From bc128fe6eb9e898ac4478a4446af9519087905f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Mon, 31 Mar 2025 09:55:40 +0200 Subject: [PATCH] added height field physics shape type --- Editor/RigidBodyWindow.cpp | 1 + WickedEngine/wiPhysics_Jolt.cpp | 37 +++++++++++++++++++++++++++++++ WickedEngine/wiPrimitive.cpp | 5 +++++ WickedEngine/wiPrimitive.h | 1 + WickedEngine/wiScene_Components.h | 1 + WickedEngine/wiTerrain.cpp | 12 ++++++---- WickedEngine/wiVersion.cpp | 2 +- 7 files changed, 54 insertions(+), 5 deletions(-) diff --git a/Editor/RigidBodyWindow.cpp b/Editor/RigidBodyWindow.cpp index 9766c88d9..970dceb7c 100644 --- a/Editor/RigidBodyWindow.cpp +++ b/Editor/RigidBodyWindow.cpp @@ -32,6 +32,7 @@ void RigidBodyWindow::Create(EditorComponent* _editor) collisionShapeComboBox.AddItem("Cylinder", RigidBodyPhysicsComponent::CollisionShape::CYLINDER); collisionShapeComboBox.AddItem("Convex Hull", RigidBodyPhysicsComponent::CollisionShape::CONVEX_HULL); collisionShapeComboBox.AddItem("Triangle Mesh", RigidBodyPhysicsComponent::CollisionShape::TRIANGLE_MESH); + collisionShapeComboBox.AddItem("Height Field", RigidBodyPhysicsComponent::CollisionShape::HEIGHTFIELD); collisionShapeComboBox.OnSelect([&](wi::gui::EventArgs args) { wi::scene::Scene& scene = editor->GetCurrentScene(); for (auto& x : editor->translator.selected) diff --git a/WickedEngine/wiPhysics_Jolt.cpp b/WickedEngine/wiPhysics_Jolt.cpp index 01f55b1c9..6e0156169 100644 --- a/WickedEngine/wiPhysics_Jolt.cpp +++ b/WickedEngine/wiPhysics_Jolt.cpp @@ -1542,6 +1542,43 @@ namespace wi::physics return; } break; + + case RigidBodyPhysicsComponent::CollisionShape::HEIGHTFIELD: + if (mesh != nullptr) + { + wi::vector heights; + heights.reserve(mesh->vertex_positions.size()); + + wi::primitive::AABB aabb; + + for (XMFLOAT3 pos : mesh->vertex_positions) + { + pos.x *= scale_local.x; + pos.y *= scale_local.y; + pos.z *= scale_local.z; + heights.push_back(pos.y); + aabb.AddPoint(pos); + } + + XMFLOAT3 min = aabb.getMin(); + min.y = 0; + + uint32_t dim = (uint32_t)std::sqrt((double)heights.size()); + wilog_assert(dim >= 2, "Height field shape dimension must be at least 2!"); + + Vec3 scale = cast(aabb.getHalfWidth()) * 2 / (float)(dim - 1); + scale.SetY(1); + + HeightFieldShapeSettings settings(heights.data(), cast(min), scale, dim); + settings.SetEmbedded(); + shape_result = settings.Create(); + } + else + { + wi::backlog::post("CreateRigidBodyShape failed: height field physics requested, but no MeshComponent provided!", wi::backlog::LogLevel::Error); + return; + } + break; } if (!shape_result.IsValid()) diff --git a/WickedEngine/wiPrimitive.cpp b/WickedEngine/wiPrimitive.cpp index fd32ae93b..2f57e0114 100644 --- a/WickedEngine/wiPrimitive.cpp +++ b/WickedEngine/wiPrimitive.cpp @@ -205,6 +205,11 @@ namespace wi::primitive { return AABB(wi::math::Min(a.getMin(), b.getMin()), wi::math::Max(a.getMax(), b.getMax())); } + void AABB::AddPoint(const XMFLOAT3& pos) + { + _min = wi::math::Min(_min, pos); + _max = wi::math::Max(_max, pos); + } void AABB::Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri) { if (archive.IsReadMode()) diff --git a/WickedEngine/wiPrimitive.h b/WickedEngine/wiPrimitive.h index 083bff4ee..3249da92f 100644 --- a/WickedEngine/wiPrimitive.h +++ b/WickedEngine/wiPrimitive.h @@ -50,6 +50,7 @@ namespace wi::primitive bool intersects(const BoundingFrustum& frustum) const; AABB operator* (float a); static AABB Merge(const AABB& a, const AABB& b); + void AddPoint(const XMFLOAT3& pos); // projects the AABB to the screen, returns a 2D rectangle in UV-space as Vector(topleftX, topleftY, bottomrightX, bottomrightY), each value is in range [0, 1] XMFLOAT4 ProjectToScreen(const XMMATRIX& ViewProjection) const; diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index f6cd875c8..d546dfe9d 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -412,6 +412,7 @@ namespace wi::scene CONVEX_HULL, TRIANGLE_MESH, CYLINDER, + HEIGHTFIELD, ENUM_FORCE_UINT32 = 0xFFFFFFFF }; CollisionShape shape; diff --git a/WickedEngine/wiTerrain.cpp b/WickedEngine/wiTerrain.cpp index 799560fe1..3b769a976 100644 --- a/WickedEngine/wiTerrain.cpp +++ b/WickedEngine/wiTerrain.cpp @@ -808,10 +808,14 @@ namespace wi::terrain if (rigidbody == nullptr) { RigidBodyPhysicsComponent& newrigidbody = scene->rigidbodies.Create(chunk_data.entity); - newrigidbody.shape = RigidBodyPhysicsComponent::TRIANGLE_MESH; + newrigidbody.shape = RigidBodyPhysicsComponent::HEIGHTFIELD; newrigidbody.mass = 0; // terrain chunks are static newrigidbody.friction = 0.8f; - newrigidbody.mesh_lod = 2; + //newrigidbody.mesh_lod = 2; + } + else + { + rigidbody->shape = RigidBodyPhysicsComponent::HEIGHTFIELD; } } else if(rigidbody != nullptr) @@ -1037,10 +1041,10 @@ namespace wi::terrain // Precompute the physics shape here on separate thread, because computing shape for triangle mesh would be slow on main thread: // Note that this is mesh.precomputed_rigidbody_physics_shape and not a component in scene.rigidbodies, so this only contains the shape, not the simulated rigid bodies RigidBodyPhysicsComponent& newrigidbody = mesh.precomputed_rigidbody_physics_shape; - newrigidbody.shape = RigidBodyPhysicsComponent::TRIANGLE_MESH; + newrigidbody.shape = RigidBodyPhysicsComponent::HEIGHTFIELD; newrigidbody.mass = 0; // terrain chunks are static newrigidbody.friction = 0.8f; - newrigidbody.mesh_lod = 2; + //newrigidbody.mesh_lod = 2; wi::physics::CreateRigidBodyShape(newrigidbody, transform.scale_local, &mesh); } diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 7726503ba..d80a8bab8 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 = 726; + const int revision = 727; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);