bullet: Sync with upstream 3.24

Remove upstreamed patch.
This commit is contained in:
Rémi Verschelde 2022-05-17 00:02:51 +02:00
parent 4a96db7196
commit 7515b47e8e
41 changed files with 3287 additions and 182 deletions

View File

@ -152,6 +152,7 @@ if env["builtin_bullet"]:
"BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.cpp", "BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.cpp",
"BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp", "BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp",
"BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp", "BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp",
"BulletDynamics/Featherstone/btMultiBodySphericalJointLimit.cpp",
"BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp", "BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp",
"BulletDynamics/MLCPSolvers/btDantzigLCP.cpp", "BulletDynamics/MLCPSolvers/btDantzigLCP.cpp",
"BulletDynamics/MLCPSolvers/btMLCPSolver.cpp", "BulletDynamics/MLCPSolvers/btMLCPSolver.cpp",
@ -177,6 +178,10 @@ if env["builtin_bullet"]:
"BulletSoftBody/btDeformableContactProjection.cpp", "BulletSoftBody/btDeformableContactProjection.cpp",
"BulletSoftBody/btDeformableMultiBodyDynamicsWorld.cpp", "BulletSoftBody/btDeformableMultiBodyDynamicsWorld.cpp",
"BulletSoftBody/btDeformableContactConstraint.cpp", "BulletSoftBody/btDeformableContactConstraint.cpp",
"BulletSoftBody/BulletReducedDeformableBody/btReducedDeformableBody.cpp",
"BulletSoftBody/BulletReducedDeformableBody/btReducedDeformableBodyHelpers.cpp",
"BulletSoftBody/BulletReducedDeformableBody/btReducedDeformableBodySolver.cpp",
"BulletSoftBody/BulletReducedDeformableBody/btReducedDeformableContactConstraint.cpp",
"BulletSoftBody/poly34.cpp", "BulletSoftBody/poly34.cpp",
# clew # clew
"clew/clew.c", "clew/clew.c",

View File

@ -20,7 +20,7 @@ Files extracted from upstream source:
## bullet ## bullet
- Upstream: https://github.com/bulletphysics/bullet3 - Upstream: https://github.com/bulletphysics/bullet3
- Version: 3.21 (6a59241074720e9df119f2f86bc01765917feb1e, 2021) - Version: 3.24 (7dee3436e747958e7088dfdcea0e4ae031ce619e, 2022)
- License: zlib - License: zlib
Files extracted from upstream source: Files extracted from upstream source:

View File

@ -135,7 +135,11 @@ public:
int otherSize = otherArray.size(); int otherSize = otherArray.size();
resize(otherSize); resize(otherSize);
otherArray.copy(0, otherSize, m_data); //don't use otherArray.copy, it can leak memory
for (int i = 0; i < otherSize; i++)
{
m_data[i] = otherArray[i];
}
} }
/// return the number of elements in the array /// return the number of elements in the array
@ -506,7 +510,11 @@ public:
{ {
int otherSize = otherArray.size(); int otherSize = otherArray.size();
resize(otherSize); resize(otherSize);
otherArray.copy(0, otherSize, m_data); //don't use otherArray.copy, it can leak memory
for (int i = 0; i < otherSize; i++)
{
m_data[i] = otherArray[i];
}
} }
void removeAtIndex(int index) void removeAtIndex(int index)

View File

