Clean up the code and change the warmstart() method

This commit is contained in:
Daniel Chappuis 2013-01-17 23:13:18 +01:00
parent 9cf672c51c
commit 2d0da2cc1c
2 changed files with 127 additions and 281 deletions

View File

@ -35,7 +35,7 @@ using namespace std;
// Constructor // Constructor
ConstraintSolver::ConstraintSolver(DynamicsWorld* world) ConstraintSolver::ConstraintSolver(DynamicsWorld* world)
:world(world), nbConstraints(0), mNbIterations(10), mContactConstraints(0), :world(world), nbConstraints(0), mNbIterations(10), mContactConstraints(0),
mLinearVelocities(0), mAngularVelocities(0) { mLinearVelocities(0), mAngularVelocities(0) {
} }
@ -44,7 +44,7 @@ ConstraintSolver::~ConstraintSolver() {
} }
// Initialize the constraint solver before each solving // Initialize the constraint solver
void ConstraintSolver::initialize() { void ConstraintSolver::initialize() {
nbConstraints = 0; nbConstraints = 0;
@ -120,51 +120,31 @@ void ConstraintSolver::initialize() {
assert(mMapBodyToIndex.size() == nbBodies); assert(mMapBodyToIndex.size() == nbBodies);
} }
// Initialize bodies velocities // Initialize the constrained bodies
void ConstraintSolver::initializeBodies() { void ConstraintSolver::initializeBodies() {
// For each current body that is implied in some constraint // For each current body that is implied in some constraint
RigidBody* rigidBody; RigidBody* rigidBody;
RigidBody* body; for (set<RigidBody*>::iterator it = mConstraintBodies.begin(); it != mConstraintBodies.end(); ++it) {
uint b=0;
for (set<RigidBody*>::iterator it = mConstraintBodies.begin(); it != mConstraintBodies.end(); ++it, b++) {
rigidBody = *it; rigidBody = *it;
uint bodyNumber = mMapBodyToIndex[rigidBody]; uint bodyNumber = mMapBodyToIndex[rigidBody];
// TODO : Use polymorphism and remove this downcasting // TODO : Use polymorphism and remove this downcasting
assert(rigidBody); assert(rigidBody);
// Compute the vector V1 with initial velocities values
int bodyIndexArray = 6 * bodyNumber;
mLinearVelocities[bodyNumber] = rigidBody->getLinearVelocity() + mTimeStep * rigidBody->getMassInverse() * rigidBody->getExternalForce(); mLinearVelocities[bodyNumber] = rigidBody->getLinearVelocity() + mTimeStep * rigidBody->getMassInverse() * rigidBody->getExternalForce();
mAngularVelocities[bodyNumber] = rigidBody->getAngularVelocity() + mTimeStep * rigidBody->getInertiaTensorInverseWorld() * rigidBody->getExternalTorque(); mAngularVelocities[bodyNumber] = rigidBody->getAngularVelocity() + mTimeStep * rigidBody->getInertiaTensorInverseWorld() * rigidBody->getExternalTorque();
// Initialize the mass and inertia tensor matrices
Minv_sp_inertia[bodyNumber].setAllValues(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
Minv_sp_mass_diag[bodyNumber] = 0.0;
// If the motion of the rigid body is enabled
if (rigidBody->getIsMotionEnabled()) {
Minv_sp_inertia[bodyNumber] = rigidBody->getInertiaTensorInverseWorld();
Minv_sp_mass_diag[bodyNumber] = rigidBody->getMassInverse();
}
} }
} }
// Fill in all the matrices needed to solve the LCP problem // Initialize the contact constraints before solving the system
// Notice that all the active constraints should have been evaluated first void ConstraintSolver::initializeContactConstraints() {
void ConstraintSolver::initializeContactConstraints(decimal dt) {
decimal oneOverDT = 1.0 / dt;
// For each contact constraint // For each contact constraint
for (uint c=0; c<mNbContactConstraints; c++) { for (uint c=0; c<mNbContactConstraints; c++) {
ContactConstraint& constraint = mContactConstraints[c]; ContactConstraint& constraint = mContactConstraints[c];
uint indexBody1 = constraint.indexBody1;
uint indexBody2 = constraint.indexBody2;
Matrix3x3& I1 = constraint.inverseInertiaTensorBody1; Matrix3x3& I1 = constraint.inverseInertiaTensorBody1;
Matrix3x3& I2 = constraint.inverseInertiaTensorBody2; Matrix3x3& I2 = constraint.inverseInertiaTensorBody2;
@ -221,17 +201,6 @@ void ConstraintSolver::initializeContactConstraints(decimal dt) {
contact.restitutionBias = constraint.restitutionFactor * deltaVDotN; contact.restitutionBias = constraint.restitutionFactor * deltaVDotN;
} }
// Fill in the J_sp matrix
realContact->computeJacobianPenetration(contact.J_spBody1Penetration, contact.J_spBody2Penetration);
realContact->computeJacobianFriction1(contact.J_spBody1Friction1, contact.J_spBody2Friction1);
realContact->computeJacobianFriction2(contact.J_spBody1Friction2, contact.J_spBody2Friction2);
// Fill in the body mapping matrix
//for(int i=0; i<realContact->getNbConstraints(); i++) {
// bodyMapping[noConstraint+i][0] = constraint->getBody1();
// bodyMapping[noConstraint+i][1] = constraint->getBody2();
//}
// Fill in the limit vectors for the constraint // Fill in the limit vectors for the constraint
realContact->computeLowerBoundPenetration(contact.lowerBoundPenetration); realContact->computeLowerBoundPenetration(contact.lowerBoundPenetration);
realContact->computeLowerBoundFriction1(contact.lowerBoundFriction1); realContact->computeLowerBoundFriction1(contact.lowerBoundFriction1);
@ -240,147 +209,74 @@ void ConstraintSolver::initializeContactConstraints(decimal dt) {
realContact->computeUpperBoundFriction1(contact.upperBoundFriction1); realContact->computeUpperBoundFriction1(contact.upperBoundFriction1);
realContact->computeUpperBoundFriction2(contact.upperBoundFriction2); realContact->computeUpperBoundFriction2(contact.upperBoundFriction2);
// Fill in the error vector
realContact->computeErrorPenetration(contact.errorPenetration);
// Get the cached lambda values of the constraint // Get the cached lambda values of the constraint
contact.penetrationImpulse = realContact->getCachedLambda(0); contact.penetrationImpulse = realContact->getCachedLambda(0);
contact.friction1Impulse = realContact->getCachedLambda(1); contact.friction1Impulse = realContact->getCachedLambda(1);
contact.friction2Impulse = realContact->getCachedLambda(2); contact.friction2Impulse = realContact->getCachedLambda(2);
//for (int i=0; i<constraint->getNbConstraints(); i++) {
// lambdaInit[noConstraint + i] = constraint->getCachedLambda(i);
// }
contact.errorPenetration = 0.0;
decimal slop = 0.005;
if (realContact->getPenetrationDepth() > slop) {
contact.errorPenetration -= 0.2 * oneOverDT * std::max(double(realContact->getPenetrationDepth() - slop), 0.0);
}
// ---------- Penetration ---------- //
// b = errorValues * oneOverDT;
contact.b_Penetration = contact.errorPenetration;
} }
} }
} }
// Compute the matrix B_sp // Warm start the solver
void ConstraintSolver::computeMatrixB_sp() { // For each constraint, we apply the previous impulse (from the previous step)
uint indexConstraintArray, indexBody1, indexBody2; // at the beginning. With this technique, we will converge faster towards
// the solution of the linear system
void ConstraintSolver::warmStart() {
// For each constraint // For each constraint
for (uint m = 0; m<mNbContactConstraints; m++) { for (uint c=0; c<mNbContactConstraints; c++) {
ContactConstraint& constraint = mContactConstraints[m]; ContactConstraint& constraint = mContactConstraints[c];
for (uint c=0; c<constraint.nbContacts; c++) { for (uint i=0; i<constraint.nbContacts; i++) {
ContactPointConstraint& contact = constraint.contacts[c]; ContactPointConstraint& contact = constraint.contacts[i];
// ---------- Penetration ---------- // // --------- Penetration --------- //
indexBody1 = constraint.indexBody1; // Compute the impulse P=J^T * lambda
indexBody2 = constraint.indexBody2; const Vector3 linearImpulseBody1 = -contact.normal * contact.penetrationImpulse;
contact.B_spBody1Penetration[0] = Minv_sp_mass_diag[indexBody1] * contact.J_spBody1Penetration[0]; const Vector3 angularImpulseBody1 = -contact.r1CrossN * contact.penetrationImpulse;
contact.B_spBody1Penetration[1] = Minv_sp_mass_diag[indexBody1] * contact.J_spBody1Penetration[1]; const Vector3 linearImpulseBody2 = contact.normal * contact.penetrationImpulse;
contact.B_spBody1Penetration[2] = Minv_sp_mass_diag[indexBody1] * contact.J_spBody1Penetration[2]; const Vector3 angularImpulseBody2 = contact.r2CrossN * contact.penetrationImpulse;
contact.B_spBody2Penetration[0] = Minv_sp_mass_diag[indexBody2] * contact.J_spBody2Penetration[0]; const Impulse impulsePenetration(linearImpulseBody1, angularImpulseBody1,
contact.B_spBody2Penetration[1] = Minv_sp_mass_diag[indexBody2] * contact.J_spBody2Penetration[1]; linearImpulseBody2, angularImpulseBody2);
contact.B_spBody2Penetration[2] = Minv_sp_mass_diag[indexBody2] * contact.J_spBody2Penetration[2];
for (uint i=0; i<3; i++) { // Apply the impulse to the bodies of the constraint
contact.B_spBody1Penetration[3 + i] = 0.0; applyImpulse(impulsePenetration, constraint);
contact.B_spBody2Penetration[3 + i] = 0.0;
for (uint j=0; j<3; j++) {
contact.B_spBody1Penetration[3 + i] += Minv_sp_inertia[indexBody1].getValue(i, j) * contact.J_spBody1Penetration[3 + j];
contact.B_spBody2Penetration[3 + i] += Minv_sp_inertia[indexBody2].getValue(i, j) * contact.J_spBody2Penetration[3 + j];
}
}
// ---------- Friction 1 ---------- // // --------- Friction 1 --------- //
Matrix3x3& I1 = constraint.inverseInertiaTensorBody1; // Compute the impulse P=J^T * lambda
Matrix3x3& I2 = constraint.inverseInertiaTensorBody2; Vector3 linearImpulseBody1Friction1 = -contact.frictionVector1 * contact.friction1Impulse;
Vector3 angularImpulseBody1Friction1 = -contact.r1CrossT1 * contact.friction1Impulse;
Vector3 linearImpulseBody2Friction1 = contact.frictionVector1 * contact.friction1Impulse;
Vector3 angularImpulseBody2Friction1 = contact.r2CrossT1 * contact.friction1Impulse;
Impulse impulseFriction1(linearImpulseBody1Friction1, angularImpulseBody1Friction1,
linearImpulseBody2Friction1, angularImpulseBody2Friction1);
Vector3 JspLinBody1 = Vector3(0, 0, 0); // Apply the impulses to the bodies of the constraint
Vector3 JspAngBody1 = Vector3(0, 0, 0); applyImpulse(impulseFriction1, constraint);
Vector3 JspLinBody2 = Vector3(0, 0, 0);
Vector3 JspAngBody2 = Vector3(0, 0, 0);
if (constraint.isBody1Moving) { // --------- Friction 2 --------- //
JspLinBody1 += -constraint.massInverseBody1 * contact.frictionVector1;
JspAngBody1 += I1 * (-contact.r1CrossT1);
}
if (constraint.isBody2Moving) {
JspLinBody2 += constraint.massInverseBody2 * contact.frictionVector1;
JspAngBody2 += I1 * (contact.r2CrossT1);
}
/* // Compute the impulse P=J^T * lambda
std::cout << "------ New Version ----" << std::endl; Vector3 linearImpulseBody1Friction2 = -contact.frictionVector2 * contact.friction2Impulse;
std::cout << "JspLinBody1 : " << JspLinBody1.getX() << ", " << JspLinBody1.getY() << ", " << JspLinBody1.getZ() << std::endl; Vector3 angularImpulseBody1Friction2 = -contact.r1CrossT2 * contact.friction2Impulse;
std::cout << "JspAngBody1 : " << JspAngBody1.getX() << ", " << JspAngBody1.getY() << ", " << JspAngBody1.getZ() << std::endl; Vector3 linearImpulseBody2Friction2 = contact.frictionVector2 * contact.friction2Impulse;
std::cout << "JspLinBody2 : " << JspLinBody2.getX() << ", " << JspLinBody2.getY() << ", " << JspLinBody2.getZ() << std::endl; Vector3 angularImpulseBody2Friction2 = contact.r2CrossT2 * contact.friction2Impulse;
std::cout << "JspAngBody2 : " << JspAngBody2.getX() << ", " << JspAngBody2.getY() << ", " << JspAngBody2.getZ() << std::endl; Impulse impulseFriction2(linearImpulseBody1Friction2, angularImpulseBody1Friction2,
linearImpulseBody2Friction2, angularImpulseBody2Friction2);
std::cout << ": friction vector 1 : " << contact.frictionVector1.getX() << ", " << contact.frictionVector1.getY() << ", " << contact.frictionVector1.getZ() << std::endl; // Apply the impulses to the bodies of the constraint
std::cout << ": r1 x t1 : " << contact.r1CrossT1.getX() << ", " << contact.r1CrossT1.getY() << ", " << contact.r1CrossT1.getZ() << std::endl; applyImpulse(impulseFriction2, constraint);
std::cout << ": r2 x t1 : " << contact.r2CrossT1.getX() << ", " << contact.r2CrossT1.getY() << ", " << contact.r2CrossT1.getZ() << std::endl;
std::cout << ": inverse mass body 1 = " << constraint.massInverseBody1 << std::endl;
std::cout << ": inverse mass body 2 = " << constraint.massInverseBody2 << std::endl;
*/
contact.B_spBody1Friction1[0] = Minv_sp_mass_diag[indexBody1] * contact.J_spBody1Friction1[0];
contact.B_spBody1Friction1[1] = Minv_sp_mass_diag[indexBody1] * contact.J_spBody1Friction1[1];
contact.B_spBody1Friction1[2] = Minv_sp_mass_diag[indexBody1] * contact.J_spBody1Friction1[2];
contact.B_spBody2Friction1[0] = Minv_sp_mass_diag[indexBody2] * contact.J_spBody2Friction1[0];
contact.B_spBody2Friction1[1] = Minv_sp_mass_diag[indexBody2] * contact.J_spBody2Friction1[1];
contact.B_spBody2Friction1[2] = Minv_sp_mass_diag[indexBody2] * contact.J_spBody2Friction1[2];
for (uint i=0; i<3; i++) {
contact.B_spBody1Friction1[3 + i] = 0.0;
contact.B_spBody2Friction1[3 + i] = 0.0;
for (uint j=0; j<3; j++) {
contact.B_spBody1Friction1[3 + i] += Minv_sp_inertia[indexBody1].getValue(i, j) * contact.J_spBody1Friction1[3 + j];
contact.B_spBody2Friction1[3 + i] += Minv_sp_inertia[indexBody2].getValue(i, j) * contact.J_spBody2Friction1[3 + j];
}
}
/*
std::cout << "------ Old Version ----" << std::endl;
std::cout << "JspLinBody1 : " << contact.B_spBody1Friction1[0] << ", " << contact.B_spBody1Friction1[1] << ", " << contact.B_spBody1Friction1[2] << std::endl;
std::cout << "JspAngBody1 : " << contact.B_spBody1Friction1[3] << ", " << contact.B_spBody1Friction1[4] << ", " << contact.B_spBody1Friction1[5] << std::endl;
std::cout << "JspLinBody2 : " << contact.B_spBody2Friction1[0] << ", " << contact.B_spBody2Friction1[1] << ", " << contact.B_spBody2Friction1[2] << std::endl;
std::cout << "JspAngBody2 : " << contact.B_spBody2Friction1[3] << ", " << contact.B_spBody2Friction1[4] << ", " << contact.B_spBody2Friction1[5] << std::endl;
*/
// ---------- Friction 2 ---------- //
contact.B_spBody1Friction2[0] = Minv_sp_mass_diag[indexBody1] * contact.J_spBody1Friction2[0];
contact.B_spBody1Friction2[1] = Minv_sp_mass_diag[indexBody1] * contact.J_spBody1Friction2[1];
contact.B_spBody1Friction2[2] = Minv_sp_mass_diag[indexBody1] * contact.J_spBody1Friction2[2];
contact.B_spBody2Friction2[0] = Minv_sp_mass_diag[indexBody2] * contact.J_spBody2Friction2[0];
contact.B_spBody2Friction2[1] = Minv_sp_mass_diag[indexBody2] * contact.J_spBody2Friction2[1];
contact.B_spBody2Friction2[2] = Minv_sp_mass_diag[indexBody2] * contact.J_spBody2Friction2[2];
for (uint i=0; i<3; i++) {
contact.B_spBody1Friction2[3 + i] = 0.0;
contact.B_spBody2Friction2[3 + i] = 0.0;
for (uint j=0; j<3; j++) {
contact.B_spBody1Friction2[3 + i] += Minv_sp_inertia[indexBody1].getValue(i, j) * contact.J_spBody1Friction2[3 + j];
contact.B_spBody2Friction2[3 + i] += Minv_sp_inertia[indexBody2].getValue(i, j) * contact.J_spBody2Friction2[3 + j];
}
}
} }
} }
} }
// Solve a LCP problem using the Projected-Gauss-Seidel algorithm // Solve the contact constraints by applying sequential impulses
// This method outputs the result in the lambda vector void ConstraintSolver::solveContactConstraints() {
void ConstraintSolver::solveLCP() {
uint indexBody1Array, indexBody2Array;
decimal deltaLambda; decimal deltaLambda;
decimal lambdaTemp; decimal lambdaTemp;
uint iter; uint iter;
@ -400,9 +296,6 @@ void ConstraintSolver::solveLCP() {
ContactPointConstraint& contact = constraint.contacts[i]; ContactPointConstraint& contact = constraint.contacts[i];
indexBody1Array = constraint.indexBody1;
indexBody2Array = constraint.indexBody2;
const Vector3& v1 = mLinearVelocities[constraint.indexBody1]; const Vector3& v1 = mLinearVelocities[constraint.indexBody1];
const Vector3& w1 = mAngularVelocities[constraint.indexBody1]; const Vector3& w1 = mAngularVelocities[constraint.indexBody1];
const Vector3& v2 = mLinearVelocities[constraint.indexBody2]; const Vector3& v2 = mLinearVelocities[constraint.indexBody2];
@ -434,10 +327,10 @@ void ConstraintSolver::solveLCP() {
deltaLambda = contact.penetrationImpulse - lambdaTemp; deltaLambda = contact.penetrationImpulse - lambdaTemp;
// Compute the impulse P=J^T * lambda // Compute the impulse P=J^T * lambda
const Vector3 linearImpulseBody1 = -contact.normal * deltaLambda; Vector3 linearImpulseBody1 = -contact.normal * deltaLambda;
const Vector3 angularImpulseBody1 = -contact.r1CrossN * deltaLambda; Vector3 angularImpulseBody1 = -contact.r1CrossN * deltaLambda;
const Vector3 linearImpulseBody2 = contact.normal * deltaLambda; Vector3 linearImpulseBody2 = contact.normal * deltaLambda;
const Vector3 angularImpulseBody2 = contact.r2CrossN * deltaLambda; Vector3 angularImpulseBody2 = contact.r2CrossN * deltaLambda;
const Impulse impulsePenetration(linearImpulseBody1, angularImpulseBody1, const Impulse impulsePenetration(linearImpulseBody1, angularImpulseBody1,
linearImpulseBody2, angularImpulseBody2); linearImpulseBody2, angularImpulseBody2);
@ -457,12 +350,12 @@ void ConstraintSolver::solveLCP() {
deltaLambda = contact.friction1Impulse - lambdaTemp; deltaLambda = contact.friction1Impulse - lambdaTemp;
// Compute the impulse P=J^T * lambda // Compute the impulse P=J^T * lambda
Vector3 linearImpulseBody1Friction1 = -contact.frictionVector1 * deltaLambda; linearImpulseBody1 = -contact.frictionVector1 * deltaLambda;
Vector3 angularImpulseBody1Friction1 = -contact.r1CrossT1 * deltaLambda; angularImpulseBody1 = -contact.r1CrossT1 * deltaLambda;
Vector3 linearImpulseBody2Friction1 = contact.frictionVector1 * deltaLambda; linearImpulseBody2 = contact.frictionVector1 * deltaLambda;
Vector3 angularImpulseBody2Friction1 = contact.r2CrossT1 * deltaLambda; angularImpulseBody2 = contact.r2CrossT1 * deltaLambda;
Impulse impulseFriction1(linearImpulseBody1Friction1, angularImpulseBody1Friction1, const Impulse impulseFriction1(linearImpulseBody1, angularImpulseBody1,
linearImpulseBody2Friction1, angularImpulseBody2Friction1); linearImpulseBody2, angularImpulseBody2);
// Apply the impulses to the bodies of the constraint // Apply the impulses to the bodies of the constraint
applyImpulse(impulseFriction1, constraint); applyImpulse(impulseFriction1, constraint);
@ -480,12 +373,12 @@ void ConstraintSolver::solveLCP() {
deltaLambda = contact.friction2Impulse - lambdaTemp; deltaLambda = contact.friction2Impulse - lambdaTemp;
// Compute the impulse P=J^T * lambda // Compute the impulse P=J^T * lambda
Vector3 linearImpulseBody1Friction2 = -contact.frictionVector2 * deltaLambda; linearImpulseBody1 = -contact.frictionVector2 * deltaLambda;
Vector3 angularImpulseBody1Friction2 = -contact.r1CrossT2 * deltaLambda; angularImpulseBody1 = -contact.r1CrossT2 * deltaLambda;
Vector3 linearImpulseBody2Friction2 = contact.frictionVector2 * deltaLambda; linearImpulseBody2 = contact.frictionVector2 * deltaLambda;
Vector3 angularImpulseBody2Friction2 = contact.r2CrossT2 * deltaLambda; angularImpulseBody2 = contact.r2CrossT2 * deltaLambda;
Impulse impulseFriction2(linearImpulseBody1Friction2, angularImpulseBody1Friction2, const Impulse impulseFriction2(linearImpulseBody1, angularImpulseBody1,
linearImpulseBody2Friction2, angularImpulseBody2Friction2); linearImpulseBody2, angularImpulseBody2);
// Apply the impulses to the bodies of the constraint // Apply the impulses to the bodies of the constraint
applyImpulse(impulseFriction2, constraint); applyImpulse(impulseFriction2, constraint);
@ -494,60 +387,9 @@ void ConstraintSolver::solveLCP() {
} }
} }
// Compute the vector a used in the solve() method // Store the computed impulses to use them to
// Note that a = B * lambda // warm start the solver at the next iteration
void ConstraintSolver::warmStart() { void ConstraintSolver::storeImpulses() {
uint i;
uint indexBody1Array, indexBody2Array;
// For each constraint
for (uint c=0; c<mNbContactConstraints; c++) {
ContactConstraint& constraint = mContactConstraints[c];
for (uint i=0; i<constraint.nbContacts; i++) {
ContactPointConstraint& contact = constraint.contacts[i];
indexBody1Array = constraint.indexBody1;
indexBody2Array = constraint.indexBody2;
// --------- Penetration --------- //
for (uint j=0; j<3; j++) {
mLinearVelocities[indexBody1Array][j] += contact.B_spBody1Penetration[j] * contact.penetrationImpulse;
mAngularVelocities[indexBody1Array][j] += contact.B_spBody1Penetration[j + 3] * contact.penetrationImpulse;
mLinearVelocities[indexBody2Array][j] += contact.B_spBody2Penetration[j] * contact.penetrationImpulse;
mAngularVelocities[indexBody2Array][j] += contact.B_spBody2Penetration[j + 3] * contact.penetrationImpulse;
}
// --------- Friction 1 --------- //
for (uint j=0; j<3; j++) {
mLinearVelocities[indexBody1Array][j] += contact.B_spBody1Friction1[j] * contact.friction1Impulse;
mAngularVelocities[indexBody1Array][j] += contact.B_spBody1Friction1[j + 3] * contact.friction1Impulse;
mLinearVelocities[indexBody2Array][j] += contact.B_spBody2Friction1[j] * contact.friction1Impulse;
mAngularVelocities[indexBody2Array][j] += contact.B_spBody2Friction1[j + 3] * contact.friction1Impulse;
}
// --------- Friction 2 --------- //
for (uint j=0; j<3; j++) {
mLinearVelocities[indexBody1Array][j] += contact.B_spBody1Friction2[j] * contact.friction2Impulse;
mAngularVelocities[indexBody1Array][j] += contact.B_spBody1Friction2[j + 3] * contact.friction2Impulse;
mLinearVelocities[indexBody2Array][j] += contact.B_spBody2Friction2[j] * contact.friction2Impulse;
mAngularVelocities[indexBody2Array][j] += contact.B_spBody2Friction2[j + 3] * contact.friction2Impulse;
}
}
}
}
// Cache the lambda values in order to reuse them in the next step
// to initialize the lambda vector
void ConstraintSolver::cacheLambda() {
// For each constraint // For each constraint
for (uint c=0; c<mNbContactConstraints; c++) { for (uint c=0; c<mNbContactConstraints; c++) {
@ -565,10 +407,10 @@ void ConstraintSolver::cacheLambda() {
} }
} }
// Solve the current LCP problem // Solve the constraints
void ConstraintSolver::solve(decimal dt) { void ConstraintSolver::solve(decimal timeStep) {
mTimeStep = dt; mTimeStep = timeStep;
// Initialize the solver // Initialize the solver
initialize(); initialize();
@ -576,16 +418,13 @@ void ConstraintSolver::solve(decimal dt) {
initializeBodies(); initializeBodies();
// Fill-in all the matrices needed to solve the LCP problem // Fill-in all the matrices needed to solve the LCP problem
initializeContactConstraints(dt); initializeContactConstraints();
// Compute the matrix B // Solve the contact constraints
computeMatrixB_sp(); solveContactConstraints();
// Solve the LCP problem (computation of lambda)
solveLCP();
// Cache the lambda values in order to use them in the next step // Cache the lambda values in order to use them in the next step
cacheLambda(); storeImpulses();
} }
// Apply an impulse to the two bodies of a constraint // Apply an impulse to the two bodies of a constraint

View File

@ -82,27 +82,13 @@ struct ContactPointConstraint {
decimal inversePenetrationMass; // Inverse of the matrix K for the penenetration decimal inversePenetrationMass; // Inverse of the matrix K for the penenetration
decimal inverseFriction1Mass; // Inverse of the matrix K for the 1st friction decimal inverseFriction1Mass; // Inverse of the matrix K for the 1st friction
decimal inverseFriction2Mass; // Inverse of the matrix K for the 2nd friction decimal inverseFriction2Mass; // Inverse of the matrix K for the 2nd friction
decimal J_spBody1Penetration[6];
decimal J_spBody2Penetration[6];
decimal J_spBody1Friction1[6];
decimal J_spBody2Friction1[6];
decimal J_spBody1Friction2[6];
decimal J_spBody2Friction2[6];
decimal lowerBoundPenetration; decimal lowerBoundPenetration;
decimal upperBoundPenetration; decimal upperBoundPenetration;
decimal lowerBoundFriction1; decimal lowerBoundFriction1;
decimal upperBoundFriction1; decimal upperBoundFriction1;
decimal lowerBoundFriction2; decimal lowerBoundFriction2;
decimal upperBoundFriction2; decimal upperBoundFriction2;
decimal errorPenetration;
Contact* contact; // TODO : REMOVE THIS Contact* contact; // TODO : REMOVE THIS
decimal b_Penetration;
decimal B_spBody1Penetration[6];
decimal B_spBody2Penetration[6];
decimal B_spBody1Friction1[6];
decimal B_spBody2Friction1[6];
decimal B_spBody1Friction2[6];
decimal B_spBody2Friction2[6];
}; };
// Structure ContactConstraint // Structure ContactConstraint
@ -123,7 +109,7 @@ struct ContactConstraint {
decimal restitutionFactor; // Mix of the restitution factor for two bodies decimal restitutionFactor; // Mix of the restitution factor for two bodies
}; };
// TODO : Rewrite this coment to use the Sequential Impulse technique
/* ------------------------------------------------------------------- /* -------------------------------------------------------------------
Class ConstrainSolver : Class ConstrainSolver :
This class represents the constraint solver. The constraint solver This class represents the constraint solver. The constraint solver
@ -150,7 +136,11 @@ struct ContactConstraint {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class ConstraintSolver { class ConstraintSolver {
private: private:
// -------------------- Attributes -------------------- //
DynamicsWorld* world; // Reference to the world DynamicsWorld* world; // Reference to the world
std::vector<Constraint*> activeConstraints; // Current active constraints in the physics world std::vector<Constraint*> activeConstraints; // Current active constraints in the physics world
bool isErrorCorrectionActive; // True if error correction (with world order) is active bool isErrorCorrectionActive; // True if error correction (with world order) is active
@ -159,19 +149,6 @@ class ConstraintSolver {
uint nbBodies; // Current number of bodies in the physics world uint nbBodies; // Current number of bodies in the physics world
RigidBody* bodyMapping[NB_MAX_CONSTRAINTS][2]; // 2-dimensional array that contains the mapping of body reference RigidBody* bodyMapping[NB_MAX_CONSTRAINTS][2]; // 2-dimensional array that contains the mapping of body reference
// in the J_sp and B_sp matrices. For instance the cell bodyMapping[i][j] contains // in the J_sp and B_sp matrices. For instance the cell bodyMapping[i][j] contains
// the pointer to the body that correspond to the 1x6 J_ij matrix in the
// J_sp matrix. An integer body index refers to its index in the "bodies" std::vector
decimal J_sp[NB_MAX_CONSTRAINTS][2*6]; // 2-dimensional array that correspond to the sparse representation of the jacobian matrix of all constraints
// This array contains for each constraint two 1x6 Jacobian matrices (one for each body of the constraint)
// a 1x6 matrix
decimal B_sp[2][6*NB_MAX_CONSTRAINTS]; // 2-dimensional array that correspond to a useful matrix in sparse representation
// This array contains for each constraint two 6x1 matrices (one for each body of the constraint)
// a 6x1 matrix
decimal b[NB_MAX_CONSTRAINTS]; // Vector "b" of the LCP problem
decimal d[NB_MAX_CONSTRAINTS]; // Vector "d"
Matrix3x3 Minv_sp_inertia[NB_MAX_BODIES]; // 3x3 world inertia tensor matrix I for each body (from the Minv_sp matrix)
decimal Minv_sp_mass_diag[NB_MAX_BODIES]; // Array that contains for each body the inverse of its mass
// This is an array of size nbBodies that contains in each cell a 6x6 matrix
Vector3* mLinearVelocities; // Array of constrained linear velocities Vector3* mLinearVelocities; // Array of constrained linear velocities
Vector3* mAngularVelocities; // Array of constrained angular velocities Vector3* mAngularVelocities; // Array of constrained angular velocities
decimal mTimeStep; // Current time step decimal mTimeStep; // Current time step
@ -188,14 +165,26 @@ class ConstraintSolver {
// Map body to index // Map body to index
std::map<RigidBody*, uint> mMapBodyToIndex; std::map<RigidBody*, uint> mMapBodyToIndex;
// -------------------- Methods -------------------- //
void initialize(); // Initialize the constraint solver before each solving // Initialize the constraint solver
void initializeBodies(); // Initialize bodies velocities void initialize();
void initializeContactConstraints(decimal dt); // Fill in all the matrices needed to solve the LCP problem
void computeMatrixB_sp(); // Compute the matrix B_sp // Initialize the constrained bodies
void cacheLambda(); // Cache the lambda values in order to reuse them in the next step to initialize the lambda vector void initializeBodies();
void warmStart(); // Compute the vector a used in the solve() method
void solveLCP(); // Solve a LCP problem using Projected-Gauss-Seidel algorithm // Initialize the contact constraints before solving the system
void initializeContactConstraints();
// Store the computed impulses to use them to
// warm start the solver at the next iteration
void storeImpulses();
// Warm start the solver
void warmStart();
// Solve the contact constraints by applying sequential impulses
void solveContactConstraints();
// Apply an impulse to the two bodies of a constraint // Apply an impulse to the two bodies of a constraint
void applyImpulse(const Impulse& impulse, const ContactConstraint& constraint); void applyImpulse(const Impulse& impulse, const ContactConstraint& constraint);
@ -204,14 +193,32 @@ class ConstraintSolver {
decimal computeMixRestitutionFactor(const RigidBody *body1, const RigidBody *body2) const; decimal computeMixRestitutionFactor(const RigidBody *body1, const RigidBody *body2) const;
public: public:
ConstraintSolver(DynamicsWorld* world); // Constructor
virtual ~ConstraintSolver(); // Destructor // -------------------- Methods -------------------- //
void solve(decimal dt); // Solve the current LCP problem
bool isConstrainedBody(RigidBody* body) const; // Return true if the body is in at least one constraint // Constructor
Vector3 getConstrainedLinearVelocityOfBody(RigidBody *body); // Return the constrained linear velocity of a body after solving the LCP problem ConstraintSolver(DynamicsWorld* world);
Vector3 getConstrainedAngularVelocityOfBody(RigidBody* body); // Return the constrained angular velocity of a body after solving the LCP problem
void cleanup(); // Cleanup of the constraint solver // Destructor
void setNbLCPIterations(uint mNbIterations); // Set the number of iterations of the LCP solver virtual ~ConstraintSolver();
// Solve the constraints
void solve(decimal timeStep);
// Return true if the body is in at least one constraint
bool isConstrainedBody(RigidBody* body) const;
// Return the constrained linear velocity of a body after solving the constraints
Vector3 getConstrainedLinearVelocityOfBody(RigidBody *body);
// Return the constrained angular velocity of a body after solving the constraints
Vector3 getConstrainedAngularVelocityOfBody(RigidBody* body);
// Clean up the constraint solver
void cleanup();
// Set the number of iterations of the LCP solver
void setNbLCPIterations(uint mNbIterations);
}; };
// Return true if the body is in at least one constraint // Return true if the body is in at least one constraint
@ -219,21 +226,21 @@ inline bool ConstraintSolver::isConstrainedBody(RigidBody* body) const {
return mConstraintBodies.count(body) == 1; return mConstraintBodies.count(body) == 1;
} }
// Return the constrained linear velocity of a body after solving the LCP problem // Return the constrained linear velocity of a body after solving the constraints
inline Vector3 ConstraintSolver::getConstrainedLinearVelocityOfBody(RigidBody* body) { inline Vector3 ConstraintSolver::getConstrainedLinearVelocityOfBody(RigidBody* body) {
assert(isConstrainedBody(body)); assert(isConstrainedBody(body));
uint indexBodyArray = mMapBodyToIndex[body]; uint indexBodyArray = mMapBodyToIndex[body];
return mLinearVelocities[indexBodyArray]; return mLinearVelocities[indexBodyArray];
} }
// Return the constrained angular velocity of a body after solving the LCP problem // Return the constrained angular velocity of a body after solving the constraints
inline Vector3 ConstraintSolver::getConstrainedAngularVelocityOfBody(RigidBody *body) { inline Vector3 ConstraintSolver::getConstrainedAngularVelocityOfBody(RigidBody *body) {
assert(isConstrainedBody(body)); assert(isConstrainedBody(body));
uint indexBodyArray = mMapBodyToIndex[body]; uint indexBodyArray = mMapBodyToIndex[body];
return mAngularVelocities[indexBodyArray]; return mAngularVelocities[indexBodyArray];
} }
// Cleanup of the constraint solver // Clean up the constraint solver
inline void ConstraintSolver::cleanup() { inline void ConstraintSolver::cleanup() {
mMapBodyToIndex.clear(); mMapBodyToIndex.clear();
mConstraintBodies.clear(); mConstraintBodies.clear();