add contact constraint as projections in CG

This commit is contained in:
Xuchen Han
2019-07-04 23:07:02 -07:00
parent 32836b0694
commit 35ce2ae0e2
9 changed files with 392 additions and 141 deletions

View File

@@ -17,7 +17,6 @@ subject to the following restrictions:
#define BT_DISCRETE_DYNAMICS_WORLD_H #define BT_DISCRETE_DYNAMICS_WORLD_H
#include "btDynamicsWorld.h" #include "btDynamicsWorld.h"
class btDispatcher; class btDispatcher;
class btOverlappingPairCache; class btOverlappingPairCache;
class btConstraintSolver; class btConstraintSolver;
@@ -26,6 +25,7 @@ class btTypedConstraint;
class btActionInterface; class btActionInterface;
class btPersistentManifold; class btPersistentManifold;
class btIDebugDraw; class btIDebugDraw;
struct InplaceSolverIslandCallback; struct InplaceSolverIslandCallback;
#include "LinearMath/btAlignedObjectArray.h" #include "LinearMath/btAlignedObjectArray.h"
@@ -76,7 +76,7 @@ protected:
virtual void calculateSimulationIslands(); virtual void calculateSimulationIslands();
virtual void solveConstraints(btContactSolverInfo & solverInfo);
virtual void updateActivationState(btScalar timeStep); virtual void updateActivationState(btScalar timeStep);
@@ -95,7 +95,7 @@ protected:
void serializeRigidBodies(btSerializer * serializer); void serializeRigidBodies(btSerializer * serializer);
void serializeDynamicsWorldInfo(btSerializer * serializer); void serializeDynamicsWorldInfo(btSerializer * serializer);
public: public:
BT_DECLARE_ALIGNED_ALLOCATOR(); BT_DECLARE_ALIGNED_ALLOCATOR();
@@ -107,6 +107,8 @@ public:
///if maxSubSteps > 0, it will interpolate motion between fixedTimeStep's ///if maxSubSteps > 0, it will interpolate motion between fixedTimeStep's
virtual int stepSimulation(btScalar timeStep, int maxSubSteps = 1, btScalar fixedTimeStep = btScalar(1.) / btScalar(60.)); virtual int stepSimulation(btScalar timeStep, int maxSubSteps = 1, btScalar fixedTimeStep = btScalar(1.) / btScalar(60.));
virtual void solveConstraints(btContactSolverInfo & solverInfo);
virtual void synchronizeMotionStates(); virtual void synchronizeMotionStates();
///this can be useful to synchronize a single rigid body -> graphics object ///this can be useful to synchronize a single rigid body -> graphics object

View File

