-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathManifold.cpp
More file actions
120 lines (97 loc) · 3.1 KB
/
Manifold.cpp
File metadata and controls
120 lines (97 loc) · 3.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include "Manifold.h"
#include <cmath>
#include <algorithm>
#include "PolygonComponent.h"
void Manifold::Solve(void)
{
Dispatch[A->shape->GetType()][B->shape->GetType()](this, A, B);
}
void Manifold::Initialize(void)
{
// Calculate average restitution
e = std::min(A->restitution, B->restitution);
// Calculate static and dynamic friction
sf = std::sqrt(A->staticFriction * B->staticFriction);
df = std::sqrt(A->dynamicFriction * B->dynamicFriction);
for (unsigned int i = 0; i < contact_count; ++i)
{
// Calculate radii from COM to contact
sf::Vector2f ra = contacts[i] - A->position;
sf::Vector2f rb = contacts[i] - B->position;
sf::Vector2f rv = B->velocity + Cross(B->angularVelocity, rb) -
A->velocity - Cross(A->angularVelocity, ra);
// Determine if we should perform a resting collision or not
// The idea is if the only thing moving this object is gravity,
// then the collision should be performed without any restitution
if (LenSqr(rv) < LenSqr(dt * gravity) + EPSILON)
e = 0.0f;
}
}
void Manifold::ApplyImpulse(void)
{
// Early out and positional correct if both objects have infinite mass
if (Equal(A->im + B->im, 0))
{
InfiniteMassCorrection();
return;
}
for (unsigned int i = 0; i < contact_count; ++i)
{
// Calculate radii from COM to contact
sf::Vector2f ra = contacts[i] - A->position;
sf::Vector2f rb = contacts[i] - B->position;
// Relative velocity
sf::Vector2f rv = B->velocity + Cross(B->angularVelocity, rb) -
A->velocity - Cross(A->angularVelocity, ra);
// Relative velocity along the normal
float contactVel = Dot(rv, normal);
// Do not resolve if velocities are separating
if (contactVel > 0)
return;
float raCrossN = Cross(ra, normal);
float rbCrossN = Cross(rb, normal);
float invMassSum = A->im + B->im + Sqr(raCrossN) * A->iI + Sqr(rbCrossN) * B->iI;
// Calculate impulse scalar
float j = -(1.0f + e) * contactVel;
j /= invMassSum;
j /= (float)contact_count;
// Apply impulse
sf::Vector2f impulse = normal * j;
A->ApplyImpulse(-impulse, ra);
B->ApplyImpulse(impulse, rb);
// Friction impulse
rv = B->velocity + Cross(B->angularVelocity, rb) -
A->velocity - Cross(A->angularVelocity, ra);
sf::Vector2f t = rv - (normal * Dot(rv, normal));
Normalize(&t);
// j tangent magnitude
float jt = -Dot(rv, t);
jt /= invMassSum;
jt /= (float)contact_count;
// Don't apply tiny friction impulses
if (Equal(jt, 0.0f))
return;
// Coulumb's law
sf::Vector2f tangentImpulse;
if (std::abs(jt) < j * sf)
tangentImpulse = t * jt;
else
tangentImpulse = t * -j * df;
// Apply friction impulse
A->ApplyImpulse(-tangentImpulse, ra);
B->ApplyImpulse(tangentImpulse, rb);
}
}
void Manifold::PositionalCorrection(void)
{
const float k_slop = 0.05f; // Penetration allowance
const float percent = 0.4f; // Penetration percentage to correct
sf::Vector2f correction = (std::max(penetration - k_slop, 0.0f) / (A->im + B->im)) * normal * percent;
A->position -= correction * A->im;
B->position += correction * B->im;
}
void Manifold::InfiniteMassCorrection(void)
{
A->velocity.Set(0, 0);
B->velocity.Set(0, 0);
}