Skip to content

Commit

Permalink
feat(penetration_constraint): add restititution
Browse files Browse the repository at this point in the history
  • Loading branch information
fallenatlas committed Jul 3, 2024
1 parent 842c84a commit f0628f9
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 67 deletions.
2 changes: 2 additions & 0 deletions engine/src/physics/constraints/penetration_constraint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ CUBOS_REFLECT_IMPL(cubos::engine::PenetrationConstraint)
.withField("frictionMass", &PenetrationConstraint::frictionMass)
.withField("frictionImpulse1", &PenetrationConstraint::frictionImpulse1)
.withField("frictionImpulse2", &PenetrationConstraint::frictionImpulse2)
.withField("restitution", &PenetrationConstraint::restitution)
.withField("relativeVelocity", &PenetrationConstraint::relativeVelocity)

Check warning on line 23 in engine/src/physics/constraints/penetration_constraint.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/constraints/penetration_constraint.cpp#L17-L23

Added lines #L17 - L23 were not covered by tests
.withField("biasCoefficient", &PenetrationConstraint::biasCoefficient)
.withField("impulseCoefficient", &PenetrationConstraint::impulseCoefficient)
.withField("massCoefficient", &PenetrationConstraint::massCoefficient)
Expand Down
6 changes: 6 additions & 0 deletions engine/src/physics/constraints/penetration_constraint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,20 @@ namespace cubos::engine
float penetration; ///< Penetration depth of the collision.
glm::vec3 normal; ///< Normal of contact on the surface of the entity.

// separation
float normalMass; ///< Mass to use for normal impulse calculation.
float normalImpulse; ///< Accumulated impulse for separation.

// friction
float friction; ///< Friction of the constraint.
float frictionMass; ///< Mass to use for friction impulse calculation.
float frictionImpulse1; ///< Accumulated impulse for friction along the first tangent.
float frictionImpulse2; ///< Accumulated impulse for friction along the second tangent.

// restitution
float restitution; ///< Restitution coefficient of the constraint.
float relativeVelocity; ///< Relative velocity for computing restitution.

// soft constraint
float biasCoefficient;
float impulseCoefficient;
Expand Down
195 changes: 128 additions & 67 deletions engine/src/physics/solver/penetration_constraint/plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ using namespace cubos::engine;
CUBOS_DEFINE_TAG(cubos::engine::addPenetrationConstraintTag);
CUBOS_DEFINE_TAG(cubos::engine::penetrationConstraintSolveTag);
CUBOS_DEFINE_TAG(cubos::engine::penetrationConstraintSolveRelaxTag);
CUBOS_DEFINE_TAG(cubos::engine::penetrationConstraintRestitutionTag);
CUBOS_DEFINE_TAG(cubos::engine::penetrationConstraintCleanTag);