@@ -11,42 +11,14 @@
#include "btConjugateGradient.h" #include "btConjugateGradient.h"
#include "btLagrangianForce.h" #include "btLagrangianForce.h"
#include "btMassSpring.h" #include "btMassSpring.h"
#include "btContactProjection.h"
#include "btDeformableRigidDynamicsWorld.h"
struct DirichletDofProjection class btDeformableRigidDynamicsWorld;
{
using TVStack = btAlignedObjectArray<btVector3>;
const btAlignedObjectArray<btSoftBody *>& m_softBodies;
DirichletDofProjection(const btAlignedObjectArray<btSoftBody *>& softBodies)
: m_softBodies(softBodies)
{}
void operator()(TVStack& x)
{
size_t counter = 0;
for (int i = 0; i < m_softBodies.size(); ++i)
{
const btSoftBody* psb = m_softBodies[i];
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
if (psb->m_nodes[j].m_im == 0)
{
x[counter].setZero();
}
++counter;
}
}
}
};
class btBackwardEulerObjective class btBackwardEulerObjective
{ {
public: public:
using TVStack = btAlignedObjectArray<btVector3>; using TVStack = btAlignedObjectArray<btVector3>;
struct EmptyProjection
{
void operator()(TVStack& x)
{}
};
struct DefaultPreconditioner struct DefaultPreconditioner
{ {
void operator()(const TVStack& x, TVStack& b) void operator()(const TVStack& x, TVStack& b)
@@ -58,19 +30,19 @@ public:
}; };
btScalar m_dt; btScalar m_dt;
btConjugateGradient<btBackwardEulerObjective> cg; btConjugateGradient<btBackwardEulerObjective> cg;
btDeformableRigidDynamicsWorld* m_world;
btAlignedObjectArray<btLagrangianForce*> m_lf; btAlignedObjectArray<btLagrangianForce*> m_lf;
btAlignedObjectArray<btSoftBody *>& m_softBodies; btAlignedObjectArray<btSoftBody *>& m_softBodies;
std::function<void(TVStack&)> project;
std::function<void(const TVStack&, TVStack&)> precondition; std::function<void(const TVStack&, TVStack&)> precondition;
btContactProjection projection;
btBackwardEulerObjective(btAlignedObjectArray<btSoftBody *>& softBodies) btBackwardEulerObjective(btAlignedObjectArray<btSoftBody *>& softBodies, const TVStack& backup_v)
: cg(20) : cg(20)
, m_softBodies(softBodies) , m_softBodies(softBodies)
, project(EmptyProjection())
, precondition(DefaultPreconditioner()) , precondition(DefaultPreconditioner())
, projection(m_softBodies, backup_v)
{ {
// this should really be specified in initialization instead of here // TODO: this should really be specified in initialization instead of here
btMassSpring* mass_spring = new btMassSpring(m_softBodies); btMassSpring* mass_spring = new btMassSpring(m_softBodies);
m_lf.push_back(mass_spring); m_lf.push_back(mass_spring);
} }
@@ -103,7 +75,6 @@ public:
void computeStep(TVStack& dv, const TVStack& residual, const btScalar& dt) void computeStep(TVStack& dv, const TVStack& residual, const btScalar& dt)
{ {
m_dt = dt; m_dt = dt;
// TODO:figure out what the tolerance should be
btScalar tolerance = std::numeric_limits<float>::epsilon()*16 * computeNorm(residual); btScalar tolerance = std::numeric_limits<float>::epsilon()*16 * computeNorm(residual);
cg.solve(*this, dv, residual, tolerance); cg.solve(*this, dv, residual, tolerance);
} }
@@ -133,24 +104,33 @@ public:
} }
} }
void updateProjection(const TVStack& dv)
{
projection.update(m_dt, dv);
}
void reinitialize(bool nodeUpdated) void reinitialize(bool nodeUpdated)
{ {
if(nodeUpdated)
{
projection.setSoftBodies(m_softBodies);
}
for (int i = 0; i < m_lf.size(); ++i) for (int i = 0; i < m_lf.size(); ++i)
{ {
m_lf[i]->reinitialize(nodeUpdated); m_lf[i]->reinitialize(nodeUpdated);
} projection.reinitialize(nodeUpdated);
if(nodeUpdated)
{
DirichletDofProjection dirichlet(m_softBodies);
setProjection(dirichlet);
} }
} }
template <class Func> void enforceConstraint(TVStack& x)
void setProjection(Func project_func)
{ {
project = project_func; projection.enforceConstraint(x);
}
void project(TVStack& r, const TVStack& dv)
{
updateProjection(dv);
projection(r);
} }
template <class Func> template <class Func>
@@ -158,6 +138,12 @@ public:
{ {
precondition = preconditioner_func; precondition = preconditioner_func;
} }
virtual void setWorld(btDeformableRigidDynamicsWorld* world)
{
m_world = world;
projection.setWorld(world);
}
}; };
#endif /* btBackwardEulerObjective_h */ #endif /* btBackwardEulerObjective_h */

View File

