add contact constraint as projections in CG
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
80
src/BulletSoftBody/btCGProjection.h
Normal file
80
src/BulletSoftBody/btCGProjection.h
Normal 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 */
|
||||||
@@ -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));
|
||||||
|
|
||||||
|
|||||||
142
src/BulletSoftBody/btContactProjection.cpp
Normal file
142
src/BulletSoftBody/btContactProjection.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
src/BulletSoftBody/btContactProjection.h
Normal file
56
src/BulletSoftBody/btContactProjection.h
Normal 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 */
|
||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user