forked from bartvdbraak/blender
256 lines
5.3 KiB
C++
256 lines
5.3 KiB
C++
/*
|
|
* Copyright (c) 2005 Erwin Coumans http://www.erwincoumans.com
|
|
*
|
|
* Permission to use, copy, modify, distribute and sell this software
|
|
* and its documentation for any purpose is hereby granted without fee,
|
|
* provided that the above copyright notice appear in all copies.
|
|
* Erwin Coumans makes no representations about the suitability
|
|
* of this software for any purpose.
|
|
* It is provided "as is" without express or implied warranty.
|
|
*/
|
|
|
|
#include "OdeConstraintSolver.h"
|
|
|
|
#include "NarrowPhaseCollision/PersistentManifold.h"
|
|
#include "Dynamics/RigidBody.h"
|
|
#include "ContactConstraint.h"
|
|
#include "Solve2LinearConstraint.h"
|
|
#include "ContactSolverInfo.h"
|
|
#include "Dynamics/BU_Joint.h"
|
|
#include "Dynamics/ContactJoint.h"
|
|
|
|
#include "IDebugDraw.h"
|
|
|
|
#define USE_SOR_SOLVER
|
|
|
|
#include "SorLcp.h"
|
|
|
|
#include <math.h>
|
|
#include <float.h>//FLT_MAX
|
|
#ifdef WIN32
|
|
#include <memory.h>
|
|
#endif
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#ifdef WIN32
|
|
#include <malloc.h>
|
|
#else
|
|
#include <alloca.h>
|
|
#endif
|
|
|
|
class BU_Joint;
|
|
|
|
//see below
|
|
|
|
OdeConstraintSolver::OdeConstraintSolver():
|
|
m_cfm(1e-5f),
|
|
m_erp(0.3f)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//iterative lcp and penalty method
|
|
float OdeConstraintSolver::SolveGroup(PersistentManifold** manifoldPtr, int numManifolds,const ContactSolverInfo& infoGlobal,IDebugDraw* debugDrawer)
|
|
{
|
|
m_CurBody = 0;
|
|
m_CurJoint = 0;
|
|
|
|
|
|
RigidBody* bodies [MAX_RIGIDBODIES];
|
|
|
|
int numBodies = 0;
|
|
BU_Joint* joints [MAX_RIGIDBODIES*4];
|
|
int numJoints = 0;
|
|
|
|
for (int j=0;j<numManifolds;j++)
|
|
{
|
|
|
|
int body0=-1,body1=-1;
|
|
|
|
PersistentManifold* manifold = manifoldPtr[j];
|
|
if (manifold->GetNumContacts() > 0)
|
|
{
|
|
body0 = ConvertBody((RigidBody*)manifold->GetBody0(),bodies,numBodies);
|
|
body1 = ConvertBody((RigidBody*)manifold->GetBody1(),bodies,numBodies);
|
|
ConvertConstraint(manifold,joints,numJoints,bodies,body0,body1,debugDrawer);
|
|
}
|
|
}
|
|
|
|
SolveInternal1(m_cfm,m_erp,bodies,numBodies,joints,numJoints,infoGlobal);
|
|
|
|
return 0.f;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
typedef SimdScalar dQuaternion[4];
|
|
#define _R(i,j) R[(i)*4+(j)]
|
|
|
|
void dRfromQ1 (dMatrix3 R, const dQuaternion q)
|
|
{
|
|
// q = (s,vx,vy,vz)
|
|
SimdScalar qq1 = 2.f*q[1]*q[1];
|
|
SimdScalar qq2 = 2.f*q[2]*q[2];
|
|
SimdScalar qq3 = 2.f*q[3]*q[3];
|
|
_R(0,0) = 1.f - qq2 - qq3;
|
|
_R(0,1) = 2*(q[1]*q[2] - q[0]*q[3]);
|
|
_R(0,2) = 2*(q[1]*q[3] + q[0]*q[2]);
|
|
_R(0,3) = 0.f;
|
|
|
|
_R(1,0) = 2*(q[1]*q[2] + q[0]*q[3]);
|
|
_R(1,1) = 1.f - qq1 - qq3;
|
|
_R(1,2) = 2*(q[2]*q[3] - q[0]*q[1]);
|
|
_R(1,3) = 0.f;
|
|
|
|
_R(2,0) = 2*(q[1]*q[3] - q[0]*q[2]);
|
|
_R(2,1) = 2*(q[2]*q[3] + q[0]*q[1]);
|
|
_R(2,2) = 1.f - qq1 - qq2;
|
|
_R(2,3) = 0.f;
|
|
|
|
}
|
|
|
|
|
|
|
|
int OdeConstraintSolver::ConvertBody(RigidBody* body,RigidBody** bodies,int& numBodies)
|
|
{
|
|
if (!body || (body->getInvMass() == 0.f) )
|
|
{
|
|
return -1;
|
|
}
|
|
//first try to find
|
|
int i,j;
|
|
for (i=0;i<numBodies;i++)
|
|
{
|
|
if (bodies[i] == body)
|
|
return i;
|
|
}
|
|
//if not found, create a new body
|
|
bodies[numBodies++] = body;
|
|
//convert data
|
|
|
|
|
|
body->m_facc.setValue(0,0,0,0);
|
|
body->m_tacc.setValue(0,0,0,0);
|
|
|
|
//are the indices the same ?
|
|
for (i=0;i<4;i++)
|
|
{
|
|
for ( j=0;j<3;j++)
|
|
{
|
|
body->m_invI[i+4*j] = 0.f;
|
|
body->m_I[i+4*j] = 0.f;
|
|
}
|
|
}
|
|
body->m_invI[0+4*0] = body->getInvInertiaDiagLocal()[0];
|
|
body->m_invI[1+4*1] = body->getInvInertiaDiagLocal()[1];
|
|
body->m_invI[2+4*2] = body->getInvInertiaDiagLocal()[2];
|
|
|
|
body->m_I[0+0*4] = 1.f/body->getInvInertiaDiagLocal()[0];
|
|
body->m_I[1+1*4] = 1.f/body->getInvInertiaDiagLocal()[1];
|
|
body->m_I[2+2*4] = 1.f/body->getInvInertiaDiagLocal()[2];
|
|
|
|
|
|
|
|
|
|
dQuaternion q;
|
|
|
|
q[1] = body->getOrientation()[0];
|
|
q[2] = body->getOrientation()[1];
|
|
q[3] = body->getOrientation()[2];
|
|
q[0] = body->getOrientation()[3];
|
|
|
|
dRfromQ1(body->m_R,q);
|
|
|
|
return numBodies-1;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define MAX_JOINTS_1 8192
|
|
|
|
static ContactJoint gJointArray[MAX_JOINTS_1];
|
|
|
|
|
|
void OdeConstraintSolver::ConvertConstraint(PersistentManifold* manifold,BU_Joint** joints,int& numJoints,
|
|
RigidBody** bodies,int _bodyId0,int _bodyId1,IDebugDraw* debugDrawer)
|
|
{
|
|
|
|
|
|
manifold->RefreshContactPoints(((RigidBody*)manifold->GetBody0())->getCenterOfMassTransform(),
|
|
((RigidBody*)manifold->GetBody1())->getCenterOfMassTransform());
|
|
|
|
int bodyId0 = _bodyId0,bodyId1 = _bodyId1;
|
|
|
|
int i,numContacts = manifold->GetNumContacts();
|
|
|
|
bool swapBodies = (bodyId0 < 0);
|
|
|
|
|
|
RigidBody* body0,*body1;
|
|
|
|
if (swapBodies)
|
|
{
|
|
bodyId0 = _bodyId1;
|
|
bodyId1 = _bodyId0;
|
|
|
|
body0 = (RigidBody*)manifold->GetBody1();
|
|
body1 = (RigidBody*)manifold->GetBody0();
|
|
|
|
} else
|
|
{
|
|
body0 = (RigidBody*)manifold->GetBody0();
|
|
body1 = (RigidBody*)manifold->GetBody1();
|
|
}
|
|
|
|
assert(bodyId0 >= 0);
|
|
|
|
SimdVector3 color(0,1,0);
|
|
for (i=0;i<numContacts;i++)
|
|
{
|
|
|
|
if (debugDrawer)
|
|
{
|
|
const ManifoldPoint& cp = manifold->GetContactPoint(i);
|
|
|
|
debugDrawer->DrawContactPoint(
|
|
cp.m_positionWorldOnB,
|
|
cp.m_normalWorldOnB,
|
|
cp.GetDistance(),
|
|
cp.GetLifeTime(),
|
|
color);
|
|
|
|
}
|
|
assert (m_CurJoint < MAX_JOINTS_1);
|
|
|
|
// if (manifold->GetContactPoint(i).GetDistance() < 0.0f)
|
|
{
|
|
ContactJoint* cont = new (&gJointArray[m_CurJoint++]) ContactJoint( manifold ,i, swapBodies,body0,body1);
|
|
|
|
cont->node[0].joint = cont;
|
|
cont->node[0].body = bodyId0 >= 0 ? bodies[bodyId0] : 0;
|
|
|
|
cont->node[1].joint = cont;
|
|
cont->node[1].body = bodyId1 >= 0 ? bodies[bodyId1] : 0;
|
|
|
|
joints[numJoints++] = cont;
|
|
for (int i=0;i<6;i++)
|
|
cont->lambda[i] = 0.f;
|
|
|
|
cont->flags = 0;
|
|
}
|
|
}
|
|
|
|
//create a new contact constraint
|
|
};
|
|
|