Hi, I'm trying to implement a PGS solver for collision response, but I'm currently stuck.
How the problem manifests is for example a box resting on the ground, if the box is given a small rotation then it might spin out of control after a while.
Also boxes in a stack are not stable but slide apart very quickly. (without PGS my box stacks are decently stable)
Much grateful for any advice! 🙂
int maxIterations = 10;
for (int i = 0; i < maxIterations; i++) {
bool converged = true;
for (int j = 0; j < contact.counter; j++) {
ContactPoint& contactPoint = contact.points[j];
// Calculate relative velocity
glm::vec3 rA = contactPoint.coordinate - objA.position;
glm::vec3 rB = contactPoint.coordinate - objB.position;
glm::vec3 relativeVelocity = (objB.linearVelocity + glm::cross(objB.angularVelocity, rB)) - (objA.linearVelocity + glm::cross(objA.angularVelocity, rA));
// Continue if objects already are moving apart
if (glm::dot(relativeVelocity, contact.normal) > 0)
continue;
// Calculate J
float e = std::min(objA.restitution, objB.restitution);
float J = -(1.0f + e) * glm::dot(relativeVelocity, contact.normal);
J /= objA.invMass + objB.invMass +
glm::dot(glm::cross(rA, contact.normal), objA.inverseInertia * glm::cross(rA, contact.normal)) +
glm::dot(glm::cross(rB, contact.normal), objB.inverseInertia * glm::cross(rB, contact.normal));
// Clamp
float temp = contactPoint.accumulatedImpulse;
contactPoint.accumulatedImpulse = glm::max(temp + J, 0.0f);
float deltaImpulse = contactPoint.accumulatedImpulse - temp;
// Add normal
glm::vec3 deltaNormalImpulse = deltaImpulse * contact.normal;
// Apply impulse
if (glm::length(deltaNormalImpulse) > 1e-6f) {
objA.linearVelocity -= deltaNormalImpulse * objA.invMass;
objA.angularVelocity -= objA.inverseInertia * glm::cross(rA, deltaNormalImpulse);
objB.linearVelocity += deltaNormalImpulse * objB.invMass;
objB.angularVelocity += objB.inverseInertia * glm::cross(rB, deltaNormalImpulse);
converged = false;
}
}
if (converged)
break;
}
// position correction
if (objA.isStatic)
objB.position += (collisionNormal * depth);
else if (objB.isStatic)
objA.position += (-collisionNormal * depth);
else
{
float totalInverseMass = objA.invMass + objB.invMass;
float displacementA = (objA.invMass / totalInverseMass) * depth * strength;
float displacementB = (objB.invMass / totalInverseMass) * depth * strength;
objA.position -= collisionNormal * displacementA;
objB.position += collisionNormal * displacementB;
}