/******************************************************************************** * ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * * Copyright (c) 2010-2012 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * * In no event will the authors be held liable for any damages arising from the * * use of this software. * * * * Permission is granted to anyone to use this software for any purpose, * * including commercial applications, and to alter it and redistribute it * * freely, subject to the following restrictions: * * * * 1. The origin of this software must not be misrepresented; you must not claim * * that you wrote the original software. If you use this software in a * * product, an acknowledgment in the product documentation would be * * appreciated but is not required. * * * * 2. Altered source versions must be plainly marked as such, and must not be * * misrepresented as being the original software. * * * * 3. This notice may not be removed or altered from any source distribution. * * * ********************************************************************************/ // Libraries #include "ConstraintSolver.h" #include "../body/RigidBody.h" using namespace reactphysics3d; using namespace std; // Constructor ConstraintSolver::ConstraintSolver(PhysicsWorld* world) :physicsWorld(world), nbConstraints(0), nbIterationsLCP(DEFAULT_LCP_ITERATIONS), nbIterationsLCPErrorCorrection(DEFAULT_LCP_ITERATIONS_ERROR_CORRECTION), isErrorCorrectionActive(false) { } // Destructor ConstraintSolver::~ConstraintSolver() { } // Initialize the constraint solver before each solving void ConstraintSolver::initialize() { Constraint* constraint; nbConstraints = 0; nbConstraintsError = 0; // For each constraint vector::iterator it; for (it = physicsWorld->getConstraintsBeginIterator(); it != physicsWorld->getConstraintsEndIterator(); ++it) { constraint = *it; // If the constraint is active if (constraint->isActive()) { activeConstraints.push_back(constraint); // Add the two bodies of the constraint in the constraintBodies list constraintBodies.insert(constraint->getBody1()); constraintBodies.insert(constraint->getBody2()); // Fill in the body number maping bodyNumberMapping.insert(pair(constraint->getBody1(), bodyNumberMapping.size())); bodyNumberMapping.insert(pair(constraint->getBody2(), bodyNumberMapping.size())); // Update the size of the jacobian matrix nbConstraints += constraint->getNbConstraints(); // Update the size of the jacobian matrix for error correction projection if (constraint->getType() == CONTACT) { nbConstraintsError++; } } } // Compute the number of bodies that are part of some active constraint nbBodies = bodyNumberMapping.size(); assert(nbConstraints > 0 && nbConstraints <= NB_MAX_CONSTRAINTS); assert(nbConstraintsError > 0 && nbConstraintsError <= NB_MAX_CONSTRAINTS); assert(nbBodies > 0 && nbBodies <= NB_MAX_BODIES); } // Fill in all the matrices needed to solve the LCP problem // Notice that all the active constraints should have been evaluated first void ConstraintSolver::fillInMatrices(decimal dt) { Constraint* constraint; decimal oneOverDt = 1.0 / dt; // For each active constraint int noConstraint = 0; int noConstraintError = 0; for (int c=0; ccomputeJacobian(noConstraint, J_sp); // Fill in the body mapping matrix for(int i=0; igetNbConstraints(); i++) { bodyMapping[noConstraint+i][0] = constraint->getBody1(); bodyMapping[noConstraint+i][1] = constraint->getBody2(); } // Fill in the limit vectors for the constraint constraint->computeLowerBound(noConstraint, lowerBounds); constraint->computeUpperBound(noConstraint, upperBounds); // Fill in the error vector constraint->computeErrorValue(noConstraint, errorValues); // Get the cached lambda values of the constraint for (int i=0; igetNbConstraints(); i++) { lambdaInit[noConstraint + i] = constraint->getCachedLambda(i); } // If the constraint is a contact if (constraint->getType() == CONTACT) { Contact* contact = dynamic_cast(constraint); decimal penetrationDepth = contact->getPenetrationDepth(); // If error correction with projection is active if (isErrorCorrectionActive) { // Fill in the error correction projection parameters lowerBoundsError[noConstraintError] = lowerBounds[noConstraint]; upperBoundsError[noConstraintError] = upperBounds[noConstraint]; for (int i=0; i<12; i++) { J_spError[noConstraintError][i] = J_sp[noConstraint][i]; } bodyMappingError[noConstraintError][0] = constraint->getBody1(); bodyMappingError[noConstraintError][1] = constraint->getBody2(); penetrationDepths[noConstraintError] = contact->getPenetrationDepth(); // If the penetration depth is small if (penetrationDepth < PENETRATION_DEPTH_THRESHOLD_ERROR_CORRECTION) { // Use the Baumgarte error correction term for contacts instead of // first order world projection errorValues[noConstraint] += 0.1 * oneOverDt * contact->getPenetrationDepth(); } noConstraintError++; } else { // If error correction with projection is not active // Add the Baumgarte error correction term for contacts errorValues[noConstraint] += 0.1 * oneOverDt * contact->getPenetrationDepth(); } } noConstraint += constraint->getNbConstraints(); } // For each current body that is implied in some constraint RigidBody* rigidBody; Body* body; uint b=0; for (set::iterator it = constraintBodies.begin(); it != constraintBodies.end(); ++it, b++) { body = *it; uint bodyNumber = bodyNumberMapping[body]; // TODO : Use polymorphism and remove this downcasting rigidBody = dynamic_cast(body); assert(rigidBody); // Compute the vector V1 with initial velocities values Vector3 linearVelocity = rigidBody->getLinearVelocity(); Vector3 angularVelocity = rigidBody->getAngularVelocity(); int bodyIndexArray = 6 * bodyNumber; V1[bodyIndexArray] = linearVelocity[0]; V1[bodyIndexArray + 1] = linearVelocity[1]; V1[bodyIndexArray + 2] = linearVelocity[2]; V1[bodyIndexArray + 3] = angularVelocity[0]; V1[bodyIndexArray + 4] = angularVelocity[1]; V1[bodyIndexArray + 5] = angularVelocity[2]; // Compute the vector Vconstraint with final constraint velocities Vconstraint[bodyIndexArray] = 0.0; Vconstraint[bodyIndexArray + 1] = 0.0; Vconstraint[bodyIndexArray + 2] = 0.0; Vconstraint[bodyIndexArray + 3] = 0.0; Vconstraint[bodyIndexArray + 4] = 0.0; Vconstraint[bodyIndexArray + 5] = 0.0; // Compute the vector Vconstraint with final constraint velocities if (isErrorCorrectionActive) { VconstraintError[bodyIndexArray] = 0.0; VconstraintError[bodyIndexArray + 1] = 0.0; VconstraintError[bodyIndexArray + 2] = 0.0; VconstraintError[bodyIndexArray + 3] = 0.0; VconstraintError[bodyIndexArray + 4] = 0.0; VconstraintError[bodyIndexArray + 5] = 0.0; } // Compute the vector with forces and torques values Vector3 externalForce = rigidBody->getExternalForce(); Vector3 externalTorque = rigidBody->getExternalTorque(); Fext[bodyIndexArray] = externalForce[0]; Fext[bodyIndexArray + 1] = externalForce[1]; Fext[bodyIndexArray + 2] = externalForce[2]; Fext[bodyIndexArray + 3] = externalTorque[0]; Fext[bodyIndexArray + 4] = externalTorque[1]; Fext[bodyIndexArray + 5] = externalTorque[2]; // 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(); } } } // Compute the vector b void ConstraintSolver::computeVectorB(decimal dt) { uint indexBody1, indexBody2; decimal oneOverDT = 1.0 / dt; for (uint c = 0; c= PENETRATION_DEPTH_THRESHOLD_ERROR_CORRECTION) { bError[c] = penetrationDepths[c] * oneOverDT; } else { bError[c] = 0.0; } } } // Compute the matrix B_sp void ConstraintSolver::computeMatrixB_sp() { uint indexConstraintArray, indexBody1, indexBody2; // For each constraint for (uint c = 0; cgetNbConstraints(); i++) { // Get the lambda value that have just been computed activeConstraints[c]->setCachedLambda(i, lambda[noConstraint + i]); } noConstraint += activeConstraints[c]->getNbConstraints(); } }