From 8c25f2df5ee5f04f072082c1c4f4d2a294749012 Mon Sep 17 00:00:00 2001 From: Panos Karabelas Date: Tue, 14 Jan 2025 11:51:18 +0000 Subject: [PATCH] [physics] adding a physics body to an entity will now walk down the entity's children and create a compound shape, an example is the flight helmet in the objects world, which is made of multiple meshes/entities yet is now behaving a single physics body --- runtime/Game/Game.cpp | 4 + runtime/World/Components/PhysicsBody.cpp | 160 ++++++++++++----------- runtime/World/Components/PhysicsBody.h | 2 - 3 files changed, 91 insertions(+), 75 deletions(-) diff --git a/runtime/Game/Game.cpp b/runtime/Game/Game.cpp index 8a5310f75..877b359ec 100644 --- a/runtime/Game/Game.cpp +++ b/runtime/Game/Game.cpp @@ -427,6 +427,10 @@ namespace spartan entity->SetObjectName("flight_helmet"); entity->SetPosition(Vector3(0.0f, 0.1f, 0.0f)); entity->SetScale(Vector3(1.7f, 1.7f, 1.7f)); + + PhysicsBody* physics_body = entity->AddComponent().get(); + physics_body->SetMass(8.0f); + physics_body->SetShapeType(PhysicsShape::Mesh); } // damaged helmet diff --git a/runtime/World/Components/PhysicsBody.cpp b/runtime/World/Components/PhysicsBody.cpp index 878924ef9..09934dc9d 100644 --- a/runtime/World/Components/PhysicsBody.cpp +++ b/runtime/World/Components/PhysicsBody.cpp @@ -859,9 +859,9 @@ namespace spartan 1.0f, // height scale terrain->GetMinY(), // min height terrain->GetMaxY(), // max height - 1, // Up axis (0=x, 1=y, 2=z) - PHY_FLOAT, // Data type - false // Flip quad edges or not + 1, // up axis (0=x, 1=y, 2=z) + PHY_FLOAT, // data type + false // flip quad edges or not ); shape_local->setLocalScaling(vector_to_bt(size)); @@ -879,83 +879,97 @@ namespace spartan case PhysicsShape::Mesh: { - // get renderable - shared_ptr renderable = GetEntity()->GetComponent(); - if (!renderable) + function recursive_renderable_to_shape = [&](Entity* entity, btCompoundShape* compoundShape) { - SP_LOG_WARNING("PhysicsShape::Mesh requires a renderable component to be present"); - return; - } - - // get geometry - renderable->GetGeometry(&m_indices, &m_vertices); - if (m_vertices.empty()) - { - SP_LOG_WARNING("PhysicsShape::Mesh requires the renderable component to contain vertices"); - return; - } - - // determine how much detail is needed for this shape - const bool is_enterable = can_player_fit(GetEntity(), m_vertices, size); - const bool convex_hull = !is_enterable; - - if (convex_hull) - { - // create - btConvexHullShape* shape_convex = new btConvexHullShape( - reinterpret_cast(&m_vertices[0]), - static_cast(m_vertices.size()), - static_cast(sizeof(RHI_Vertex_PosTexNorTan)) - ); - shape_convex->optimizeConvexHull(); - - // add to compound - btCompoundShape* shape_compound = new btCompoundShape(); - if (renderable->HasInstancing()) + // get renderable + shared_ptr renderable = entity->GetComponent(); + if (renderable) { - for (uint32_t instance_index = 0; instance_index < renderable->GetInstanceCount(); instance_index++) + // get geometry + vector indices; + vector vertices; + renderable->GetGeometry(&indices, &vertices); + + if (vertices.empty()) { - Matrix world_transform = renderable->GetInstanceTransform(instance_index); - shape_compound->addChildShape(compute_transform(world_transform.GetTranslation(), world_transform.GetRotation(), world_transform.GetScale()), shape_convex); + SP_LOG_WARNING("PhysicsShape::Mesh requires the renderable component to contain vertices"); + return; + } + + // determine how much detail is needed for this shape + const bool is_enterable = can_player_fit(entity, vertices, size); + const bool convex_hull = !is_enterable; + + if (convex_hull) + { + // create convex hull shape + btConvexHullShape* shape_convex = new btConvexHullShape( + reinterpret_cast(&vertices[0]), + static_cast(vertices.size()), + static_cast(sizeof(RHI_Vertex_PosTexNorTan)) + ); + shape_convex->optimizeConvexHull(); + + // add to compound + if (renderable->HasInstancing()) + { + for (uint32_t instance_index = 0; instance_index < renderable->GetInstanceCount(); instance_index++) + { + Matrix world_transform = renderable->GetInstanceTransform(instance_index); + compoundShape->addChildShape(compute_transform(world_transform.GetTranslation(), world_transform.GetRotation(), world_transform.GetScale()), shape_convex); + } + } + else + { + compoundShape->addChildShape(compute_transform(Vector3::Zero, Quaternion::Identity, size), shape_convex); + } + } + else + { + // simplify the geometry if not convex hull + geometry_processing::simplify(indices, vertices, static_cast((indices.size() / 3) * 0.05f)); + + // create triangle mesh shape + btTriangleIndexVertexArray* index_vertex_array = new btTriangleIndexVertexArray( + static_cast(indices.size() / 3), + reinterpret_cast(&indices[0]), + sizeof(uint32_t) * 3, + static_cast(vertices.size()), + reinterpret_cast(&vertices[0].pos[0]), + sizeof(vertices[0]) + ); + + btBvhTriangleMeshShape* shape_triangle_mesh = new btBvhTriangleMeshShape( + index_vertex_array, + true // bvh for optimized collisions + ); + + shape_triangle_mesh->setLocalScaling(vector_to_bt(size)); + + // set properties for kinematic static collision + m_is_kinematic = true; + m_mass = 0.0f; + + compoundShape->addChildShape(compute_transform(Vector3::Zero, Quaternion::Identity, size), shape_triangle_mesh); } } - else + + // recursively process all children + vector children = entity->GetChildren(); + for (Entity* child : children) { - shape_compound->addChildShape(compute_transform(Vector3::Zero, Quaternion::Identity, size), shape_convex); + recursive_renderable_to_shape(child, compoundShape); } - - m_shape = shape_compound; - } - else - { - geometry_processing::simplify(m_indices, m_vertices, static_cast((m_indices.size() / 3) * 0.05f)); - - // create a btTriangleIndexVertexArray using indices and vertices - btTriangleIndexVertexArray* index_vertex_array = new btTriangleIndexVertexArray( - static_cast(m_indices.size() / 3), // number of triangles - reinterpret_cast(&m_indices[0]), // pointer to indices - sizeof(uint32_t) * 3, // stride between index sets (3 indices per triangle) - static_cast(m_vertices.size()), // number of vertices - reinterpret_cast(&m_vertices[0].pos[0]), // pointer to vertex positions - sizeof(m_vertices[0]) // stride between vertices - ); - - // create a btBvhTriangleMeshShape using the index-vertex array - btBvhTriangleMeshShape* shape_triangle_mesh = new btBvhTriangleMeshShape( - index_vertex_array, - true // bvh for optimized collisions - ); - - // we only need to set the scale as the rotation and position is set set in btMotionState - shape_triangle_mesh->setLocalScaling(vector_to_bt(size)); - - // btBvhTriangleMeshShape is static and expensive to collide with - m_is_kinematic = true; - m_mass = 0.0f; - - m_shape = shape_triangle_mesh; - } - + }; + + // create the compound shape + btCompoundShape* shape_compound = new btCompoundShape(); + + // start the recursive process for this entity + recursive_renderable_to_shape(GetEntity(), shape_compound); + + m_shape = shape_compound; + break; } } diff --git a/runtime/World/Components/PhysicsBody.h b/runtime/World/Components/PhysicsBody.h index 8fb157362..1033000b1 100644 --- a/runtime/World/Components/PhysicsBody.h +++ b/runtime/World/Components/PhysicsBody.h @@ -185,7 +185,5 @@ namespace spartan void* m_rigid_body = nullptr; std::shared_ptr m_car = nullptr; std::vector m_constraints; - std::vector m_vertices; - std::vector m_indices; }; }