hx3d  1
2D/3D Simple Game Framework
manifold.cpp
1 #include "hx3d/physics/2d/manifold.hpp"
2 
3 #include "hx3d/physics/2d/collisions.hpp"
4 
5 #include "hx3d/math/vector_utils.hpp"
6 
7 namespace hx3d {
8 namespace physics2d {
9 
10 Manifold::Manifold(const Ptr<Collider>& a, const Ptr<Collider>& b): a(a), b(b) {
11  penetration = 0.f;
12  normal = {0, 0};
13  mixedRestitution = 0.f;
15  mixedStaticFriction = 0.f;
16  disabled = false;
17 }
18 
20  bool value = false;
21 
22  if (a->shape == Collider::Shape::Circle && b->shape == Collider::Shape::Circle)
23  value = checkCollisions(*this, std::dynamic_pointer_cast<colliders::Circle>(a), std::dynamic_pointer_cast<colliders::Circle>(b));
24  else if (a->shape == Collider::Shape::Circle && b->shape == Collider::Shape::Polygon)
25  value = checkCollisions(*this, std::dynamic_pointer_cast<colliders::Circle>(a), std::dynamic_pointer_cast<colliders::Polygon>(b));
26  else if (a->shape == Collider::Shape::Polygon && b->shape == Collider::Shape::Circle)
27  value = checkCollisions(*this, std::dynamic_pointer_cast<colliders::Polygon>(a), std::dynamic_pointer_cast<colliders::Circle>(b));
28  else if (a->shape == Collider::Shape::Polygon && b->shape == Collider::Shape::Polygon)
29  value = checkCollisions(*this, std::dynamic_pointer_cast<colliders::Polygon>(a), std::dynamic_pointer_cast<colliders::Polygon>(b));
30 
31  return value;
32 }
33 
35  if (disabled) return;
36 
37  mixedRestitution = (a->material.restitution + b->material.restitution) / 2;
38  mixedStaticFriction = std::sqrt(a->material.staticFriction * b->material.staticFriction);
39  mixedDynamicFriction = std::sqrt(a->material.dynamicFriction * b->material.dynamicFriction);
40 
41  for (unsigned int i = 0; i < contacts.size(); ++i) {
42  glm::vec2 ra = contacts[i] - a->position;
43  glm::vec2 rb = contacts[i] - b->position;
44 
45  glm::vec2 rv = b->velocity + math::cross(b->angularVelocity, rb) - a->velocity - math::cross(a->angularVelocity, ra);
46 
47  if (math::squareLength(rv) < (0.025 + math::kEpsilon)) {
48  mixedRestitution = 0;
49  }
50  }
51 }
52 
54  if (disabled) return;
55 
56  if (math::epsEqual(a->massData.invMass + b->massData.invMass, 0.f)) {
58  return;
59  }
60 
61  for (unsigned int i = 0; i < contacts.size(); ++i) {
62  glm::vec2 ra = contacts[i] - a->position;
63  glm::vec2 rb = contacts[i] - b->position;
64 
65  glm::vec2 rv = b->velocity + math::cross(b->angularVelocity, rb) - a->velocity - math::cross(a->angularVelocity, ra);
66 
67  float contactVelocity = glm::dot(rv, normal);
68  if (contactVelocity > 0)
69  return;
70 
71  float raCross = math::cross(ra, normal);
72  float rbCross = math::cross(rb, normal);
73 
74  float invMassSum = a->massData.invMass + b->massData.invMass + (raCross * raCross) * a->massData.invInertia + (rbCross * rbCross) * b->massData.invInertia;
75 
76  float j = -(1.f + mixedRestitution) * contactVelocity;
77  j /= invMassSum;
78  j /= (float)contacts.size();
79 
80  glm::vec2 impulse = normal * j;
81  a->applyImpulse(-impulse, ra);
82  b->applyImpulse(impulse, rb);
83 
84  rv = b->velocity + math::cross(b->angularVelocity, rb) - a->velocity - math::cross(a->angularVelocity, ra);
85 
86  glm::vec2 nRv = rv - (normal * glm::dot(rv, normal));
87  glm::vec2 t = math::normalize(nRv);
88 
89  float jt = -glm::dot(rv, t);
90  jt /= invMassSum;
91  jt /= (float)contacts.size();
92 
93  if (math::epsEqual(jt, 0.f))
94  return;
95 
96  glm::vec2 tangentImpulse;
97  if (std::abs(jt) < j * mixedStaticFriction)
98  tangentImpulse = t * jt;
99  else
100  tangentImpulse = t * -j * mixedDynamicFriction;
101 
102  a->applyImpulse(-tangentImpulse, ra);
103  b->applyImpulse(tangentImpulse, rb);
104  }
105 }
106 
108  if (disabled) return;
109 
110  const float kSlop = 0.05f;
111  const float percent = 0.4f;
112 
113  glm::vec2 correction = (std::max(penetration - kSlop, 0.f) / (a->massData.invMass + b->massData.invMass)) * normal * percent;
114 
115  a->position -= correction * a->massData.invMass;
116  b->position += correction * b->massData.invMass;
117 }
118 
120  if (disabled) return;
121 
122  a->velocity = {0, 0};
123  b->velocity = {0, 0};
124 }
125 
126 bool operator<(const Manifold& m1, const Manifold& m2) {
127  return m1.penetration < m2.penetration;
128 }
129 
130 } /* physics2d */
131 } /* hx3d */
bool epsEqual(T v1, T v2)
Test values equality with epsilon.
Manifold(const Ptr< Collider > &a, const Ptr< Collider > &b)
Create a manifold.
Definition: manifold.cpp:10
std::vector< glm::vec2 > contacts
Contact points.
Definition: manifold.hpp:49
hx3d framework namespace
Definition: audio.hpp:26
float squareLength(glm::vec2 vec)
Compute the square length of a 2D vector.
Ptr< Collider > b
Second collider.
Definition: manifold.hpp:38
friend bool operator<(const Manifold &m1, const Manifold &m2)
Compare two manifolds using their penetration coefficients.
Definition: manifold.cpp:126
bool disabled
Is the contact disabled ?
Definition: manifold.hpp:44
void initialize()
Initialize the manifold.
Definition: manifold.cpp:34
float mixedStaticFriction
Mixed static friction (sf)
Definition: manifold.hpp:56
float penetration
Penetration coefficient.
Definition: manifold.hpp:41
bool solve()
Solve the contact.
Definition: manifold.cpp:19
float mixedDynamicFriction
Mixed dynamic friction (df)
Definition: manifold.hpp:54
Contact manifold definition.
Definition: manifold.hpp:33
void positionalCorrection()
Do positional correction on the colliders.
Definition: manifold.cpp:107
const float kEpsilon
Float epsilon.
Definition: constants.hpp:36
void applyImpulse()
Apply impulses to the colliders.
Definition: manifold.cpp:53
bool checkCollisions(Manifold &m, Ptr< colliders::Circle > a, Ptr< colliders::Circle > b)
Collision test between two circles.
Definition: collisions.cpp:169
void infiniteMassCorrection()
Do infinite mass correction on the colliders.
Definition: manifold.cpp:119
Ptr< Collider > a
First collider.
Definition: manifold.hpp:36
glm::vec2 normalize(glm::vec2 vec)
Normalize a 2D vector.
float mixedRestitution
Mixed restitution (e)
Definition: manifold.hpp:52
glm::vec2 cross(glm::vec2 vec, float v)
Calculate the cross product vector between a 2D vector and a scalar.
std::shared_ptr< T > Ptr
Quick-typing shared ptr.
Definition: ptr.hpp:34
glm::vec2 normal
Normal vector.
Definition: manifold.hpp:47