@ -198,7 +198,6 @@ void btCollisionWorld::updateAabbs()
{ {
BT_PROFILE("updateAabbs"); BT_PROFILE("updateAabbs");
btTransform predictedTrans;
for (int i = 0; i < m_collisionObjects.size(); i++) for (int i = 0; i < m_collisionObjects.size(); i++)
{ {
btCollisionObject* colObj = m_collisionObjects[i]; btCollisionObject* colObj = m_collisionObjects[i];

View File

@ -103,6 +103,44 @@ void btConvexTriangleCallback::processTriangle(btVector3* triangle, int partId,
if (m_convexBodyWrap->getCollisionShape()->isConvex()) if (m_convexBodyWrap->getCollisionShape()->isConvex())
{ {
#ifndef BT_DISABLE_CONVEX_CONCAVE_EARLY_OUT
//an early out optimisation if the object is separated from the triangle
//projected on the triangle normal)
{
const btVector3 v0 = m_triBodyWrap->getWorldTransform()*triangle[0];
const btVector3 v1 = m_triBodyWrap->getWorldTransform()*triangle[1];
const btVector3 v2 = m_triBodyWrap->getWorldTransform()*triangle[2];
btVector3 triangle_normal_world = ( v1 - v0).cross(v2 - v0);
triangle_normal_world.normalize();
btConvexShape* convex = (btConvexShape*)m_convexBodyWrap->getCollisionShape();
btVector3 localPt = convex->localGetSupportingVertex(m_convexBodyWrap->getWorldTransform().getBasis().inverse()*triangle_normal_world);
btVector3 worldPt = m_convexBodyWrap->getWorldTransform()*localPt;
//now check if this is fully on one side of the triangle
btScalar proj_distPt = triangle_normal_world.dot(worldPt);
btScalar proj_distTr = triangle_normal_world.dot(v0);
btScalar contact_threshold = m_manifoldPtr->getContactBreakingThreshold()+ m_resultOut->m_closestPointDistanceThreshold;
btScalar dist = proj_distTr - proj_distPt;
if (dist > contact_threshold)
return;
//also check the other side of the triangle
triangle_normal_world*=-1;
localPt = convex->localGetSupportingVertex(m_convexBodyWrap->getWorldTransform().getBasis().inverse()*triangle_normal_world);
worldPt = m_convexBodyWrap->getWorldTransform()*localPt;
//now check if this is fully on one side of the triangle
proj_distPt = triangle_normal_world.dot(worldPt);
proj_distTr = triangle_normal_world.dot(v0);
dist = proj_distTr - proj_distPt;
if (dist > contact_threshold)
return;
}
#endif //BT_DISABLE_CONVEX_CONCAVE_EARLY_OUT
btTriangleShape tm(triangle[0], triangle[1], triangle[2]); btTriangleShape tm(triangle[0], triangle[1], triangle[2]);
tm.setMargin(m_collisionMarginTriangle); tm.setMargin(m_collisionMarginTriangle);
@ -132,7 +170,10 @@ void btConvexTriangleCallback::processTriangle(btVector3* triangle, int partId,
m_resultOut->setShapeIdentifiersB(partId, triangleIndex); m_resultOut->setShapeIdentifiersB(partId, triangleIndex);
} }
{
BT_PROFILE("processCollision (GJK?)");
colAlgo->processCollision(m_convexBodyWrap, &triObWrap, *m_dispatchInfoPtr, m_resultOut); colAlgo->processCollision(m_convexBodyWrap, &triObWrap, *m_dispatchInfoPtr, m_resultOut);
}
if (m_resultOut->getBody0Internal() == m_triBodyWrap->getCollisionObject()) if (m_resultOut->getBody0Internal() == m_triBodyWrap->getCollisionObject())
{ {

View File

@ -25,6 +25,7 @@ subject to the following restrictions:
ATTRIBUTE_ALIGNED16(class) ATTRIBUTE_ALIGNED16(class)
btConvexHullShape : public btPolyhedralConvexAabbCachingShape btConvexHullShape : public btPolyhedralConvexAabbCachingShape
{ {
protected:
btAlignedObjectArray<btVector3> m_unscaledPoints; btAlignedObjectArray<btVector3> m_unscaledPoints;
public: public:

View File

@ -43,6 +43,9 @@ public:
void setTransformB(const btTransform& transB) { m_transB = transB; } void setTransformB(const btTransform& transB) { m_transB = transB; }
const btTransform& getTransformA() const { return m_transA; } const btTransform& getTransformA() const { return m_transA; }
const btTransform& getTransformB() const { return m_transB; }
// keep this for backward compatibility
const btTransform& GetTransformB() const { return m_transB; } const btTransform& GetTransformB() const { return m_transB; }
virtual btScalar getMargin() const; virtual btScalar getMargin() const;

View File

@ -902,8 +902,8 @@ void btDiscreteDynamicsWorld::createPredictiveContactsInternal(btRigidBody** bod
btVector3 distVec = (predictedTrans.getOrigin() - body->getWorldTransform().getOrigin()) * sweepResults.m_closestHitFraction; btVector3 distVec = (predictedTrans.getOrigin() - body->getWorldTransform().getOrigin()) * sweepResults.m_closestHitFraction;
btScalar distance = distVec.dot(-sweepResults.m_hitNormalWorld); btScalar distance = distVec.dot(-sweepResults.m_hitNormalWorld);
btPersistentManifold* manifold = m_dispatcher1->getNewManifold(body, sweepResults.m_hitCollisionObject);
btMutexLock(&m_predictiveManifoldsMutex); btMutexLock(&m_predictiveManifoldsMutex);
btPersistentManifold* manifold = m_dispatcher1->getNewManifold(body, sweepResults.m_hitCollisionObject);
m_predictiveManifolds.push_back(manifold); m_predictiveManifolds.push_back(manifold);
btMutexUnlock(&m_predictiveManifoldsMutex); btMutexUnlock(&m_predictiveManifoldsMutex);

View File

@ -31,7 +31,7 @@ enum btTypedMultiBodyConstraintType
MULTIBODY_CONSTRAINT_SLIDER, MULTIBODY_CONSTRAINT_SLIDER,
MULTIBODY_CONSTRAINT_SPHERICAL_MOTOR, MULTIBODY_CONSTRAINT_SPHERICAL_MOTOR,
MULTIBODY_CONSTRAINT_FIXED, MULTIBODY_CONSTRAINT_FIXED,
MULTIBODY_CONSTRAINT_SPHERICAL_LIMIT,
MAX_MULTIBODY_CONSTRAINT_TYPE, MAX_MULTIBODY_CONSTRAINT_TYPE,
}; };

View File

@ -0,0 +1,270 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2018 Erwin Coumans http://bulletphysics.org
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.
*/
///This file was written by Erwin Coumans
#include "btMultiBodySphericalJointLimit.h"
#include "btMultiBody.h"
#include "btMultiBodyLinkCollider.h"
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "LinearMath/btTransformUtil.h"
#include "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h"
#include "LinearMath/btIDebugDraw.h"
btMultiBodySphericalJointLimit::btMultiBodySphericalJointLimit(btMultiBody* body, int link,
btScalar swingxRange,
btScalar swingyRange,
btScalar twistRange,
btScalar maxAppliedImpulse)
: btMultiBodyConstraint(body, body, link, body->getLink(link).m_parent, 3, true, MULTIBODY_CONSTRAINT_SPHERICAL_LIMIT),
m_desiredVelocity(0, 0, 0),
m_desiredPosition(0,0,0,1),
m_use_multi_dof_params(false),
m_kd(1., 1., 1.),
m_kp(0.2, 0.2, 0.2),
m_erp(1),
m_rhsClamp(SIMD_INFINITY),
m_maxAppliedImpulseMultiDof(maxAppliedImpulse, maxAppliedImpulse, maxAppliedImpulse),
m_pivotA(m_bodyA->getLink(link).m_eVector),
m_pivotB(m_bodyB->getLink(link).m_eVector),
m_swingxRange(swingxRange),
m_swingyRange(swingyRange),
m_twistRange(twistRange)
{
m_maxAppliedImpulse = maxAppliedImpulse;
}
void btMultiBodySphericalJointLimit::finalizeMultiDof()
{
allocateJacobiansMultiDof();
// note: we rely on the fact that data.m_jacobians are
// always initialized to zero by the Constraint ctor
int linkDoF = 0;
unsigned int offset = 6 + (m_bodyA->getLink(m_linkA).m_dofOffset + linkDoF);
// row 0: the lower bound
// row 0: the lower bound
jacobianA(0)[offset] = 1;
jacobianB(1)[offset] = -1;
m_numDofsFinalized = m_jacSizeBoth;
}
btMultiBodySphericalJointLimit::~btMultiBodySphericalJointLimit()
{
}
int btMultiBodySphericalJointLimit::getIslandIdA() const
{
if (this->m_linkA < 0)
{
btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
if (col)
return col->getIslandTag();
}
else
{
if (m_bodyA->getLink(m_linkA).m_collider)
{
return m_bodyA->getLink(m_linkA).m_collider->getIslandTag();
}
}
return -1;
}
int btMultiBodySphericalJointLimit::getIslandIdB() const
{
if (m_linkB < 0)
{
btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
if (col)
return col->getIslandTag();
}
else
{
if (m_bodyB->getLink(m_linkB).m_collider)
{
return m_bodyB->getLink(m_linkB).m_collider->getIslandTag();
}
}
return -1;
}
void btMultiBodySphericalJointLimit::createConstraintRows(btMultiBodyConstraintArray& constraintRows,
btMultiBodyJacobianData& data,
const btContactSolverInfo& infoGlobal)
{
// only positions need to be updated -- data.m_jacobians and force
// directions were set in the ctor and never change.
if (m_numDofsFinalized != m_jacSizeBoth)
{
finalizeMultiDof();
}
//don't crash
if (m_numDofsFinalized != m_jacSizeBoth)
return;
if (m_maxAppliedImpulse == 0.f)
return;
const btScalar posError = 0;
const btVector3 zero(0, 0, 0);
btVector3 axis[3] = { btVector3(1, 0, 0), btVector3(0, 1, 0), btVector3(0, 0, 1) };
btQuaternion currentQuat(m_bodyA->getJointPosMultiDof(m_linkA)[0],
m_bodyA->getJointPosMultiDof(m_linkA)[1],
m_bodyA->getJointPosMultiDof(m_linkA)[2],
m_bodyA->getJointPosMultiDof(m_linkA)[3]);
btQuaternion refQuat = m_desiredPosition;
btVector3 vTwist(0,0,1);
btVector3 vConeNoTwist = quatRotate(currentQuat, vTwist);
vConeNoTwist.normalize();
btQuaternion qABCone = shortestArcQuat(vTwist, vConeNoTwist);
qABCone.normalize();
btQuaternion qABTwist = qABCone.inverse() * currentQuat;
qABTwist.normalize();
btQuaternion desiredQuat = qABTwist;
btQuaternion relRot = currentQuat.inverse() * desiredQuat;
btVector3 angleDiff;
btGeneric6DofSpring2Constraint::matrixToEulerXYZ(btMatrix3x3(relRot), angleDiff);
btScalar limitRanges[3] = {m_swingxRange, m_swingyRange, m_twistRange};
/// twist axis/angle
btQuaternion qMinTwist = qABTwist;
btScalar twistAngle = qABTwist.getAngle();
if (twistAngle > SIMD_PI) // long way around. flip quat and recalculate.
{
qMinTwist = -(qABTwist);
twistAngle = qMinTwist.getAngle();
}
btVector3 vTwistAxis = btVector3(qMinTwist.x(), qMinTwist.y(), qMinTwist.z());
if (twistAngle > SIMD_EPSILON)
vTwistAxis.normalize();
if (vTwistAxis.dot(vTwist)<0)
twistAngle*=-1.;
angleDiff[2] = twistAngle;
for (int row = 0; row < getNumRows(); row++)
{
btScalar allowed = limitRanges[row];
btScalar damp = 1;
if((angleDiff[row]>-allowed)&&(angleDiff[row]<allowed))
{
angleDiff[row]=0;
damp=0;
} else
{
if (angleDiff[row]>allowed)
{
angleDiff[row]-=allowed;
}
if (angleDiff[row]<-allowed)
{
angleDiff[row]+=allowed;
}
}
int dof = row;
btScalar currentVelocity = m_bodyA->getJointVelMultiDof(m_linkA)[dof];
btScalar desiredVelocity = this->m_desiredVelocity[row];
double kd = m_use_multi_dof_params ? m_kd[row % 3] : m_kd[0];
btScalar velocityError = (desiredVelocity - currentVelocity) * kd;
btMatrix3x3 frameAworld;
frameAworld.setIdentity();
frameAworld = m_bodyA->localFrameToWorld(m_linkA, frameAworld);
btScalar posError = 0;
{
btAssert(m_bodyA->getLink(m_linkA).m_jointType == btMultibodyLink::eSpherical);
switch (m_bodyA->getLink(m_linkA).m_jointType)
{
case btMultibodyLink::eSpherical:
{
btVector3 constraintNormalAng = frameAworld.getColumn(row % 3);
double kp = m_use_multi_dof_params ? m_kp[row % 3] : m_kp[0];
posError = kp*angleDiff[row % 3];
double max_applied_impulse = m_use_multi_dof_params ? m_maxAppliedImpulseMultiDof[row % 3] : m_maxAppliedImpulse;
//should multiply by time step
//max_applied_impulse *= infoGlobal.m_timeStep
double min_applied_impulse = -max_applied_impulse;
if (posError>0)
max_applied_impulse=0;
else
min_applied_impulse=0;
if (btFabs(posError)>SIMD_EPSILON)
{
btMultiBodySolverConstraint& constraintRow = constraintRows.expandNonInitializing();
fillMultiBodyConstraint(constraintRow, data, 0, 0, constraintNormalAng,
zero, zero, zero,//pure angular, so zero out linear parts
posError,
infoGlobal,
min_applied_impulse, max_applied_impulse, true,
1.0, false, 0, 0,
damp);
constraintRow.m_orgConstraint = this;
constraintRow.m_orgDofIndex = row;
}
break;
}
default:
{
btAssert(0);
}
};
}
}
}
void btMultiBodySphericalJointLimit::debugDraw(class btIDebugDraw* drawer)
{
btTransform tr;
tr.setIdentity();
if (m_bodyB)
{
btVector3 pivotBworld = m_bodyB->localPosToWorld(m_linkB, m_pivotB);
tr.setOrigin(pivotBworld);
drawer->drawTransform(tr, 0.1);
}
}

View File

@ -0,0 +1,115 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2018 Erwin Coumans http://bulletphysics.org
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.
*/
///This file was written by Erwin Coumans
#ifndef BT_MULTIBODY_SPHERICAL_JOINT_LIMIT_H
#define BT_MULTIBODY_SPHERICAL_JOINT_LIMIT_H
#include "btMultiBodyConstraint.h"
struct btSolverInfo;
class btMultiBodySphericalJointLimit : public btMultiBodyConstraint
{
protected:
btVector3 m_desiredVelocity;
btQuaternion m_desiredPosition;
bool m_use_multi_dof_params;
btVector3 m_kd;
btVector3 m_kp;
btScalar m_erp;
btScalar m_rhsClamp; //maximum error
btVector3 m_maxAppliedImpulseMultiDof;
btVector3 m_pivotA;
btVector3 m_pivotB;
btScalar m_swingxRange;
btScalar m_swingyRange;
btScalar m_twistRange;
public:
btMultiBodySphericalJointLimit(btMultiBody* body, int link,
btScalar swingxRange,
btScalar swingyRange,
btScalar twistRange,
btScalar maxAppliedImpulse);
virtual ~btMultiBodySphericalJointLimit();
virtual void finalizeMultiDof();
virtual int getIslandIdA() const;
virtual int getIslandIdB() const;
virtual void createConstraintRows(btMultiBodyConstraintArray& constraintRows,
btMultiBodyJacobianData& data,
const btContactSolverInfo& infoGlobal);
virtual void setVelocityTarget(const btVector3& velTarget, btScalar kd = 1.0)
{
m_desiredVelocity = velTarget;
m_kd = btVector3(kd, kd, kd);
m_use_multi_dof_params = false;
}
virtual void setVelocityTargetMultiDof(const btVector3& velTarget, const btVector3& kd = btVector3(1.0, 1.0, 1.0))
{
m_desiredVelocity = velTarget;
m_kd = kd;
m_use_multi_dof_params = true;
}
virtual void setPositionTarget(const btQuaternion& posTarget, btScalar kp =1.f)
{
m_desiredPosition = posTarget;
m_kp = btVector3(kp, kp, kp);
m_use_multi_dof_params = false;
}
virtual void setPositionTargetMultiDof(const btQuaternion& posTarget, const btVector3& kp = btVector3(1.f, 1.f, 1.f))
{
m_desiredPosition = posTarget;
m_kp = kp;
m_use_multi_dof_params = true;
}
virtual void setErp(btScalar erp)
{
m_erp = erp;
}
virtual btScalar getErp() const
{
return m_erp;
}
virtual void setRhsClamp(btScalar rhsClamp)
{
m_rhsClamp = rhsClamp;
}
btScalar getMaxAppliedImpulseMultiDof(int i) const
{
return m_maxAppliedImpulseMultiDof[i];
}
void setMaxAppliedImpulseMultiDof(const btVector3& maxImp)
{
m_maxAppliedImpulseMultiDof = maxImp;
m_use_multi_dof_params = true;
}
virtual void debugDraw(class btIDebugDraw* drawer);
};
#endif //BT_MULTIBODY_SPHERICAL_JOINT_LIMIT_H

View File

@ -503,8 +503,8 @@ vec3 rpyFromMatrix(const mat33 &rot)
{ {
vec3 rpy; vec3 rpy;
rpy(2) = BT_ID_ATAN2(-rot(1, 0), rot(0, 0)); rpy(2) = BT_ID_ATAN2(-rot(1, 0), rot(0, 0));
rpy(1) = BT_ID_ATAN2(rot(2, 0), BT_ID_COS(rpy(2)) * rot(0, 0) - BT_ID_SIN(rpy(0)) * rot(1, 0));
rpy(0) = BT_ID_ATAN2(-rot(2, 0), rot(2, 2)); rpy(0) = BT_ID_ATAN2(-rot(2, 0), rot(2, 2));
rpy(1) = BT_ID_ATAN2(rot(2, 0), BT_ID_COS(rpy(2)) * rot(0, 0) - BT_ID_SIN(rpy(0)) * rot(1, 0));
return rpy; return rpy;
} }
} // namespace btInverseDynamics } // namespace btInverseDynamics

View File

@ -0,0 +1,792 @@
#include "btReducedDeformableBody.h"
#include "../btSoftBodyInternals.h"
#include "btReducedDeformableBodyHelpers.h"
#include "LinearMath/btTransformUtil.h"
#include <iostream>
#include <fstream>
btReducedDeformableBody::btReducedDeformableBody(btSoftBodyWorldInfo* worldInfo, int node_count, const btVector3* x, const btScalar* m)
: btSoftBody(worldInfo, node_count, x, m), m_rigidOnly(false)
{
// reduced deformable
m_reducedModel = true;
m_nReduced = 0;
m_nFull = 0;
m_nodeIndexOffset = 0;
m_transform_lock = false;
m_ksScale = 1.0;
m_rhoScale = 1.0;
// rigid motion
m_linearVelocity.setZero();
m_angularVelocity.setZero();
m_internalDeltaLinearVelocity.setZero();
m_internalDeltaAngularVelocity.setZero();
m_angularVelocityFromReduced.setZero();
m_internalDeltaAngularVelocityFromReduced.setZero();
m_angularFactor.setValue(1, 1, 1);
m_linearFactor.setValue(1, 1, 1);
// m_invInertiaLocal.setValue(1, 1, 1);
m_invInertiaLocal.setIdentity();
m_mass = 0.0;
m_inverseMass = 0.0;
m_linearDamping = 0;
m_angularDamping = 0;
// Rayleigh damping
m_dampingAlpha = 0;
m_dampingBeta = 0;
m_rigidTransformWorld.setIdentity();
}
void btReducedDeformableBody::setReducedModes(int num_modes, int full_size)
{
m_nReduced = num_modes;
m_nFull = full_size;
m_reducedDofs.resize(m_nReduced, 0);
m_reducedDofsBuffer.resize(m_nReduced, 0);
m_reducedVelocity.resize(m_nReduced, 0);
m_reducedVelocityBuffer.resize(m_nReduced, 0);
m_reducedForceElastic.resize(m_nReduced, 0);
m_reducedForceDamping.resize(m_nReduced, 0);
m_reducedForceExternal.resize(m_nReduced, 0);
m_internalDeltaReducedVelocity.resize(m_nReduced, 0);
m_nodalMass.resize(full_size, 0);
m_localMomentArm.resize(m_nFull);
}
void btReducedDeformableBody::setMassProps(const tDenseArray& mass_array)
{
btScalar total_mass = 0;
btVector3 CoM(0, 0, 0);
for (int i = 0; i < m_nFull; ++i)
{
m_nodalMass[i] = m_rhoScale * mass_array[i];
m_nodes[i].m_im = mass_array[i] > 0 ? 1.0 / (m_rhoScale * mass_array[i]) : 0;
total_mass += m_rhoScale * mass_array[i];
CoM += m_nodalMass[i] * m_nodes[i].m_x;
}
// total rigid body mass
m_mass = total_mass;
m_inverseMass = total_mass > 0 ? 1.0 / total_mass : 0;
// original CoM
m_initialCoM = CoM / total_mass;
}
void btReducedDeformableBody::setInertiaProps()
{
// make sure the initial CoM is at the origin (0,0,0)
// for (int i = 0; i < m_nFull; ++i)
// {
// m_nodes[i].m_x -= m_initialCoM;
// }
// m_initialCoM.setZero();
m_rigidTransformWorld.setOrigin(m_initialCoM);
m_interpolationWorldTransform = m_rigidTransformWorld;
updateLocalInertiaTensorFromNodes();
// update world inertia tensor
btMatrix3x3 rotation;
rotation.setIdentity();
updateInitialInertiaTensor(rotation);
updateInertiaTensor();
m_interpolateInvInertiaTensorWorld = m_invInertiaTensorWorld;
}
void btReducedDeformableBody::setRigidVelocity(const btVector3& v)
{
m_linearVelocity = v;
}
void btReducedDeformableBody::setRigidAngularVelocity(const btVector3& omega)
{
m_angularVelocity = omega;
}
void btReducedDeformableBody::setStiffnessScale(const btScalar ks)
{
m_ksScale = ks;
}
void btReducedDeformableBody::setMassScale(const btScalar rho)
{
m_rhoScale = rho;
}
void btReducedDeformableBody::setFixedNodes(const int n_node)
{
m_fixedNodes.push_back(n_node);
m_nodes[n_node].m_im = 0; // set inverse mass to be zero for the constraint solver.
}
void btReducedDeformableBody::setDamping(const btScalar alpha, const btScalar beta)
{
m_dampingAlpha = alpha;
m_dampingBeta = beta;
}
void btReducedDeformableBody::internalInitialization()
{
// zeroing
endOfTimeStepZeroing();
// initialize rest position
updateRestNodalPositions();
// initialize local nodal moment arm form the CoM
updateLocalMomentArm();
// initialize projection matrix
updateExternalForceProjectMatrix(false);
}
void btReducedDeformableBody::updateLocalMomentArm()
{
TVStack delta_x;
delta_x.resize(m_nFull);
for (int i = 0; i < m_nFull; ++i)
{
for (int k = 0; k < 3; ++k)
{
// compute displacement
delta_x[i][k] = 0;
for (int j = 0; j < m_nReduced; ++j)
{
delta_x[i][k] += m_modes[j][3 * i + k] * m_reducedDofs[j];
}
}
// get new moment arm Sq + x0
m_localMomentArm[i] = m_x0[i] - m_initialCoM + delta_x[i];
}
}
void btReducedDeformableBody::updateExternalForceProjectMatrix(bool initialized)
{
// if not initialized, need to compute both P_A and Cq
// otherwise, only need to udpate Cq
if (!initialized)
{
// resize
m_projPA.resize(m_nReduced);
m_projCq.resize(m_nReduced);
m_STP.resize(m_nReduced);
m_MrInvSTP.resize(m_nReduced);
// P_A
for (int r = 0; r < m_nReduced; ++r)
{
m_projPA[r].resize(3 * m_nFull, 0);
for (int i = 0; i < m_nFull; ++i)
{
btMatrix3x3 mass_scaled_i = Diagonal(1) - Diagonal(m_nodalMass[i] / m_mass);
btVector3 s_ri(m_modes[r][3 * i], m_modes[r][3 * i + 1], m_modes[r][3 * i + 2]);
btVector3 prod_i = mass_scaled_i * s_ri;
for (int k = 0; k < 3; ++k)
m_projPA[r][3 * i + k] = prod_i[k];
// btScalar ratio = m_nodalMass[i] / m_mass;
// m_projPA[r] += btVector3(- m_modes[r][3 * i] * ratio,
// - m_modes[r][3 * i + 1] * ratio,
// - m_modes[r][3 * i + 2] * ratio);
}
}
}
// C(q) is updated once per position update
for (int r = 0; r < m_nReduced; ++r)
{
m_projCq[r].resize(3 * m_nFull, 0);
for (int i = 0; i < m_nFull; ++i)
{
btMatrix3x3 r_star = Cross(m_localMomentArm[i]);
btVector3 s_ri(m_modes[r][3 * i], m_modes[r][3 * i + 1], m_modes[r][3 * i + 2]);
btVector3 prod_i = r_star * m_invInertiaTensorWorld * r_star * s_ri;
for (int k = 0; k < 3; ++k)
m_projCq[r][3 * i + k] = m_nodalMass[i] * prod_i[k];
// btVector3 si(m_modes[r][3 * i], m_modes[r][3 * i + 1], m_modes[r][3 * i + 2]);
// m_projCq[r] += m_nodalMass[i] * si.cross(m_localMomentArm[i]);
}
}
}
void btReducedDeformableBody::endOfTimeStepZeroing()
{
for (int i = 0; i < m_nReduced; ++i)
{
m_reducedForceElastic[i] = 0;
m_reducedForceDamping[i] = 0;
m_reducedForceExternal[i] = 0;
m_internalDeltaReducedVelocity[i] = 0;
m_reducedDofsBuffer[i] = m_reducedDofs[i];
m_reducedVelocityBuffer[i] = m_reducedVelocity[i];
}
// std::cout << "zeroed!\n";
}
void btReducedDeformableBody::applyInternalVelocityChanges()
{
m_linearVelocity += m_internalDeltaLinearVelocity;
m_angularVelocity += m_internalDeltaAngularVelocity;
m_internalDeltaLinearVelocity.setZero();
m_internalDeltaAngularVelocity.setZero();
for (int r = 0; r < m_nReduced; ++r)
{
m_reducedVelocity[r] += m_internalDeltaReducedVelocity[r];
m_internalDeltaReducedVelocity[r] = 0;
}
}
void btReducedDeformableBody::predictIntegratedTransform(btScalar dt, btTransform& predictedTransform)
{
btTransformUtil::integrateTransform(m_rigidTransformWorld, m_linearVelocity, m_angularVelocity, dt, predictedTransform);
}
void btReducedDeformableBody::updateReducedDofs(btScalar solverdt)
{
for (int r = 0; r < m_nReduced; ++r)
{
m_reducedDofs[r] = m_reducedDofsBuffer[r] + solverdt * m_reducedVelocity[r];
}
}
void btReducedDeformableBody::mapToFullPosition(const btTransform& ref_trans)
{
btVector3 origin = ref_trans.getOrigin();
btMatrix3x3 rotation = ref_trans.getBasis();
for (int i = 0; i < m_nFull; ++i)
{
m_nodes[i].m_x = rotation * m_localMomentArm[i] + origin;
m_nodes[i].m_q = m_nodes[i].m_x;
}
}
void btReducedDeformableBody::updateReducedVelocity(btScalar solverdt)
{
// update reduced velocity
for (int r = 0; r < m_nReduced; ++r)
{
// the reduced mass is always identity!
btScalar delta_v = 0;
delta_v = solverdt * (m_reducedForceElastic[r] + m_reducedForceDamping[r]);
// delta_v = solverdt * (m_reducedForceElastic[r] + m_reducedForceDamping[r] + m_reducedForceExternal[r]);
m_reducedVelocity[r] = m_reducedVelocityBuffer[r] + delta_v;
}
}
void btReducedDeformableBody::mapToFullVelocity(const btTransform& ref_trans)
{
// compute the reduced contribution to the angular velocity
// btVector3 sum_linear(0, 0, 0);
// btVector3 sum_angular(0, 0, 0);
// m_linearVelocityFromReduced.setZero();
// m_angularVelocityFromReduced.setZero();
// for (int i = 0; i < m_nFull; ++i)
// {
// btVector3 r_com = ref_trans.getBasis() * m_localMomentArm[i];
// btMatrix3x3 r_star = Cross(r_com);
// btVector3 v_from_reduced(0, 0, 0);
// for (int k = 0; k < 3; ++k)
// {
// for (int r = 0; r < m_nReduced; ++r)
// {
// v_from_reduced[k] += m_modes[r][3 * i + k] * m_reducedVelocity[r];
// }
// }
// btVector3 delta_linear = m_nodalMass[i] * v_from_reduced;
// btVector3 delta_angular = m_nodalMass[i] * (r_star * ref_trans.getBasis() * v_from_reduced);
// sum_linear += delta_linear;
// sum_angular += delta_angular;
// // std::cout << "delta_linear: " << delta_linear[0] << "\t" << delta_linear[1] << "\t" << delta_linear[2] << "\n";
// // std::cout << "delta_angular: " << delta_angular[0] << "\t" << delta_angular[1] << "\t" << delta_angular[2] << "\n";
// // std::cout << "sum_linear: " << sum_linear[0] << "\t" << sum_linear[1] << "\t" << sum_linear[2] << "\n";
// // std::cout << "sum_angular: " << sum_angular[0] << "\t" << sum_angular[1] << "\t" << sum_angular[2] << "\n";
// }
// m_linearVelocityFromReduced = 1.0 / m_mass * (ref_trans.getBasis() * sum_linear);
// m_angularVelocityFromReduced = m_interpolateInvInertiaTensorWorld * sum_angular;
// m_linearVelocity -= m_linearVelocityFromReduced;
// m_angularVelocity -= m_angularVelocityFromReduced;
for (int i = 0; i < m_nFull; ++i)
{
m_nodes[i].m_v = computeNodeFullVelocity(ref_trans, i);
}
}
const btVector3 btReducedDeformableBody::computeTotalAngularMomentum() const
{
btVector3 L_rigid = m_invInertiaTensorWorld.inverse() * m_angularVelocity;
btVector3 L_reduced(0, 0, 0);
btMatrix3x3 omega_prime_star = Cross(m_angularVelocityFromReduced);
for (int i = 0; i < m_nFull; ++i)
{
btVector3 r_com = m_rigidTransformWorld.getBasis() * m_localMomentArm[i];
btMatrix3x3 r_star = Cross(r_com);
btVector3 v_from_reduced(0, 0, 0);
for (int k = 0; k < 3; ++k)
{
for (int r = 0; r < m_nReduced; ++r)
{
v_from_reduced[k] += m_modes[r][3 * i + k] * m_reducedVelocity[r];
}
}
L_reduced += m_nodalMass[i] * (r_star * (m_rigidTransformWorld.getBasis() * v_from_reduced - omega_prime_star * r_com));
// L_reduced += m_nodalMass[i] * (r_star * (m_rigidTransformWorld.getBasis() * v_from_reduced));
}
return L_rigid + L_reduced;
}
const btVector3 btReducedDeformableBody::computeNodeFullVelocity(const btTransform& ref_trans, int n_node) const
{
btVector3 v_from_reduced(0, 0, 0);
btVector3 r_com = ref_trans.getBasis() * m_localMomentArm[n_node];
// compute velocity contributed by the reduced velocity
for (int k = 0; k < 3; ++k)
{
for (int r = 0; r < m_nReduced; ++r)
{
v_from_reduced[k] += m_modes[r][3 * n_node + k] * m_reducedVelocity[r];
}
}
// get new velocity
btVector3 vel = m_angularVelocity.cross(r_com) +
ref_trans.getBasis() * v_from_reduced +
m_linearVelocity;
return vel;
}
const btVector3 btReducedDeformableBody::internalComputeNodeDeltaVelocity(const btTransform& ref_trans, int n_node) const
{
btVector3 deltaV_from_reduced(0, 0, 0);
btVector3 r_com = ref_trans.getBasis() * m_localMomentArm[n_node];
// compute velocity contributed by the reduced velocity
for (int k = 0; k < 3; ++k)
{
for (int r = 0; r < m_nReduced; ++r)
{
deltaV_from_reduced[k] += m_modes[r][3 * n_node + k] * m_internalDeltaReducedVelocity[r];
}
}
// get delta velocity
btVector3 deltaV = m_internalDeltaAngularVelocity.cross(r_com) +
ref_trans.getBasis() * deltaV_from_reduced +
m_internalDeltaLinearVelocity;
return deltaV;
}
void btReducedDeformableBody::proceedToTransform(btScalar dt, bool end_of_time_step)
{
btTransformUtil::integrateTransform(m_rigidTransformWorld, m_linearVelocity, m_angularVelocity, dt, m_interpolationWorldTransform);
updateInertiaTensor();
// m_interpolateInvInertiaTensorWorld = m_interpolationWorldTransform.getBasis().scaled(m_invInertiaLocal) * m_interpolationWorldTransform.getBasis().transpose();
m_rigidTransformWorld = m_interpolationWorldTransform;
m_invInertiaTensorWorld = m_interpolateInvInertiaTensorWorld;
}
void btReducedDeformableBody::transformTo(const btTransform& trs)
{
btTransform current_transform = getRigidTransform();
btTransform new_transform(trs.getBasis() * current_transform.getBasis().transpose(),
trs.getOrigin() - current_transform.getOrigin());
transform(new_transform);
}
void btReducedDeformableBody::transform(const btTransform& trs)
{
m_transform_lock = true;
// transform mesh
{
const btScalar margin = getCollisionShape()->getMargin();
ATTRIBUTE_ALIGNED16(btDbvtVolume)
vol;
btVector3 CoM = m_rigidTransformWorld.getOrigin();
btVector3 translation = trs.getOrigin();
btMatrix3x3 rotation = trs.getBasis();
for (int i = 0; i < m_nodes.size(); ++i)
{
Node& n = m_nodes[i];
n.m_x = rotation * (n.m_x - CoM) + CoM + translation;
n.m_q = rotation * (n.m_q - CoM) + CoM + translation;
n.m_n = rotation * n.m_n;
vol = btDbvtVolume::FromCR(n.m_x, margin);
m_ndbvt.update(n.m_leaf, vol);
}
updateNormals();
updateBounds();
updateConstants();
}
// update modes
updateModesByRotation(trs.getBasis());
// update inertia tensor
updateInitialInertiaTensor(trs.getBasis());
updateInertiaTensor();
m_interpolateInvInertiaTensorWorld = m_invInertiaTensorWorld;
// update rigid frame (No need to update the rotation. Nodes have already been updated.)
m_rigidTransformWorld.setOrigin(m_initialCoM + trs.getOrigin());
m_interpolationWorldTransform = m_rigidTransformWorld;
m_initialCoM = m_rigidTransformWorld.getOrigin();
internalInitialization();
}
void btReducedDeformableBody::scale(const btVector3& scl)
{
// Scaling the mesh after transform is applied is not allowed
btAssert(!m_transform_lock);
// scale the mesh
{
const btScalar margin = getCollisionShape()->getMargin();
ATTRIBUTE_ALIGNED16(btDbvtVolume)
vol;
btVector3 CoM = m_rigidTransformWorld.getOrigin();
for (int i = 0; i < m_nodes.size(); ++i)
{
Node& n = m_nodes[i];
n.m_x = (n.m_x - CoM) * scl + CoM;
n.m_q = (n.m_q - CoM) * scl + CoM;
vol = btDbvtVolume::FromCR(n.m_x, margin);
m_ndbvt.update(n.m_leaf, vol);
}
updateNormals();
updateBounds();
updateConstants();
initializeDmInverse();
}
// update inertia tensor
updateLocalInertiaTensorFromNodes();
btMatrix3x3 id;
id.setIdentity();
updateInitialInertiaTensor(id); // there is no rotation, but the local inertia tensor has changed
updateInertiaTensor();
m_interpolateInvInertiaTensorWorld = m_invInertiaTensorWorld;
internalInitialization();
}
void btReducedDeformableBody::setTotalMass(btScalar mass, bool fromfaces)
{
// Changing the total mass after transform is applied is not allowed
btAssert(!m_transform_lock);
btScalar scale_ratio = mass / m_mass;
// update nodal mass
for (int i = 0; i < m_nFull; ++i)
{
m_nodalMass[i] *= scale_ratio;
}
m_mass = mass;
m_inverseMass = mass > 0 ? 1.0 / mass : 0;
// update inertia tensors
updateLocalInertiaTensorFromNodes();
btMatrix3x3 id;
id.setIdentity();
updateInitialInertiaTensor(id); // there is no rotation, but the local inertia tensor has changed
updateInertiaTensor();
m_interpolateInvInertiaTensorWorld = m_invInertiaTensorWorld;
internalInitialization();
}
void btReducedDeformableBody::updateRestNodalPositions()
{
// update reset nodal position
m_x0.resize(m_nFull);
for (int i = 0; i < m_nFull; ++i)
{
m_x0[i] = m_nodes[i].m_x;
}
}
// reference notes:
// https://ocw.mit.edu/courses/aeronautics-and-astronautics/16-07-dynamics-fall-2009/lecture-notes/MIT16_07F09_Lec26.pdf
void btReducedDeformableBody::updateLocalInertiaTensorFromNodes()
{
btMatrix3x3 inertia_tensor;
inertia_tensor.setZero();
for (int p = 0; p < m_nFull; ++p)
{
btMatrix3x3 particle_inertia;
particle_inertia.setZero();
btVector3 r = m_nodes[p].m_x - m_initialCoM;
particle_inertia[0][0] = m_nodalMass[p] * (r[1] * r[1] + r[2] * r[2]);
particle_inertia[1][1] = m_nodalMass[p] * (r[0] * r[0] + r[2] * r[2]);
particle_inertia[2][2] = m_nodalMass[p] * (r[0] * r[0] + r[1] * r[1]);
particle_inertia[0][1] = - m_nodalMass[p] * (r[0] * r[1]);
particle_inertia[0][2] = - m_nodalMass[p] * (r[0] * r[2]);
particle_inertia[1][2] = - m_nodalMass[p] * (r[1] * r[2]);
particle_inertia[1][0] = particle_inertia[0][1];
particle_inertia[2][0] = particle_inertia[0][2];
particle_inertia[2][1] = particle_inertia[1][2];
inertia_tensor += particle_inertia;
}
m_invInertiaLocal = inertia_tensor.inverse();
}
void btReducedDeformableBody::updateInitialInertiaTensor(const btMatrix3x3& rotation)
{
// m_invInertiaTensorWorldInitial = rotation.scaled(m_invInertiaLocal) * rotation.transpose();
m_invInertiaTensorWorldInitial = rotation * m_invInertiaLocal * rotation.transpose();
}
void btReducedDeformableBody::updateModesByRotation(const btMatrix3x3& rotation)
{
for (int r = 0; r < m_nReduced; ++r)
{
for (int i = 0; i < m_nFull; ++i)
{
btVector3 nodal_disp(m_modes[r][3 * i], m_modes[r][3 * i + 1], m_modes[r][3 * i + 2]);
nodal_disp = rotation * nodal_disp;
for (int k = 0; k < 3; ++k)
{
m_modes[r][3 * i + k] = nodal_disp[k];
}
}
}
}
void btReducedDeformableBody::updateInertiaTensor()
{
m_invInertiaTensorWorld = m_rigidTransformWorld.getBasis() * m_invInertiaTensorWorldInitial * m_rigidTransformWorld.getBasis().transpose();
}
void btReducedDeformableBody::applyDamping(btScalar timeStep)
{
m_linearVelocity *= btScalar(1) - m_linearDamping;
m_angularDamping *= btScalar(1) - m_angularDamping;
}
void btReducedDeformableBody::applyCentralImpulse(const btVector3& impulse)
{
m_linearVelocity += impulse * m_linearFactor * m_inverseMass;
#if defined(BT_CLAMP_VELOCITY_TO) && BT_CLAMP_VELOCITY_TO > 0
clampVelocity(m_linearVelocity);
#endif
}
void btReducedDeformableBody::applyTorqueImpulse(const btVector3& torque)
{
m_angularVelocity += m_interpolateInvInertiaTensorWorld * torque * m_angularFactor;
#if defined(BT_CLAMP_VELOCITY_TO) && BT_CLAMP_VELOCITY_TO > 0
clampVelocity(m_angularVelocity);
#endif
}
void btReducedDeformableBody::internalApplyRigidImpulse(const btVector3& impulse, const btVector3& rel_pos)
{
if (m_inverseMass == btScalar(0.))
{
std::cout << "something went wrong...probably didn't initialize?\n";
btAssert(false);
}
// delta linear velocity
m_internalDeltaLinearVelocity += impulse * m_linearFactor * m_inverseMass;
// delta angular velocity
btVector3 torque = rel_pos.cross(impulse * m_linearFactor);
m_internalDeltaAngularVelocity += m_interpolateInvInertiaTensorWorld * torque * m_angularFactor;
}
btVector3 btReducedDeformableBody::getRelativePos(int n_node)
{
btMatrix3x3 rotation = m_interpolationWorldTransform.getBasis();
btVector3 ri = rotation * m_localMomentArm[n_node];
return ri;
}
btMatrix3x3 btReducedDeformableBody::getImpulseFactor(int n_node)
{
// relative position
btMatrix3x3 rotation = m_interpolationWorldTransform.getBasis();
btVector3 ri = rotation * m_localMomentArm[n_node];
btMatrix3x3 ri_skew = Cross(ri);
// calculate impulse factor
// rigid part
btScalar inv_mass = m_nodalMass[n_node] > btScalar(0) ? btScalar(1) / m_mass : btScalar(0);
btMatrix3x3 K1 = Diagonal(inv_mass);
K1 -= ri_skew * m_interpolateInvInertiaTensorWorld * ri_skew;
// reduced deformable part
btMatrix3x3 SA;
SA.setZero();
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
for (int r = 0; r < m_nReduced; ++r)
{
SA[i][j] += m_modes[r][3 * n_node + i] * (m_projPA[r][3 * n_node + j] + m_projCq[r][3 * n_node + j]);
}
}
}
btMatrix3x3 RSARinv = rotation * SA * rotation.transpose();
TVStack omega_helper; // Sum_i m_i r*_i R S_i
omega_helper.resize(m_nReduced);
for (int r = 0; r < m_nReduced; ++r)
{
omega_helper[r].setZero();
for (int i = 0; i < m_nFull; ++i)
{
btMatrix3x3 mi_rstar_i = rotation * Cross(m_localMomentArm[i]) * m_nodalMass[i];
btVector3 s_ri(m_modes[r][3 * i], m_modes[r][3 * i + 1], m_modes[r][3 * i + 2]);
omega_helper[r] += mi_rstar_i * rotation * s_ri;
}
}
btMatrix3x3 sum_multiply_A;
sum_multiply_A.setZero();
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
for (int r = 0; r < m_nReduced; ++r)
{
sum_multiply_A[i][j] += omega_helper[r][i] * (m_projPA[r][3 * n_node + j] + m_projCq[r][3 * n_node + j]);
}
}
}
btMatrix3x3 K2 = RSARinv + ri_skew * m_interpolateInvInertiaTensorWorld * sum_multiply_A * rotation.transpose();
return m_rigidOnly ? K1 : K1 + K2;
}
void btReducedDeformableBody::internalApplyFullSpaceImpulse(const btVector3& impulse, const btVector3& rel_pos, int n_node, btScalar dt)
{
if (!m_rigidOnly)
{
// apply impulse force
applyFullSpaceNodalForce(impulse / dt, n_node);
// update delta damping force
tDenseArray reduced_vel_tmp;
reduced_vel_tmp.resize(m_nReduced);
for (int r = 0; r < m_nReduced; ++r)
{
reduced_vel_tmp[r] = m_reducedVelocity[r] + m_internalDeltaReducedVelocity[r];
}
applyReducedDampingForce(reduced_vel_tmp);
// applyReducedDampingForce(m_internalDeltaReducedVelocity);
// delta reduced velocity
for (int r = 0; r < m_nReduced; ++r)
{
// The reduced mass is always identity!
m_internalDeltaReducedVelocity[r] += dt * (m_reducedForceDamping[r] + m_reducedForceExternal[r]);
}
}
internalApplyRigidImpulse(impulse, rel_pos);
}
void btReducedDeformableBody::applyFullSpaceNodalForce(const btVector3& f_ext, int n_node)
{
// f_local = R^-1 * f_ext //TODO: interpoalted transfrom
// btVector3 f_local = m_rigidTransformWorld.getBasis().transpose() * f_ext;
btVector3 f_local = m_interpolationWorldTransform.getBasis().transpose() * f_ext;
// f_ext_r = [S^T * P]_{n_node} * f_local
tDenseArray f_ext_r;
f_ext_r.resize(m_nReduced, 0);
for (int r = 0; r < m_nReduced; ++r)
{
m_reducedForceExternal[r] = 0;
for (int k = 0; k < 3; ++k)
{
f_ext_r[r] += (m_projPA[r][3 * n_node + k] + m_projCq[r][3 * n_node + k]) * f_local[k];
}
m_reducedForceExternal[r] += f_ext_r[r];
}
}
void btReducedDeformableBody::applyRigidGravity(const btVector3& gravity, btScalar dt)
{
// update rigid frame velocity
m_linearVelocity += dt * gravity;
}
void btReducedDeformableBody::applyReducedElasticForce(const tDenseArray& reduce_dofs)
{
for (int r = 0; r < m_nReduced; ++r)
{
m_reducedForceElastic[r] = - m_ksScale * m_Kr[r] * reduce_dofs[r];
}
}
void btReducedDeformableBody::applyReducedDampingForce(const tDenseArray& reduce_vel)
{
for (int r = 0; r < m_nReduced; ++r)
{
m_reducedForceDamping[r] = - m_dampingBeta * m_ksScale * m_Kr[r] * reduce_vel[r];
}
}
btScalar btReducedDeformableBody::getTotalMass() const
{
return m_mass;
}
btTransform& btReducedDeformableBody::getRigidTransform()
{
return m_rigidTransformWorld;
}
const btVector3& btReducedDeformableBody::getLinearVelocity() const
{
return m_linearVelocity;
}
const btVector3& btReducedDeformableBody::getAngularVelocity() const
{
return m_angularVelocity;
}
void btReducedDeformableBody::disableReducedModes(const bool rigid_only)
{
m_rigidOnly = rigid_only;
}
bool btReducedDeformableBody::isReducedModesOFF() const
{
return m_rigidOnly;
}

View File

@ -0,0 +1,257 @@
#ifndef BT_REDUCED_SOFT_BODY_H
#define BT_REDUCED_SOFT_BODY_H
#include "../btSoftBody.h"
#include "LinearMath/btAlignedObjectArray.h"
#include "LinearMath/btVector3.h"
#include "LinearMath/btMatrix3x3.h"
#include "LinearMath/btTransform.h"
// Reduced deformable body is a simplified deformable object embedded in a rigid frame.
class btReducedDeformableBody : public btSoftBody
{
public:
//
// Typedefs
//
typedef btAlignedObjectArray<btVector3> TVStack;
// typedef btAlignedObjectArray<btMatrix3x3> tBlockDiagMatrix;
typedef btAlignedObjectArray<btScalar> tDenseArray;
typedef btAlignedObjectArray<btAlignedObjectArray<btScalar> > tDenseMatrix;
private:
// flag to turn off the reduced modes
bool m_rigidOnly;
// Flags for transform. Once transform is applied, users cannot scale the mesh or change its total mass.
bool m_transform_lock;
// scaling factors
btScalar m_rhoScale; // mass density scale
btScalar m_ksScale; // stiffness scale
// projection matrix
tDenseMatrix m_projPA; // Eqn. 4.11 from Rahul Sheth's thesis
tDenseMatrix m_projCq;
tDenseArray m_STP;
tDenseArray m_MrInvSTP;
TVStack m_localMomentArm; // Sq + x0
btVector3 m_internalDeltaLinearVelocity;
btVector3 m_internalDeltaAngularVelocity;
tDenseArray m_internalDeltaReducedVelocity;
btVector3 m_linearVelocityFromReduced; // contribution to the linear velocity from reduced velocity
btVector3 m_angularVelocityFromReduced; // contribution to the angular velocity from reduced velocity
btVector3 m_internalDeltaAngularVelocityFromReduced;
protected:
// rigid frame
btScalar m_mass; // total mass of the rigid frame
btScalar m_inverseMass; // inverse of the total mass of the rigid frame
btVector3 m_linearVelocity;
btVector3 m_angularVelocity;
btScalar m_linearDamping; // linear damping coefficient
btScalar m_angularDamping; // angular damping coefficient
btVector3 m_linearFactor;
btVector3 m_angularFactor;
// btVector3 m_invInertiaLocal;
btMatrix3x3 m_invInertiaLocal;
btTransform m_rigidTransformWorld;
btMatrix3x3 m_invInertiaTensorWorldInitial;
btMatrix3x3 m_invInertiaTensorWorld;
btMatrix3x3 m_interpolateInvInertiaTensorWorld;
btVector3 m_initialCoM; // initial center of mass (original of the m_rigidTransformWorld)
// damping
btScalar m_dampingAlpha;
btScalar m_dampingBeta;
public:
//
// Fields
//
// reduced space
int m_nReduced;
int m_nFull;
tDenseMatrix m_modes; // modes of the reduced deformable model. Each inner array is a mode, outer array size = n_modes
tDenseArray m_reducedDofs; // Reduced degree of freedom
tDenseArray m_reducedDofsBuffer; // Reduced degree of freedom at t^n
tDenseArray m_reducedVelocity; // Reduced velocity array
tDenseArray m_reducedVelocityBuffer; // Reduced velocity array at t^n
tDenseArray m_reducedForceExternal; // reduced external force
tDenseArray m_reducedForceElastic; // reduced internal elastic force
tDenseArray m_reducedForceDamping; // reduced internal damping force
tDenseArray m_eigenvalues; // eigenvalues of the reduce deformable model
tDenseArray m_Kr; // reduced stiffness matrix
// full space
TVStack m_x0; // Rest position
tDenseArray m_nodalMass; // Mass on each node
btAlignedObjectArray<int> m_fixedNodes; // index of the fixed nodes
int m_nodeIndexOffset; // offset of the node index needed for contact solver when there are multiple reduced deformable body in the world.
// contacts
btAlignedObjectArray<int> m_contactNodesList;
//
// Api
//
btReducedDeformableBody(btSoftBodyWorldInfo* worldInfo, int node_count, const btVector3* x, const btScalar* m);
~btReducedDeformableBody() {}
//
// initializing helpers
//
void internalInitialization();
void setReducedModes(int num_modes, int full_size);
void setMassProps(const tDenseArray& mass_array);
void setInertiaProps();
void setRigidVelocity(const btVector3& v);
void setRigidAngularVelocity(const btVector3& omega);
void setStiffnessScale(const btScalar ks);
void setMassScale(const btScalar rho);
void setFixedNodes(const int n_node);
void setDamping(const btScalar alpha, const btScalar beta);
void disableReducedModes(const bool rigid_only);
virtual void setTotalMass(btScalar mass, bool fromfaces = false);
//
// various internal updates
//
virtual void transformTo(const btTransform& trs);
virtual void transform(const btTransform& trs);
// caution:
// need to use scale before using transform, because the scale is performed in the local frame
// (i.e., may have some rotation already, but the m_rigidTransformWorld doesn't have this info)
virtual void scale(const btVector3& scl);
private:
void updateRestNodalPositions();
void updateInitialInertiaTensor(const btMatrix3x3& rotation);
void updateLocalInertiaTensorFromNodes();
void updateInertiaTensor();
void updateModesByRotation(const btMatrix3x3& rotation);
public:
void updateLocalMomentArm();
void predictIntegratedTransform(btScalar dt, btTransform& predictedTransform);
// update the external force projection matrix
void updateExternalForceProjectMatrix(bool initialized);
void endOfTimeStepZeroing();
void applyInternalVelocityChanges();
//
// position and velocity update related
//
// compute reduced degree of freedoms
void updateReducedDofs(btScalar solverdt);
// compute reduced velocity update (for explicit time stepping)
void updateReducedVelocity(btScalar solverdt);
// map to full degree of freedoms
void mapToFullPosition(const btTransform& ref_trans);
// compute full space velocity from the reduced velocity
void mapToFullVelocity(const btTransform& ref_trans);
// compute total angular momentum
const btVector3 computeTotalAngularMomentum() const;
// get a single node's full space velocity from the reduced velocity
const btVector3 computeNodeFullVelocity(const btTransform& ref_trans, int n_node) const;
// get a single node's all delta velocity
const btVector3 internalComputeNodeDeltaVelocity(const btTransform& ref_trans, int n_node) const;
//
// rigid motion related
//
void applyDamping(btScalar timeStep);
void applyCentralImpulse(const btVector3& impulse);
void applyTorqueImpulse(const btVector3& torque);
void proceedToTransform(btScalar dt, bool end_of_time_step);
//
// force related
//
// apply impulse to the rigid frame
void internalApplyRigidImpulse(const btVector3& impulse, const btVector3& rel_pos);
// apply impulse to nodes in the full space
void internalApplyFullSpaceImpulse(const btVector3& impulse, const btVector3& rel_pos, int n_node, btScalar dt);
// apply nodal external force in the full space
void applyFullSpaceNodalForce(const btVector3& f_ext, int n_node);
// apply gravity to the rigid frame
void applyRigidGravity(const btVector3& gravity, btScalar dt);
// apply reduced elastic force
void applyReducedElasticForce(const tDenseArray& reduce_dofs);
// apply reduced damping force
void applyReducedDampingForce(const tDenseArray& reduce_vel);
// calculate the impulse factor
virtual btMatrix3x3 getImpulseFactor(int n_node);
// get relative position from a node to the CoM of the rigid frame
btVector3 getRelativePos(int n_node);
//
// accessors
//
bool isReducedModesOFF() const;
btScalar getTotalMass() const;
btTransform& getRigidTransform();
const btVector3& getLinearVelocity() const;
const btVector3& getAngularVelocity() const;
#if defined(BT_CLAMP_VELOCITY_TO) && BT_CLAMP_VELOCITY_TO > 0
void clampVelocity(btVector3& v) const {
v.setX(
fmax(-BT_CLAMP_VELOCITY_TO,
fmin(BT_CLAMP_VELOCITY_TO, v.getX()))
);
v.setY(
fmax(-BT_CLAMP_VELOCITY_TO,
fmin(BT_CLAMP_VELOCITY_TO, v.getY()))
);
v.setZ(
fmax(-BT_CLAMP_VELOCITY_TO,
fmin(BT_CLAMP_VELOCITY_TO, v.getZ()))
);
}
#endif
};
#endif // BT_REDUCED_SOFT_BODY_H

View File

@ -0,0 +1,215 @@
#include "btReducedDeformableBodyHelpers.h"
#include "../btSoftBodyHelpers.h"
#include <iostream>
#include <string>
#include <sstream>
btReducedDeformableBody* btReducedDeformableBodyHelpers::createReducedDeformableObject(btSoftBodyWorldInfo& worldInfo, const std::string& file_path, const std::string& vtk_file, const int num_modes, bool rigid_only) {
std::string filename = file_path + vtk_file;
btReducedDeformableBody* rsb = btReducedDeformableBodyHelpers::createFromVtkFile(worldInfo, filename.c_str());
rsb->setReducedModes(num_modes, rsb->m_nodes.size());
btReducedDeformableBodyHelpers::readReducedDeformableInfoFromFiles(rsb, file_path.c_str());
rsb->disableReducedModes(rigid_only);
return rsb;
}
btReducedDeformableBody* btReducedDeformableBodyHelpers::createFromVtkFile(btSoftBodyWorldInfo& worldInfo, const char* vtk_file)
{
std::ifstream fs;
fs.open(vtk_file);
btAssert(fs);
typedef btAlignedObjectArray<int> Index;
std::string line;
btAlignedObjectArray<btVector3> X;
btVector3 position;
btAlignedObjectArray<Index> indices;
bool reading_points = false;
bool reading_tets = false;
size_t n_points = 0;
size_t n_tets = 0;
size_t x_count = 0;
size_t indices_count = 0;
while (std::getline(fs, line))
{
std::stringstream ss(line);
if (line.size() == (size_t)(0))
{
}
else if (line.substr(0, 6) == "POINTS")
{
reading_points = true;
reading_tets = false;
ss.ignore(128, ' '); // ignore "POINTS"
ss >> n_points;
X.resize(n_points);
}
else if (line.substr(0, 5) == "CELLS")
{
reading_points = false;
reading_tets = true;
ss.ignore(128, ' '); // ignore "CELLS"
ss >> n_tets;
indices.resize(n_tets);
}
else if (line.substr(0, 10) == "CELL_TYPES")
{
reading_points = false;
reading_tets = false;
}
else if (reading_points)
{
btScalar p;
ss >> p;
position.setX(p);
ss >> p;
position.setY(p);
ss >> p;
position.setZ(p);
//printf("v %f %f %f\n", position.getX(), position.getY(), position.getZ());
X[x_count++] = position;
}
else if (reading_tets)
{
int d;
ss >> d;
if (d != 4)
{
printf("Load deformable failed: Only Tetrahedra are supported in VTK file.\n");
fs.close();
return 0;
}
ss.ignore(128, ' '); // ignore "4"
Index tet;
tet.resize(4);
for (size_t i = 0; i < 4; i++)
{
ss >> tet[i];
//printf("%d ", tet[i]);
}
//printf("\n");
indices[indices_count++] = tet;
}
}
btReducedDeformableBody* rsb = new btReducedDeformableBody(&worldInfo, n_points, &X[0], 0);
for (int i = 0; i < n_tets; ++i)
{
const Index& ni = indices[i];
rsb->appendTetra(ni[0], ni[1], ni[2], ni[3]);
{
rsb->appendLink(ni[0], ni[1], 0, true);
rsb->appendLink(ni[1], ni[2], 0, true);
rsb->appendLink(ni[2], ni[0], 0, true);
rsb->appendLink(ni[0], ni[3], 0, true);
rsb->appendLink(ni[1], ni[3], 0, true);
rsb->appendLink(ni[2], ni[3], 0, true);
}
}
btSoftBodyHelpers::generateBoundaryFaces(rsb);
rsb->initializeDmInverse();
rsb->m_tetraScratches.resize(rsb->m_tetras.size());
rsb->m_tetraScratchesTn.resize(rsb->m_tetras.size());
printf("Nodes: %u\r\n", rsb->m_nodes.size());
printf("Links: %u\r\n", rsb->m_links.size());
printf("Faces: %u\r\n", rsb->m_faces.size());
printf("Tetras: %u\r\n", rsb->m_tetras.size());
fs.close();
return rsb;
}
void btReducedDeformableBodyHelpers::readReducedDeformableInfoFromFiles(btReducedDeformableBody* rsb, const char* file_path)
{
// read in eigenmodes, stiffness and mass matrices
std::string eigenvalues_file = std::string(file_path) + "eigenvalues.bin";
btReducedDeformableBodyHelpers::readBinaryVec(rsb->m_eigenvalues, rsb->m_nReduced, eigenvalues_file.c_str());
std::string Kr_file = std::string(file_path) + "K_r_diag_mat.bin";
btReducedDeformableBodyHelpers::readBinaryVec(rsb->m_Kr, rsb->m_nReduced, Kr_file.c_str());
// std::string Mr_file = std::string(file_path) + "M_r_diag_mat.bin";
// btReducedDeformableBodyHelpers::readBinaryVec(rsb->m_Mr, rsb->m_nReduced, Mr_file.c_str());
std::string modes_file = std::string(file_path) + "modes.bin";
btReducedDeformableBodyHelpers::readBinaryMat(rsb->m_modes, rsb->m_nReduced, 3 * rsb->m_nFull, modes_file.c_str());
// read in full nodal mass
std::string M_file = std::string(file_path) + "M_diag_mat.bin";
btAlignedObjectArray<btScalar> mass_array;
btReducedDeformableBodyHelpers::readBinaryVec(mass_array, rsb->m_nFull, M_file.c_str());
rsb->setMassProps(mass_array);
// calculate the inertia tensor in the local frame
rsb->setInertiaProps();
// other internal initialization
rsb->internalInitialization();
}
// read in a vector from the binary file
void btReducedDeformableBodyHelpers::readBinaryVec(btReducedDeformableBody::tDenseArray& vec,
const unsigned int n_size, // #entries read
const char* file)
{
std::ifstream f_in(file, std::ios::in | std::ios::binary);
// first get size
unsigned int size=0;
f_in.read((char*)&size, 4);//sizeof(unsigned int));
btAssert(size >= n_size); // make sure the #requested mode is smaller than the #available modes
// read data
vec.resize(n_size);
double temp;
for (unsigned int i = 0; i < n_size; ++i)
{
f_in.read((char*)&temp, sizeof(double));
vec[i] = btScalar(temp);
}
f_in.close();
}
// read in a matrix from the binary file
void btReducedDeformableBodyHelpers::readBinaryMat(btReducedDeformableBody::tDenseMatrix& mat,
const unsigned int n_modes, // #modes, outer array size
const unsigned int n_full, // inner array size
const char* file)
{
std::ifstream f_in(file, std::ios::in | std::ios::binary);
// first get size
unsigned int v_size=0;
f_in.read((char*)&v_size, 4);//sizeof(unsigned int));
btAssert(v_size >= n_modes * n_full); // make sure the #requested mode is smaller than the #available modes
// read data
mat.resize(n_modes);
for (int i = 0; i < n_modes; ++i)
{
for (int j = 0; j < n_full; ++j)
{
double temp;
f_in.read((char*)&temp, sizeof(double));
if (mat[i].size() != n_modes)
mat[i].resize(n_full);
mat[i][j] = btScalar(temp);
}
}
f_in.close();
}
void btReducedDeformableBodyHelpers::calculateLocalInertia(btVector3& inertia, const btScalar mass, const btVector3& half_extents, const btVector3& margin)
{
btScalar lx = btScalar(2.) * (half_extents[0] + margin[0]);
btScalar ly = btScalar(2.) * (half_extents[1] + margin[1]);
btScalar lz = btScalar(2.) * (half_extents[2] + margin[2]);
inertia.setValue(mass / (btScalar(12.0)) * (ly * ly + lz * lz),
mass / (btScalar(12.0)) * (lx * lx + lz * lz),
mass / (btScalar(12.0)) * (lx * lx + ly * ly));
}

View File

@ -0,0 +1,25 @@
#ifndef BT_REDUCED_SOFT_BODY_HELPERS_H
#define BT_REDUCED_SOFT_BODY_HELPERS_H
#include "btReducedDeformableBody.h"
#include <string>
struct btReducedDeformableBodyHelpers
{
// create a reduced deformable object
static btReducedDeformableBody* createReducedDeformableObject(btSoftBodyWorldInfo& worldInfo, const std::string& file_path, const std::string& vtk_file, const int num_modes, bool rigid_only);
// read in geometry info from Vtk file
static btReducedDeformableBody* createFromVtkFile(btSoftBodyWorldInfo& worldInfo, const char* vtk_file);
// read in all reduced files
static void readReducedDeformableInfoFromFiles(btReducedDeformableBody* rsb, const char* file_path);
// read in a binary vector
static void readBinaryVec(btReducedDeformableBody::tDenseArray& vec, const unsigned int n_size, const char* file);
// read in a binary matrix
static void readBinaryMat(btReducedDeformableBody::tDenseMatrix& mat, const unsigned int n_modes, const unsigned int n_full, const char* file);
// calculate the local inertia tensor for a box shape reduced deformable object
static void calculateLocalInertia(btVector3& inertia, const btScalar mass, const btVector3& half_extents, const btVector3& margin);
};
#endif // BT_REDUCED_SOFT_BODY_HELPERS_H

View File

@ -0,0 +1,325 @@
#include "btReducedDeformableBodySolver.h"
#include "btReducedDeformableBody.h"
btReducedDeformableBodySolver::btReducedDeformableBodySolver()
{
m_ascendOrder = true;
m_reducedSolver = true;
m_dampingAlpha = 0;
m_dampingBeta = 0;
m_gravity = btVector3(0, 0, 0);
}
void btReducedDeformableBodySolver::setGravity(const btVector3& gravity)
{
m_gravity = gravity;
}
void btReducedDeformableBodySolver::reinitialize(const btAlignedObjectArray<btSoftBody*>& bodies, btScalar dt)
{
m_softBodies.copyFromArray(bodies);
bool nodeUpdated = updateNodes();
if (nodeUpdated)
{
m_dv.resize(m_numNodes, btVector3(0, 0, 0));
m_ddv.resize(m_numNodes, btVector3(0, 0, 0));
m_residual.resize(m_numNodes, btVector3(0, 0, 0));
m_backupVelocity.resize(m_numNodes, btVector3(0, 0, 0));
}
// need to setZero here as resize only set value for newly allocated items
for (int i = 0; i < m_numNodes; ++i)
{
m_dv[i].setZero();
m_ddv[i].setZero();
m_residual[i].setZero();
}
if (dt > 0)
{
m_dt = dt;
}
m_objective->reinitialize(nodeUpdated, dt);
int N = bodies.size();
if (nodeUpdated)
{
m_staticConstraints.resize(N);
m_nodeRigidConstraints.resize(N);
// m_faceRigidConstraints.resize(N);
}
for (int i = 0; i < N; ++i)
{
m_staticConstraints[i].clear();
m_nodeRigidConstraints[i].clear();
// m_faceRigidConstraints[i].clear();
}
for (int i = 0; i < m_softBodies.size(); ++i)
{
btReducedDeformableBody* rsb = static_cast<btReducedDeformableBody*>(m_softBodies[i]);
rsb->m_contactNodesList.clear();
}
// set node index offsets
int sum = 0;
for (int i = 0; i < m_softBodies.size(); ++i)
{
btReducedDeformableBody* rsb = static_cast<btReducedDeformableBody*>(m_softBodies[i]);
rsb->m_nodeIndexOffset = sum;
sum += rsb->m_nodes.size();
}
btDeformableBodySolver::updateSoftBodies();
}
void btReducedDeformableBodySolver::predictMotion(btScalar solverdt)
{
applyExplicitForce(solverdt);
// predict new mesh location
predictReduceDeformableMotion(solverdt);
//TODO: check if there is anything missed from btDeformableBodySolver::predictDeformableMotion
}
void btReducedDeformableBodySolver::predictReduceDeformableMotion(btScalar solverdt)
{
for (int i = 0; i < m_softBodies.size(); ++i)
{
btReducedDeformableBody* rsb = static_cast<btReducedDeformableBody*>(m_softBodies[i]);
if (!rsb->isActive())
{
continue;
}
// clear contacts variables
rsb->m_nodeRigidContacts.resize(0);
rsb->m_faceRigidContacts.resize(0);
rsb->m_faceNodeContacts.resize(0);
// calculate inverse mass matrix for all nodes
for (int j = 0; j < rsb->m_nodes.size(); ++j)
{
if (rsb->m_nodes[j].m_im > 0)
{
rsb->m_nodes[j].m_effectiveMass_inv = rsb->m_nodes[j].m_effectiveMass.inverse();
}
}
// rigid motion: t, R at time^*
rsb->predictIntegratedTransform(solverdt, rsb->getInterpolationWorldTransform());
// update reduced dofs at time^*
// rsb->updateReducedDofs(solverdt);
// update local moment arm at time^*
// rsb->updateLocalMomentArm();
// rsb->updateExternalForceProjectMatrix(true);
// predict full space velocity at time^* (needed for constraints)
rsb->mapToFullVelocity(rsb->getInterpolationWorldTransform());
// update full space nodal position at time^*
rsb->mapToFullPosition(rsb->getInterpolationWorldTransform());
// update bounding box
rsb->updateBounds();
// update tree
rsb->updateNodeTree(true, true);
if (!rsb->m_fdbvt.empty())
{
rsb->updateFaceTree(true, true);
}
}
}
void btReducedDeformableBodySolver::applyExplicitForce(btScalar solverdt)
{
for (int i = 0; i < m_softBodies.size(); ++i)
{
btReducedDeformableBody* rsb = static_cast<btReducedDeformableBody*>(m_softBodies[i]);
// apply gravity to the rigid frame, get m_linearVelocity at time^*
rsb->applyRigidGravity(m_gravity, solverdt);
if (!rsb->isReducedModesOFF())
{
// add internal force (elastic force & damping force)
rsb->applyReducedElasticForce(rsb->m_reducedDofsBuffer);
rsb->applyReducedDampingForce(rsb->m_reducedVelocityBuffer);
// get reduced velocity at time^*
rsb->updateReducedVelocity(solverdt);
}
// apply damping (no need at this point)
// rsb->applyDamping(solverdt);
}
}
void btReducedDeformableBodySolver::applyTransforms(btScalar timeStep)
{
for (int i = 0; i < m_softBodies.size(); ++i)
{
btReducedDeformableBody* rsb = static_cast<btReducedDeformableBody*>(m_softBodies[i]);
// rigid motion
rsb->proceedToTransform(timeStep, true);
if (!rsb->isReducedModesOFF())
{
// update reduced dofs for time^n+1
rsb->updateReducedDofs(timeStep);
// update local moment arm for time^n+1
rsb->updateLocalMomentArm();
rsb->updateExternalForceProjectMatrix(true);
}
// update mesh nodal positions for time^n+1
rsb->mapToFullPosition(rsb->getRigidTransform());
// update mesh nodal velocity
rsb->mapToFullVelocity(rsb->getRigidTransform());
// end of time step clean up and update
rsb->endOfTimeStepZeroing();
// update the rendering mesh
rsb->interpolateRenderMesh();
}
}
void btReducedDeformableBodySolver::setConstraints(const btContactSolverInfo& infoGlobal)
{
for (int i = 0; i < m_softBodies.size(); ++i)
{
btReducedDeformableBody* rsb = static_cast<btReducedDeformableBody*>(m_softBodies[i]);
if (!rsb->isActive())
{
continue;
}
// set fixed constraints
for (int j = 0; j < rsb->m_fixedNodes.size(); ++j)
{
int i_node = rsb->m_fixedNodes[j];
if (rsb->m_nodes[i_node].m_im == 0)
{
for (int k = 0; k < 3; ++k)
{
btVector3 dir(0, 0, 0);
dir[k] = 1;
btReducedDeformableStaticConstraint static_constraint(rsb, &rsb->m_nodes[i_node], rsb->getRelativePos(i_node), rsb->m_x0[i_node], dir, infoGlobal, m_dt);
m_staticConstraints[i].push_back(static_constraint);
}
}
}
btAssert(rsb->m_fixedNodes.size() * 3 == m_staticConstraints[i].size());
// set Deformable Node vs. Rigid constraint
for (int j = 0; j < rsb->m_nodeRigidContacts.size(); ++j)
{
const btSoftBody::DeformableNodeRigidContact& contact = rsb->m_nodeRigidContacts[j];
// skip fixed points
if (contact.m_node->m_im == 0)
{
continue;
}
btReducedDeformableNodeRigidContactConstraint constraint(rsb, contact, infoGlobal, m_dt);
m_nodeRigidConstraints[i].push_back(constraint);
rsb->m_contactNodesList.push_back(contact.m_node->index - rsb->m_nodeIndexOffset);
}
// std::cout << "contact node list size: " << rsb->m_contactNodesList.size() << "\n";
// std::cout << "#contact nodes: " << m_nodeRigidConstraints[i].size() << "\n";
}
}
btScalar btReducedDeformableBodySolver::solveContactConstraints(btCollisionObject** deformableBodies, int numDeformableBodies, const btContactSolverInfo& infoGlobal)
{
btScalar residualSquare = 0;
for (int i = 0; i < m_softBodies.size(); ++i)
{
btAlignedObjectArray<int> m_orderNonContactConstraintPool;
btAlignedObjectArray<int> m_orderContactConstraintPool;
btReducedDeformableBody* rsb = static_cast<btReducedDeformableBody*>(m_softBodies[i]);
// shuffle the order of applying constraint
m_orderNonContactConstraintPool.resize(m_staticConstraints[i].size());
m_orderContactConstraintPool.resize(m_nodeRigidConstraints[i].size());
if (infoGlobal.m_solverMode & SOLVER_RANDMIZE_ORDER)
{
// fixed constraint order
for (int j = 0; j < m_staticConstraints[i].size(); ++j)
{
m_orderNonContactConstraintPool[j] = m_ascendOrder ? j : m_staticConstraints[i].size() - 1 - j;
}
// contact constraint order
for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j)
{
m_orderContactConstraintPool[j] = m_ascendOrder ? j : m_nodeRigidConstraints[i].size() - 1 - j;
}
m_ascendOrder = m_ascendOrder ? false : true;
}
else
{
for (int j = 0; j < m_staticConstraints[i].size(); ++j)
{
m_orderNonContactConstraintPool[j] = j;
}
// contact constraint order
for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j)
{
m_orderContactConstraintPool[j] = j;
}
}
// handle fixed constraint
for (int k = 0; k < m_staticConstraints[i].size(); ++k)
{
btReducedDeformableStaticConstraint& constraint = m_staticConstraints[i][m_orderNonContactConstraintPool[k]];
btScalar localResidualSquare = constraint.solveConstraint(infoGlobal);
residualSquare = btMax(residualSquare, localResidualSquare);
}
// handle contact constraint
// node vs rigid contact
// std::cout << "!!#contact_nodes: " << m_nodeRigidConstraints[i].size() << '\n';
for (int k = 0; k < m_nodeRigidConstraints[i].size(); ++k)
{
btReducedDeformableNodeRigidContactConstraint& constraint = m_nodeRigidConstraints[i][m_orderContactConstraintPool[k]];
btScalar localResidualSquare = constraint.solveConstraint(infoGlobal);
residualSquare = btMax(residualSquare, localResidualSquare);
}
// face vs rigid contact
// for (int k = 0; k < m_faceRigidConstraints[i].size(); ++k)
// {
// btReducedDeformableFaceRigidContactConstraint& constraint = m_faceRigidConstraints[i][k];
// btScalar localResidualSquare = constraint.solveConstraint(infoGlobal);
// residualSquare = btMax(residualSquare, localResidualSquare);
// }
}
return residualSquare;
}
void btReducedDeformableBodySolver::deformableBodyInternalWriteBack()
{
// reduced deformable update
for (int i = 0; i < m_softBodies.size(); ++i)
{
btReducedDeformableBody* rsb = static_cast<btReducedDeformableBody*>(m_softBodies[i]);
rsb->applyInternalVelocityChanges();
}
m_ascendOrder = true;
}

View File

@ -0,0 +1,61 @@
#ifndef BT_REDUCED_DEFORMABLE_BODY_DYNAMICS_WORLD_H
#define BT_REDUCED_DEFORMABLE_BODY_DYNAMICS_WORLD_H
#include "BulletSoftBody/btDeformableBodySolver.h"
#include "btReducedDeformableContactConstraint.h"
class btReducedDeformableBody;
class btReducedDeformableBodySolver : public btDeformableBodySolver
{
protected:
bool m_ascendOrder;
btScalar m_dampingAlpha;
btScalar m_dampingBeta;
btVector3 m_gravity;
void predictReduceDeformableMotion(btScalar solverdt);
void applyExplicitForce(btScalar solverdt);
public:
btAlignedObjectArray<btAlignedObjectArray<btReducedDeformableStaticConstraint> > m_staticConstraints;
btAlignedObjectArray<btAlignedObjectArray<btReducedDeformableNodeRigidContactConstraint> > m_nodeRigidConstraints;
btAlignedObjectArray<btAlignedObjectArray<btReducedDeformableFaceRigidContactConstraint> > m_faceRigidConstraints;
btReducedDeformableBodySolver();
~btReducedDeformableBodySolver() {}
virtual void setGravity(const btVector3& gravity);
virtual SolverTypes getSolverType() const
{
return REDUCED_DEFORMABLE_SOLVER;
}
// resize/clear data structures
virtual void reinitialize(const btAlignedObjectArray<btSoftBody*>& bodies, btScalar dt);
virtual void predictMotion(btScalar solverdt);
virtual void applyTransforms(btScalar timeStep);
// set up contact constraints
virtual void setConstraints(const btContactSolverInfo& infoGlobal);
// solve all constraints (fixed and contact)
virtual btScalar solveContactConstraints(btCollisionObject** deformableBodies, int numDeformableBodies, const btContactSolverInfo& infoGlobal);
// apply all the delta velocities
virtual void deformableBodyInternalWriteBack();
// virtual void setProjection() {}
// virtual void setLagrangeMultiplier() {}
// virtual void setupDeformableSolve(bool implicit);
};
#endif // BT_REDUCED_DEFORMABLE_BODY_DYNAMICS_WORLD_H

View File

@ -0,0 +1,579 @@
#include "btReducedDeformableContactConstraint.h"
#include <iostream>
// ================= static constraints ===================
btReducedDeformableStaticConstraint::btReducedDeformableStaticConstraint(
btReducedDeformableBody* rsb,
btSoftBody::Node* node,
const btVector3& ri,
const btVector3& x0,
const btVector3& dir,
const btContactSolverInfo& infoGlobal,
btScalar dt)
: m_rsb(rsb), m_ri(ri), m_targetPos(x0), m_impulseDirection(dir), m_dt(dt), btDeformableStaticConstraint(node, infoGlobal)
{
m_erp = 0.2;
m_appliedImpulse = 0;
// get impulse factor
m_impulseFactorMatrix = rsb->getImpulseFactor(m_node->index);
m_impulseFactor = (m_impulseFactorMatrix * m_impulseDirection).dot(m_impulseDirection);
btScalar vel_error = btDot(-m_node->m_v, m_impulseDirection);
btScalar pos_error = btDot(m_targetPos - m_node->m_x, m_impulseDirection);
m_rhs = (vel_error + m_erp * pos_error / m_dt) / m_impulseFactor;
}
btScalar btReducedDeformableStaticConstraint::solveConstraint(const btContactSolverInfo& infoGlobal)
{
// target velocity of fixed constraint is 0
btVector3 deltaVa = getDeltaVa();
btScalar deltaV_rel = btDot(deltaVa, m_impulseDirection);
btScalar deltaImpulse = m_rhs - deltaV_rel / m_impulseFactor;
m_appliedImpulse = m_appliedImpulse + deltaImpulse;
btVector3 impulse = deltaImpulse * m_impulseDirection;
applyImpulse(impulse);
// calculate residual
btScalar residualSquare = m_impulseFactor * deltaImpulse;
residualSquare *= residualSquare;
return residualSquare;
}
// this calls reduced deformable body's internalApplyFullSpaceImpulse
void btReducedDeformableStaticConstraint::applyImpulse(const btVector3& impulse)
{
// apply full space impulse
m_rsb->internalApplyFullSpaceImpulse(impulse, m_ri, m_node->index, m_dt);
}
btVector3 btReducedDeformableStaticConstraint::getDeltaVa() const
{
return m_rsb->internalComputeNodeDeltaVelocity(m_rsb->getInterpolationWorldTransform(), m_node->index);
}
// ================= base contact constraints ===================
btReducedDeformableRigidContactConstraint::btReducedDeformableRigidContactConstraint(
btReducedDeformableBody* rsb,
const btSoftBody::DeformableRigidContact& c,
const btContactSolverInfo& infoGlobal,
btScalar dt)
: m_rsb(rsb), m_dt(dt), btDeformableRigidContactConstraint(c, infoGlobal)
{
m_nodeQueryIndex = 0;
m_appliedNormalImpulse = 0;
m_appliedTangentImpulse = 0;
m_rhs = 0;
m_rhs_tangent = 0;
m_cfm = infoGlobal.m_deformable_cfm;
m_cfm_friction = 0;
m_erp = infoGlobal.m_deformable_erp;
m_erp_friction = infoGlobal.m_deformable_erp;
m_friction = infoGlobal.m_friction;
m_collideStatic = m_contact->m_cti.m_colObj->isStaticObject();
m_collideMultibody = (m_contact->m_cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK);
}
void btReducedDeformableRigidContactConstraint::setSolverBody(const int bodyId, btSolverBody& solver_body)
{
if (!m_collideMultibody)
{
m_solverBodyId = bodyId;
m_solverBody = &solver_body;
m_linearComponentNormal = -m_contactNormalA * m_solverBody->internalGetInvMass();
btVector3 torqueAxis = -m_relPosA.cross(m_contactNormalA);
m_angularComponentNormal = m_solverBody->m_originalBody->getInvInertiaTensorWorld() * torqueAxis;
m_linearComponentTangent = m_contactTangent * m_solverBody->internalGetInvMass();
btVector3 torqueAxisTangent = m_relPosA.cross(m_contactTangent);
m_angularComponentTangent = m_solverBody->m_originalBody->getInvInertiaTensorWorld() * torqueAxisTangent;
}
}
btVector3 btReducedDeformableRigidContactConstraint::getVa() const
{
btVector3 Va(0, 0, 0);
if (!m_collideStatic)
{
Va = btDeformableRigidContactConstraint::getVa();
}
return Va;
}
btScalar btReducedDeformableRigidContactConstraint::solveConstraint(const btContactSolverInfo& infoGlobal)
{
// btVector3 Va = getVa();
// btVector3 deltaVa = Va - m_bufferVelocityA;
// if (!m_collideStatic)
// {
// std::cout << "moving collision!!!\n";
// std::cout << "relPosA: " << m_relPosA[0] << "\t" << m_relPosA[1] << "\t" << m_relPosA[2] << "\n";
// std::cout << "moving rigid linear_vel: " << m_solverBody->m_originalBody->getLinearVelocity()[0] << '\t'
// << m_solverBody->m_originalBody->getLinearVelocity()[1] << '\t'
// << m_solverBody->m_originalBody->getLinearVelocity()[2] << '\n';
// }
btVector3 deltaVa = getDeltaVa();
btVector3 deltaVb = getDeltaVb();
// if (!m_collideStatic)
// {
// std::cout << "deltaVa: " << deltaVa[0] << '\t' << deltaVa[1] << '\t' << deltaVa[2] << '\n';
// std::cout << "deltaVb: " << deltaVb[0] << '\t' << deltaVb[1] << '\t' << deltaVb[2] << '\n';
// }
// get delta relative velocity and magnitude (i.e., how much impulse has been applied?)
btVector3 deltaV_rel = deltaVa - deltaVb;
btScalar deltaV_rel_normal = -btDot(deltaV_rel, m_contactNormalA);
// if (!m_collideStatic)
// {
// std::cout << "deltaV_rel: " << deltaV_rel[0] << '\t' << deltaV_rel[1] << '\t' << deltaV_rel[2] << "\n";
// std::cout << "deltaV_rel_normal: " << deltaV_rel_normal << "\n";
// std::cout << "normal_A: " << m_contactNormalA[0] << '\t' << m_contactNormalA[1] << '\t' << m_contactNormalA[2] << '\n';
// }
// get the normal impulse to be applied
btScalar deltaImpulse = m_rhs - m_appliedNormalImpulse * m_cfm - deltaV_rel_normal / m_normalImpulseFactor;
// if (!m_collideStatic)
// {
// std::cout << "m_rhs: " << m_rhs << '\t' << "m_appliedNormalImpulse: " << m_appliedNormalImpulse << "\n";
// std::cout << "m_normalImpulseFactor: " << m_normalImpulseFactor << '\n';
// }
{
// cumulative impulse that has been applied
btScalar sum = m_appliedNormalImpulse + deltaImpulse;
// if the cumulative impulse is pushing the object into the rigid body, set it zero
if (sum < 0)
{
deltaImpulse = -m_appliedNormalImpulse;
m_appliedNormalImpulse = 0;
}
else
{
m_appliedNormalImpulse = sum;
}
}
// if (!m_collideStatic)
// {
// std::cout << "m_appliedNormalImpulse: " << m_appliedNormalImpulse << '\n';
// std::cout << "deltaImpulse: " << deltaImpulse << '\n';
// }
// residual is the nodal normal velocity change in current iteration
btScalar residualSquare = deltaImpulse * m_normalImpulseFactor; // get residual
residualSquare *= residualSquare;
// apply Coulomb friction (based on delta velocity, |dv_t| = |dv_n * friction|)
btScalar deltaImpulse_tangent = 0;
btScalar deltaImpulse_tangent2 = 0;
{
// calculate how much impulse is needed
// btScalar deltaV_rel_tangent = btDot(deltaV_rel, m_contactTangent);
// btScalar impulse_changed = deltaV_rel_tangent * m_tangentImpulseFactorInv;
// deltaImpulse_tangent = m_rhs_tangent - impulse_changed;
// btScalar sum = m_appliedTangentImpulse + deltaImpulse_tangent;
btScalar lower_limit = - m_appliedNormalImpulse * m_friction;
btScalar upper_limit = m_appliedNormalImpulse * m_friction;
// if (sum > upper_limit)
// {
// deltaImpulse_tangent = upper_limit - m_appliedTangentImpulse;
// m_appliedTangentImpulse = upper_limit;
// }
// else if (sum < lower_limit)
// {
// deltaImpulse_tangent = lower_limit - m_appliedTangentImpulse;
// m_appliedTangentImpulse = lower_limit;
// }
// else
// {
// m_appliedTangentImpulse = sum;
// }
//
calculateTangentialImpulse(deltaImpulse_tangent, m_appliedTangentImpulse, m_rhs_tangent,
m_tangentImpulseFactorInv, m_contactTangent, lower_limit, upper_limit, deltaV_rel);
if (m_collideMultibody)
{
calculateTangentialImpulse(deltaImpulse_tangent2, m_appliedTangentImpulse2, m_rhs_tangent2,
m_tangentImpulseFactorInv2, m_contactTangent2, lower_limit, upper_limit, deltaV_rel);
}
if (!m_collideStatic)
{
// std::cout << "m_contactTangent: " << m_contactTangent[0] << "\t" << m_contactTangent[1] << "\t" << m_contactTangent[2] << "\n";
// std::cout << "deltaV_rel_tangent: " << deltaV_rel_tangent << '\n';
// std::cout << "deltaImpulseTangent: " << deltaImpulse_tangent << '\n';
// std::cout << "m_appliedTangentImpulse: " << m_appliedTangentImpulse << '\n';
}
}
// get the total impulse vector
btVector3 impulse_normal = deltaImpulse * m_contactNormalA;
btVector3 impulse_tangent = deltaImpulse_tangent * (-m_contactTangent);
btVector3 impulse_tangent2 = deltaImpulse_tangent2 * (-m_contactTangent2);
btVector3 impulse = impulse_normal + impulse_tangent + impulse_tangent2;
applyImpulse(impulse);
// apply impulse to the rigid/multibodies involved and change their velocities
if (!m_collideStatic)
{
// std::cout << "linear_component: " << m_linearComponentNormal[0] << '\t'
// << m_linearComponentNormal[1] << '\t'
// << m_linearComponentNormal[2] << '\n';
// std::cout << "angular_component: " << m_angularComponentNormal[0] << '\t'
// << m_angularComponentNormal[1] << '\t'
// << m_angularComponentNormal[2] << '\n';
if (!m_collideMultibody) // collision with rigid body
{
// std::cout << "rigid impulse applied!!\n";
// std::cout << "delta Linear: " << m_solverBody->getDeltaLinearVelocity()[0] << '\t'
// << m_solverBody->getDeltaLinearVelocity()[1] << '\t'
// << m_solverBody->getDeltaLinearVelocity()[2] << '\n';
// std::cout << "delta Angular: " << m_solverBody->getDeltaAngularVelocity()[0] << '\t'
// << m_solverBody->getDeltaAngularVelocity()[1] << '\t'
// << m_solverBody->getDeltaAngularVelocity()[2] << '\n';
m_solverBody->internalApplyImpulse(m_linearComponentNormal, m_angularComponentNormal, deltaImpulse);
m_solverBody->internalApplyImpulse(m_linearComponentTangent, m_angularComponentTangent, deltaImpulse_tangent);
// std::cout << "after\n";
// std::cout << "rigid impulse applied!!\n";
// std::cout << "delta Linear: " << m_solverBody->getDeltaLinearVelocity()[0] << '\t'
// << m_solverBody->getDeltaLinearVelocity()[1] << '\t'
// << m_solverBody->getDeltaLinearVelocity()[2] << '\n';
// std::cout << "delta Angular: " << m_solverBody->getDeltaAngularVelocity()[0] << '\t'
// << m_solverBody->getDeltaAngularVelocity()[1] << '\t'
// << m_solverBody->getDeltaAngularVelocity()[2] << '\n';
}
else // collision with multibody
{
btMultiBodyLinkCollider* multibodyLinkCol = 0;
multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(m_contact->m_cti.m_colObj);
if (multibodyLinkCol)
{
const btScalar* deltaV_normal = &m_contact->jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
// apply normal component of the impulse
multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_normal, -deltaImpulse);
// const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
// std::cout << "deltaV_normal: ";
// for (int i = 0; i < ndof; ++i)
// {
// std::cout << i << "\t" << deltaV_normal[i] << '\n';
// }
if (impulse_tangent.norm() > SIMD_EPSILON)
{
// apply tangential component of the impulse
const btScalar* deltaV_t1 = &m_contact->jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_t1, deltaImpulse_tangent);
const btScalar* deltaV_t2 = &m_contact->jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_t2, deltaImpulse_tangent2);
}
}
}
}
return residualSquare;
}
void btReducedDeformableRigidContactConstraint::calculateTangentialImpulse(btScalar& deltaImpulse_tangent,
btScalar& appliedImpulse,
const btScalar rhs_tangent,
const btScalar tangentImpulseFactorInv,
const btVector3& tangent,
const btScalar lower_limit,
const btScalar upper_limit,
const btVector3& deltaV_rel)
{
btScalar deltaV_rel_tangent = btDot(deltaV_rel, tangent);
btScalar impulse_changed = deltaV_rel_tangent * tangentImpulseFactorInv;
deltaImpulse_tangent = rhs_tangent - m_cfm_friction * appliedImpulse - impulse_changed;
btScalar sum = appliedImpulse + deltaImpulse_tangent;
if (sum > upper_limit)
{
deltaImpulse_tangent = upper_limit - appliedImpulse;
appliedImpulse = upper_limit;
}
else if (sum < lower_limit)
{
deltaImpulse_tangent = lower_limit - appliedImpulse;
appliedImpulse = lower_limit;
}
else
{
appliedImpulse = sum;
}
}
// ================= node vs rigid constraints ===================
btReducedDeformableNodeRigidContactConstraint::btReducedDeformableNodeRigidContactConstraint(
btReducedDeformableBody* rsb,
const btSoftBody::DeformableNodeRigidContact& contact,
const btContactSolverInfo& infoGlobal,
btScalar dt)
: m_node(contact.m_node), btReducedDeformableRigidContactConstraint(rsb, contact, infoGlobal, dt)
{
m_contactNormalA = contact.m_cti.m_normal;
m_contactNormalB = -contact.m_cti.m_normal;
if (contact.m_node->index < rsb->m_nodes.size())
{
m_nodeQueryIndex = contact.m_node->index;
}
else
{
m_nodeQueryIndex = m_node->index - rsb->m_nodeIndexOffset;
}
if (m_contact->m_cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
{
m_relPosA = contact.m_c1;
}
else
{
m_relPosA = btVector3(0,0,0);
}
m_relPosB = m_node->m_x - m_rsb->getRigidTransform().getOrigin();
if (m_collideStatic) // colliding with static object, only consider reduced deformable body's impulse factor
{
m_impulseFactor = m_rsb->getImpulseFactor(m_nodeQueryIndex);
}
else // colliding with dynamic object, consider both reduced deformable and rigid body's impulse factors
{
m_impulseFactor = m_rsb->getImpulseFactor(m_nodeQueryIndex) + contact.m_c0;
}
m_normalImpulseFactor = (m_impulseFactor * m_contactNormalA).dot(m_contactNormalA);
m_tangentImpulseFactor = 0;
warmStarting();
}
void btReducedDeformableNodeRigidContactConstraint::warmStarting()
{
btVector3 va = getVa();
btVector3 vb = getVb();
m_bufferVelocityA = va;
m_bufferVelocityB = vb;
// we define the (+) direction of errors to be the outward surface normal of the rigid object
btVector3 v_rel = vb - va;
// get tangent direction of the relative velocity
btVector3 v_tangent = v_rel - v_rel.dot(m_contactNormalA) * m_contactNormalA;
if (v_tangent.norm() < SIMD_EPSILON)
{
m_contactTangent = btVector3(0, 0, 0);
// tangent impulse factor
m_tangentImpulseFactor = 0;
m_tangentImpulseFactorInv = 0;
}
else
{
if (!m_collideMultibody)
{
m_contactTangent = v_tangent.normalized();
m_contactTangent2.setZero();
// tangent impulse factor 1
m_tangentImpulseFactor = (m_impulseFactor * m_contactTangent).dot(m_contactTangent);
m_tangentImpulseFactorInv = btScalar(1) / m_tangentImpulseFactor;
// tangent impulse factor 2
m_tangentImpulseFactor2 = 0;
m_tangentImpulseFactorInv2 = 0;
}
else // multibody requires 2 contact directions
{
m_contactTangent = m_contact->t1;
m_contactTangent2 = m_contact->t2;
// tangent impulse factor 1
m_tangentImpulseFactor = (m_impulseFactor * m_contactTangent).dot(m_contactTangent);
m_tangentImpulseFactorInv = btScalar(1) / m_tangentImpulseFactor;
// tangent impulse factor 2
m_tangentImpulseFactor2 = (m_impulseFactor * m_contactTangent2).dot(m_contactTangent2);
m_tangentImpulseFactorInv2 = btScalar(1) / m_tangentImpulseFactor2;
}
}
// initial guess for normal impulse
{
btScalar velocity_error = btDot(v_rel, m_contactNormalA); // magnitude of relative velocity
btScalar position_error = 0;
if (m_penetration > 0)
{
velocity_error += m_penetration / m_dt;
}
else
{
// add penetration correction vel
position_error = m_penetration * m_erp / m_dt;
}
// get the initial estimate of impulse magnitude to be applied
m_rhs = -(velocity_error + position_error) / m_normalImpulseFactor;
}
// initial guess for tangential impulse
{
btScalar velocity_error = btDot(v_rel, m_contactTangent);
m_rhs_tangent = velocity_error * m_tangentImpulseFactorInv;
if (m_collideMultibody)
{
btScalar velocity_error2 = btDot(v_rel, m_contactTangent2);
m_rhs_tangent2 = velocity_error2 * m_tangentImpulseFactorInv2;
}
}
// warm starting
// applyImpulse(m_rhs * m_contactNormalA);
// if (!m_collideStatic)
// {
// const btSoftBody::sCti& cti = m_contact->m_cti;
// if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
// {
// m_solverBody->internalApplyImpulse(m_linearComponentNormal, m_angularComponentNormal, -m_rhs);
// }
// }
}
btVector3 btReducedDeformableNodeRigidContactConstraint::getVb() const
{
return m_node->m_v;
}
btVector3 btReducedDeformableNodeRigidContactConstraint::getDeltaVa() const
{
btVector3 deltaVa(0, 0, 0);
if (!m_collideStatic)
{
if (!m_collideMultibody) // for rigid body
{
deltaVa = m_solverBody->internalGetDeltaLinearVelocity() + m_solverBody->internalGetDeltaAngularVelocity().cross(m_relPosA);
}
else // for multibody
{
btMultiBodyLinkCollider* multibodyLinkCol = 0;
multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(m_contact->m_cti.m_colObj);
if (multibodyLinkCol)
{
const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
const btScalar* J_n = &m_contact->jacobianData_normal.m_jacobians[0];
const btScalar* J_t1 = &m_contact->jacobianData_t1.m_jacobians[0];
const btScalar* J_t2 = &m_contact->jacobianData_t2.m_jacobians[0];
const btScalar* local_dv = multibodyLinkCol->m_multiBody->getDeltaVelocityVector();
// add in the normal component of the va
btScalar vel = 0;
for (int k = 0; k < ndof; ++k)
{
vel += local_dv[k] * J_n[k];
}
deltaVa = m_contact->m_cti.m_normal * vel;
// add in the tangential components of the va
vel = 0;
for (int k = 0; k < ndof; ++k)
{
vel += local_dv[k] * J_t1[k];
}
deltaVa += m_contact->t1 * vel;
vel = 0;
for (int k = 0; k < ndof; ++k)
{
vel += local_dv[k] * J_t2[k];
}
deltaVa += m_contact->t2 * vel;
}
}
}
return deltaVa;
}
btVector3 btReducedDeformableNodeRigidContactConstraint::getDeltaVb() const
{
// std::cout << "node: " << m_node->index << '\n';
return m_rsb->internalComputeNodeDeltaVelocity(m_rsb->getInterpolationWorldTransform(), m_nodeQueryIndex);
}
btVector3 btReducedDeformableNodeRigidContactConstraint::getSplitVb() const
{
return m_node->m_splitv;
}
btVector3 btReducedDeformableNodeRigidContactConstraint::getDv(const btSoftBody::Node* node) const
{
return m_total_normal_dv + m_total_tangent_dv;
}
void btReducedDeformableNodeRigidContactConstraint::applyImpulse(const btVector3& impulse)
{
m_rsb->internalApplyFullSpaceImpulse(impulse, m_relPosB, m_nodeQueryIndex, m_dt);
// m_rsb->applyFullSpaceImpulse(impulse, m_relPosB, m_node->index, m_dt);
// m_rsb->mapToFullVelocity(m_rsb->getInterpolationWorldTransform());
// if (!m_collideStatic)
// {
// // std::cout << "impulse applied: " << impulse[0] << '\t' << impulse[1] << '\t' << impulse[2] << '\n';
// // std::cout << "node: " << m_node->index << " vel: " << m_node->m_v[0] << '\t' << m_node->m_v[1] << '\t' << m_node->m_v[2] << '\n';
// btVector3 v_after = getDeltaVb() + m_node->m_v;
// // std::cout << "vel after: " << v_after[0] << '\t' << v_after[1] << '\t' << v_after[2] << '\n';
// }
// std::cout << "node: " << m_node->index << " pos: " << m_node->m_x[0] << '\t' << m_node->m_x[1] << '\t' << m_node->m_x[2] << '\n';
}
// ================= face vs rigid constraints ===================
btReducedDeformableFaceRigidContactConstraint::btReducedDeformableFaceRigidContactConstraint(
btReducedDeformableBody* rsb,
const btSoftBody::DeformableFaceRigidContact& contact,
const btContactSolverInfo& infoGlobal,
btScalar dt,
bool useStrainLimiting)
: m_face(contact.m_face), m_useStrainLimiting(useStrainLimiting), btReducedDeformableRigidContactConstraint(rsb, contact, infoGlobal, dt)
{}
btVector3 btReducedDeformableFaceRigidContactConstraint::getVb() const
{
const btSoftBody::DeformableFaceRigidContact* contact = getContact();
btVector3 vb = m_face->m_n[0]->m_v * contact->m_bary[0] + m_face->m_n[1]->m_v * contact->m_bary[1] + m_face->m_n[2]->m_v * contact->m_bary[2];
return vb;
}
btVector3 btReducedDeformableFaceRigidContactConstraint::getSplitVb() const
{
const btSoftBody::DeformableFaceRigidContact* contact = getContact();
btVector3 vb = (m_face->m_n[0]->m_splitv) * contact->m_bary[0] + (m_face->m_n[1]->m_splitv) * contact->m_bary[1] + (m_face->m_n[2]->m_splitv) * contact->m_bary[2];
return vb;
}
btVector3 btReducedDeformableFaceRigidContactConstraint::getDv(const btSoftBody::Node* node) const
{
btVector3 face_dv = m_total_normal_dv + m_total_tangent_dv;
const btSoftBody::DeformableFaceRigidContact* contact = getContact();
if (m_face->m_n[0] == node)
{
return face_dv * contact->m_weights[0];
}
if (m_face->m_n[1] == node)
{
return face_dv * contact->m_weights[1];
}
btAssert(node == m_face->m_n[2]);
return face_dv * contact->m_weights[2];
}
void btReducedDeformableFaceRigidContactConstraint::applyImpulse(const btVector3& impulse)
{
//
}

View File

@ -0,0 +1,194 @@
#include "../btDeformableContactConstraint.h"
#include "btReducedDeformableBody.h"
// ================= static constraints ===================
class btReducedDeformableStaticConstraint : public btDeformableStaticConstraint
{
public:
btReducedDeformableBody* m_rsb;
btScalar m_dt;
btVector3 m_ri;
btVector3 m_targetPos;
btVector3 m_impulseDirection;
btMatrix3x3 m_impulseFactorMatrix;
btScalar m_impulseFactor;
btScalar m_rhs;
btScalar m_appliedImpulse;
btScalar m_erp;
btReducedDeformableStaticConstraint(btReducedDeformableBody* rsb,
btSoftBody::Node* node,
const btVector3& ri,
const btVector3& x0,
const btVector3& dir,
const btContactSolverInfo& infoGlobal,
btScalar dt);
// btReducedDeformableStaticConstraint(const btReducedDeformableStaticConstraint& other);
btReducedDeformableStaticConstraint() {}
virtual ~btReducedDeformableStaticConstraint() {}
virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal);
// this calls reduced deformable body's applyFullSpaceImpulse
virtual void applyImpulse(const btVector3& impulse);
btVector3 getDeltaVa() const;
// virtual void applySplitImpulse(const btVector3& impulse) {}
};
// ================= base contact constraints ===================
class btReducedDeformableRigidContactConstraint : public btDeformableRigidContactConstraint
{
public:
bool m_collideStatic; // flag for collision with static object
bool m_collideMultibody; // flag for collision with multibody
int m_nodeQueryIndex;
int m_solverBodyId; // for debugging
btReducedDeformableBody* m_rsb;
btSolverBody* m_solverBody;
btScalar m_dt;
btScalar m_appliedNormalImpulse;
btScalar m_appliedTangentImpulse;
btScalar m_appliedTangentImpulse2;
btScalar m_normalImpulseFactor;
btScalar m_tangentImpulseFactor;
btScalar m_tangentImpulseFactor2;
btScalar m_tangentImpulseFactorInv;
btScalar m_tangentImpulseFactorInv2;
btScalar m_rhs;
btScalar m_rhs_tangent;
btScalar m_rhs_tangent2;
btScalar m_cfm;
btScalar m_cfm_friction;
btScalar m_erp;
btScalar m_erp_friction;
btScalar m_friction;
btVector3 m_contactNormalA; // surface normal for rigid body (opposite direction as impulse)
btVector3 m_contactNormalB; // surface normal for reduced deformable body (opposite direction as impulse)
btVector3 m_contactTangent; // tangential direction of the relative velocity
btVector3 m_contactTangent2; // 2nd tangential direction of the relative velocity
btVector3 m_relPosA; // relative position of the contact point for A (rigid)
btVector3 m_relPosB; // relative position of the contact point for B
btMatrix3x3 m_impulseFactor; // total impulse matrix
btVector3 m_bufferVelocityA; // velocity at the beginning of the iteration
btVector3 m_bufferVelocityB;
btVector3 m_linearComponentNormal; // linear components for the solver body
btVector3 m_angularComponentNormal; // angular components for the solver body
// since 2nd contact direction only applies to multibody, these components will never be used
btVector3 m_linearComponentTangent;
btVector3 m_angularComponentTangent;
btReducedDeformableRigidContactConstraint(btReducedDeformableBody* rsb,
const btSoftBody::DeformableRigidContact& c,
const btContactSolverInfo& infoGlobal,
btScalar dt);
// btReducedDeformableRigidContactConstraint(const btReducedDeformableRigidContactConstraint& other);
btReducedDeformableRigidContactConstraint() {}
virtual ~btReducedDeformableRigidContactConstraint() {}
void setSolverBody(const int bodyId, btSolverBody& solver_body);
virtual void warmStarting() {}
virtual btScalar solveConstraint(const btContactSolverInfo& infoGlobal);
void calculateTangentialImpulse(btScalar& deltaImpulse_tangent,
btScalar& appliedImpulse,
const btScalar rhs_tangent,
const btScalar tangentImpulseFactorInv,
const btVector3& tangent,
const btScalar lower_limit,
const btScalar upper_limit,
const btVector3& deltaV_rel);
virtual void applyImpulse(const btVector3& impulse) {}
virtual void applySplitImpulse(const btVector3& impulse) {} // TODO: may need later
virtual btVector3 getVa() const;
virtual btVector3 getDeltaVa() const = 0;
virtual btVector3 getDeltaVb() const = 0;
};
// ================= node vs rigid constraints ===================
class btReducedDeformableNodeRigidContactConstraint : public btReducedDeformableRigidContactConstraint
{
public:
btSoftBody::Node* m_node;
btReducedDeformableNodeRigidContactConstraint(btReducedDeformableBody* rsb,
const btSoftBody::DeformableNodeRigidContact& contact,
const btContactSolverInfo& infoGlobal,
btScalar dt);
// btReducedDeformableNodeRigidContactConstraint(const btReducedDeformableNodeRigidContactConstraint& other);
btReducedDeformableNodeRigidContactConstraint() {}
virtual ~btReducedDeformableNodeRigidContactConstraint() {}
virtual void warmStarting();
// get the velocity of the deformable node in contact
virtual btVector3 getVb() const;
// get the velocity change of the rigid body
virtual btVector3 getDeltaVa() const;
// get velocity change of the node in contat
virtual btVector3 getDeltaVb() const;
// get the split impulse velocity of the deformable face at the contact point
virtual btVector3 getSplitVb() const;
// get the velocity change of the input soft body node in the constraint
virtual btVector3 getDv(const btSoftBody::Node*) const;
// cast the contact to the desired type
const btSoftBody::DeformableNodeRigidContact* getContact() const
{
return static_cast<const btSoftBody::DeformableNodeRigidContact*>(m_contact);
}
// this calls reduced deformable body's applyFullSpaceImpulse
virtual void applyImpulse(const btVector3& impulse);
};
// ================= face vs rigid constraints ===================
class btReducedDeformableFaceRigidContactConstraint : public btReducedDeformableRigidContactConstraint
{
public:
btSoftBody::Face* m_face;
bool m_useStrainLimiting;
btReducedDeformableFaceRigidContactConstraint(btReducedDeformableBody* rsb,
const btSoftBody::DeformableFaceRigidContact& contact,
const btContactSolverInfo& infoGlobal,
btScalar dt,
bool useStrainLimiting);
// btReducedDeformableFaceRigidContactConstraint(const btReducedDeformableFaceRigidContactConstraint& other);
btReducedDeformableFaceRigidContactConstraint() {}
virtual ~btReducedDeformableFaceRigidContactConstraint() {}
// get the velocity of the deformable face at the contact point
virtual btVector3 getVb() const;
// get the split impulse velocity of the deformable face at the contact point
virtual btVector3 getSplitVb() const;
// get the velocity change of the input soft body node in the constraint
virtual btVector3 getDv(const btSoftBody::Node*) const;
// cast the contact to the desired type
const btSoftBody::DeformableFaceRigidContact* getContact() const
{
return static_cast<const btSoftBody::DeformableFaceRigidContact*>(m_contact);
}
// this calls reduced deformable body's applyFullSpaceImpulse
virtual void applyImpulse(const btVector3& impulse);
};

