Skip to content

Commit

Permalink
[physics] shapes which are good candidates for convex hulls are now b…
Browse files Browse the repository at this point in the history
…etter detected
  • Loading branch information
PanosK92 committed Jan 8, 2025
1 parent 5d9d60f commit f8f4440
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 56 deletions.
10 changes: 5 additions & 5 deletions runtime/Game/Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -740,8 +740,8 @@ namespace Spartan
if (entity->IsActive() && entity->GetComponent<Renderable>() != nullptr)
{
PhysicsBody* physics_body = entity->AddComponent<PhysicsBody>().get();
physics_body->SetMass(0.0f);
physics_body->SetShapeType(PhysicsShape::Mesh);
physics_body->SetMass(0.0f); // static
}
}
}
Expand Down Expand Up @@ -822,7 +822,7 @@ namespace Spartan
if (entity->GetComponent<Renderable>() != nullptr)
{
PhysicsBody* physics_body = entity->AddComponent<PhysicsBody>().get();
physics_body->SetMass(0.0f); // static
physics_body->SetMass(0.0f);
physics_body->SetShapeType(PhysicsShape::Mesh);
}
}
Expand Down Expand Up @@ -895,7 +895,7 @@ namespace Spartan
if (entity->IsActive() && entity->GetComponent<Renderable>() != nullptr)
{
PhysicsBody* physics_body = entity->AddComponent<PhysicsBody>().get();
physics_body->SetMass(0.0f); // static
physics_body->SetMass(0.0f);
physics_body->SetShapeType(PhysicsShape::Mesh);
}
}
Expand Down Expand Up @@ -924,7 +924,7 @@ namespace Spartan
if (entity->GetComponent<Renderable>() != nullptr)
{
PhysicsBody* physics_body = entity->AddComponent<PhysicsBody>().get();
physics_body->SetMass(0.0f); // static
physics_body->SetMass(0.0f);
physics_body->SetShapeType(PhysicsShape::Mesh);
}
}
Expand Down Expand Up @@ -952,7 +952,7 @@ namespace Spartan
if (entity->GetComponent<Renderable>() != nullptr)
{
PhysicsBody* physics_body = entity->AddComponent<PhysicsBody>().get();
physics_body->SetMass(0.0f); // static
physics_body->SetMass(0.0f);
physics_body->SetShapeType(PhysicsShape::Mesh);
}
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/Rendering/Renderer_Passes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2122,7 +2122,7 @@ namespace Spartan
static RHI_PipelineState pso;
pso.shaders[RHI_Shader_Type::Vertex] = shader_v;
pso.shaders[RHI_Shader_Type::Pixel] = shader_p;
pso.rasterizer_state = GetRasterizerState(Renderer_RasterizerState::Solid);
pso.rasterizer_state = GetRasterizerState(Renderer_RasterizerState::Wireframe);
pso.blend_state = GetBlendState(Renderer_BlendState::Alpha);
pso.depth_stencil_state = GetDepthStencilState(Renderer_DepthStencilState::ReadGreaterEqual);
pso.render_target_color_textures[0] = tex_out;
Expand Down
94 changes: 44 additions & 50 deletions runtime/World/Components/PhysicsBody.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ SP_WARNINGS_OFF
#include <BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h>
#include <BulletCollision/CollisionShapes/btConvexHullShape.h>
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
#include <BulletCollision/Gimpact/btGImpactShape.h>
SP_WARNINGS_ON
//====================================================================

Expand Down Expand Up @@ -85,82 +86,67 @@ namespace Spartan
return transform;
}

bool can_a_capsule_enter(Renderable* renderable, const vector<RHI_Vertex_PosTexNorTan>& vertices, const Vector3& scale)
bool can_fit_the_player(Entity* entity, const vector<RHI_Vertex_PosTexNorTan>& vertices, const Vector3& scale)
{
// skip objects which are too small for a human to fit inside
if (renderable->GetBoundingBox(BoundingBoxType::Transformed).Volume() < 1.0f)
const BoundingBox& bounding_box = entity->GetComponent<Renderable>()->GetBoundingBox(BoundingBoxType::Transformed);

// skip tiny objects
if (bounding_box.Volume() < 1.0f)
return false;

// human dimensions
float capsuleHeight = 1.8f; // meters
float capsuleRadius = 0.5f; // meters

auto is_inside_capsule = [&](const Vector3& point)
{
Vector3 pointToBase = point - Vector3(0.0f, 0.0f, 0.0f); // base at y = 0
float distanceFromCenter = sqrt(pointToBase.x * pointToBase.x + pointToBase.z * pointToBase.z);

// check if inside the cylindrical part
if (point.y >= 0.0f && point.y <= capsuleHeight)
{
return distanceFromCenter <= capsuleRadius;
}

// check if inside the cap part (hemispheres)
if (point.y > 0.0f && point.y < capsuleHeight)
{
float yDistanceFromCap = fabs(point.y - capsuleHeight);
float capRadius = sqrt(capsuleRadius * capsuleRadius - yDistanceFromCap * yDistanceFromCap);
return distanceFromCenter <= capRadius;
}

return false; // Point outside the capsule
};
// a sphere of 2 meters could fit most humans
float radius = 2.0f;
Vector3 center = bounding_box.GetCenter();

int outside_vertex_count = 0;
for (const auto& vertex : vertices)
{
Vector3 position = Vector3(vertex.pos[0], vertex.pos[1], vertex.pos[2]) * scale;

if (!is_inside_capsule(position))
// scale the vertex position
Vector3 position = Vector3(vertex.pos[0], vertex.pos[1], vertex.pos[2]) * entity->GetMatrix();

// check if the vertex is outside the sphere
float distance_squared = (position - center).LengthSquared();
if (distance_squared > radius * radius)
{
outside_vertex_count++;
}
}

// calculate the percentage of vertices outside the sphere
float outside_percentage = static_cast<float>(outside_vertex_count) / vertices.size();
const float hollow_threshold = 0.90f; // 90%
const float hollow_threshold = 0.8f;

// return true if most of the vertices are outside the sphere
return outside_percentage >= hollow_threshold;
}
}