@@ -0,0 +1,80 @@
// btCGProjection.h
// BulletSoftBody
//
// Created by Xuchen Han on 7/4/19.
//
#ifndef BT_CG_PROJECTION_H
#define BT_CG_PROJECTION_H
#include "btSoftBody.h"
#include <unordered_map>
class btDeformableRigidDynamicsWorld;
class btCGProjection
{
public:
// static const int dim = 3;
using TVStack = btAlignedObjectArray<btVector3>;
using TVArrayStack = btAlignedObjectArray<btAlignedObjectArray<btVector3> >;
using TArrayStack = btAlignedObjectArray<btAlignedObjectArray<btScalar> >;
btAlignedObjectArray<btSoftBody *> m_softBodies;
btDeformableRigidDynamicsWorld* m_world;
std::unordered_map<btSoftBody::Node *, size_t> m_indices;
TVArrayStack m_constrainedDirections;
TArrayStack m_constrainedValues;
const TVStack& m_backupVelocity;
btCGProjection(btAlignedObjectArray<btSoftBody *>& softBodies, const TVStack& backup_v)
: m_softBodies(softBodies)
, m_backupVelocity(backup_v)
{
}
virtual ~btCGProjection()
{
}
// apply the constraints
virtual void operator()(TVStack& x) = 0;
// update the constraints
virtual void update(btScalar dt, const TVStack& dv) = 0;
virtual void reinitialize(bool nodeUpdated)
{
if (nodeUpdated)
updateId();
m_constrainedValues.resize(m_indices.size());
m_constrainedDirections.resize(m_indices.size());
}
void updateId()
{
size_t index = 0;
m_indices.clear();
for (int i = 0; i < m_softBodies.size(); ++i)
{
btSoftBody* psb = m_softBodies[i];
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
m_indices[&(psb->m_nodes[j])] = index++;
}
}
}
void setSoftBodies(btAlignedObjectArray<btSoftBody* > softBodies)
{
m_softBodies.copyFromArray(softBodies);
}
virtual void setWorld(btDeformableRigidDynamicsWorld* world)
{
m_world = world;
}
};
#endif /* btCGProjection_h */

View File