View File

@ -25,12 +25,18 @@
#include "btDeformableNeoHookeanForce.h" #include "btDeformableNeoHookeanForce.h"
#include "btDeformableContactProjection.h" #include "btDeformableContactProjection.h"
#include "btPreconditioner.h" #include "btPreconditioner.h"
#include "btDeformableMultiBodyDynamicsWorld.h" // #include "btDeformableMultiBodyDynamicsWorld.h"
#include "LinearMath/btQuickprof.h" #include "LinearMath/btQuickprof.h"
class btDeformableBackwardEulerObjective class btDeformableBackwardEulerObjective
{ {
public: public:
enum _
{
Mass_preconditioner,
KKT_preconditioner
};
typedef btAlignedObjectArray<btVector3> TVStack; typedef btAlignedObjectArray<btVector3> TVStack;
btScalar m_dt; btScalar m_dt;
btAlignedObjectArray<btDeformableLagrangianForce*> m_lf; btAlignedObjectArray<btDeformableLagrangianForce*> m_lf;

View File

@ -23,6 +23,7 @@ btDeformableBodySolver::btDeformableBodySolver()
: m_numNodes(0), m_cg(kMaxConjugateGradientIterations), m_cr(kMaxConjugateGradientIterations), m_maxNewtonIterations(1), m_newtonTolerance(1e-4), m_lineSearch(false), m_useProjection(false) : m_numNodes(0), m_cg(kMaxConjugateGradientIterations), m_cr(kMaxConjugateGradientIterations), m_maxNewtonIterations(1), m_newtonTolerance(1e-4), m_lineSearch(false), m_useProjection(false)
{ {
m_objective = new btDeformableBackwardEulerObjective(m_softBodies, m_backupVelocity); m_objective = new btDeformableBackwardEulerObjective(m_softBodies, m_backupVelocity);
m_reducedSolver = false;
} }
btDeformableBodySolver::~btDeformableBodySolver() btDeformableBodySolver::~btDeformableBodySolver()
@ -401,7 +402,7 @@ void btDeformableBodySolver::predictMotion(btScalar solverdt)
} }
} }
} }
m_objective->applyExplicitForce(m_residual); applyExplicitForce();
for (int i = 0; i < m_softBodies.size(); ++i) for (int i = 0; i < m_softBodies.size(); ++i)
{ {
btSoftBody* psb = m_softBodies[i]; btSoftBody* psb = m_softBodies[i];
@ -411,6 +412,7 @@ void btDeformableBodySolver::predictMotion(btScalar solverdt)
psb->m_nodeRigidContacts.resize(0); psb->m_nodeRigidContacts.resize(0);
psb->m_faceRigidContacts.resize(0); psb->m_faceRigidContacts.resize(0);
psb->m_faceNodeContacts.resize(0); psb->m_faceNodeContacts.resize(0);
psb->m_faceNodeContactsCCD.resize(0);
// predict motion for collision detection // predict motion for collision detection
predictDeformableMotion(psb, solverdt); predictDeformableMotion(psb, solverdt);
} }
@ -503,3 +505,89 @@ void btDeformableBodySolver::setLineSearch(bool lineSearch)
{ {
m_lineSearch = lineSearch; m_lineSearch = lineSearch;
} }
void btDeformableBodySolver::applyExplicitForce()
{
m_objective->applyExplicitForce(m_residual);
}
void btDeformableBodySolver::applyTransforms(btScalar timeStep)
{
for (int i = 0; i < m_softBodies.size(); ++i)
{
btSoftBody* psb = m_softBodies[i];
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
btSoftBody::Node& node = psb->m_nodes[j];
btScalar maxDisplacement = psb->getWorldInfo()->m_maxDisplacement;
btScalar clampDeltaV = maxDisplacement / timeStep;
for (int c = 0; c < 3; c++)
{
if (node.m_v[c] > clampDeltaV)
{
node.m_v[c] = clampDeltaV;
}
if (node.m_v[c] < -clampDeltaV)
{
node.m_v[c] = -clampDeltaV;
}
}
node.m_x = node.m_x + timeStep * (node.m_v + node.m_splitv);
node.m_q = node.m_x;
node.m_vn = node.m_v;
}
// enforce anchor constraints
for (int j = 0; j < psb->m_deformableAnchors.size(); ++j)
{
btSoftBody::DeformableNodeRigidAnchor& a = psb->m_deformableAnchors[j];
btSoftBody::Node* n = a.m_node;
n->m_x = a.m_cti.m_colObj->getWorldTransform() * a.m_local;
// update multibody anchor info
if (a.m_cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
{
btMultiBodyLinkCollider* multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(a.m_cti.m_colObj);
if (multibodyLinkCol)
{
btVector3 nrm;
const btCollisionShape* shp = multibodyLinkCol->getCollisionShape();
const btTransform& wtr = multibodyLinkCol->getWorldTransform();
psb->m_worldInfo->m_sparsesdf.Evaluate(
wtr.invXform(n->m_x),
shp,
nrm,
0);
a.m_cti.m_normal = wtr.getBasis() * nrm;
btVector3 normal = a.m_cti.m_normal;
btVector3 t1 = generateUnitOrthogonalVector(normal);
btVector3 t2 = btCross(normal, t1);
btMultiBodyJacobianData jacobianData_normal, jacobianData_t1, jacobianData_t2;
findJacobian(multibodyLinkCol, jacobianData_normal, a.m_node->m_x, normal);
findJacobian(multibodyLinkCol, jacobianData_t1, a.m_node->m_x, t1);
findJacobian(multibodyLinkCol, jacobianData_t2, a.m_node->m_x, t2);
btScalar* J_n = &jacobianData_normal.m_jacobians[0];
btScalar* J_t1 = &jacobianData_t1.m_jacobians[0];
btScalar* J_t2 = &jacobianData_t2.m_jacobians[0];
btScalar* u_n = &jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
btScalar* u_t1 = &jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
btScalar* u_t2 = &jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
btMatrix3x3 rot(normal.getX(), normal.getY(), normal.getZ(),
t1.getX(), t1.getY(), t1.getZ(),
t2.getX(), t2.getY(), t2.getZ()); // world frame to local frame
const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
btMatrix3x3 local_impulse_matrix = (Diagonal(n->m_im) + OuterProduct(J_n, J_t1, J_t2, u_n, u_t1, u_t2, ndof)).inverse();
a.m_c0 = rot.transpose() * local_impulse_matrix * rot;
a.jacobianData_normal = jacobianData_normal;
a.jacobianData_t1 = jacobianData_t1;
a.jacobianData_t2 = jacobianData_t2;
a.t1 = t1;
a.t2 = t2;
}
}
}
psb->interpolateRenderMesh();
}
}