class MotionState : public btMotionState
{
public:
MotionState(PhysicsBody* rigidBody) { m_rigidBody = rigidBody; }
MotionState(PhysicsBody* rigid_body_) { m_rigid_body = rigid_body_; }

// engine -> bullet
void getWorldTransform(btTransform& worldTrans) const override
void getWorldTransform(btTransform& transform) const override
{
const Vector3 last_position = m_rigidBody->GetEntity()->GetPosition();
const Quaternion last_rotation = m_rigidBody->GetEntity()->GetRotation();
const Vector3 last_position = m_rigid_body->GetEntity()->GetPosition();
const Quaternion last_rotation = m_rigid_body->GetEntity()->GetRotation();

worldTrans.setOrigin(vector_to_bt(last_position + last_rotation * m_rigidBody->GetCenterOfMass()));
worldTrans.setRotation(quaternion_to_bt(last_rotation));
transform.setOrigin(vector_to_bt(last_position + last_rotation * m_rigid_body->GetCenterOfMass()));
transform.setRotation(quaternion_to_bt(last_rotation));
}

// bullet -> engine
void setWorldTransform(const btTransform& worldTrans) override
void setWorldTransform(const btTransform& transform) override
{
const Quaternion new_rotation = bt_to_quaternion(worldTrans.getRotation());
const Vector3 new_position = bt_to_vector(worldTrans.getOrigin()) - new_rotation * m_rigidBody->GetCenterOfMass();
const Quaternion new_rotation = bt_to_quaternion(transform.getRotation());
const Vector3 new_position = bt_to_vector(transform.getOrigin()) - new_rotation * m_rigid_body->GetCenterOfMass();

m_rigidBody->GetEntity()->SetPosition(new_position);
m_rigidBody->GetEntity()->SetRotation(new_rotation);
m_rigid_body->GetEntity()->SetPosition(new_position);
m_rigid_body->GetEntity()->SetRotation(new_rotation);
}
private:
PhysicsBody* m_rigidBody;
PhysicsBody* m_rigid_body;
};

PhysicsBody::PhysicsBody(Entity* entity) : Component(entity)
Expand Down Expand Up @@ -907,7 +893,7 @@ namespace Spartan
}

// determine how much detail is needed for this shape
const bool is_enterable = can_a_capsule_enter(renderable.get(), vertices, size);
const bool is_enterable = can_fit_the_player(GetEntity(), vertices, size);
const bool is_low_poly = vertices.size() < 1000;
const bool convex_hull = !is_enterable && !is_low_poly;

Expand Down Expand Up @@ -940,18 +926,26 @@ namespace Spartan
}
else
{
btTriangleMesh* shape_local = new btTriangleMesh();
// create
btTriangleMesh* mesh = new btTriangleMesh();
for (uint32_t i = 0; i < static_cast<uint32_t>(indices.size()); i += 3)
{
btVector3 vertex0(vertices[indices[i]].pos[0], vertices[indices[i]].pos[1], vertices[indices[i]].pos[2]);
btVector3 vertex1(vertices[indices[i + 1]].pos[0], vertices[indices[i + 1]].pos[1], vertices[indices[i + 1]].pos[2]);
btVector3 vertex2(vertices[indices[i + 2]].pos[0], vertices[indices[i + 2]].pos[1], vertices[indices[i + 2]].pos[2]);
shape_local->addTriangle(vertex0, vertex1, vertex2);

mesh->addTriangle(vertex0, vertex1, vertex2);
}
shape_local->setScaling(vector_to_bt(size));

m_shape = new btBvhTriangleMeshShape(shape_local, true);
m_mass = 0.0f; // btBvhTriangleMeshShape is static
// convert to btBvhTriangleMeshShape
btBvhTriangleMeshShape* shape_triangle_mesh = new btBvhTriangleMeshShape(mesh, true);
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;
}

break;
Expand Down

0 comments on commit f8f4440

Please sign in to comment.