From 65081ab9ab7f90a6ebbf0290a11d8c1007190631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Sat, 22 Feb 2025 08:13:03 +0100 Subject: [PATCH] terrain physics optimization --- WickedEngine/wiPhysics_Jolt.cpp | 15 ++++ WickedEngine/wiScene_Components.h | 128 +++++++++++++++--------------- WickedEngine/wiTerrain.cpp | 31 +++++--- WickedEngine/wiVersion.cpp | 2 +- 4 files changed, 102 insertions(+), 74 deletions(-) diff --git a/WickedEngine/wiPhysics_Jolt.cpp b/WickedEngine/wiPhysics_Jolt.cpp index 25bb4b5ea2..c2370cb23a 100644 --- a/WickedEngine/wiPhysics_Jolt.cpp +++ b/WickedEngine/wiPhysics_Jolt.cpp @@ -313,6 +313,10 @@ namespace wi::physics } return *(RigidBody*)physicscomponent.physicsobject.get(); } + const RigidBody& GetRigidBody(const wi::scene::RigidBodyPhysicsComponent& physicscomponent) + { + return *(RigidBody*)physicscomponent.physicsobject.get(); + } SoftBody& GetSoftBody(wi::scene::SoftBodyPhysicsComponent& physicscomponent) { if (physicscomponent.physicsobject == nullptr) @@ -321,6 +325,10 @@ namespace wi::physics } return *(SoftBody*)physicscomponent.physicsobject.get(); } + const SoftBody& GetSoftBody(const wi::scene::SoftBodyPhysicsComponent& physicscomponent) + { + return *(SoftBody*)physicscomponent.physicsobject.get(); + } void AddRigidBody( wi::scene::Scene& scene, @@ -341,6 +349,13 @@ namespace wi::physics XMStoreFloat4x4(&transform.world, parentMatrix * transform.GetLocalMatrix()); transform.ApplyTransform(); + if (mesh != nullptr && mesh->precomputed_rigidbody_physics_shape.physicsobject != nullptr) + { + // The shape comes from mesh's precomputed shape: + const RigidBody& precomputed_rigidbody_with_shape = GetRigidBody(mesh->precomputed_rigidbody_physics_shape); + physicsobject.shape = precomputed_rigidbody_with_shape.shape; + } + if (physicsobject.shape == nullptr) // shape creation can be called from outside as optimization from threads { CreateRigidBodyShape(physicscomponent, transform.scale_local, mesh); diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index eb24e75750..e2a5dde505 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -382,6 +382,69 @@ namespace wi::scene void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri); }; + struct RigidBodyPhysicsComponent + { + enum FLAGS + { + EMPTY = 0, + DISABLE_DEACTIVATION = 1 << 0, + KINEMATIC = 1 << 1, + START_DEACTIVATED = 1 << 2, + }; + uint32_t _flags = EMPTY; + + enum CollisionShape + { + BOX, + SPHERE, + CAPSULE, + CONVEX_HULL, + TRIANGLE_MESH, + CYLINDER, + ENUM_FORCE_UINT32 = 0xFFFFFFFF + }; + CollisionShape shape; + float mass = 1.0f; // Set to 0 to make body static + float friction = 0.2f; + float restitution = 0.1f; + float damping_linear = 0.05f; + float damping_angular = 0.05f; + float buoyancy = 1.2f; + XMFLOAT3 local_offset = XMFLOAT3(0, 0, 0); + + struct BoxParams + { + XMFLOAT3 halfextents = XMFLOAT3(1, 1, 1); + } box; + struct SphereParams + { + float radius = 1; + } sphere; + struct CapsuleParams + { + float radius = 1; + float height = 1; + } capsule; // also cylinder params + + // This will force LOD level for rigid body if it is a TRIANGLE_MESH shape: + // The geometry for LOD level will be taken from MeshComponent. + // The physics object will need to be recreated for it to take effect. + uint32_t mesh_lod = 0; + + // 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. + + constexpr void SetDisableDeactivation(bool value) { if (value) { _flags |= DISABLE_DEACTIVATION; } else { _flags &= ~DISABLE_DEACTIVATION; } } + constexpr void SetKinematic(bool value) { if (value) { _flags |= KINEMATIC; } else { _flags &= ~KINEMATIC; } } + constexpr void SetStartDeactivated(bool value) { if (value) { _flags |= START_DEACTIVATED; } else { _flags &= ~START_DEACTIVATED; } } + + constexpr bool IsDisableDeactivation() const { return _flags & DISABLE_DEACTIVATION; } + constexpr bool IsKinematic() const { return _flags & KINEMATIC; } + constexpr bool IsStartDeactivated() const { return _flags & START_DEACTIVATED; } + + void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri); + }; + struct MeshComponent { enum FLAGS @@ -512,6 +575,8 @@ namespace wi::scene }; wi::vector cluster_ranges; + RigidBodyPhysicsComponent precomputed_rigidbody_physics_shape; // you can precompute a physics shape here if you need without using a real rigid body component yet + constexpr void SetRenderable(bool value) { if (value) { _flags |= RENDERABLE; } else { _flags &= ~RENDERABLE; } } constexpr void SetDoubleSided(bool value) { if (value) { _flags |= DOUBLE_SIDED; } else { _flags &= ~DOUBLE_SIDED; } } constexpr void SetDoubleSidedShadow(bool value) { if (value) { _flags |= DOUBLE_SIDED_SHADOW; } else { _flags &= ~DOUBLE_SIDED_SHADOW; } } @@ -955,69 +1020,6 @@ namespace wi::scene }; }; - struct RigidBodyPhysicsComponent - { - enum FLAGS - { - EMPTY = 0, - DISABLE_DEACTIVATION = 1 << 0, - KINEMATIC = 1 << 1, - START_DEACTIVATED = 1 << 2, - }; - uint32_t _flags = EMPTY; - - enum CollisionShape - { - BOX, - SPHERE, - CAPSULE, - CONVEX_HULL, - TRIANGLE_MESH, - CYLINDER, - ENUM_FORCE_UINT32 = 0xFFFFFFFF - }; - CollisionShape shape; - float mass = 1.0f; // Set to 0 to make body static - float friction = 0.2f; - float restitution = 0.1f; - float damping_linear = 0.05f; - float damping_angular = 0.05f; - float buoyancy = 1.2f; - XMFLOAT3 local_offset = XMFLOAT3(0, 0, 0); - - struct BoxParams - { - XMFLOAT3 halfextents = XMFLOAT3(1, 1, 1); - } box; - struct SphereParams - { - float radius = 1; - } sphere; - struct CapsuleParams - { - float radius = 1; - float height = 1; - } capsule; // also cylinder params - - // This will force LOD level for rigid body if it is a TRIANGLE_MESH shape: - // The geometry for LOD level will be taken from MeshComponent. - // The physics object will need to be recreated for it to take effect. - uint32_t mesh_lod = 0; - - // 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. - - constexpr void SetDisableDeactivation(bool value) { if (value) { _flags |= DISABLE_DEACTIVATION; } else { _flags &= ~DISABLE_DEACTIVATION; } } - constexpr void SetKinematic(bool value) { if (value) { _flags |= KINEMATIC; } else { _flags &= ~KINEMATIC; } } - constexpr void SetStartDeactivated(bool value) { if (value) { _flags |= START_DEACTIVATED; } else { _flags &= ~START_DEACTIVATED; } } - - constexpr bool IsDisableDeactivation() const { return _flags & DISABLE_DEACTIVATION; } - constexpr bool IsKinematic() const { return _flags & KINEMATIC; } - constexpr bool IsStartDeactivated() const { return _flags & START_DEACTIVATED; } - - void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri); - }; - struct SoftBodyPhysicsComponent { enum FLAGS diff --git a/WickedEngine/wiTerrain.cpp b/WickedEngine/wiTerrain.cpp index c6ef5ee209..799560fe19 100644 --- a/WickedEngine/wiTerrain.cpp +++ b/WickedEngine/wiTerrain.cpp @@ -556,8 +556,8 @@ namespace wi::terrain void Terrain::Generation_Update(const CameraComponent& camera) { - // The generation task is always cancelled every frame so we are sure that generation is not running at this point - Generation_Cancel(); + if (wi::jobsystem::IsBusy(generator->workload)) + return; // updating can't run while generation is running. Note: we could cancel here, but it could take long until cancel request is fulfilled (happened with physics mesh creations) bool restart_generation = false; if (!IsGenerationStarted()) @@ -803,12 +803,20 @@ namespace wi::terrain { const ObjectComponent* object = scene->objects.GetComponent(chunk_data.entity); - if (rigidbody == nullptr && dist < physics_generation) + if (dist < physics_generation) { - RigidBodyPhysicsComponent& newrigidbody = scene->rigidbodies.Create(chunk_data.entity); - newrigidbody.shape = RigidBodyPhysicsComponent::TRIANGLE_MESH; - newrigidbody.mass = 0; // terrain chunks are static - newrigidbody.friction = 0.8f; + if (rigidbody == nullptr) + { + RigidBodyPhysicsComponent& newrigidbody = scene->rigidbodies.Create(chunk_data.entity); + newrigidbody.shape = RigidBodyPhysicsComponent::TRIANGLE_MESH; + newrigidbody.mass = 0; // terrain chunks are static + newrigidbody.friction = 0.8f; + newrigidbody.mesh_lod = 2; + } + } + else if(rigidbody != nullptr) + { + scene->rigidbodies.Remove(chunk_data.entity); } } else @@ -842,6 +850,7 @@ namespace wi::terrain } // Start the generation on a background thread and keep it running until the next frame + generator->cancelled.store(false); generator->workload.priority = wi::jobsystem::Priority::Low; wi::jobsystem::Execute(generator->workload, [=](wi::jobsystem::JobArgs a) { @@ -1023,13 +1032,15 @@ namespace wi::terrain // Create the textures for virtual texture update: CreateChunkRegionTexture(chunk_data); - const int dist = std::max(std::abs(center_chunk.x - chunk.x), std::abs(center_chunk.z - chunk.z)); - if (IsPhysicsEnabled() && dist < physics_generation) + if (IsPhysicsEnabled()) { - RigidBodyPhysicsComponent& newrigidbody = generator->scene.rigidbodies.Create(chunk_data.entity); + // 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.mass = 0; // terrain chunks are static newrigidbody.friction = 0.8f; + newrigidbody.mesh_lod = 2; wi::physics::CreateRigidBodyShape(newrigidbody, transform.scale_local, &mesh); } diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 98b2150e6c..b4cdb2d294 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 = 687; + const int revision = 688; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);