/******************************************************************************** * 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 "DynamicsWorld.h" #include "../body/RigidBody.h" using namespace reactphysics3d; using namespace std; // Constructor ConstraintSolver::ConstraintSolver(DynamicsWorld* world) :world(world), nbConstraints(0), mNbIterations(10), mContactConstraints(0), Vconstraint(0), Wconstraint(0), V1(0), W1(0) { } // Destructor ConstraintSolver::~ConstraintSolver() { } // Initialize the constraint solver before each solving void ConstraintSolver::initialize() { nbConstraints = 0; // TOOD : Use better allocation here mContactConstraints = new ContactConstraint[world->getNbContactManifolds()]; mNbContactConstraints = 0; // For each contact manifold of the world vector::iterator it; for (it = world->getContactManifoldsBeginIterator(); it != world->getContactManifoldsEndIterator(); ++it) { ContactManifold contactManifold = *it; ContactConstraint& constraint = mContactConstraints[mNbContactConstraints]; assert(contactManifold.nbContacts > 0); RigidBody* body1 = contactManifold.contacts[0]->getBody1(); RigidBody* body2 = contactManifold.contacts[0]->getBody2(); // Fill in the body number maping mMapBodyToIndex.insert(make_pair(body1, mMapBodyToIndex.size())); mMapBodyToIndex.insert(make_pair(body2, mMapBodyToIndex.size())); // Add the two bodies of the constraint in the constraintBodies list mConstraintBodies.insert(body1); mConstraintBodies.insert(body2); Vector3 x1 = body1->getTransform().getPosition(); Vector3 x2 = body2->getTransform().getPosition(); constraint.indexBody1 = mMapBodyToIndex[body1]; constraint.indexBody2 = mMapBodyToIndex[body2]; constraint.inverseInertiaTensorBody1 = body1->getInertiaTensorInverseWorld(); constraint.inverseInertiaTensorBody2 = body2->getInertiaTensorInverseWorld(); constraint.isBody1Moving = body1->getIsMotionEnabled(); constraint.isBody2Moving = body2->getIsMotionEnabled(); constraint.massInverseBody1 = body1->getMassInverse(); constraint.massInverseBody2 = body2->getMassInverse(); constraint.nbContacts = contactManifold.nbContacts; // For each contact point of the contact manifold for (uint c=0; cgetWorldPointOnBody1(); Vector3 p2 = contact->getWorldPointOnBody2(); contactPointConstraint.contact = contact; contactPointConstraint.normal = contact->getNormal(); contactPointConstraint.r1 = p1 - x1; contactPointConstraint.r2 = p2 - x2; contactPointConstraint.frictionVector1 = contact->getFrictionVector1(); contactPointConstraint.frictionVector2 = contact->getFrictionVector2(); } mNbContactConstraints++; } // Compute the number of bodies that are part of some active constraint nbBodies = mConstraintBodies.size(); Vconstraint = new Vector3[nbBodies]; Wconstraint = new Vector3[nbBodies]; V1 = new Vector3[nbBodies]; W1 = new Vector3[nbBodies]; assert(mMapBodyToIndex.size() == nbBodies); } // Initialize bodies velocities void ConstraintSolver::initializeBodies() { // For each current body that is implied in some constraint RigidBody* rigidBody; RigidBody* body; uint b=0; for (set::iterator it = mConstraintBodies.begin(); it != mConstraintBodies.end(); ++it, b++) { rigidBody = *it; uint bodyNumber = mMapBodyToIndex[rigidBody]; // TODO : Use polymorphism and remove this downcasting assert(rigidBody); // Compute the vector V1 with initial velocities values int bodyIndexArray = 6 * bodyNumber; V1[bodyNumber] = rigidBody->getLinearVelocity(); W1[bodyNumber] = rigidBody->getAngularVelocity(); // Compute the vector Vconstraint with final constraint velocities Vconstraint[bodyNumber] = Vector3(0, 0, 0); Wconstraint[bodyNumber] = Vector3(0, 0, 0); // 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 // Notice that all the active constraints should have been evaluated first void ConstraintSolver::initializeContactConstraints(decimal dt) { decimal oneOverDT = 1.0 / dt; // For each contact constraint for (uint c=0; ccomputeJacobianPenetration(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; igetNbConstraints(); i++) { // bodyMapping[noConstraint+i][0] = constraint->getBody1(); // bodyMapping[noConstraint+i][1] = constraint->getBody2(); //} // Fill in the limit vectors for the constraint realContact->computeLowerBoundPenetration(contact.lowerBoundPenetration); realContact->computeLowerBoundFriction1(contact.lowerBoundFriction1); realContact->computeLowerBoundFriction2(contact.lowerBoundFriction2); realContact->computeUpperBoundPenetration(contact.upperBoundPenetration); realContact->computeUpperBoundFriction1(contact.upperBoundFriction1); realContact->computeUpperBoundFriction2(contact.upperBoundFriction2); // Fill in the error vector realContact->computeErrorPenetration(contact.errorPenetration); contact.errorFriction1 = 0.0; contact.errorFriction2 = 0.0; // Get the cached lambda values of the constraint contact.penetrationImpulse = realContact->getCachedLambda(0); contact.friction1Impulse = realContact->getCachedLambda(1); contact.friction2Impulse = realContact->getCachedLambda(2); //for (int i=0; igetNbConstraints(); 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); } contact.errorFriction1 = 0.0; contact.errorFriction2 = 0.0; // ---------- Penetration ---------- // // b = errorValues * oneOverDT; contact.b_Penetration = contact.errorPenetration * oneOverDT; // ---------- Friction 1 ---------- // contact.b_Friction1 = contact.errorFriction1 * oneOverDT; // ---------- Friction 2 ---------- // contact.b_Friction2 = contact.errorFriction2 * oneOverDT; } } } // Compute the matrix B_sp void ConstraintSolver::computeMatrixB_sp() { uint indexConstraintArray, indexBody1, indexBody2; // For each constraint for (uint m = 0; m::iterator it = mConstraintBodies.begin(); it != mConstraintBodies.end(); ++it) { RigidBody* rigidBody = *it; uint bodyNumber = mMapBodyToIndex[rigidBody]; aLinear[bodyNumber] = oneOverDt * V1[bodyNumber] + rigidBody->getMassInverse() * rigidBody->getExternalForce(); aAngular[bodyNumber] = oneOverDt * W1[bodyNumber] + rigidBody->getInertiaTensorInverseWorld() * rigidBody->getExternalTorque(); } // For each constraint for (uint c=0; csetCachedLambda(0, contact.penetrationImpulse); contact.contact->setCachedLambda(1, contact.friction1Impulse); contact.contact->setCachedLambda(2, contact.friction2Impulse); } } }