@@ -89,7 +89,7 @@ public:
// } // }
// return the number of iterations taken // return the number of iterations taken
int solve(const TM& A, TVStack& x, const TVStack& b, btScalar tolerance) int solve(TM& A, TVStack& x, const TVStack& b, btScalar tolerance)
{ {
btAssert(x.size() == b.size()); btAssert(x.size() == b.size());
reinitialize(b); reinitialize(b);
@@ -97,7 +97,8 @@ public:
// r = b - A * x --with assigned dof zeroed out // r = b - A * x --with assigned dof zeroed out
A.multiply(x, temp); A.multiply(x, temp);
r = sub(b, temp); r = sub(b, temp);
A.project(r); A.project(r,x);
A.enforceConstraint(x);
btScalar r_norm = std::sqrt(squaredNorm(r)); btScalar r_norm = std::sqrt(squaredNorm(r));
if (r_norm < tolerance) { if (r_norm < tolerance) {
@@ -124,7 +125,8 @@ public:
multAndAddTo(-alpha, temp, r); multAndAddTo(-alpha, temp, r);
// zero out the dofs of r // zero out the dofs of r
A.project(r); A.project(r,x);
A.enforceConstraint(x);
r_norm = std::sqrt(squaredNorm(r)); r_norm = std::sqrt(squaredNorm(r));

View File

@@ -0,0 +1,142 @@
//
// btContactProjection.cpp
// BulletSoftBody
//
// Created by Xuchen Han on 7/4/19.
//
#include "btContactProjection.h"
#include "btDeformableRigidDynamicsWorld.h"
void btContactProjection::update(btScalar dt, const TVStack& dv)
{
size_t counter = 0;
for (int i = 0; i < m_softBodies.size(); ++i)
{
btSoftBody* psb = m_softBodies[i];
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
psb->m_nodes[j].m_v = m_backupVelocity[counter] + dv[counter];
++counter;
}
}
///solve rigid body constraints
m_world->btSoftRigidDynamicsWorld::btDiscreteDynamicsWorld::solveConstraints(m_world->getSolverInfo());
// clear the old constraints
for (int i = 0; i < m_constrainedDirections.size(); ++i)
{
m_constrainedDirections[i].clear();
m_constrainedValues[i].clear();
}
// Set dirichlet constraints
counter = 0;
for (int i = 0; i < m_softBodies.size(); ++i)
{
const btSoftBody* psb = m_softBodies[i];
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
if (psb->m_nodes[j].m_im == 0)
{
m_constrainedDirections[counter].push_back(btVector3(1,0,0));
m_constrainedDirections[counter].push_back(btVector3(0,1,0));
m_constrainedDirections[counter].push_back(btVector3(0,0,1));
m_constrainedValues[counter].push_back(0);
m_constrainedValues[counter].push_back(0);
m_constrainedValues[counter].push_back(0);
}
++counter;
}
}
// loop through contacts to create contact constraints
for (int i = 0; i < m_softBodies.size(); ++i)
{
btSoftBody* psb = m_softBodies[i];
btMultiBodyJacobianData jacobianData;
const btScalar mrg = psb->getCollisionShape()->getMargin();
for (int i = 0, ni = psb->m_rcontacts.size(); i < ni; ++i)
{
const btSoftBody::RContact& c = psb->m_rcontacts[i];
// skip anchor points
if (c.m_node->m_im == 0)
continue;
const btSoftBody::sCti& cti = c.m_cti;
if (cti.m_colObj->hasContactResponse())
{
btVector3 va(0, 0, 0);
btRigidBody* rigidCol = 0;
btMultiBodyLinkCollider* multibodyLinkCol = 0;
btScalar* deltaV;
// grab the velocity of the rigid body
if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
{
rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj);
va = rigidCol ? (rigidCol->getVelocityInLocalPoint(c.m_c1)) * dt : btVector3(0, 0, 0);
}
else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
{
multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
if (multibodyLinkCol)
{
const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
jacobianData.m_jacobians.resize(ndof);
jacobianData.m_deltaVelocitiesUnitImpulse.resize(ndof);
btScalar* jac = &jacobianData.m_jacobians[0];
multibodyLinkCol->m_multiBody->fillContactJacobianMultiDof(multibodyLinkCol->m_link, c.m_node->m_x, cti.m_normal, jac, jacobianData.scratch_r, jacobianData.scratch_v, jacobianData.scratch_m);
deltaV = &jacobianData.m_deltaVelocitiesUnitImpulse[0];
multibodyLinkCol->m_multiBody->calcAccelerationDeltasMultiDof(&jacobianData.m_jacobians[0], deltaV, jacobianData.scratch_r, jacobianData.scratch_v);
btScalar vel = 0.0;
for (int j = 0; j < ndof; ++j)
{
vel += multibodyLinkCol->m_multiBody->getVelocityVector()[j] * jac[j];
}
va = cti.m_normal * vel * dt;
}
}
// TODO: rethink what the velocity of the soft body node should be
// const btVector3 vb = c.m_node->m_x - c.m_node->m_q;
const btVector3 vb = c.m_node->m_v * dt;
const btVector3 vr = vb - va;
const btScalar dn = btDot(vr, cti.m_normal);
if (dn <= SIMD_EPSILON)
{
const btScalar dp = btMin((btDot(c.m_node->m_x, cti.m_normal) + cti.m_offset), mrg);
const btVector3 fv = vr - (cti.m_normal * dn);
// c0 is the impulse matrix, c3 is 1 - the friction coefficient or 0, c4 is the contact hardness coefficient
// const btVector3 impulse = c.m_c0 * ((vr - (fv * c.m_c3)));
const btVector3 impulse = c.m_c0 * ((vr - (fv * c.m_c3))+ (cti.m_normal * (dp * c.m_c4)));
//c.m_node->m_v -= impulse * c.m_c2 / dt;
// TODO: only contact is considered here, add friction later
btVector3 normal = cti.m_normal.normalized();
btVector3 dv = -impulse * c.m_c2;
btScalar dvn = dv.dot(normal);
m_constrainedDirections[m_indices[c.m_node]].push_back(normal);
m_constrainedValues[m_indices[c.m_node]].push_back(dvn);
if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
{
if (rigidCol)
rigidCol->applyImpulse(impulse, c.m_c1);
}
else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
{
if (multibodyLinkCol)
{
double multiplier = 0.5;
multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof(deltaV, -impulse.length() * multiplier);
}
}
}
}
}
}
}

View File

@@ -0,0 +1,56 @@
//
// btContactProjection.h
// BulletSoftBody
//
// Created by Xuchen Han on 7/4/19.
//
#ifndef BT_CONTACT_PROJECTION_H
#define BT_CONTACT_PROJECTION_H
#include "btCGProjection.h"
#include "btSoftBody.h"
#include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h"
#include "BulletDynamics/Featherstone/btMultiBodyConstraint.h"
#include <iostream>
class btContactProjection : public btCGProjection
{
public:
btContactProjection(btAlignedObjectArray<btSoftBody *>& softBodies, const btAlignedObjectArray<btVector3>& backup_v)
: btCGProjection(softBodies, backup_v)
{
}
virtual ~btContactProjection()
{
}
// apply the constraints
virtual void operator()(TVStack& x)
{
for (int i = 0; i < x.size(); ++i)
{
for (int j = 0; j < m_constrainedDirections[i].size(); ++j)
{
x[i] -= x[i].dot(m_constrainedDirections[i][j]) * m_constrainedDirections[i][j];
}
}
}
virtual void enforceConstraint(TVStack& x)
{
for (int i = 0; i < x.size(); ++i)
{
for (int j = 0; j < m_constrainedDirections[i].size(); ++j)
{
x[i] -= x[i].dot(m_constrainedDirections[i][j]) * m_constrainedDirections[i][j];
x[i] += m_constrainedValues[i][j] * m_constrainedDirections[i][j];
}
}
}
// update the constraints
virtual void update(btScalar dt, const TVStack& dv);
};
#endif /* btContactProjection_h */

View File

@@ -10,12 +10,14 @@
#include "btSoftBodySolvers.h" #include "btSoftBodySolvers.h"
#include "btBackwardEulerObjective.h" #include "btBackwardEulerObjective.h"
#include "btDeformableRigidDynamicsWorld.h"
#include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h" #include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h"
#include "BulletDynamics/Featherstone/btMultiBodyConstraint.h" #include "BulletDynamics/Featherstone/btMultiBodyConstraint.h"
struct btCollisionObjectWrapper; struct btCollisionObjectWrapper;
class btDeformableRigidDynamicsWorld;
class btDeformableBodySolver : public btSoftBodySolver class btDeformableBodySolver : public btSoftBodySolver
{ {
using TVStack = btAlignedObjectArray<btVector3>; using TVStack = btAlignedObjectArray<btVector3>;
@@ -29,13 +31,16 @@ protected:
btBackwardEulerObjective m_objective; btBackwardEulerObjective m_objective;
int m_solveIterations; int m_solveIterations;
int m_impulseIterations; int m_impulseIterations;
btDeformableRigidDynamicsWorld* m_world;
btAlignedObjectArray<btVector3> m_backupVelocity;
public: public:
btDeformableBodySolver() btDeformableBodySolver()
: m_numNodes(0) : m_numNodes(0)
, m_objective(m_softBodySet) , m_objective(m_softBodySet, m_backupVelocity)
, m_solveIterations(1) , m_solveIterations(1)
, m_impulseIterations(1) , m_impulseIterations(1)
, m_world(nullptr)
{ {
} }
@@ -76,23 +81,11 @@ public:
{ {
bool nodeUpdated = updateNodes(); bool nodeUpdated = updateNodes();
reinitialize(nodeUpdated); reinitialize(nodeUpdated);
backupVelocity();
for (int i = 0; i < m_solveIterations; ++i) for (int i = 0; i < m_solveIterations; ++i)
{ {
// get the velocity after contact solve
// TODO: perform contact solve here
for (int j = 0; j < m_impulseIterations; ++j)
{
for (int s = 0; s < m_softBodySet.size(); ++s)
VSolve_RContacts(m_softBodySet[s], 0, solverdt);
}
// advect with v_n+1 ** to update position based states
// where v_n+1 ** is the velocity after contact response
// only need to advect x here if elastic force is implicit // only need to advect x here if elastic force is implicit
// prepareSolve(solverdt); // prepareSolve(solverdt);
m_objective.computeResidual(solverdt, m_residual); m_objective.computeResidual(solverdt, m_residual);
m_objective.computeStep(m_dv, m_residual, solverdt); m_objective.computeStep(m_dv, m_residual, solverdt);
@@ -107,7 +100,9 @@ public:
{ {
m_dv.resize(m_numNodes); m_dv.resize(m_numNodes);
m_residual.resize(m_numNodes); m_residual.resize(m_numNodes);
m_backupVelocity.resize(m_numNodes);
} }
for (int i = 0; i < m_dv.size(); ++i) for (int i = 0; i < m_dv.size(); ++i)
{ {
m_dv[i].setZero(); m_dv[i].setZero();
@@ -151,7 +146,22 @@ public:
btSoftBody* psb = m_softBodySet[i]; btSoftBody* psb = m_softBodySet[i];
for (int j = 0; j < psb->m_nodes.size(); ++j) for (int j = 0; j < psb->m_nodes.size(); ++j)
{ {
psb->m_nodes[j].m_v += m_dv[counter++]; psb->m_nodes[j].m_v = m_backupVelocity[counter] + m_dv[counter];
++counter;
}
}
}
void backupVelocity()
{
// serial implementation
int counter = 0;
for (int i = 0; i < m_softBodySet.size(); ++i)
{
btSoftBody* psb = m_softBodySet[i];
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
m_backupVelocity[counter++] = psb->m_nodes[j].m_v;
} }
} }
} }
@@ -168,6 +178,7 @@ public:
} }
return false; return false;
} }
virtual void predictMotion(float solverdt) virtual void predictMotion(float solverdt)
{ {
for (int i = 0; i < m_softBodySet.size(); ++i) for (int i = 0; i < m_softBodySet.size(); ++i)
@@ -192,78 +203,11 @@ public:
// TODO // TODO
} }
void VSolve_RContacts(btSoftBody* psb, btScalar kst, btScalar dt) virtual void setWorld(btDeformableRigidDynamicsWorld* world)
{ {
const btScalar mrg = psb->getCollisionShape()->getMargin(); m_world = world;
btMultiBodyJacobianData jacobianData; m_objective.setWorld(world);
for (int i = 0, ni = psb->m_rcontacts.size(); i < ni; ++i)
{
const btSoftBody::RContact& c = psb->m_rcontacts[i];
const btSoftBody::sCti& cti = c.m_cti;
if (cti.m_colObj->hasContactResponse())
{
btVector3 va(0, 0, 0);
btRigidBody* rigidCol = 0;
btMultiBodyLinkCollider* multibodyLinkCol = 0;
btScalar* deltaV;
if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
{
rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj);
va = rigidCol ? rigidCol->getVelocityInLocalPoint(c.m_c1) * dt : btVector3(0, 0, 0);
}
else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
{
multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
if (multibodyLinkCol)
{
const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
jacobianData.m_jacobians.resize(ndof);
jacobianData.m_deltaVelocitiesUnitImpulse.resize(ndof);
btScalar* jac = &jacobianData.m_jacobians[0];
multibodyLinkCol->m_multiBody->fillContactJacobianMultiDof(multibodyLinkCol->m_link, c.m_node->m_x, cti.m_normal, jac, jacobianData.scratch_r, jacobianData.scratch_v, jacobianData.scratch_m);
deltaV = &jacobianData.m_deltaVelocitiesUnitImpulse[0];
multibodyLinkCol->m_multiBody->calcAccelerationDeltasMultiDof(&jacobianData.m_jacobians[0], deltaV, jacobianData.scratch_r, jacobianData.scratch_v);
btScalar vel = 0.0;
for (int j = 0; j < ndof; ++j)
{
vel += multibodyLinkCol->m_multiBody->getVelocityVector()[j] * jac[j];
}
va = cti.m_normal * vel * dt;
}
}
const btVector3 vb = c.m_node->m_x - c.m_node->m_q;
const btVector3 vr = vb - va;
const btScalar dn = btDot(vr, cti.m_normal);
if (dn <= SIMD_EPSILON)
{
const btScalar dp = btMin((btDot(c.m_node->m_x, cti.m_normal) + cti.m_offset), mrg);
const btVector3 fv = vr - (cti.m_normal * dn);
// c0 is the impulse matrix, c3 is 1 - the friction coefficient or 0, c4 is the contact hardness coefficient
const btVector3 impulse = c.m_c0 * ((vr - (fv * c.m_c3) + (cti.m_normal * (dp * c.m_c4))) * kst);
c.m_node->m_v -= impulse * c.m_c2 / dt;
if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
{
if (rigidCol)
rigidCol->applyImpulse(impulse, c.m_c1);
}
else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
{
if (multibodyLinkCol)
{
double multiplier = 0.5;
multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof(deltaV, -impulse.length() * multiplier);
}
}
}
}
}
} }
}; };
#endif /* btDeformableBodySolver_h */ #endif /* btDeformableBodySolver_h */