void solvePenetrationConstraint(Query<Entity, const Mass&, AccumulatedCorrection&, Velocity&, PenetrationConstraint&,
Expand All @@ -31,8 +32,7 @@ void solvePenetrationConstraint(Query<Entity, const Mass&, AccumulatedCorrection
glm::vec3 v1 = velocity1.vec;
glm::vec3 v2 = velocity2.vec;

Check warning on line 33 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L32-L33

Added lines #L32 - L33 were not covered by tests

// for each contact point, for now its for each entity
for (int i = 0; i < 2; i++)
// for each contact point in the future, since we have particles now we only need to do it once
{
float totalImpulse = constraint.normalImpulse;

Check warning on line 37 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L37

Added line #L37 was not covered by tests

Expand Down Expand Up @@ -86,14 +86,7 @@ void solvePenetrationConstraint(Query<Entity, const Mass&, AccumulatedCorrection
// Clamp the accumulated impulse
float newImpulse = glm::max(totalImpulse + impulse, 0.0F);
impulse = newImpulse - totalImpulse;
if (i == 0)
{
constraint.normalImpulse = newImpulse;
}
else
{
constraint.normalImpulse = newImpulse;
}
constraint.normalImpulse = newImpulse;

Check warning on line 89 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L89

Added line #L89 was not covered by tests

glm::vec3 p = constraint.normal * impulse;
if (ent1 == constraint.entity)
Expand All @@ -109,69 +102,64 @@ void solvePenetrationConstraint(Query<Entity, const Mass&, AccumulatedCorrection
}

// Friction
float normalImpulse = constraint.normalImpulse;
float frictionImpulse1 = constraint.frictionImpulse1;
float frictionImpulse2 = constraint.frictionImpulse2;

// Relative velocity at contact
glm::vec3 vr2;
glm::vec3 vr1;
if (ent1 == constraint.entity)
{
vr2 = velocity2.vec;
vr1 = velocity1.vec;
}
else
// for each contact point in the future, since we have particles now we only need to do it once
{
vr2 = velocity1.vec;
vr1 = velocity2.vec;
}

glm::vec3 vr = vr2 - vr1;
glm::vec3 tangent1 = vr - glm::dot(vr, constraint.normal) * constraint.normal;
glm::vec3 tangent2;
float tangentLenSq = glm::length2(tangent1);
if (tangentLenSq > 1e-3)
{
tangent1 = glm::normalize(tangent1);
tangent2 = glm::cross(constraint.normal, tangent1);
float normalImpulse = constraint.normalImpulse;
float frictionImpulse1 = constraint.frictionImpulse1;
float frictionImpulse2 = constraint.frictionImpulse2;

Check warning on line 109 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L107-L109

Added lines #L107 - L109 were not covered by tests

float vn1 = glm::dot(vr, tangent1);
float vn2 = glm::dot(vr, tangent2);
if (vn1 < 1e-3)
// Relative velocity at contact
glm::vec3 vr2;
glm::vec3 vr1;
if (ent1 == constraint.entity)

Check warning on line 114 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L114

Added line #L114 was not covered by tests
{
vn1 = 0.0F;
vr2 = velocity2.vec;
vr1 = velocity1.vec;

Check warning on line 117 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L116-L117

Added lines #L116 - L117 were not covered by tests
}
if (vn2 < 1e-3)
else
{
vn2 = 0.0F;
vr2 = velocity1.vec;
vr1 = velocity2.vec;

Check warning on line 122 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L121-L122

Added lines #L121 - L122 were not covered by tests
}

// Compute friction force
float impulse1 = -constraint.frictionMass * vn1;
float impulse2 = -constraint.frictionMass * vn2;

// Clamp the accumulated force
float maxFriction = constraint.friction * normalImpulse;
float newImpulse1 = glm::clamp(frictionImpulse1 + impulse1, -maxFriction, maxFriction);
float newImpulse2 = glm::clamp(frictionImpulse2 + impulse2, -maxFriction, maxFriction);
impulse1 = newImpulse1 - frictionImpulse1;
impulse2 = newImpulse2 - frictionImpulse2;
constraint.frictionImpulse1 = newImpulse1;
constraint.frictionImpulse2 = newImpulse2;

// Apply contact impulse
glm::vec3 p1 = tangent1 * impulse1;
glm::vec3 p2 = tangent2 * impulse2;
if (ent1 == constraint.entity)
glm::vec3 vr = vr2 - vr1;
glm::vec3 tangent1 = vr - glm::dot(vr, constraint.normal) * constraint.normal;

Check warning on line 126 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L125-L126

Added lines #L125 - L126 were not covered by tests
glm::vec3 tangent2;
float tangentLenSq = glm::length2(tangent1);
if (tangentLenSq > 1e-6)

Check warning on line 129 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L128-L129

Added lines #L128 - L129 were not covered by tests
{
v1 -= p1 * mass1.inverseMass + p2 * mass1.inverseMass;
v2 += p1 * mass2.inverseMass + p2 * mass2.inverseMass;
}
else
{
v1 += p1 * mass1.inverseMass + p2 * mass1.inverseMass;
v2 -= p1 * mass2.inverseMass + p2 * mass2.inverseMass;
tangent1 = glm::normalize(tangent1);
tangent2 = glm::cross(constraint.normal, tangent1);

Check warning on line 132 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L131-L132

Added lines #L131 - L132 were not covered by tests

float vn1 = glm::dot(vr, tangent1);
float vn2 = glm::dot(vr, tangent2);

Check warning on line 135 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L134-L135

Added lines #L134 - L135 were not covered by tests

// Compute friction force
float impulse1 = -constraint.frictionMass * vn1;
float impulse2 = -constraint.frictionMass * vn2;

Check warning on line 139 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L138-L139

Added lines #L138 - L139 were not covered by tests

// Clamp the accumulated force
float maxFriction = constraint.friction * normalImpulse;
float newImpulse1 = glm::clamp(frictionImpulse1 + impulse1, -maxFriction, maxFriction);
float newImpulse2 = glm::clamp(frictionImpulse2 + impulse2, -maxFriction, maxFriction);
impulse1 = newImpulse1 - frictionImpulse1;
impulse2 = newImpulse2 - frictionImpulse2;
constraint.frictionImpulse1 = newImpulse1;
constraint.frictionImpulse2 = newImpulse2;

Check warning on line 148 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L142-L148

Added lines #L142 - L148 were not covered by tests

// Apply contact impulse
glm::vec3 p1 = tangent1 * impulse1;
glm::vec3 p2 = tangent2 * impulse2;
if (ent1 == constraint.entity)

Check warning on line 153 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L151-L153

Added lines #L151 - L153 were not covered by tests
{
v1 -= p1 * mass1.inverseMass + p2 * mass1.inverseMass;
v2 += p1 * mass2.inverseMass + p2 * mass2.inverseMass;

Check warning on line 156 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L155-L156

Added lines #L155 - L156 were not covered by tests
}
else
{
v1 += p1 * mass1.inverseMass + p2 * mass1.inverseMass;
v2 -= p1 * mass2.inverseMass + p2 * mass2.inverseMass;

Check warning on line 161 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L160-L161

Added lines #L160 - L161 were not covered by tests
}
}
}

Expand All @@ -193,6 +181,7 @@ void cubos::engine::penetrationConstraintPlugin(Cubos& cubos)
cubos.tag(addPenetrationConstraintTag);
cubos.tag(penetrationConstraintSolveTag);
cubos.tag(penetrationConstraintSolveRelaxTag);
cubos.tag(penetrationConstraintRestitutionTag);

Check warning on line 184 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L184

Added line #L184 was not covered by tests
cubos.tag(penetrationConstraintCleanTag);

cubos.system("solve contacts bias")
Expand All @@ -213,15 +202,68 @@ void cubos::engine::penetrationConstraintPlugin(Cubos& cubos)
const FixedDeltaTime& fixedDeltaTime,
const Substeps& substeps) { solvePenetrationConstraint(query, fixedDeltaTime, substeps, false); });

cubos.system("add restitution")
.tagged(penetrationConstraintRestitutionTag)
.after(penetrationConstraintSolveRelaxTag)
.before(physicsFinalizePositionTag)
.tagged(fixedStepTag)
.call([](Query<Entity, const Mass&, AccumulatedCorrection&, Velocity&, PenetrationConstraint&, Entity,

Check warning on line 210 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L205-L210

Added lines #L205 - L210 were not covered by tests
const Mass&, AccumulatedCorrection&, Velocity&>
query) {
for (auto [ent1, mass1, correction1, velocity1, constraint, ent2, mass2, correction2, velocity2] : query)

Check warning on line 213 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L213

Added line #L213 was not covered by tests
{
if (constraint.restitution == 0.0F)

Check warning on line 215 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L215

Added line #L215 was not covered by tests
{
continue;

Check warning on line 217 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L217

Added line #L217 was not covered by tests
}

if (constraint.relativeVelocity > -0.1F || constraint.normalImpulse == 0.0F)

Check warning on line 220 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L220

Added line #L220 was not covered by tests
{
continue;

Check warning on line 222 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L222

Added line #L222 was not covered by tests
}

// Relative normal velocity at contact
glm::vec3 vr2;
glm::vec3 vr1;
if (ent1 == constraint.entity)

Check warning on line 228 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L228

Added line #L228 was not covered by tests
{
vr2 = velocity2.vec;
vr1 = velocity1.vec;

Check warning on line 231 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L230-L231

Added lines #L230 - L231 were not covered by tests
}
else
{
vr2 = velocity1.vec;
vr1 = velocity2.vec;

Check warning on line 236 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L235-L236

Added lines #L235 - L236 were not covered by tests
}

float vn = glm::dot(vr2 - vr1, constraint.normal);

Check warning on line 239 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L239

Added line #L239 was not covered by tests

// compute normal impulse
float impulse = -constraint.normalMass * (vn + constraint.restitution * constraint.relativeVelocity);

Check warning on line 242 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L242

Added line #L242 was not covered by tests

// Clamp the accumulated impulse
float newImpulse = glm::max(constraint.normalImpulse + impulse, 0.0F);
impulse = newImpulse - constraint.normalImpulse;
constraint.normalImpulse = newImpulse;

Check warning on line 247 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L245-L247

Added lines #L245 - L247 were not covered by tests

// Apply impulse
glm::vec3 p = constraint.normal * impulse;
velocity1.vec = velocity1.vec - p * mass1.inverseMass;
velocity2.vec = velocity2.vec + p * mass2.inverseMass;

Check warning on line 252 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L250-L252

Added lines #L250 - L252 were not covered by tests
}
});

Check warning on line 254 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L254

Added line #L254 was not covered by tests

cubos.system("add penetration constraint pair")
.tagged(addPenetrationConstraintTag)
.tagged(physicsPrepareSolveTag)
.call([](Commands cmds, Query<Entity, const Mass&, const CollidingWith&, Entity, const Mass&> query,
.call([](Commands cmds,

Check warning on line 259 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L259

Added line #L259 was not covered by tests
Query<Entity, const Mass&, const Velocity&, const CollidingWith&, Entity, const Mass&, const Velocity&>
query,
const FixedDeltaTime& fixedDeltaTime, const Substeps& substeps) {
float subDeltaTime = fixedDeltaTime.value / (float)substeps.value;
float contactHertz = glm::min(30.0F, 0.25F * (1.0F / subDeltaTime));

for (auto [ent1, mass1, collidingWith, ent2, mass2] : query)
for (auto [ent1, mass1, velocity1, collidingWith, ent2, mass2, velocity2] : query)

Check warning on line 266 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L266

Added line #L266 was not covered by tests
{
float kNormal = mass1.inverseMass + mass2.inverseMass;
float normalMass = kNormal > 0.0F ? 1.0F / kNormal : 0.0F;
Expand All @@ -233,6 +275,23 @@ void cubos::engine::penetrationConstraintPlugin(Cubos& cubos)
// determine friction (set to predefined value for now)
float friction = 0.01F;

Check warning on line 276 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L276

Added line #L276 was not covered by tests

// determine restitution (set to predefined value for now)
float restitution = 1.0F;

Check warning on line 279 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L279

Added line #L279 was not covered by tests
glm::vec3 vr2;
glm::vec3 vr1;
if (ent1 == collidingWith.entity)

Check warning on line 282 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L282

Added line #L282 was not covered by tests
{
vr2 = velocity2.vec;
vr1 = velocity1.vec;

Check warning on line 285 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L284-L285

Added lines #L284 - L285 were not covered by tests
}
else
{
vr2 = velocity1.vec;
vr1 = velocity2.vec;

Check warning on line 290 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L289-L290

Added lines #L289 - L290 were not covered by tests
}

float relativeVelocity = glm::dot(vr2 - vr1, collidingWith.normal);

Check warning on line 293 in engine/src/physics/solver/penetration_constraint/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver/penetration_constraint/plugin.cpp#L293

Added line #L293 was not covered by tests

// Soft contact
const float zeta = 10.0F;
float omega = 2.0F * glm::pi<float>() * contactHertz;
Expand All @@ -254,6 +313,8 @@ void cubos::engine::penetrationConstraintPlugin(Cubos& cubos)
.frictionMass = frictionMass,
.frictionImpulse1 = 0.0F,
.frictionImpulse2 = 0.0F,
.restitution = restitution,
.relativeVelocity = relativeVelocity,
.biasCoefficient = biasCoefficient,
.impulseCoefficient = impulseCoefficient,
.massCoefficient = massCoefficient});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace cubos::engine
extern Tag addPenetrationConstraintTag;
extern Tag penetrationConstraintCleanTag;
extern Tag penetrationConstraintSolveTag;
extern Tag penetrationConstraintRestitutionTag;
extern Tag penetrationConstraintSolveRelaxTag;

/// @brief Plugin entry function.
Expand Down

0 comments on commit f0628f9

Please sign in to comment.