View File

@ -24,8 +24,8 @@
#include "btConjugateResidual.h" #include "btConjugateResidual.h"
#include "btConjugateGradient.h" #include "btConjugateGradient.h"
struct btCollisionObjectWrapper; struct btCollisionObjectWrapper;
class btDeformableBackwardEulerObjective; // class btDeformableBackwardEulerObjective;
class btDeformableMultiBodyDynamicsWorld; // class btDeformableMultiBodyDynamicsWorld;
class btDeformableBodySolver : public btSoftBodySolver class btDeformableBodySolver : public btSoftBodySolver
{ {
@ -46,6 +46,7 @@ protected:
int m_maxNewtonIterations; // max number of newton iterations int m_maxNewtonIterations; // max number of newton iterations
btScalar m_newtonTolerance; // stop newton iterations if f(x) < m_newtonTolerance btScalar m_newtonTolerance; // stop newton iterations if f(x) < m_newtonTolerance
bool m_lineSearch; // If true, use newton's method with line search under implicit scheme bool m_lineSearch; // If true, use newton's method with line search under implicit scheme
bool m_reducedSolver; // flag for reduced soft body solver
public: public:
// handles data related to objective function // handles data related to objective function
btDeformableBackwardEulerObjective* m_objective; btDeformableBackwardEulerObjective* m_objective;
@ -68,11 +69,18 @@ public:
// solve the momentum equation // solve the momentum equation
virtual void solveDeformableConstraints(btScalar solverdt); virtual void solveDeformableConstraints(btScalar solverdt);
// set gravity (get from deformable world)
virtual void setGravity(const btVector3& gravity)
{
// for full deformable object, we don't store gravity in the solver
// this function is overriden in the reduced deformable object
}
// resize/clear data structures // resize/clear data structures
void reinitialize(const btAlignedObjectArray<btSoftBody*>& softBodies, btScalar dt); virtual void reinitialize(const btAlignedObjectArray<btSoftBody*>& softBodies, btScalar dt);
// set up contact constraints // set up contact constraints
void setConstraints(const btContactSolverInfo& infoGlobal); virtual void setConstraints(const btContactSolverInfo& infoGlobal);
// add in elastic forces and gravity to obtain v_{n+1}^* and calls predictDeformableMotion // add in elastic forces and gravity to obtain v_{n+1}^* and calls predictDeformableMotion
virtual void predictMotion(btScalar solverdt); virtual void predictMotion(btScalar solverdt);
@ -85,7 +93,7 @@ public:
void backupVelocity(); void backupVelocity();
// set m_dv and m_backupVelocity to desired value to prepare for momentum solve // set m_dv and m_backupVelocity to desired value to prepare for momentum solve
void setupDeformableSolve(bool implicit); virtual void setupDeformableSolve(bool implicit);
// set the current velocity to that backed up in m_backupVelocity // set the current velocity to that backed up in m_backupVelocity
void revertVelocity(); void revertVelocity();
@ -150,6 +158,62 @@ public:
// used in line search // used in line search
btScalar kineticEnergy(); btScalar kineticEnergy();
// add explicit force to the velocity in the objective class
virtual void applyExplicitForce();
// execute position/velocity update and apply anchor constraints in the integrateTransforms from the Dynamics world
virtual void applyTransforms(btScalar timeStep);
virtual void setStrainLimiting(bool opt)
{
m_objective->m_projection.m_useStrainLimiting = opt;
}
virtual void setPreconditioner(int opt)
{
switch (opt)
{
case btDeformableBackwardEulerObjective::Mass_preconditioner:
m_objective->m_preconditioner = m_objective->m_massPreconditioner;
break;
case btDeformableBackwardEulerObjective::KKT_preconditioner:
m_objective->m_preconditioner = m_objective->m_KKTPreconditioner;
break;
default:
btAssert(false);
break;
}
}
virtual btAlignedObjectArray<btDeformableLagrangianForce*>* getLagrangianForceArray()
{
return &(m_objective->m_lf);
}
virtual const btAlignedObjectArray<btSoftBody::Node*>* getIndices()
{
return m_objective->getIndices();
}
virtual void setProjection()
{
m_objective->m_projection.setProjection();
}
virtual void setLagrangeMultiplier()
{
m_objective->m_projection.setLagrangeMultiplier();
}
virtual bool isReducedSolver()
{
return m_reducedSolver;
}
virtual void deformableBodyInternalWriteBack() {}
// unused functions // unused functions
virtual void optimize(btAlignedObjectArray<btSoftBody*>& softBodies, bool forceUpdate = false) {} virtual void optimize(btAlignedObjectArray<btSoftBody*>& softBodies, bool forceUpdate = false) {}
virtual void solveConstraints(btScalar dt) {} virtual void solveConstraints(btScalar dt) {}

View File

@ -268,7 +268,7 @@ btScalar btDeformableRigidContactConstraint::solveConstraint(const btContactSolv
{ {
dn += m_penetration * infoGlobal.m_deformable_erp / infoGlobal.m_timeStep; dn += m_penetration * infoGlobal.m_deformable_erp / infoGlobal.m_timeStep;
} }
// dn is the normal component of velocity difference. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt // dn is the normal component of velocity diffrerence. Approximates the residual. // todo xuchenhan@: this prob needs to be scaled by dt
btVector3 impulse = m_contact->m_c0 * (vr + m_total_normal_dv * infoGlobal.m_deformable_cfm + ((m_penetration > 0) ? m_penetration / infoGlobal.m_timeStep * cti.m_normal : btVector3(0, 0, 0))); btVector3 impulse = m_contact->m_c0 * (vr + m_total_normal_dv * infoGlobal.m_deformable_cfm + ((m_penetration > 0) ? m_penetration / infoGlobal.m_timeStep * cti.m_normal : btVector3(0, 0, 0)));
if (!infoGlobal.m_splitImpulse) if (!infoGlobal.m_splitImpulse)
{ {
@ -487,9 +487,6 @@ void btDeformableFaceRigidContactConstraint::applyImpulse(const btVector3& impul
btVector3 dv = impulse * contact->m_c2; btVector3 dv = impulse * contact->m_c2;
btSoftBody::Face* face = contact->m_face; btSoftBody::Face* face = contact->m_face;
// save applied impulse
contact->m_cti.m_impulse = impulse;
btVector3& v0 = face->m_n[0]->m_v; btVector3& v0 = face->m_n[0]->m_v;
btVector3& v1 = face->m_n[1]->m_v; btVector3& v1 = face->m_n[1]->m_v;
btVector3& v2 = face->m_n[2]->m_v; btVector3& v2 = face->m_n[2]->m_v;

View File

@ -14,11 +14,16 @@
*/ */
#include "btDeformableMultiBodyConstraintSolver.h" #include "btDeformableMultiBodyConstraintSolver.h"
#include "BulletReducedDeformableBody/btReducedDeformableBodySolver.h"
#include <iostream> #include <iostream>
// override the iterations method to include deformable/multibody contact // override the iterations method to include deformable/multibody contact
btScalar btDeformableMultiBodyConstraintSolver::solveDeformableGroupIterations(btCollisionObject** bodies, int numBodies, btCollisionObject** deformableBodies, int numDeformableBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer) btScalar btDeformableMultiBodyConstraintSolver::solveDeformableGroupIterations(btCollisionObject** bodies, int numBodies, btCollisionObject** deformableBodies, int numDeformableBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer)
{ {
{ {
// pair deformable body with solver body
pairDeformableAndSolverBody(bodies, numBodies, numDeformableBodies, infoGlobal);
///this is a special step to resolve penetrations (just for contacts) ///this is a special step to resolve penetrations (just for contacts)
solveGroupCacheFriendlySplitImpulseIterations(bodies, numBodies, deformableBodies, numDeformableBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer); solveGroupCacheFriendlySplitImpulseIterations(bodies, numBodies, deformableBodies, numDeformableBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
@ -37,6 +42,10 @@ btScalar btDeformableMultiBodyConstraintSolver::solveDeformableGroupIterations(b
// solver body velocity <- rigid body velocity // solver body velocity <- rigid body velocity
writeToSolverBody(bodies, numBodies, infoGlobal); writeToSolverBody(bodies, numBodies, infoGlobal);
// std::cout << "------------Iteration " << iteration << "------------\n";
// std::cout << "m_leastSquaresResidual: " << m_leastSquaresResidual << "\n";
if (m_leastSquaresResidual <= infoGlobal.m_leastSquaresResidualThreshold || (iteration >= (maxIterations - 1))) if (m_leastSquaresResidual <= infoGlobal.m_leastSquaresResidualThreshold || (iteration >= (maxIterations - 1)))
{ {
#ifdef VERBOSE_RESIDUAL_PRINTF #ifdef VERBOSE_RESIDUAL_PRINTF
@ -51,6 +60,9 @@ btScalar btDeformableMultiBodyConstraintSolver::solveDeformableGroupIterations(b
m_analyticsData.m_numBodies = numBodies; m_analyticsData.m_numBodies = numBodies;
m_analyticsData.m_numContactManifolds = numManifolds; m_analyticsData.m_numContactManifolds = numManifolds;
m_analyticsData.m_remainingLeastSquaresResidual = m_leastSquaresResidual; m_analyticsData.m_remainingLeastSquaresResidual = m_leastSquaresResidual;
m_deformableSolver->deformableBodyInternalWriteBack();
// std::cout << "[===================Next Step===================]\n";
break; break;
} }
} }
@ -78,6 +90,12 @@ void btDeformableMultiBodyConstraintSolver::solveDeformableBodyGroup(btCollision
void btDeformableMultiBodyConstraintSolver::writeToSolverBody(btCollisionObject** bodies, int numBodies, const btContactSolverInfo& infoGlobal) void btDeformableMultiBodyConstraintSolver::writeToSolverBody(btCollisionObject** bodies, int numBodies, const btContactSolverInfo& infoGlobal)
{ {
// reduced soft body solver directly modifies the solver body
if (m_deformableSolver->isReducedSolver())
{
return;
}
for (int i = 0; i < numBodies; i++) for (int i = 0; i < numBodies; i++)
{ {
int bodyId = getOrInitSolverBody(*bodies[i], infoGlobal.m_timeStep); int bodyId = getOrInitSolverBody(*bodies[i], infoGlobal.m_timeStep);
@ -94,6 +112,12 @@ void btDeformableMultiBodyConstraintSolver::writeToSolverBody(btCollisionObject*
void btDeformableMultiBodyConstraintSolver::solverBodyWriteBack(const btContactSolverInfo& infoGlobal) void btDeformableMultiBodyConstraintSolver::solverBodyWriteBack(const btContactSolverInfo& infoGlobal)
{ {
// reduced soft body solver directly modifies the solver body
if (m_deformableSolver->isReducedSolver())
{
return;
}
for (int i = 0; i < m_tmpSolverBodyPool.size(); i++) for (int i = 0; i < m_tmpSolverBodyPool.size(); i++)
{ {
btRigidBody* body = m_tmpSolverBodyPool[i].m_originalBody; btRigidBody* body = m_tmpSolverBodyPool[i].m_originalBody;
@ -105,6 +129,53 @@ void btDeformableMultiBodyConstraintSolver::solverBodyWriteBack(const btContactS
} }
} }
void btDeformableMultiBodyConstraintSolver::pairDeformableAndSolverBody(btCollisionObject** bodies, int numBodies, int numDeformableBodies, const btContactSolverInfo& infoGlobal)
{
if (!m_deformableSolver->isReducedSolver())
{
return;
}
btReducedDeformableBodySolver* solver = static_cast<btReducedDeformableBodySolver*>(m_deformableSolver);
for (int i = 0; i < numDeformableBodies; ++i)
{
for (int k = 0; k < solver->m_nodeRigidConstraints[i].size(); ++k)
{
btReducedDeformableNodeRigidContactConstraint& constraint = solver->m_nodeRigidConstraints[i][k];
if (!constraint.m_contact->m_cti.m_colObj->isStaticObject())
{
btCollisionObject& col_obj = const_cast<btCollisionObject&>(*constraint.m_contact->m_cti.m_colObj);
// object index in the solver body pool
int bodyId = getOrInitSolverBody(col_obj, infoGlobal.m_timeStep);
const btRigidBody* body = btRigidBody::upcast(bodies[bodyId]);
if (body && body->getInvMass())
{
// std::cout << "Node: " << constraint.m_node->index << ", body: " << bodyId << "\n";
btSolverBody& solverBody = m_tmpSolverBodyPool[bodyId];
constraint.setSolverBody(bodyId, solverBody);
}
}
}
// for (int j = 0; j < numBodies; j++)
// {
// int bodyId = getOrInitSolverBody(*bodies[j], infoGlobal.m_timeStep);
// btRigidBody* body = btRigidBody::upcast(bodies[j]);
// if (body && body->getInvMass())
// {
// btSolverBody& solverBody = m_tmpSolverBodyPool[bodyId];
// m_deformableSolver->pairConstraintWithSolverBody(i, bodyId, solverBody);
// }
// }
}
}
void btDeformableMultiBodyConstraintSolver::solveGroupCacheFriendlySplitImpulseIterations(btCollisionObject** bodies, int numBodies, btCollisionObject** deformableBodies, int numDeformableBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer) void btDeformableMultiBodyConstraintSolver::solveGroupCacheFriendlySplitImpulseIterations(btCollisionObject** bodies, int numBodies, btCollisionObject** deformableBodies, int numDeformableBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer)
{ {
BT_PROFILE("solveGroupCacheFriendlySplitImpulseIterations"); BT_PROFILE("solveGroupCacheFriendlySplitImpulseIterations");

View File

@ -43,6 +43,9 @@ protected:
// write the velocity of the underlying rigid body to the the the solver body // write the velocity of the underlying rigid body to the the the solver body
void writeToSolverBody(btCollisionObject * *bodies, int numBodies, const btContactSolverInfo& infoGlobal); void writeToSolverBody(btCollisionObject * *bodies, int numBodies, const btContactSolverInfo& infoGlobal);
// let each deformable body knows which solver body is in constact
void pairDeformableAndSolverBody(btCollisionObject** bodies, int numBodies, int numDeformableBodies, const btContactSolverInfo& infoGlobal);
virtual void solveGroupCacheFriendlySplitImpulseIterations(btCollisionObject * *bodies, int numBodies, btCollisionObject** deformableBodies, int numDeformableBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer); virtual void solveGroupCacheFriendlySplitImpulseIterations(btCollisionObject * *bodies, int numBodies, btCollisionObject** deformableBodies, int numDeformableBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer);
virtual btScalar solveDeformableGroupIterations(btCollisionObject * *bodies, int numBodies, btCollisionObject** deformableBodies, int numDeformableBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer); virtual btScalar solveDeformableGroupIterations(btCollisionObject * *bodies, int numBodies, btCollisionObject** deformableBodies, int numDeformableBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer);

View File

@ -94,7 +94,7 @@ void btDeformableMultiBodyDynamicsWorld::internalSingleStepSimulation(btScalar t
beforeSolverCallbacks(timeStep); beforeSolverCallbacks(timeStep);
///solve contact constraints and then deformable bodies momemtum equation // ///solve contact constraints and then deformable bodies momemtum equation
solveConstraints(timeStep); solveConstraints(timeStep);
afterSolverCallbacks(timeStep); afterSolverCallbacks(timeStep);
@ -201,7 +201,7 @@ void btDeformableMultiBodyDynamicsWorld::performGeometricCollisions(btScalar tim
if (psb->isActive()) if (psb->isActive())
{ {
// clear contact points in the previous iteration // clear contact points in the previous iteration
psb->m_faceNodeContacts.clear(); psb->m_faceNodeContactsCCD.clear();
// update m_q and normals for CCD calculation // update m_q and normals for CCD calculation
for (int j = 0; j < psb->m_nodes.size(); ++j) for (int j = 0; j < psb->m_nodes.size(); ++j)
@ -237,7 +237,8 @@ void btDeformableMultiBodyDynamicsWorld::performGeometricCollisions(btScalar tim
btSoftBody* psb = m_softBodies[i]; btSoftBody* psb = m_softBodies[i];
if (psb->isActive()) if (psb->isActive())
{ {
penetration_count += psb->m_faceNodeContacts.size(); penetration_count += psb->m_faceNodeContactsCCD.size();
;
} }
} }
if (penetration_count == 0) if (penetration_count == 0)
@ -297,83 +298,7 @@ void btDeformableMultiBodyDynamicsWorld::integrateTransforms(btScalar timeStep)
BT_PROFILE("integrateTransforms"); BT_PROFILE("integrateTransforms");
positionCorrection(timeStep); positionCorrection(timeStep);
btMultiBodyDynamicsWorld::integrateTransforms(timeStep); btMultiBodyDynamicsWorld::integrateTransforms(timeStep);
for (int i = 0; i < m_softBodies.size(); ++i) m_deformableBodySolver->applyTransforms(timeStep);
{
btSoftBody* psb = m_softBodies[i];
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
btSoftBody::Node& node = psb->m_nodes[j];
btScalar maxDisplacement = psb->getWorldInfo()->m_maxDisplacement;
btScalar clampDeltaV = maxDisplacement / timeStep;
for (int c = 0; c < 3; c++)
{
if (node.m_v[c] > clampDeltaV)
{
node.m_v[c] = clampDeltaV;
}
if (node.m_v[c] < -clampDeltaV)
{
node.m_v[c] = -clampDeltaV;
}
}
node.m_x = node.m_x + timeStep * (node.m_v + node.m_splitv);
node.m_q = node.m_x;
node.m_vn = node.m_v;
}
// enforce anchor constraints
for (int j = 0; j < psb->m_deformableAnchors.size(); ++j)
{
btSoftBody::DeformableNodeRigidAnchor& a = psb->m_deformableAnchors[j];
btSoftBody::Node* n = a.m_node;
n->m_x = a.m_cti.m_colObj->getWorldTransform() * a.m_local;
// update multibody anchor info
if (a.m_cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
{
btMultiBodyLinkCollider* multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(a.m_cti.m_colObj);
if (multibodyLinkCol)
{
btVector3 nrm;
const btCollisionShape* shp = multibodyLinkCol->getCollisionShape();
const btTransform& wtr = multibodyLinkCol->getWorldTransform();
psb->m_worldInfo->m_sparsesdf.Evaluate(
wtr.invXform(n->m_x),
shp,
nrm,
0);
a.m_cti.m_normal = wtr.getBasis() * nrm;
btVector3 normal = a.m_cti.m_normal;
btVector3 t1 = generateUnitOrthogonalVector(normal);
btVector3 t2 = btCross(normal, t1);
btMultiBodyJacobianData jacobianData_normal, jacobianData_t1, jacobianData_t2;
findJacobian(multibodyLinkCol, jacobianData_normal, a.m_node->m_x, normal);
findJacobian(multibodyLinkCol, jacobianData_t1, a.m_node->m_x, t1);
findJacobian(multibodyLinkCol, jacobianData_t2, a.m_node->m_x, t2);
btScalar* J_n = &jacobianData_normal.m_jacobians[0];
btScalar* J_t1 = &jacobianData_t1.m_jacobians[0];
btScalar* J_t2 = &jacobianData_t2.m_jacobians[0];
btScalar* u_n = &jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
btScalar* u_t1 = &jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
btScalar* u_t2 = &jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
btMatrix3x3 rot(normal.getX(), normal.getY(), normal.getZ(),
t1.getX(), t1.getY(), t1.getZ(),
t2.getX(), t2.getY(), t2.getZ()); // world frame to local frame
const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
btMatrix3x3 local_impulse_matrix = (Diagonal(n->m_im) + OuterProduct(J_n, J_t1, J_t2, u_n, u_t1, u_t2, ndof)).inverse();
a.m_c0 = rot.transpose() * local_impulse_matrix * rot;
a.jacobianData_normal = jacobianData_normal;
a.jacobianData_t1 = jacobianData_t1;
a.jacobianData_t2 = jacobianData_t2;
a.t1 = t1;
a.t2 = t2;
}
}
}
psb->interpolateRenderMesh();
}
} }
void btDeformableMultiBodyDynamicsWorld::solveConstraints(btScalar timeStep) void btDeformableMultiBodyDynamicsWorld::solveConstraints(btScalar timeStep)
@ -390,9 +315,9 @@ void btDeformableMultiBodyDynamicsWorld::solveConstraints(btScalar timeStep)
// set up the directions in which the velocity does not change in the momentum solve // set up the directions in which the velocity does not change in the momentum solve
if (m_useProjection) if (m_useProjection)
m_deformableBodySolver->m_objective->m_projection.setProjection(); m_deformableBodySolver->setProjection();
else else
m_deformableBodySolver->m_objective->m_projection.setLagrangeMultiplier(); m_deformableBodySolver->setLagrangeMultiplier();
// for explicit scheme, m_backupVelocity = v_{n+1}^* // for explicit scheme, m_backupVelocity = v_{n+1}^*
// for implicit scheme, m_backupVelocity = v_n // for implicit scheme, m_backupVelocity = v_n
@ -518,6 +443,12 @@ void btDeformableMultiBodyDynamicsWorld::predictUnconstraintMotion(btScalar time
m_deformableBodySolver->predictMotion(timeStep); m_deformableBodySolver->predictMotion(timeStep);
} }
void btDeformableMultiBodyDynamicsWorld::setGravity(const btVector3& gravity)
{
btDiscreteDynamicsWorld::setGravity(gravity);
m_deformableBodySolver->setGravity(gravity);
}
void btDeformableMultiBodyDynamicsWorld::reinitialize(btScalar timeStep) void btDeformableMultiBodyDynamicsWorld::reinitialize(btScalar timeStep)
{ {
m_internalTime += timeStep; m_internalTime += timeStep;
@ -532,14 +463,14 @@ void btDeformableMultiBodyDynamicsWorld::reinitialize(btScalar timeStep)
if (m_useProjection) if (m_useProjection)
{ {
m_deformableBodySolver->m_useProjection = true; m_deformableBodySolver->m_useProjection = true;
m_deformableBodySolver->m_objective->m_projection.m_useStrainLimiting = true; m_deformableBodySolver->setStrainLimiting(true);
m_deformableBodySolver->m_objective->m_preconditioner = m_deformableBodySolver->m_objective->m_massPreconditioner; m_deformableBodySolver->setPreconditioner(btDeformableBackwardEulerObjective::Mass_preconditioner);
} }
else else
{ {
m_deformableBodySolver->m_useProjection = false; m_deformableBodySolver->m_useProjection = false;
m_deformableBodySolver->m_objective->m_projection.m_useStrainLimiting = false; m_deformableBodySolver->setStrainLimiting(false);
m_deformableBodySolver->m_objective->m_preconditioner = m_deformableBodySolver->m_objective->m_KKTPreconditioner; m_deformableBodySolver->setPreconditioner(btDeformableBackwardEulerObjective::KKT_preconditioner);
} }
} }
@ -681,7 +612,7 @@ void btDeformableMultiBodyDynamicsWorld::afterSolverCallbacks(btScalar timeStep)
void btDeformableMultiBodyDynamicsWorld::addForce(btSoftBody* psb, btDeformableLagrangianForce* force) void btDeformableMultiBodyDynamicsWorld::addForce(btSoftBody* psb, btDeformableLagrangianForce* force)
{ {
btAlignedObjectArray<btDeformableLagrangianForce*>& forces = m_deformableBodySolver->m_objective->m_lf; btAlignedObjectArray<btDeformableLagrangianForce*>& forces = *m_deformableBodySolver->getLagrangianForceArray();
bool added = false; bool added = false;
for (int i = 0; i < forces.size(); ++i) for (int i = 0; i < forces.size(); ++i)
{ {
@ -695,14 +626,14 @@ void btDeformableMultiBodyDynamicsWorld::addForce(btSoftBody* psb, btDeformableL
if (!added) if (!added)
{ {
force->addSoftBody(psb); force->addSoftBody(psb);
force->setIndices(m_deformableBodySolver->m_objective->getIndices()); force->setIndices(m_deformableBodySolver->getIndices());
forces.push_back(force); forces.push_back(force);
} }
} }
void btDeformableMultiBodyDynamicsWorld::removeForce(btSoftBody* psb, btDeformableLagrangianForce* force) void btDeformableMultiBodyDynamicsWorld::removeForce(btSoftBody* psb, btDeformableLagrangianForce* force)
{ {
btAlignedObjectArray<btDeformableLagrangianForce*>& forces = m_deformableBodySolver->m_objective->m_lf; btAlignedObjectArray<btDeformableLagrangianForce*>& forces = *m_deformableBodySolver->getLagrangianForceArray();
int removed_index = -1; int removed_index = -1;
for (int i = 0; i < forces.size(); ++i) for (int i = 0; i < forces.size(); ++i)
{ {
@ -720,7 +651,7 @@ void btDeformableMultiBodyDynamicsWorld::removeForce(btSoftBody* psb, btDeformab
void btDeformableMultiBodyDynamicsWorld::removeSoftBodyForce(btSoftBody* psb) void btDeformableMultiBodyDynamicsWorld::removeSoftBodyForce(btSoftBody* psb)
{ {
btAlignedObjectArray<btDeformableLagrangianForce*>& forces = m_deformableBodySolver->m_objective->m_lf; btAlignedObjectArray<btDeformableLagrangianForce*>& forces = *m_deformableBodySolver->getLagrangianForceArray();
for (int i = 0; i < forces.size(); ++i) for (int i = 0; i < forces.size(); ++i)
{ {
forces[i]->removeSoftBody(psb); forces[i]->removeSoftBody(psb);

View File

@ -19,7 +19,7 @@
#include "btSoftMultiBodyDynamicsWorld.h" #include "btSoftMultiBodyDynamicsWorld.h"
#include "btDeformableLagrangianForce.h" #include "btDeformableLagrangianForce.h"
#include "btDeformableMassSpringForce.h" #include "btDeformableMassSpringForce.h"
#include "btDeformableBodySolver.h" // #include "btDeformableBodySolver.h"
#include "btDeformableMultiBodyConstraintSolver.h" #include "btDeformableMultiBodyConstraintSolver.h"
#include "btSoftBodyHelpers.h" #include "btSoftBodyHelpers.h"
#include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h" #include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h"
@ -121,6 +121,8 @@ public:
return m_sbi; return m_sbi;
} }
virtual void setGravity(const btVector3& gravity);
void reinitialize(btScalar timeStep); void reinitialize(btScalar timeStep);
void applyRigidBodyGravity(btScalar timeStep); void applyRigidBodyGravity(btScalar timeStep);

View File

@ -231,6 +231,9 @@ void btSoftBody::initDefaults()
m_gravityFactor = 1; m_gravityFactor = 1;
m_cacheBarycenter = false; m_cacheBarycenter = false;
m_fdbvnt = 0; m_fdbvnt = 0;
// reduced flag
m_reducedModel = false;
} }
// //
@ -1483,6 +1486,21 @@ void btSoftBody::randomizeConstraints()
#undef NEXTRAND #undef NEXTRAND
} }
void btSoftBody::updateState(const btAlignedObjectArray<btVector3>& q, const btAlignedObjectArray<btVector3>& v)
{
int node_count = m_nodes.size();
btAssert(node_count == q.size());
btAssert(node_count == v.size());
for (int i = 0; i < node_count; i++)
{
Node& n = m_nodes[i];
n.m_x = q[i];
n.m_q = q[i];
n.m_v = v[i];
n.m_vn = v[i];
}
}
// //
void btSoftBody::releaseCluster(int index) void btSoftBody::releaseCluster(int index)
{ {
@ -3879,7 +3897,7 @@ void btSoftBody::PSolve_RContacts(btSoftBody* psb, btScalar kst, btScalar ti)
btVector3 va(0, 0, 0); btVector3 va(0, 0, 0);
btRigidBody* rigidCol = 0; btRigidBody* rigidCol = 0;
btMultiBodyLinkCollider* multibodyLinkCol = 0; btMultiBodyLinkCollider* multibodyLinkCol = 0;
btScalar* deltaV; btScalar* deltaV = NULL;
if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY) if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
{ {

View File

@ -225,10 +225,8 @@ public:
{ {
const btCollisionObject* m_colObj; /* Rigid body */ const btCollisionObject* m_colObj; /* Rigid body */
btVector3 m_normal; /* Outward normal */ btVector3 m_normal; /* Outward normal */
mutable btVector3 m_impulse; /* Applied impulse */
btScalar m_offset; /* Offset from origin */ btScalar m_offset; /* Offset from origin */
btVector3 m_bary; /* Barycentric weights for faces */ btVector3 m_bary; /* Barycentric weights for faces */
sCti() : m_impulse(0, 0, 0) {}
}; };
/* sMedium */ /* sMedium */
@ -409,6 +407,7 @@ public:
btScalar m_friction; // Friction btScalar m_friction; // Friction
btScalar m_imf; // inverse mass of the face at contact point btScalar m_imf; // inverse mass of the face at contact point
btScalar m_c0; // scale of the impulse matrix; btScalar m_c0; // scale of the impulse matrix;
const btCollisionObject* m_colObj; // Collision object to collide with.
}; };
/* SContact */ /* SContact */
@ -800,6 +799,7 @@ public:
typedef btAlignedObjectArray<Material*> tMaterialArray; typedef btAlignedObjectArray<Material*> tMaterialArray;
typedef btAlignedObjectArray<Joint*> tJointArray; typedef btAlignedObjectArray<Joint*> tJointArray;
typedef btAlignedObjectArray<btSoftBody*> tSoftBodyArray; typedef btAlignedObjectArray<btSoftBody*> tSoftBodyArray;
typedef btAlignedObjectArray<btAlignedObjectArray<btScalar> > tDenseMatrix;
// //
// Fields // Fields
@ -825,6 +825,7 @@ public:
btAlignedObjectArray<DeformableNodeRigidContact> m_nodeRigidContacts; btAlignedObjectArray<DeformableNodeRigidContact> m_nodeRigidContacts;
btAlignedObjectArray<DeformableFaceNodeContact> m_faceNodeContacts; btAlignedObjectArray<DeformableFaceNodeContact> m_faceNodeContacts;
btAlignedObjectArray<DeformableFaceRigidContact> m_faceRigidContacts; btAlignedObjectArray<DeformableFaceRigidContact> m_faceRigidContacts;
btAlignedObjectArray<DeformableFaceNodeContact> m_faceNodeContactsCCD;
tSContactArray m_scontacts; // Soft contacts tSContactArray m_scontacts; // Soft contacts
tJointArray m_joints; // Joints tJointArray m_joints; // Joints
tMaterialArray m_materials; // Materials tMaterialArray m_materials; // Materials
@ -857,6 +858,8 @@ public:
btScalar m_restLengthScale; btScalar m_restLengthScale;
bool m_reducedModel; // Reduced deformable model flag
// //
// Api // Api
// //
@ -894,7 +897,7 @@ public:
int node1) const; int node1) const;
bool checkLink(const Node* node0, bool checkLink(const Node* node0,
const Node* node1) const; const Node* node1) const;
/* Check for existing face */ /* Check for existring face */
bool checkFace(int node0, bool checkFace(int node0,
int node1, int node1,
int node2) const; int node2) const;
@ -1003,15 +1006,15 @@ public:
/* Get best fit rigid transform */ /* Get best fit rigid transform */
btTransform getRigidTransform(); btTransform getRigidTransform();
/* Transform to given pose */ /* Transform to given pose */
void transformTo(const btTransform& trs); virtual void transformTo(const btTransform& trs);
/* Transform */ /* Transform */
void transform(const btTransform& trs); virtual void transform(const btTransform& trs);
/* Translate */ /* Translate */
void translate(const btVector3& trs); virtual void translate(const btVector3& trs);
/* Rotate */ /* Rotate */
void rotate(const btQuaternion& rot); virtual void rotate(const btQuaternion& rot);
/* Scale */ /* Scale */
void scale(const btVector3& scl); virtual void scale(const btVector3& scl);
/* Get link resting lengths scale */ /* Get link resting lengths scale */
btScalar getRestLengthScale(); btScalar getRestLengthScale();
/* Scale resting length of all springs */ /* Scale resting length of all springs */
@ -1053,6 +1056,9 @@ public:
Material* mat = 0); Material* mat = 0);
/* Randomize constraints to reduce solver bias */ /* Randomize constraints to reduce solver bias */
void randomizeConstraints(); void randomizeConstraints();
void updateState(const btAlignedObjectArray<btVector3>& qs, const btAlignedObjectArray<btVector3>& vs);
/* Release clusters */ /* Release clusters */
void releaseCluster(int index); void releaseCluster(int index);
void releaseClusters(); void releaseClusters();
@ -1098,6 +1104,13 @@ public:
void setZeroVelocity(); void setZeroVelocity();
bool wantsSleeping(); bool wantsSleeping();
virtual btMatrix3x3 getImpulseFactor(int n_node)
{
btMatrix3x3 tmp;
tmp.setIdentity();
return tmp;
}
// //
// Functionality to deal with new accelerated solvers. // Functionality to deal with new accelerated solvers.
// //

View File

@ -18,6 +18,7 @@ subject to the following restrictions:
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <iomanip>
#include <sstream> #include <sstream>
#include <string.h> #include <string.h>
#include <algorithm> #include <algorithm>
@ -1487,6 +1488,37 @@ void btSoftBodyHelpers::writeObj(const char* filename, const btSoftBody* psb)
fs.close(); fs.close();
} }
void btSoftBodyHelpers::writeState(const char* file, const btSoftBody* psb)
{
std::ofstream fs;
fs.open(file);
btAssert(fs);
fs << std::scientific << std::setprecision(16);
// Only write out for trimesh, directly write out all the nodes and faces.xs
for (int i = 0; i < psb->m_nodes.size(); ++i)
{
fs << "q";
for (int d = 0; d < 3; d++)
{
fs << " " << psb->m_nodes[i].m_q[d];
}
fs << "\n";
}
for (int i = 0; i < psb->m_nodes.size(); ++i)
{
fs << "v";
for (int d = 0; d < 3; d++)
{
fs << " " << psb->m_nodes[i].m_v[d];
}
fs << "\n";
}
fs.close();
}
void btSoftBodyHelpers::duplicateFaces(const char* filename, const btSoftBody* psb) void btSoftBodyHelpers::duplicateFaces(const char* filename, const btSoftBody* psb)
{ {
std::ifstream fs_read; std::ifstream fs_read;

View File

@ -146,6 +146,11 @@ struct btSoftBodyHelpers
static void writeObj(const char* file, const btSoftBody* psb); static void writeObj(const char* file, const btSoftBody* psb);
static void writeState(const char* file, const btSoftBody* psb);
//this code cannot be here, dependency on example code are not allowed
//static std::string loadDeformableState(btAlignedObjectArray<btVector3>& qs, btAlignedObjectArray<btVector3>& vs, const char* filename, CommonFileIOInterface* fileIO);
static void getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, const btVector3& p, btVector4& bary); static void getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, const btVector3& p, btVector4& bary);
static void getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& p, btVector4& bary); static void getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& p, btVector4& bary);

View File

@ -1691,12 +1691,19 @@ struct btSoftColliders
if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY) if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
{ {
const btTransform& wtr = m_rigidBody ? m_rigidBody->getWorldTransform() : m_colObj1Wrap->getCollisionObject()->getWorldTransform(); const btTransform& wtr = m_rigidBody ? m_rigidBody->getWorldTransform() : m_colObj1Wrap->getCollisionObject()->getWorldTransform();
static const btMatrix3x3 iwiStatic(0, 0, 0, 0, 0, 0, 0, 0, 0);
const btMatrix3x3& iwi = m_rigidBody ? m_rigidBody->getInvInertiaTensorWorld() : iwiStatic;
const btVector3 ra = n.m_x - wtr.getOrigin(); const btVector3 ra = n.m_x - wtr.getOrigin();
static const btMatrix3x3 iwiStatic(0, 0, 0, 0, 0, 0, 0, 0, 0);
const btMatrix3x3& iwi = m_rigidBody ? m_rigidBody->getInvInertiaTensorWorld() : iwiStatic;
if (psb->m_reducedModel)
{
c.m_c0 = MassMatrix(imb, iwi, ra); //impulse factor K of the rigid body only (not the inverse)
}
else
{
c.m_c0 = ImpulseMatrix(1, n.m_effectiveMass_inv, imb, iwi, ra); c.m_c0 = ImpulseMatrix(1, n.m_effectiveMass_inv, imb, iwi, ra);
// c.m_c0 = ImpulseMatrix(1, ima, imb, iwi, ra); // c.m_c0 = ImpulseMatrix(1, ima, imb, iwi, ra);
}
c.m_c1 = ra; c.m_c1 = ra;
} }
else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK) else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
@ -1724,7 +1731,16 @@ struct btSoftColliders
t1.getX(), t1.getY(), t1.getZ(), t1.getX(), t1.getY(), t1.getZ(),
t2.getX(), t2.getY(), t2.getZ()); // world frame to local frame t2.getX(), t2.getY(), t2.getZ()); // world frame to local frame
const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6; const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
btMatrix3x3 local_impulse_matrix = (n.m_effectiveMass_inv + OuterProduct(J_n, J_t1, J_t2, u_n, u_t1, u_t2, ndof)).inverse();
btMatrix3x3 local_impulse_matrix;
if (psb->m_reducedModel)
{
local_impulse_matrix = OuterProduct(J_n, J_t1, J_t2, u_n, u_t1, u_t2, ndof);
}
else
{
local_impulse_matrix = (n.m_effectiveMass_inv + OuterProduct(J_n, J_t1, J_t2, u_n, u_t1, u_t2, ndof)).inverse();
}
c.m_c0 = rot.transpose() * local_impulse_matrix * rot; c.m_c0 = rot.transpose() * local_impulse_matrix * rot;
c.jacobianData_normal = jacobianData_normal; c.jacobianData_normal = jacobianData_normal;
c.jacobianData_t1 = jacobianData_t1; c.jacobianData_t1 = jacobianData_t1;
@ -1944,6 +1960,7 @@ struct btSoftColliders
c.m_weights = btVector3(0, 0, 0); c.m_weights = btVector3(0, 0, 0);
c.m_imf = 0; c.m_imf = 0;
c.m_c0 = 0; c.m_c0 = 0;
c.m_colObj = psb[1];
psb[0]->m_faceNodeContacts.push_back(c); psb[0]->m_faceNodeContacts.push_back(c);
} }
} }
@ -2019,6 +2036,7 @@ struct btSoftColliders
c.m_weights = btVector3(0, 0, 0); c.m_weights = btVector3(0, 0, 0);
c.m_imf = 0; c.m_imf = 0;
c.m_c0 = 0; c.m_c0 = 0;
c.m_colObj = psb[1];
psb[0]->m_faceNodeContacts.push_back(c); psb[0]->m_faceNodeContacts.push_back(c);
} }
} }
@ -2050,7 +2068,8 @@ struct btSoftColliders
c.m_margin = mrg; c.m_margin = mrg;
c.m_imf = 0; c.m_imf = 0;
c.m_c0 = 0; c.m_c0 = 0;
psb[0]->m_faceNodeContacts.push_back(c); c.m_colObj = psb[1];
psb[0]->m_faceNodeContactsCCD.push_back(c);
} }
} }
void Process(const btDbvntNode* lface1, void Process(const btDbvntNode* lface1,
@ -2114,7 +2133,8 @@ struct btSoftColliders
c.m_margin = mrg; c.m_margin = mrg;
c.m_imf = 0; c.m_imf = 0;
c.m_c0 = 0; c.m_c0 = 0;
psb[0]->m_faceNodeContacts.push_back(c); c.m_colObj = psb[1];
psb[0]->m_faceNodeContactsCCD.push_back(c);
} }
} }
} }