View File

@@ -18,12 +18,52 @@ void btDeformableRigidDynamicsWorld::internalSingleStepSimulation(btScalar timeS
{ {
btAssert("Solver initialization failed\n"); btAssert("Solver initialization failed\n");
} }
// from btDiscreteDynamicsWorld singleStepSimulation
if (0 != m_internalPreTickCallback)
{
(*m_internalPreTickCallback)(this, timeStep);
}
btSoftRigidDynamicsWorld::btDiscreteDynamicsWorld::internalSingleStepSimulation(timeStep); ///apply gravity, predict motion
btDiscreteDynamicsWorld::predictUnconstraintMotion(timeStep);
btDispatcherInfo& dispatchInfo = btSoftRigidDynamicsWorld::btDiscreteDynamicsWorld::getDispatchInfo();
dispatchInfo.m_timeStep = timeStep;
dispatchInfo.m_stepCount = 0;
dispatchInfo.m_debugDraw = btSoftRigidDynamicsWorld::btDiscreteDynamicsWorld::getDebugDrawer();
// only used in CCD
// createPredictiveContacts(timeStep);
///perform collision detection
btSoftRigidDynamicsWorld::btDiscreteDynamicsWorld::performDiscreteCollisionDetection();
btSoftRigidDynamicsWorld::btDiscreteDynamicsWorld::calculateSimulationIslands();
btSoftRigidDynamicsWorld::btDiscreteDynamicsWorld::getSolverInfo().m_timeStep = timeStep;
if (0 != m_internalTickCallback)
{
(*m_internalTickCallback)(this, timeStep);
}
// btSoftRigidDynamicsWorld::btDiscreteDynamicsWorld::internalSingleStepSimulation(timeStep);
///solve deformable bodies constraints ///solve deformable bodies constraints
solveDeformableBodiesConstraints(timeStep); solveDeformableBodiesConstraints(timeStep);
predictUnconstraintMotion(timeStep);
//integrate transforms
btSoftRigidDynamicsWorld::btDiscreteDynamicsWorld::integrateTransforms(timeStep);
///update vehicle simulation
btSoftRigidDynamicsWorld::btDiscreteDynamicsWorld::updateActions(timeStep);
btSoftRigidDynamicsWorld::btDiscreteDynamicsWorld::updateActivationState(timeStep);
///update soft bodies ///update soft bodies
m_deformableBodySolver->updateSoftBodies(); m_deformableBodySolver->updateSoftBodies();

View File

@@ -31,7 +31,6 @@ class btDeformableRigidDynamicsWorld : public btSoftRigidDynamicsWorld
///Solver classes that encapsulate multiple deformable bodies for solving ///Solver classes that encapsulate multiple deformable bodies for solving
btDeformableBodySolver* m_deformableBodySolver; btDeformableBodySolver* m_deformableBodySolver;
protected: protected:
virtual void internalSingleStepSimulation(btScalar timeStep); virtual void internalSingleStepSimulation(btScalar timeStep);
@@ -65,7 +64,7 @@ public:
virtual void predictUnconstraintMotion(btScalar timeStep) virtual void predictUnconstraintMotion(btScalar timeStep)
{ {
btDiscreteDynamicsWorld::predictUnconstraintMotion(timeStep); // btDiscreteDynamicsWorld::predictUnconstraintMotion(timeStep);
m_deformableBodySolver->predictMotion(float(timeStep)); m_deformableBodySolver->predictMotion(float(timeStep));
} }
// virtual void internalStepSingleStepSimulation(btScalar timeStep); // virtual void internalStepSingleStepSimulation(btScalar timeStep);