From: Daniel Karbach Date: Fri, 2 Dec 2016 15:45:56 +0000 (+0100) Subject: half-{complete,assed} sphere collision detection X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;p=gong.git half-{complete,assed} sphere collision detection --- diff --git a/src/physics/Contact.hpp b/src/physics/Contact.hpp new file mode 100644 index 0000000..b7109b1 --- /dev/null +++ b/src/physics/Contact.hpp @@ -0,0 +1,27 @@ +#ifndef GONG_PHYSICS_CONTACT_HPP_ +#define GONG_PHYSICS_CONTACT_HPP_ + +#include "../graphics/glm.hpp" + + +namespace gong { +namespace physics { + +class Object; + +struct Contact { + + glm::vec3 point; + glm::vec3 normal; + Object *a; + Object *b; + + Contact(const glm::vec3 &p, const glm::vec3 &n, Object *a, Object *b) + : point(p), normal(n), a(a), b(b) { } + +}; + +} +} + +#endif diff --git a/src/physics/Object.hpp b/src/physics/Object.hpp index 576317c..f4f7f4a 100644 --- a/src/physics/Object.hpp +++ b/src/physics/Object.hpp @@ -4,15 +4,25 @@ #include "State.hpp" #include "../geometry/primitive.hpp" +#include + namespace gong { namespace physics { +struct Contact; +class Sphere; + struct Object { State state; geometry::AABB bounds; + void TestCollision(Object &, std::vector &); + + virtual void ReverseCollisionTest(Object &, std::vector &) = 0; + virtual void ActualCollisionTest(Sphere &, std::vector &) = 0; + }; } diff --git a/src/physics/Simulation.hpp b/src/physics/Simulation.hpp index 9d41877..889c455 100644 --- a/src/physics/Simulation.hpp +++ b/src/physics/Simulation.hpp @@ -9,6 +9,7 @@ namespace gong { namespace physics { +struct Contact; struct Derivative; struct Object; struct State; @@ -24,6 +25,7 @@ private: private: std::vector objects; + std::vector contacts; glm::vec3 gravity; }; diff --git a/src/physics/Sphere.hpp b/src/physics/Sphere.hpp new file mode 100644 index 0000000..0acbc0b --- /dev/null +++ b/src/physics/Sphere.hpp @@ -0,0 +1,34 @@ +#ifndef GONG_PHYSICS_SPHERE_HPP_ +#define GONG_PHYSICS_SPHERE_HPP_ + +#include "Object.hpp" +#include "../geometry/primitive.hpp" + + +namespace gong { +namespace physics { + +class Sphere +: public Object { + +public: + explicit Sphere(float radius); + + /// Get geometric description of shape in world coordinates + geometry::Sphere Shape() { + return geometry::Sphere{ state.pos, radius }; + } + +private: + void ReverseCollisionTest(Object &, std::vector &) override; + void ActualCollisionTest(Sphere &, std::vector &) override; + +private: + float radius; + +}; + +} +} + +#endif diff --git a/src/physics/State.hpp b/src/physics/State.hpp index 76ff16c..1a64310 100644 --- a/src/physics/State.hpp +++ b/src/physics/State.hpp @@ -29,6 +29,12 @@ struct State { float inertia; /// 1/inertia float inverse_inertia; + + /// calculate velocity at given point + /// (same coordinate system as used by pos) + glm::vec3 VelAt(const glm::vec3 &p) const noexcept { + return (lin * inverse_mass) + glm::cross((ang * inverse_inertia), p - pos); + } }; } diff --git a/src/physics/objects.cpp b/src/physics/objects.cpp new file mode 100644 index 0000000..e4075b3 --- /dev/null +++ b/src/physics/objects.cpp @@ -0,0 +1,28 @@ +#include "Contact.hpp" +#include "Sphere.hpp" + + +namespace gong { +namespace physics { + +Sphere::Sphere(float r) +: radius(r) { + bounds.min = glm::vec3(-r); + bounds.max = glm::vec3(r); +} + +void Sphere::ReverseCollisionTest(Object &other, std::vector &contacts) { + other.ActualCollisionTest(*this, contacts); +} + +void Sphere::ActualCollisionTest(Sphere &other, std::vector &contacts) { + float dist; + glm::vec3 norm; + if (Intersection(Shape(), other.Shape(), dist, norm)) { + glm::vec3 point(state.pos + ((dist - radius) * norm)); + contacts.emplace_back(point, norm, this, &other); + } +} + +} +} diff --git a/src/physics/sim.cpp b/src/physics/sim.cpp index 568d28c..68cc3e0 100644 --- a/src/physics/sim.cpp +++ b/src/physics/sim.cpp @@ -1,8 +1,11 @@ +#include "Contact.hpp" #include "Derivative.hpp" #include "Object.hpp" #include "Simulation.hpp" #include "State.hpp" +#include "../geometry/primitive.hpp" + namespace gong { namespace physics { @@ -29,12 +32,33 @@ Derivative::Derivative( } +void Object::TestCollision(Object &other, std::vector &contacts) { + if (!Intersection(bounds, other.bounds)) { + return; + } + // TODO: actual object shape intersection test + ReverseCollisionTest(other, contacts); +} + + void Simulation::Update(float dt) { // integrate state for (Object *o : objects) { Integrate(o->state, dt); } - // TODO: detect collisions + + // detect collisions + contacts.clear(); + if (objects.size() < 2) { + // we don't handle self-collision, so nothing to do + return; + } + for (std::size_t i = 0; i < objects.size() - 1; ++i) { + for (std::size_t j = i + 1; j < objects.size(); ++j) { + objects[i]->TestCollision(*objects[j], contacts); + } + } + // TODO: resolve collisions }