View File

@ -36,7 +36,8 @@ public:
CL_SIMD_SOLVER, CL_SIMD_SOLVER,
DX_SOLVER, DX_SOLVER,
DX_SIMD_SOLVER, DX_SIMD_SOLVER,
DEFORMABLE_SOLVER DEFORMABLE_SOLVER,
REDUCED_DEFORMABLE_SOLVER
}; };
protected: protected:

View File

@ -25,7 +25,7 @@ subject to the following restrictions:
#include <float.h> #include <float.h>
/* SVN $Revision$ on $Date$ from http://bullet.googlecode.com*/ /* SVN $Revision$ on $Date$ from http://bullet.googlecode.com*/
#define BT_BULLET_VERSION 320 #define BT_BULLET_VERSION 324
inline int btGetVersion() inline int btGetVersion()
{ {
@ -107,7 +107,7 @@ inline int btIsDoublePrecision()
#define btFsel(a,b,c) __fsel((a),(b),(c)) #define btFsel(a,b,c) __fsel((a),(b),(c))
#else #else
#if defined (_M_ARM) #if defined (_M_ARM) || defined (_M_ARM64)
//Do not turn SSE on for ARM (may want to turn on BT_USE_NEON however) //Do not turn SSE on for ARM (may want to turn on BT_USE_NEON however)
#elif (defined (_WIN32) && (_MSC_VER) && _MSC_VER >= 1400) && (!defined (BT_USE_DOUBLE_PRECISION)) #elif (defined (_WIN32) && (_MSC_VER) && _MSC_VER >= 1400) && (!defined (BT_USE_DOUBLE_PRECISION))

View File

@ -481,7 +481,7 @@ public:
buffer[9] = '3'; buffer[9] = '3';
buffer[10] = '2'; buffer[10] = '2';
buffer[11] = '1'; buffer[11] = '4';
} }
virtual void startSerialization() virtual void startSerialization()

View File

@ -34,6 +34,7 @@ btTransform
btVector3 m_origin; btVector3 m_origin;
public: public:
BT_DECLARE_ALIGNED_ALLOCATOR();
/**@brief No initialization constructor */ /**@brief No initialization constructor */
btTransform() {} btTransform() {}
/**@brief Constructor from btQuaternion (optional btVector3 ) /**@brief Constructor from btQuaternion (optional btVector3 )

View File

@ -1 +1 @@
3.21 3.24

View File

@ -36,6 +36,7 @@
#include "BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp" #include "BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp"
#include "BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp" #include "BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp"
#include "BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp" #include "BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp"
#include "BulletDynamics/Featherstone/btMultiBodySphericalJointLimit.cpp"
#include "BulletDynamics/Vehicle/btRaycastVehicle.cpp" #include "BulletDynamics/Vehicle/btRaycastVehicle.cpp"
#include "BulletDynamics/Vehicle/btWheelInfo.cpp" #include "BulletDynamics/Vehicle/btWheelInfo.cpp"
#include "BulletDynamics/Character/btKinematicCharacterController.cpp" #include "BulletDynamics/Character/btKinematicCharacterController.cpp"

View File

@ -1,38 +0,0 @@
diff --git a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h
index f2cc3409f9..70915366e0 100644
--- a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h
+++ b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h
@@ -4,8 +4,8 @@ Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
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,
+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.
@@ -71,9 +71,9 @@ public:
const btVector3& normal,
btScalar distance) : m_localPointA(pointA),
m_localPointB(pointB),
+ m_positionWorldOnB(0,0,0),
+ m_positionWorldOnA(0,0,0),
m_normalWorldOnB(normal),
- m_positionWorldOnB(0,0,0),
- m_positionWorldOnA(0,0,0),
m_distance1(distance),
m_combinedFriction(btScalar(0.)),
m_combinedRollingFriction(btScalar(0.)),
@@ -95,8 +95,8 @@ public:
m_contactERP(0.f),
m_frictionCFM(0.f),
m_lifeTime(0),
- m_lateralFrictionDir1(0,0,0),
- m_lateralFrictionDir2(0,0,0)
+ m_lateralFrictionDir1(0,0,0),
+ m_lateralFrictionDir2(0,0,0)
{
}