Merge remote-tracking branch 'bp/master'

This commit is contained in:
Erwin Coumans
2020-06-30 16:41:23 -07:00
25 changed files with 1191 additions and 176 deletions
+1
View File
@@ -470,6 +470,7 @@ IF (BUILD_UNIT_TESTS)
ENDIF()
set (BULLET_CONFIG_CMAKE_PATH lib${LIB_SUFFIX}/cmake/bullet )
list (APPEND BULLET_DEFINITIONS ${BULLET_DOUBLE_DEF})
list (APPEND BULLET_LIBRARIES LinearMath)
list (APPEND BULLET_LIBRARIES Bullet3Common)
list (APPEND BULLET_LIBRARIES BulletInverseDynamics)
@@ -21,11 +21,13 @@ struct CommonDeformableBodyBase : public CommonMultiBodyBase
btAlignedObjectArray<btDeformableLagrangianForce*> m_forces;
btSoftBody* m_pickedSoftBody;
btDeformableMousePickingForce* m_mouseForce;
btScalar m_maxPickingForce;
btScalar m_pickingForceElasticStiffness, m_pickingForceDampingStiffness, m_maxPickingForce;
CommonDeformableBodyBase(GUIHelperInterface* helper)
: CommonMultiBodyBase(helper),
m_pickedSoftBody(0),
m_mouseForce(0),
m_pickingForceElasticStiffness(100),
m_pickingForceDampingStiffness(0.0),
m_maxPickingForce(0.3)
{
}
@@ -115,7 +117,7 @@ struct CommonDeformableBodyBase : public CommonMultiBodyBase
m_pickedSoftBody = psb;
psb->setActivationState(DISABLE_DEACTIVATION);
const btSoftBody::Face& f = psb->m_faces[face_id];
btDeformableMousePickingForce* mouse_force = new btDeformableMousePickingForce(100, 0, f, m_hitPos, m_maxPickingForce);
btDeformableMousePickingForce* mouse_force = new btDeformableMousePickingForce(m_pickingForceElasticStiffness, m_pickingForceDampingStiffness, f, m_hitPos, m_maxPickingForce);
m_mouseForce = mouse_force;
getDeformableDynamicsWorld()->addForce(psb, mouse_force);
}
+273
View File
@@ -0,0 +1,273 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2019 Google Inc. 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.
*/
#include "Collide.h"
///btBulletDynamicsCommon.h is the main Bullet include file, contains most common include files.
#include "btBulletDynamicsCommon.h"
#include "BulletSoftBody/btDeformableMultiBodyDynamicsWorld.h"
#include "BulletSoftBody/btSoftBody.h"
#include "BulletSoftBody/btSoftBodyHelpers.h"
#include "BulletSoftBody/btDeformableBodySolver.h"
#include "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h"
#include "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h"
#include "../CommonInterfaces/CommonParameterInterface.h"
#include <stdio.h> //printf debugging
#include "../CommonInterfaces/CommonDeformableBodyBase.h"
#include "../Utils/b3ResourcePath.h"
///The Collide shows the contact between volumetric deformable objects and rigid objects.
static btScalar E = 50;
static btScalar nu = 0.3;
static btScalar damping_alpha = 0.1;
static btScalar damping_beta = 0.01;
static btScalar COLLIDING_VELOCITY = 15;
struct TetraCube
{
#include "../SoftDemo/cube.inl"
};
class Collide : public CommonDeformableBodyBase
{
btDeformableLinearElasticityForce* m_linearElasticity;
public:
Collide(struct GUIHelperInterface* helper)
: CommonDeformableBodyBase(helper)
{
m_linearElasticity = 0;
}
virtual ~Collide()
{
}
void initPhysics();
void exitPhysics();
void resetCamera()
{
float dist = 20;
float pitch = 0;
float yaw = 90;
float targetPos[3] = {0, 3, 0};
m_guiHelper->resetCamera(dist, yaw, pitch, targetPos[0], targetPos[1], targetPos[2]);
}
void Ctor_RbUpStack()
{
float mass = 0.5;
btCollisionShape* shape = new btBoxShape(btVector3(2, 2, 2));
btTransform startTransform;
startTransform.setIdentity();
startTransform.setOrigin(btVector3(0,-2,0));
btRigidBody* rb = createRigidBody(mass, startTransform, shape);
rb->setLinearVelocity(btVector3(0,+COLLIDING_VELOCITY, 0));
}
void stepSimulation(float deltaTime)
{
m_linearElasticity->setPoissonRatio(nu);
m_linearElasticity->setYoungsModulus(E);
m_linearElasticity->setDamping(damping_alpha, damping_beta);
float internalTimeStep = 1. / 60.f;
m_dynamicsWorld->stepSimulation(deltaTime, 1, internalTimeStep);
}
virtual void renderScene()
{
CommonDeformableBodyBase::renderScene();
btDeformableMultiBodyDynamicsWorld* deformableWorld = getDeformableDynamicsWorld();
for (int i = 0; i < deformableWorld->getSoftBodyArray().size(); i++)
{
btSoftBody* psb = (btSoftBody*)deformableWorld->getSoftBodyArray()[i];
{
btSoftBodyHelpers::DrawFrame(psb, deformableWorld->getDebugDrawer());
btSoftBodyHelpers::Draw(psb, deformableWorld->getDebugDrawer(), deformableWorld->getDrawFlags());
}
}
}
};
void Collide::initPhysics()
{
m_guiHelper->setUpAxis(1);
///collision configuration contains default setup for memory, collision setup
m_collisionConfiguration = new btSoftBodyRigidBodyCollisionConfiguration();
///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
m_broadphase = new btDbvtBroadphase();
btDeformableBodySolver* deformableBodySolver = new btDeformableBodySolver();
btDeformableMultiBodyConstraintSolver* sol = new btDeformableMultiBodyConstraintSolver();
sol->setDeformableSolver(deformableBodySolver);
m_solver = sol;
m_dynamicsWorld = new btDeformableMultiBodyDynamicsWorld(m_dispatcher, m_broadphase, sol, m_collisionConfiguration, deformableBodySolver);
btVector3 gravity = btVector3(0, 0, 0);
m_dynamicsWorld->setGravity(gravity);
m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld);
// create volumetric soft body
{
btSoftBody* psb = btSoftBodyHelpers::CreateFromTetGenData(getDeformableDynamicsWorld()->getWorldInfo(),
TetraCube::getElements(),
0,
TetraCube::getNodes(),
false, true, true);
getDeformableDynamicsWorld()->addSoftBody(psb);
psb->scale(btVector3(2, 2, 2));
psb->translate(btVector3(0, 7, 0));
psb->getCollisionShape()->setMargin(0.1);
psb->setTotalMass(0.5);
psb->m_cfg.kKHR = 1; // collision hardness with kinematic objects
psb->m_cfg.kCHR = 1; // collision hardness with rigid body
psb->m_cfg.kDF = 0;
psb->m_cfg.collisions = btSoftBody::fCollision::SDF_RD;
psb->m_cfg.collisions |= btSoftBody::fCollision::SDF_RDN;
psb->m_sleepingThreshold = 0;
btSoftBodyHelpers::generateBoundaryFaces(psb);
psb->setVelocity(btVector3(0, -COLLIDING_VELOCITY, 0));
btDeformableLinearElasticityForce* linearElasticity = new btDeformableLinearElasticityForce(100,100,0.01);
m_linearElasticity = linearElasticity;
getDeformableDynamicsWorld()->addForce(psb, linearElasticity);
m_forces.push_back(linearElasticity);
}
getDeformableDynamicsWorld()->setImplicit(true);
getDeformableDynamicsWorld()->setLineSearch(false);
getDeformableDynamicsWorld()->setUseProjection(true);
getDeformableDynamicsWorld()->getSolverInfo().m_deformable_erp = 0.3;
getDeformableDynamicsWorld()->getSolverInfo().m_deformable_maxErrorReduction = btScalar(200);
getDeformableDynamicsWorld()->getSolverInfo().m_leastSquaresResidualThreshold = 1e-3;
getDeformableDynamicsWorld()->getSolverInfo().m_splitImpulse = true;
getDeformableDynamicsWorld()->getSolverInfo().m_numIterations = 100;
// add a few rigid bodies
Ctor_RbUpStack();
m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld);
// {
// SliderParams slider("Young's Modulus", &E);
// slider.m_minVal = 0;
// slider.m_maxVal = 2000;
// if (m_guiHelper->getParameterInterface())
// m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
// }
// {
// SliderParams slider("Poisson Ratio", &nu);
// slider.m_minVal = 0.05;
// slider.m_maxVal = 0.49;
// if (m_guiHelper->getParameterInterface())
// m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
// }
// {
// SliderParams slider("Mass Damping", &damping_alpha);
// slider.m_minVal = 0.001;
// slider.m_maxVal = 0.01;
// if (m_guiHelper->getParameterInterface())
// m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
// }
// {
// SliderParams slider("Stiffness Damping", &damping_beta);
// slider.m_minVal = 0.001;
// slider.m_maxVal = 0.01;
// if (m_guiHelper->getParameterInterface())
// m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
// }
{
SliderParams slider("Young's Modulus", &E);
slider.m_minVal = 0;
slider.m_maxVal = 2000;
if (m_guiHelper->getParameterInterface())
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
}
{
SliderParams slider("Poisson Ratio", &nu);
slider.m_minVal = 0.05;
slider.m_maxVal = 0.49;
if (m_guiHelper->getParameterInterface())
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
}
{
SliderParams slider("Mass Damping", &damping_alpha);
slider.m_minVal = 0;
slider.m_maxVal = 1;
if (m_guiHelper->getParameterInterface())
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
}
{
SliderParams slider("Stiffness Damping", &damping_beta);
slider.m_minVal = 0;
slider.m_maxVal = 0.1;
if (m_guiHelper->getParameterInterface())
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
}
}
void Collide::exitPhysics()
{
//cleanup in the reverse order of creation/initialization
removePickingConstraint();
//remove the rigidbodies from the dynamics world and delete them
int i;
for (i = m_dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--)
{
btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
btRigidBody* body = btRigidBody::upcast(obj);
if (body && body->getMotionState())
{
delete body->getMotionState();
}
m_dynamicsWorld->removeCollisionObject(obj);
delete obj;
}
// delete forces
for (int j = 0; j < m_forces.size(); j++)
{
btDeformableLagrangianForce* force = m_forces[j];
delete force;
}
m_forces.clear();
//delete collision shapes
for (int j = 0; j < m_collisionShapes.size(); j++)
{
btCollisionShape* shape = m_collisionShapes[j];
delete shape;
}
m_collisionShapes.clear();
delete m_dynamicsWorld;
delete m_solver;
delete m_broadphase;
delete m_dispatcher;
delete m_collisionConfiguration;
}
class CommonExampleInterface* CollideCreateFunc(struct CommonExampleOptions& options)
{
return new Collide(options.m_guiHelper);
}
+19
View File
@@ -0,0 +1,19 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2019 Google Inc. 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.
*/
#ifndef _COLLIDE_H
#define _COLLIDE_H
class CommonExampleInterface* CollideCreateFunc(struct CommonExampleOptions& options);
#endif //_COLLIDE_H
@@ -31,6 +31,7 @@ public:
DeformableSelfCollision(struct GUIHelperInterface* helper)
: CommonDeformableBodyBase(helper)
{
m_maxPickingForce = 0.004;
}
virtual ~DeformableSelfCollision()
{
@@ -93,7 +94,7 @@ void DeformableSelfCollision::initPhysics()
{
///create a ground
btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(150.), btScalar(2.5), btScalar(150.)));
groundShape->setMargin(0.0001);
groundShape->setMargin(0.02);
m_collisionShapes.push_back(groundShape);
btTransform groundTransform;
@@ -152,6 +153,7 @@ void DeformableSelfCollision::addCloth(btVector3 origin)
clothTransform.setOrigin(btVector3(0,0.2,0)+origin);
psb->transform(clothTransform);
psb->m_cfg.collisions = btSoftBody::fCollision::SDF_RD;
psb->m_cfg.collisions |= btSoftBody::fCollision::SDF_RDN;
psb->m_cfg.collisions |= btSoftBody::fCollision::SDF_RDF;
psb->m_cfg.collisions |= btSoftBody::fCollision::VF_DD;
getDeformableDynamicsWorld()->addSoftBody(psb);
@@ -164,6 +166,7 @@ void DeformableSelfCollision::addCloth(btVector3 origin)
btVector3 gravity = btVector3(0, -9.8, 0);
btDeformableGravityForce* gravity_force = new btDeformableGravityForce(gravity);
getDeformableDynamicsWorld()->addForce(psb, gravity_force);
getDeformableDynamicsWorld()->setUseProjection(true);
m_forces.push_back(gravity_force);
}
@@ -0,0 +1,262 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2019 Google Inc. 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.
*/
#include "LargeDeformation.h"
///btBulletDynamicsCommon.h is the main Bullet include file, contains most common include files.
#include "btBulletDynamicsCommon.h"
#include "BulletSoftBody/btDeformableMultiBodyDynamicsWorld.h"
#include "BulletSoftBody/btSoftBody.h"
#include "BulletSoftBody/btSoftBodyHelpers.h"
#include "BulletSoftBody/btDeformableBodySolver.h"
#include "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h"
#include "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h"
#include "../CommonInterfaces/CommonParameterInterface.h"
#include <stdio.h> //printf debugging
#include "../CommonInterfaces/CommonDeformableBodyBase.h"
#include "../Utils/b3ResourcePath.h"
///The LargeDeformation shows the contact between volumetric deformable objects and rigid objects.
static btScalar E = 50;
static btScalar nu = 0.3;
static btScalar damping_alpha = 0.1;
static btScalar damping_beta = 0.01;
struct TetraCube
{
#include "../SoftDemo/cube.inl"
};
class LargeDeformation : public CommonDeformableBodyBase
{
btDeformableLinearElasticityForce* m_linearElasticity;
public:
LargeDeformation(struct GUIHelperInterface* helper)
: CommonDeformableBodyBase(helper)
{
m_linearElasticity = 0;
}
virtual ~LargeDeformation()
{
}
void initPhysics();
void exitPhysics();
void resetCamera()
{
float dist = 20;
float pitch = -45;
float yaw = 100;
float targetPos[3] = {0, 3, 0};
m_guiHelper->resetCamera(dist, yaw, pitch, targetPos[0], targetPos[1], targetPos[2]);
}
void stepSimulation(float deltaTime)
{
m_linearElasticity->setPoissonRatio(nu);
m_linearElasticity->setYoungsModulus(E);
m_linearElasticity->setDamping(damping_alpha, damping_beta);
float internalTimeStep = 1. / 60.f;
m_dynamicsWorld->stepSimulation(deltaTime, 1, internalTimeStep);
}
virtual void renderScene()
{
CommonDeformableBodyBase::renderScene();
btDeformableMultiBodyDynamicsWorld* deformableWorld = getDeformableDynamicsWorld();
for (int i = 0; i < deformableWorld->getSoftBodyArray().size(); i++)
{
btSoftBody* psb = (btSoftBody*)deformableWorld->getSoftBodyArray()[i];
{
btSoftBodyHelpers::DrawFrame(psb, deformableWorld->getDebugDrawer());
btSoftBodyHelpers::Draw(psb, deformableWorld->getDebugDrawer(), deformableWorld->getDrawFlags());
}
}
}
};
void LargeDeformation::initPhysics()
{
m_guiHelper->setUpAxis(1);
///collision configuration contains default setup for memory, collision setup
m_collisionConfiguration = new btSoftBodyRigidBodyCollisionConfiguration();
///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
m_broadphase = new btDbvtBroadphase();
btDeformableBodySolver* deformableBodySolver = new btDeformableBodySolver();
btDeformableMultiBodyConstraintSolver* sol = new btDeformableMultiBodyConstraintSolver();
sol->setDeformableSolver(deformableBodySolver);
m_solver = sol;
m_dynamicsWorld = new btDeformableMultiBodyDynamicsWorld(m_dispatcher, m_broadphase, sol, m_collisionConfiguration, deformableBodySolver);
m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld);
// create volumetric soft body
{
btSoftBody* psb = btSoftBodyHelpers::CreateFromTetGenData(getDeformableDynamicsWorld()->getWorldInfo(),
TetraCube::getElements(),
0,
TetraCube::getNodes(),
false, true, true);
getDeformableDynamicsWorld()->addSoftBody(psb);
psb->scale(btVector3(2, 2, 2));
psb->translate(btVector3(0, 5, 0));
psb->getCollisionShape()->setMargin(0.1);
psb->setTotalMass(0.5);
psb->m_cfg.kKHR = 1; // collision hardness with kinematic objects
psb->m_cfg.kCHR = 1; // collision hardness with rigid body
psb->m_cfg.kDF = 0.5;
psb->m_cfg.collisions = btSoftBody::fCollision::SDF_RD;
psb->m_cfg.collisions |= btSoftBody::fCollision::SDF_RDN;
psb->m_sleepingThreshold = 0;
btSoftBodyHelpers::generateBoundaryFaces(psb);
for (int i = 0; i < psb->m_nodes.size(); ++i)
{
for (int j = 0; j < 3; ++j)
psb->m_nodes[i].m_x[j] = ((double) 2*rand() / (RAND_MAX))-1.0;
psb->m_nodes[i].m_x[1]+=8;
}
btDeformableLinearElasticityForce* linearElasticity = new btDeformableLinearElasticityForce(100,100,0.01);
m_linearElasticity = linearElasticity;
getDeformableDynamicsWorld()->addForce(psb, linearElasticity);
m_forces.push_back(linearElasticity);
}
getDeformableDynamicsWorld()->setImplicit(true);
getDeformableDynamicsWorld()->setLineSearch(false);
getDeformableDynamicsWorld()->setUseProjection(true);
getDeformableDynamicsWorld()->getSolverInfo().m_deformable_erp = 0.1;
getDeformableDynamicsWorld()->getSolverInfo().m_deformable_maxErrorReduction = btScalar(20);
getDeformableDynamicsWorld()->getSolverInfo().m_leastSquaresResidualThreshold = 1e-3;
getDeformableDynamicsWorld()->getSolverInfo().m_splitImpulse = true;
getDeformableDynamicsWorld()->getSolverInfo().m_numIterations = 100;
// add a few rigid bodies
m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld);
{
SliderParams slider("Young's Modulus", &E);
slider.m_minVal = 0;
slider.m_maxVal = 2000;
if (m_guiHelper->getParameterInterface())
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
}
{
SliderParams slider("Poisson Ratio", &nu);
slider.m_minVal = 0.05;
slider.m_maxVal = 0.49;
if (m_guiHelper->getParameterInterface())
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
}
{
SliderParams slider("Mass Damping", &damping_alpha);
slider.m_minVal = 0;
slider.m_maxVal = 1;
if (m_guiHelper->getParameterInterface())
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
}
{
SliderParams slider("Stiffness Damping", &damping_beta);
slider.m_minVal = 0;
slider.m_maxVal = 0.1;
if (m_guiHelper->getParameterInterface())
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
}
// {
// SliderParams slider("Young's Modulus", &E);
// slider.m_minVal = 0;
// slider.m_maxVal = 200;
// if (m_guiHelper->getParameterInterface())
// m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
// }
// {
// SliderParams slider("Poisson Ratio", &nu);
// slider.m_minVal = 0.05;
// slider.m_maxVal = 0.40;
// if (m_guiHelper->getParameterInterface())
// m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
// }
// {
// SliderParams slider("Mass Damping", &damping_alpha);
// slider.m_minVal = 0.001;
// slider.m_maxVal = 0.01;
// if (m_guiHelper->getParameterInterface())
// m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
// }
// {
// SliderParams slider("Stiffness Damping", &damping_beta);
// slider.m_minVal = 0.001;
// slider.m_maxVal = 0.01;
// if (m_guiHelper->getParameterInterface())
// m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
// }
}
void LargeDeformation::exitPhysics()
{
//cleanup in the reverse order of creation/initialization
removePickingConstraint();
//remove the rigidbodies from the dynamics world and delete them
int i;
for (i = m_dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--)
{
btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
btRigidBody* body = btRigidBody::upcast(obj);
if (body && body->getMotionState())
{
delete body->getMotionState();
}
m_dynamicsWorld->removeCollisionObject(obj);
delete obj;
}
// delete forces
for (int j = 0; j < m_forces.size(); j++)
{
btDeformableLagrangianForce* force = m_forces[j];
delete force;
}
m_forces.clear();
//delete collision shapes
for (int j = 0; j < m_collisionShapes.size(); j++)
{
btCollisionShape* shape = m_collisionShapes[j];
delete shape;
}
m_collisionShapes.clear();
delete m_dynamicsWorld;
delete m_solver;
delete m_broadphase;
delete m_dispatcher;
delete m_collisionConfiguration;
}
class CommonExampleInterface* LargeDeformationCreateFunc(struct CommonExampleOptions& options)
{
return new LargeDeformation(options.m_guiHelper);
}
@@ -0,0 +1,19 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2019 Google Inc. 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.
*/
#ifndef _LARGE_DEFORMATION_H
#define _LARGE_DEFORMATION_H
class CommonExampleInterface* LargeDeformationCreateFunc(struct CommonExampleOptions& options);
#endif //_LARGE_DEFORMATION_H
@@ -27,9 +27,10 @@
#include "../Utils/b3ResourcePath.h"
///The VolumetricDeformable shows the contact between volumetric deformable objects and rigid objects.
static btScalar E = 25;
static btScalar E = 50;
static btScalar nu = 0.3;
static btScalar damping = 0.01;
static btScalar damping_alpha = 0.1;
static btScalar damping_beta = 0.01;
struct TetraCube
{
@@ -38,13 +39,16 @@ struct TetraCube
class VolumetricDeformable : public CommonDeformableBodyBase
{
btDeformableNeoHookeanForce* m_neohookean;
btDeformableLinearElasticityForce* m_linearElasticity;
public:
VolumetricDeformable(struct GUIHelperInterface* helper)
: CommonDeformableBodyBase(helper)
{
m_neohookean = 0;
m_linearElasticity = 0;
m_pickingForceElasticStiffness = 100;
m_pickingForceDampingStiffness = 0;
m_maxPickingForce = 1e10; // allow large picking force with implicit scheme.
}
virtual ~VolumetricDeformable()
{
@@ -64,12 +68,12 @@ public:
void stepSimulation(float deltaTime)
{
m_neohookean->setPoissonRatio(nu);
m_neohookean->setYoungsModulus(E);
m_neohookean->setDamping(damping);
m_linearElasticity->setPoissonRatio(nu);
m_linearElasticity->setYoungsModulus(E);
m_linearElasticity->setDamping(damping_alpha, damping_beta);
//use a smaller internal timestep, there are stability issues
float internalTimeStep = 1. / 480.f;
m_dynamicsWorld->stepSimulation(deltaTime, 8, internalTimeStep);
float internalTimeStep = 1. / 240;
m_dynamicsWorld->stepSimulation(deltaTime, 4, internalTimeStep);
}
void createStaticBox(const btVector3& halfEdge, const btVector3& translation)
@@ -100,7 +104,7 @@ public:
void Ctor_RbUpStack(int count)
{
float mass = 0.2;
float mass = 2;
btCompoundShape* cylinderCompound = new btCompoundShape;
btCollisionShape* cylinderShape = new btCylinderShapeX(btVector3(2, .5, .5));
@@ -187,7 +191,7 @@ void VolumetricDeformable::initPhysics()
btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, groundShape, localInertia);
btRigidBody* body = new btRigidBody(rbInfo);
body->setFriction(0.5);
body->setFriction(1);
//add the ground to the dynamics world
m_dynamicsWorld->addRigidBody(body);
@@ -208,29 +212,32 @@ void VolumetricDeformable::initPhysics()
getDeformableDynamicsWorld()->addSoftBody(psb);
psb->scale(btVector3(2, 2, 2));
psb->translate(btVector3(0, 5, 0));
psb->getCollisionShape()->setMargin(0.025);
psb->getCollisionShape()->setMargin(0.1);
psb->setTotalMass(0.5);
psb->m_cfg.kKHR = 1; // collision hardness with kinematic objects
psb->m_cfg.kCHR = 1; // collision hardness with rigid body
psb->m_cfg.kDF = 0.5;
psb->m_cfg.kDF = 2;
psb->m_cfg.collisions = btSoftBody::fCollision::SDF_RD;
psb->m_cfg.collisions |= btSoftBody::fCollision::SDF_RDF;
psb->m_cfg.collisions |= btSoftBody::fCollision::SDF_RDF;
psb->m_cfg.collisions |= btSoftBody::fCollision::SDF_RDN;
psb->m_sleepingThreshold = 0;
btSoftBodyHelpers::generateBoundaryFaces(psb);
btDeformableGravityForce* gravity_force = new btDeformableGravityForce(gravity);
getDeformableDynamicsWorld()->addForce(psb, gravity_force);
m_forces.push_back(gravity_force);
btDeformableNeoHookeanForce* neohookean = new btDeformableNeoHookeanForce(500,2000,0.01);
m_neohookean = neohookean;
getDeformableDynamicsWorld()->addForce(psb, neohookean);
m_forces.push_back(neohookean);
btDeformableLinearElasticityForce* linearElasticity = new btDeformableLinearElasticityForce(100,100,0.01);
m_linearElasticity = linearElasticity;
getDeformableDynamicsWorld()->addForce(psb, linearElasticity);
m_forces.push_back(linearElasticity);
}
getDeformableDynamicsWorld()->setImplicit(false);
getDeformableDynamicsWorld()->setImplicit(true);
getDeformableDynamicsWorld()->setLineSearch(false);
getDeformableDynamicsWorld()->setUseProjection(true);
getDeformableDynamicsWorld()->getSolverInfo().m_deformable_erp = 0.3;
getDeformableDynamicsWorld()->getSolverInfo().m_deformable_maxErrorReduction = btScalar(200);
getDeformableDynamicsWorld()->getSolverInfo().m_leastSquaresResidualThreshold = 1e-3;
getDeformableDynamicsWorld()->getSolverInfo().m_splitImpulse = true;
getDeformableDynamicsWorld()->getSolverInfo().m_numIterations = 100;
// add a few rigid bodies
Ctor_RbUpStack(4);
m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld);
@@ -238,24 +245,31 @@ void VolumetricDeformable::initPhysics()
{
SliderParams slider("Young's Modulus", &E);
slider.m_minVal = 0;
slider.m_maxVal = 50;
slider.m_maxVal = 2000;
if (m_guiHelper->getParameterInterface())
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
}
{
SliderParams slider("Poisson Ratio", &nu);
slider.m_minVal = 0.05;
slider.m_maxVal = 0.40;
slider.m_maxVal = 0.49;
if (m_guiHelper->getParameterInterface())
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
}
{
SliderParams slider("Damping", &damping);
slider.m_minVal = 0.01;
slider.m_maxVal = 0.02;
SliderParams slider("Mass Damping", &damping_alpha);
slider.m_minVal = 0;
slider.m_maxVal = 1;
if (m_guiHelper->getParameterInterface())
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
}
{
SliderParams slider("Stiffness Damping", &damping_beta);
slider.m_minVal = 0;
slider.m_maxVal = 0.1;
if (m_guiHelper->getParameterInterface())
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
}
}
void VolumetricDeformable::exitPhysics()
+4
View File
@@ -373,6 +373,10 @@ SET(BulletExampleBrowser_SRCS
../DeformableDemo/SplitImpulse.h
../DeformableDemo/VolumetricDeformable.cpp
../DeformableDemo/VolumetricDeformable.h
../DeformableDemo/Collide.cpp
../DeformableDemo/Collide.h
../DeformableDemo/LargeDeformation.cpp
../DeformableDemo/LargeDeformation.h
../DeformableDemo/DeformableClothAnchor.cpp
../DeformableDemo/DeformableClothAnchor.h
../DeformableDemo/MultibodyClothAnchor.cpp
@@ -52,6 +52,8 @@
#include "../DeformableDemo/PinchFriction.h"
#include "../DeformableDemo/DeformableMultibody.h"
#include "../DeformableDemo/VolumetricDeformable.h"
#include "../DeformableDemo/LargeDeformation.h"
#include "../DeformableDemo/Collide.h"
#include "../DeformableDemo/GraspDeformable.h"
#include "../DeformableDemo/DeformableContact.h"
#include "../DeformableDemo/DeformableClothAnchor.h"
@@ -202,6 +204,8 @@ static ExampleEntry gDefaultExamples[] =
ExampleEntry(1, "Grasp Deformable Cube", "Grasping test", PinchCreateFunc),
ExampleEntry(1, "Grasp Deformable with Motor", "Grasping test", GraspDeformableCreateFunc),
ExampleEntry(1, "Volumetric Deformable Objects", "Volumetric Deformable test", VolumetricDeformableCreateFunc),
ExampleEntry(1, "Extreme Deformation", "Recovery from extreme deformation", LargeDeformationCreateFunc),
ExampleEntry(1, "Colliding Test", "Volumetric deformable collide with rigid box", CollideCreateFunc),
ExampleEntry(1, "Rigid Cloth Anchor", "Deformable Rigid body Anchor test", DeformableClothAnchorCreateFunc),
ExampleEntry(1, "Multibody Cloth Anchor", "Deformable Multibody Anchor test", MultibodyClothAnchorCreateFunc),
ExampleEntry(1, "Deformable-MultiBody Contact", "MultiBody and Deformable contact", DeformableMultibodyCreateFunc),
@@ -10,16 +10,28 @@ import pybullet_data
import pybullet as p1
import random
from enum import Enum
class InitializationStrategy(Enum):
"""Set how the environment is initialized."""
START = 0
RANDOM = 1 # random state initialization (RSI)
class PyBulletDeepMimicEnv(Env):
def __init__(self, arg_parser=None, enable_draw=False, pybullet_client=None):
def __init__(self, arg_parser=None, enable_draw=False, pybullet_client=None,
time_step=1./240,
init_strategy=InitializationStrategy.RANDOM):
super().__init__(arg_parser, enable_draw)
self._num_agents = 1
self._pybullet_client = pybullet_client
self._isInitialized = False
self._useStablePD = True
self._arg_parser = arg_parser
self.timeStep = time_step
self._init_strategy = init_strategy
print("Initialization strategy: {:s}".format(init_strategy))
self.reset()
def reset(self):
@@ -52,7 +64,7 @@ class PyBulletDeepMimicEnv(Env):
motionPath = pybullet_data.getDataPath() + "/" + motion_file[0]
#motionPath = pybullet_data.getDataPath()+"/motions/humanoid3d_backflip.txt"
self._mocapData.Load(motionPath)
timeStep = 1. / 240.
timeStep = self.timeStep
useFixedBase = False
self._humanoid = humanoid_stable_pd.HumanoidStablePD(self._pybullet_client, self._mocapData,
timeStep, useFixedBase, self._arg_parser)
@@ -77,9 +89,14 @@ class PyBulletDeepMimicEnv(Env):
time.sleep(timeStep)
#print("numframes = ", self._humanoid._mocap_data.NumFrames())
#startTime = random.randint(0,self._humanoid._mocap_data.NumFrames()-2)
rnrange = 1000
rn = random.randint(0, rnrange)
startTime = float(rn) / rnrange * self._humanoid.getCycleTime()
if self._init_strategy == InitializationStrategy.RANDOM:
rnrange = 1000
rn = random.randint(0, rnrange)
startTime = float(rn) / rnrange * self._humanoid.getCycleTime()
elif self._init_strategy == InitializationStrategy.START:
startTime = 0
self.t = startTime
self._humanoid.setSimTime(startTime)
@@ -263,6 +280,7 @@ class PyBulletDeepMimicEnv(Env):
#print("pybullet_deep_mimic_env:update timeStep=",timeStep," t=",self.t)
self._pybullet_client.setTimeStep(timeStep)
self._humanoid._timeStep = timeStep
self.timeStep = timeStep
for i in range(1):
self.t += timeStep
@@ -314,7 +332,7 @@ class PyBulletDeepMimicEnv(Env):
def check_valid_episode(self):
#could check if limbs exceed velocity threshold
return true
return True
def getKeyboardEvents(self):
return self._pybullet_client.getKeyboardEvents()
@@ -19,18 +19,29 @@ import pybullet as p2
import pybullet_data
from pybullet_utils import bullet_client as bc
from pkg_resources import parse_version
from pybullet_envs.deep_mimic.env.pybullet_deep_mimic_env import PyBulletDeepMimicEnv
from pybullet_envs.deep_mimic.env.pybullet_deep_mimic_env import PyBulletDeepMimicEnv, InitializationStrategy
from pybullet_utils.arg_parser import ArgParser
from pybullet_utils.logger import Logger
from typing import Optional
logger = logging.getLogger(__name__)
class HumanoidDeepBulletEnv(gym.Env):
"""Base Gym environment for DeepMimic."""
metadata = {'render.modes': ['human', 'rgb_array'], 'video.frames_per_second': 50}
def __init__(self, renders=False, arg_file=''):
def __init__(self, renders=False, arg_file='', test_mode=False,
time_step=1./240,
rescale_actions=True,
rescale_observations=True):
"""
Args:
test_mode (bool): in test mode, the `reset()` method will always set the mocap clip time
to 0.
time_step (float): physics time step.
"""
self._arg_parser = ArgParser()
Logger.print2("===========================================================")
succ = False
@@ -39,15 +50,33 @@ class HumanoidDeepBulletEnv(gym.Env):
succ = self._arg_parser.load_file(path)
Logger.print2(arg_file)
assert succ, Logger.print2('Failed to load args from: ' + arg_file)
self._p = None
self._time_step = 1./240.
self._internal_env = None
self._p: Optional[BulletClient] = None
self._time_step = time_step
self._internal_env: Optional[PyBulletDeepMimicEnv] = None
self._renders = renders
self._discrete_actions = False
self._arg_file=arg_file
self._render_height = 200
self._render_width = 320
self._arg_file = arg_file
self._render_height = 400
self._render_width = 640
self._rescale_actions = rescale_actions
self._rescale_observations = rescale_observations
self.agent_id = -1
self._numSteps = None
self.test_mode = test_mode
if self.test_mode:
print("Environment running in TEST mode")
self.reset()
# Query the policy at 30Hz
self.policy_query_30 = True
if self.policy_query_30:
self._policy_step = 1./30
else:
self._policy_step = 1./240
self._num_env_steps = int(self._policy_step / self._time_step)
self.theta_threshold_radians = 12 * 2 * math.pi / 360
self.x_threshold = 0.4 #2.4
@@ -94,8 +123,6 @@ class HumanoidDeepBulletEnv(gym.Env):
self.viewer = None
self._configure()
# Query the policy at 30Hz
self.policy_query_30 = True
def _configure(self, display=None):
self.display = display
@@ -105,42 +132,73 @@ class HumanoidDeepBulletEnv(gym.Env):
return [seed]
def step(self, action):
#apply control action
agent_id = -1
agent_id = self.agent_id
if self._rescale_actions:
# Rescale the action
mean = -self._action_offset
std = 1./self._action_scale
action = action * std + mean
# Record reward
reward = self._internal_env.calc_reward(agent_id)
# Apply control action
self._internal_env.set_action(agent_id, action)
#step sim
self._internal_env.update(self._time_step)
if self.policy_query_30:
# Step simulation until a new action is required
while not self._internal_env.need_new_action(agent_id):
self._p.stepSimulation()
self._internal_env.t += self._time_step
# print("t:", self._internal_env.t)
# print("next update time:", self._internal_env.needs_update_time)
# print("Performing update")
#record state
start_time = self._internal_env.t
# step sim
for i in range(self._num_env_steps):
self._internal_env.update(self._time_step)
elapsed_time = self._internal_env.t - start_time
self._numSteps += 1
# Record state
self.state = self._internal_env.record_state(agent_id)
#record reward
reward = self._internal_env.calc_reward(agent_id)
#record done
if self._rescale_observations:
state = np.array(self.state)
mean = -self._state_offset
std = 1./self._state_scale
state = (state - mean) / (std + 1e-8)
# Record done
done = self._internal_env.is_episode_end()
return np.array(self.state), reward, done, {}
info = {}
return state, reward, done, info
def reset(self):
# print("-----------reset simulation---------------")
if self._internal_env==None:
self._internal_env = PyBulletDeepMimicEnv(self._arg_parser, self._renders)
# use the initialization strategy
if self._internal_env is None:
if self.test_mode:
init_strat = InitializationStrategy.START
else:
init_strat = InitializationStrategy.RANDOM
self._internal_env = PyBulletDeepMimicEnv(self._arg_parser, self._renders,
time_step=self._time_step,
init_strategy=init_strat)
self._internal_env.reset()
self._p = self._internal_env._pybullet_client
agent_id = -1 #unused here
state = self._internal_env.record_state(agent_id)
agent_id = self.agent_id # unused here
self._state_offset = self._internal_env.build_state_offset(self.agent_id)
self._state_scale = self._internal_env.build_state_scale(self.agent_id)
self._action_offset = self._internal_env.build_action_offset(self.agent_id)
self._action_scale = self._internal_env.build_action_scale(self.agent_id)
self._numSteps = 0
# Record state
self.state = self._internal_env.record_state(agent_id)
# return state as ndarray
state = np.array(self.state)
if self._rescale_observations:
mean = -self._state_offset
std = 1./self._state_scale
state = (state - mean) / (std + 1e-8)
return state
def render(self, mode='human', close=False):
@@ -148,8 +206,15 @@ class HumanoidDeepBulletEnv(gym.Env):
self._renders = True
if mode != "rgb_array":
return np.array([])
base_pos=[0,0,0]
self._cam_dist = 2
human = self._internal_env._humanoid
base_pos, orn = self._p.getBasePositionAndOrientation(human._sim_model)
base_pos = np.asarray(base_pos)
# track the position
base_pos[1] += 0.3
rpy = self._p.getEulerFromQuaternion(orn) # rpy, in radians
rpy = 180 / np.pi * np.asarray(rpy) # convert rpy in degrees
self._cam_dist = 3
self._cam_pitch = 0.3
self._cam_yaw = 0
if (not self._p == None):
@@ -159,10 +224,9 @@ class HumanoidDeepBulletEnv(gym.Env):
yaw=self._cam_yaw,
pitch=self._cam_pitch,
roll=0,
upAxisIndex=2)
upAxisIndex=1)
proj_matrix = self._p.computeProjectionMatrixFOV(fov=60,
aspect=float(self._render_width) /
self._render_height,
aspect=float(self._render_width) / self._render_height,
nearVal=0.1,
farVal=100.0)
(_, _, px, _, _) = self._p.getCameraImage(
@@ -171,6 +235,12 @@ class HumanoidDeepBulletEnv(gym.Env):
renderer=self._p.ER_BULLET_HARDWARE_OPENGL,
viewMatrix=view_matrix,
projectionMatrix=proj_matrix)
# self._p.resetDebugVisualizerCamera(
# cameraDistance=2 * self._cam_dist,
# cameraYaw=self._cam_yaw,
# cameraPitch=self._cam_pitch,
# cameraTargetPosition=base_pos
# )
else:
px = np.array([[[255,255,255,255]]*self._render_width]*self._render_height, dtype=np.uint8)
rgb_array = np.array(px, dtype=np.uint8)
@@ -48,6 +48,7 @@ struct btContactSolverInfoData
btScalar m_erp2; //error reduction for contact constraints
btScalar m_deformable_erp; //error reduction for deformable constraints
btScalar m_deformable_cfm; //constraint force mixing for deformable constraints
btScalar m_deformable_maxErrorReduction; // maxErrorReduction for deformable contact
btScalar m_globalCfm; //constraint force mixing for contacts and non-contacts
btScalar m_frictionERP; //error reduction for friction constraints
btScalar m_frictionCFM; //constraint force mixing for friction constraints
@@ -86,6 +87,7 @@ struct btContactSolverInfo : public btContactSolverInfoData
m_erp2 = btScalar(0.2);
m_deformable_erp = btScalar(0.06);
m_deformable_cfm = btScalar(0.01);
m_deformable_maxErrorReduction = btScalar(0.1);
m_globalCfm = btScalar(0.);
m_frictionERP = btScalar(0.2); //positional friction 'anchors' are disabled by default
m_frictionCFM = btScalar(0.);
+11 -5
View File
@@ -37,6 +37,12 @@ public:
BT_PROFILE("CGSolve");
btAssert(x.size() == b.size());
reinitialize(b);
temp = b;
A.project(temp);
p = temp;
A.precondition(p, z);
btScalar d0 = this->dot(z, temp);
d0 = btMin(btScalar(1), d0);
// r = b - A * x --with assigned dof zeroed out
A.multiply(x, temp);
r = this->sub(b, temp);
@@ -45,7 +51,7 @@ public:
A.precondition(r, z);
A.project(z);
btScalar r_dot_z = this->dot(z, r);
if (r_dot_z <= Base::m_tolerance)
if (r_dot_z <= Base::m_tolerance * d0)
{
if (verbose)
{
@@ -61,7 +67,7 @@ public:
// temp = A*p
A.multiply(p, temp);
A.project(temp);
if (this->dot(p, temp) < SIMD_EPSILON)
if (this->dot(p, temp) < 0)
{
if (verbose)
std::cout << "Encountered negative direction in CG!" << std::endl;
@@ -81,11 +87,11 @@ public:
A.precondition(r, z);
r_dot_z = r_dot_z_new;
r_dot_z_new = this->dot(r, z);
if (r_dot_z_new < Base::m_tolerance)
if (r_dot_z_new < Base::m_tolerance * d0)
{
if (verbose)
{
std::cout << "ConjugateGradient iterations " << k << std::endl;
std::cout << "ConjugateGradient iterations " << k << " residual = " << r_dot_z_new << std::endl;
}
return k;
}
@@ -95,7 +101,7 @@ public:
}
if (verbose)
{
std::cout << "ConjugateGradient max iterations reached " << Base::m_maxIterations << std::endl;
std::cout << "ConjugateGradient max iterations reached " << Base::m_maxIterations << " error = " << r_dot_z_new << std::endl;
}
return Base::m_maxIterations;
}
@@ -46,6 +46,17 @@ void btDeformableBackwardEulerObjective::reinitialize(bool nodeUpdated, btScalar
{
m_lf[i]->reinitialize(nodeUpdated);
}
btMatrix3x3 I;
I.setIdentity();
for (int i = 0; i < m_softBodies.size(); ++i)
{
btSoftBody* psb = m_softBodies[i];
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
if (psb->m_nodes[j].m_im > 0)
psb->m_nodes[j].m_effectiveMass = I * (1.0 / psb->m_nodes[j].m_im);
}
}
m_projection.reinitialize(nodeUpdated);
// m_preconditioner->reinitialize(nodeUpdated);
}
@@ -133,10 +144,23 @@ void btDeformableBackwardEulerObjective::applyForce(TVStack& force, bool setZero
counter += psb->m_nodes.size();
continue;
}
for (int j = 0; j < psb->m_nodes.size(); ++j)
if (m_implicit)
{
btScalar one_over_mass = (psb->m_nodes[j].m_im == 0) ? 0 : psb->m_nodes[j].m_im;
psb->m_nodes[j].m_v += one_over_mass * force[counter++];
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
if (psb->m_nodes[j].m_im != 0)
{
psb->m_nodes[j].m_v += psb->m_nodes[j].m_effectiveMass_inv * force[counter++];
}
}
}
else
{
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
btScalar one_over_mass = (psb->m_nodes[j].m_im == 0) ? 0 : psb->m_nodes[j].m_im;
psb->m_nodes[j].m_v += one_over_mass * force[counter++];
}
}
}
if (setZero)
@@ -190,10 +214,56 @@ void btDeformableBackwardEulerObjective::applyExplicitForce(TVStack& force)
{
m_softBodies[i]->advanceDeformation();
}
for (int i = 0; i < m_lf.size(); ++i)
if (m_implicit)
{
m_lf[i]->addScaledExplicitForce(m_dt, force);
// apply forces except gravity force
btVector3 gravity;
for (int i = 0; i < m_lf.size(); ++i)
{
if (m_lf[i]->getForceType() == BT_GRAVITY_FORCE)
{
gravity = static_cast<btDeformableGravityForce*>(m_lf[i])->m_gravity;
}
else
{
m_lf[i]->addScaledForces(m_dt, force);
}
}
for (int i = 0; i < m_lf.size(); ++i)
{
m_lf[i]->addScaledHessian(m_dt);
}
for (int i = 0; i < m_softBodies.size(); ++i)
{
btSoftBody* psb = m_softBodies[i];
if (psb->isActive())
{
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
// add gravity explicitly
psb->m_nodes[j].m_v += m_dt * psb->m_gravityFactor * gravity;
}
}
}
}
else
{
for (int i = 0; i < m_lf.size(); ++i)
{
m_lf[i]->addScaledExplicitForce(m_dt, force);
}
}
// calculate inverse mass matrix for all nodes
for (int i = 0; i < m_softBodies.size(); ++i)
{
btSoftBody* psb = m_softBodies[i];
if (psb->isActive())
{
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
psb->m_nodes[j].m_effectiveMass_inv = psb->m_nodes[j].m_effectiveMass.inverse();
}
}
}
applyForce(force, true);
}
+38 -9
View File
@@ -20,7 +20,7 @@
#include "LinearMath/btQuickprof.h"
static const int kMaxConjugateGradientIterations = 300;
btDeformableBodySolver::btDeformableBodySolver()
: m_numNodes(0), m_cg(kMaxConjugateGradientIterations), m_cr(kMaxConjugateGradientIterations), m_maxNewtonIterations(5), 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);
}
@@ -276,7 +276,14 @@ void btDeformableBodySolver::updateVelocity()
{
m_dv[counter].setZero();
}
psb->m_nodes[j].m_v = m_backupVelocity[counter] + m_dv[counter] - psb->m_nodes[j].m_splitv;
if (m_implicit)
{
psb->m_nodes[j].m_v = m_backupVelocity[counter] + m_dv[counter];
}
else
{
psb->m_nodes[j].m_v = m_backupVelocity[counter] + m_dv[counter] - psb->m_nodes[j].m_splitv;
}
psb->m_maxSpeedSquared = btMax(psb->m_maxSpeedSquared, psb->m_nodes[j].m_v.length2());
++counter;
}
@@ -296,7 +303,7 @@ void btDeformableBodySolver::updateTempPosition()
}
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
psb->m_nodes[j].m_q = psb->m_nodes[j].m_x + m_dt * psb->m_nodes[j].m_v;
psb->m_nodes[j].m_q = psb->m_nodes[j].m_x + m_dt * (psb->m_nodes[j].m_v + psb->m_nodes[j].m_splitv);
++counter;
}
psb->updateDeformation();
@@ -331,8 +338,9 @@ void btDeformableBodySolver::setupDeformableSolve(bool implicit)
{
if (implicit)
{
if ((psb->m_nodes[j].m_v - m_backupVelocity[counter]).norm() < SIMD_EPSILON)
m_dv[counter] = psb->m_nodes[j].m_v - m_backupVelocity[counter];
// setting the initial guess for newton, need m_dv = v_{n+1} - v_n for dofs that are in constraint.
if (psb->m_nodes[j].m_v == m_backupVelocity[counter])
m_dv[counter].setZero();
else
m_dv[counter] = psb->m_nodes[j].m_v - psb->m_nodes[j].m_vn;
m_backupVelocity[counter] = psb->m_nodes[j].m_vn;
@@ -376,6 +384,20 @@ bool btDeformableBodySolver::updateNodes()
void btDeformableBodySolver::predictMotion(btScalar solverdt)
{
// apply explicit forces to velocity
if (m_implicit)
{
for (int i = 0; i < m_softBodies.size(); ++i)
{
btSoftBody* psb = m_softBodies[i];
if (psb->isActive())
{
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
psb->m_nodes[j].m_q = psb->m_nodes[j].m_x + psb->m_nodes[j].m_v * solverdt;
}
}
}
}
m_objective->applyExplicitForce(m_residual);
for (int i = 0; i < m_softBodies.size(); ++i)
{
@@ -424,12 +446,19 @@ void btDeformableBodySolver::predictDeformableMotion(btSoftBody* psb, btScalar d
// apply drag
n.m_v *= (1 - psb->m_cfg.drag);
// scale velocity back
if (n.m_v.norm() > max_v)
if (m_implicit)
{
n.m_v.safeNormalize();
n.m_v *= max_v;
n.m_q = n.m_x;
}
else
{
if (n.m_v.norm() > max_v)
{
n.m_v.safeNormalize();
n.m_v *= max_v;
}
n.m_q = n.m_x + n.m_v * dt;
}
n.m_q = n.m_x + n.m_v * dt;
n.m_splitv.setZero();
n.m_constrained = false;
}
@@ -278,19 +278,19 @@ btScalar btDeformableRigidContactConstraint::solveConstraint(const btContactSolv
btVector3 impulse_tangent = impulse - impulse_normal;
if (dn > 0)
{
m_binding = false;
return 0;
}
m_binding = true;
btScalar residualSquare = dn * dn;
btVector3 old_total_tangent_dv = m_total_tangent_dv;
// m_c2 is the inverse mass of the deformable node/face
m_total_normal_dv -= impulse_normal * m_contact->m_c2;
m_total_tangent_dv -= impulse_tangent * m_contact->m_c2;
// m_c5 is the inverse mass of the deformable node/face
m_total_normal_dv -= m_contact->m_c5 * impulse_normal;
m_total_tangent_dv -= m_contact->m_c5 * impulse_tangent;
if (m_total_normal_dv.dot(cti.m_normal) < 0)
{
// separating in the normal direction
m_binding = false;
m_static = false;
impulse_tangent.setZero();
}
@@ -309,7 +309,8 @@ btScalar btDeformableRigidContactConstraint::solveConstraint(const btContactSolv
{
m_total_tangent_dv = m_total_tangent_dv.normalized() * m_total_normal_dv.safeNorm() * m_contact->m_c3;
}
impulse_tangent = -btScalar(1) / m_contact->m_c2 * (m_total_tangent_dv - old_total_tangent_dv);
// impulse_tangent = -btScalar(1)/m_contact->m_c2 * (m_total_tangent_dv - old_total_tangent_dv);
impulse_tangent = m_contact->m_c5.inverse() * (old_total_tangent_dv - m_total_tangent_dv);
}
else
{
@@ -354,7 +355,7 @@ btScalar btDeformableRigidContactConstraint::solveConstraint(const btContactSolv
btScalar btDeformableRigidContactConstraint::solveSplitImpulse(const btContactSolverInfo& infoGlobal)
{
btScalar MAX_PENETRATION_CORRECTION = 0.1;
btScalar MAX_PENETRATION_CORRECTION = infoGlobal.m_deformable_maxErrorReduction;
const btSoftBody::sCti& cti = m_contact->m_cti;
btVector3 vb = getSplitVb();
btVector3 va = getSplitVa();
@@ -435,14 +436,14 @@ btVector3 btDeformableNodeRigidContactConstraint::getDv(const btSoftBody::Node*
void btDeformableNodeRigidContactConstraint::applyImpulse(const btVector3& impulse)
{
const btSoftBody::DeformableNodeRigidContact* contact = getContact();
btVector3 dv = impulse * contact->m_c2;
btVector3 dv = contact->m_c5 * impulse;
contact->m_node->m_v -= dv;
}
void btDeformableNodeRigidContactConstraint::applySplitImpulse(const btVector3& impulse)
{
const btSoftBody::DeformableNodeRigidContact* contact = getContact();
btVector3 dv = impulse * contact->m_c2;
btVector3 dv = contact->m_c5 * impulse;
contact->m_node->m_splitv -= dv;
}
@@ -70,6 +70,12 @@ btScalar btDeformableContactProjection::solveSplitImpulse(btCollisionObject** de
{
continue;
}
for (int k = 0; k < m_nodeRigidConstraints[j].size(); ++k)
{
btDeformableNodeRigidContactConstraint& constraint = m_nodeRigidConstraints[j][k];
btScalar localResidualSquare = constraint.solveSplitImpulse(infoGlobal);
residualSquare = btMax(residualSquare, localResidualSquare);
}
for (int k = 0; k < m_faceRigidConstraints[j].size(); ++k)
{
btDeformableFaceRigidContactConstraint& constraint = m_faceRigidConstraints[j][k];
@@ -140,15 +146,6 @@ void btDeformableContactProjection::setConstraints(const btContactSolverInfo& in
}
btDeformableFaceRigidContactConstraint constraint(contact, infoGlobal, m_useStrainLimiting);
m_faceRigidConstraints[i].push_back(constraint);
// btVector3 va = constraint.getVa();
// btVector3 vb = constraint.getVb();
// const btVector3 vr = vb - va;
// const btSoftBody::sCti& cti = contact.m_cti;
// const btScalar dn = btDot(vr, cti.m_normal);
// if (dn < SIMD_EPSILON)
// {
// m_faceRigidConstraints[i].push_back(constraint);
// }
}
}
}
@@ -175,7 +172,6 @@ void btDeformableContactProjection::project(TVStack& x)
if (free_dir.safeNorm() < SIMD_EPSILON)
{
x[i] -= x[i].dot(dir0) * dir0;
x[i] -= x[i].dot(dir1) * dir1;
}
else
{
@@ -256,33 +252,36 @@ void btDeformableContactProjection::setProjection()
{
int index = m_nodeRigidConstraints[i][j].m_node->index;
m_nodeRigidConstraints[i][j].m_node->m_constrained = true;
if (m_nodeRigidConstraints[i][j].m_static)
if (m_nodeRigidConstraints[i][j].m_binding)
{
if (m_projectionsDict.find(index) == NULL)
if (m_nodeRigidConstraints[i][j].m_static)
{
m_projectionsDict.insert(index, units);
}
else
{
btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
for (int k = 0; k < 3; ++k)
if (m_projectionsDict.find(index) == NULL)
{
projections.push_back(units[k]);
m_projectionsDict.insert(index, units);
}
else
{
btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
for (int k = 0; k < 3; ++k)
{
projections.push_back(units[k]);
}
}
}
}
else
{
if (m_projectionsDict.find(index) == NULL)
{
btAlignedObjectArray<btVector3> projections;
projections.push_back(m_nodeRigidConstraints[i][j].m_normal);
m_projectionsDict.insert(index, projections);
}
else
{
btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
projections.push_back(m_nodeRigidConstraints[i][j].m_normal);
if (m_projectionsDict.find(index) == NULL)
{
btAlignedObjectArray<btVector3> projections;
projections.push_back(m_nodeRigidConstraints[i][j].m_normal);
m_projectionsDict.insert(index, projections);
}
else
{
btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
projections.push_back(m_nodeRigidConstraints[i][j].m_normal);
}
}
}
}
@@ -309,9 +308,9 @@ void btDeformableContactProjection::setProjection()
else
{
btAlignedObjectArray<btVector3>& projections = *m_projectionsDict[index];
for (int k = 0; k < 3; ++k)
for (int l = 0; l < 3; ++l)
{
projections.push_back(units[k]);
projections.push_back(units[l]);
}
}
}
@@ -66,6 +66,8 @@ public:
// add all damping forces
virtual void addScaledDampingForce(btScalar scale, TVStack& force) = 0;
virtual void addScaledHessian(btScalar scale) {}
virtual btDeformableLagrangianForceType getForceType() = 0;
virtual void reinitialize(bool nodeUpdated)
@@ -18,23 +18,64 @@
#include "btDeformableLagrangianForce.h"
#include "LinearMath/btQuickprof.h"
#include "btSoftBodyInternals.h"
#define TETRA_FLAT_THRESHOLD 0.01
class btDeformableLinearElasticityForce : public btDeformableLagrangianForce
{
public:
typedef btAlignedObjectArray<btVector3> TVStack;
btScalar m_mu, m_lambda;
btScalar m_mu_damp, m_lambda_damp;
btDeformableLinearElasticityForce() : m_mu(1), m_lambda(1)
btScalar m_E, m_nu; // Young's modulus and Poisson ratio
btScalar m_damping_alpha, m_damping_beta;
btDeformableLinearElasticityForce() : m_mu(1), m_lambda(1), m_damping_alpha(0.01), m_damping_beta(0.01)
{
btScalar damping = 0.05;
m_mu_damp = damping * m_mu;
m_lambda_damp = damping * m_lambda;
updateYoungsModulusAndPoissonRatio();
}
btDeformableLinearElasticityForce(btScalar mu, btScalar lambda, btScalar damping = 0.05) : m_mu(mu), m_lambda(lambda)
btDeformableLinearElasticityForce(btScalar mu, btScalar lambda, btScalar damping_alpha = 0.01, btScalar damping_beta = 0.01) : m_mu(mu), m_lambda(lambda), m_damping_alpha(damping_alpha), m_damping_beta(damping_beta)
{
m_mu_damp = damping * m_mu;
m_lambda_damp = damping * m_lambda;
updateYoungsModulusAndPoissonRatio();
}
void updateYoungsModulusAndPoissonRatio()
{
// conversion from Lame Parameters to Young's modulus and Poisson ratio
// https://en.wikipedia.org/wiki/Lam%C3%A9_parameters
m_E = m_mu * (3 * m_lambda + 2 * m_mu) / (m_lambda + m_mu);
m_nu = m_lambda * 0.5 / (m_mu + m_lambda);
}
void updateLameParameters()
{
// conversion from Young's modulus and Poisson ratio to Lame Parameters
// https://en.wikipedia.org/wiki/Lam%C3%A9_parameters
m_mu = m_E * 0.5 / (1 + m_nu);
m_lambda = m_E * m_nu / ((1 + m_nu) * (1 - 2 * m_nu));
}
void setYoungsModulus(btScalar E)
{
m_E = E;
updateLameParameters();
}
void setPoissonRatio(btScalar nu)
{
m_nu = nu;
updateLameParameters();
}
void setDamping(btScalar damping_alpha, btScalar damping_beta)
{
m_damping_alpha = damping_alpha;
m_damping_beta = damping_beta;
}
void setLameParameters(btScalar mu, btScalar lambda)
{
m_mu = mu;
m_lambda = lambda;
updateYoungsModulusAndPoissonRatio();
}
virtual void addScaledForces(btScalar scale, TVStack& force)
@@ -51,8 +92,10 @@ public:
// The damping matrix is calculated using the time n state as described in https://www.math.ucla.edu/~jteran/papers/GSSJT15.pdf to allow line search
virtual void addScaledDampingForce(btScalar scale, TVStack& force)
{
if (m_mu_damp == 0 && m_lambda_damp == 0)
if (m_damping_alpha == 0 && m_damping_beta == 0)
return;
btScalar mu_damp = m_damping_beta * m_mu;
btScalar lambda_damp = m_damping_beta * m_lambda;
int numNodes = getNumNodes();
btAssert(numNodes <= force.size());
btVector3 grad_N_hat_1st_col = btVector3(-1, -1, -1);
@@ -65,6 +108,7 @@ public:
}
for (int j = 0; j < psb->m_tetras.size(); ++j)
{
bool close_to_flat = (psb->m_tetraScratches[j].m_J < TETRA_FLAT_THRESHOLD);
btSoftBody::Tetra& tetra = psb->m_tetras[j];
btSoftBody::Node* node0 = tetra.m_n[0];
btSoftBody::Node* node1 = tetra.m_n[1];
@@ -75,13 +119,19 @@ public:
size_t id2 = node2->index;
size_t id3 = node3->index;
btMatrix3x3 dF = DsFromVelocity(node0, node1, node2, node3) * tetra.m_Dm_inverse;
if (!close_to_flat)
{
dF = psb->m_tetraScratches[j].m_corotation.transpose() * dF;
}
btMatrix3x3 I;
I.setIdentity();
btMatrix3x3 dP = (dF + dF.transpose()) * m_mu_damp + I * (dF[0][0] + dF[1][1] + dF[2][2]) * m_lambda_damp;
// firstPiolaDampingDifferential(psb->m_tetraScratchesTn[j], dF, dP);
btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose() * grad_N_hat_1st_col);
btMatrix3x3 dP = (dF + dF.transpose()) * mu_damp + I * ((dF[0][0] + dF[1][1] + dF[2][2]) * lambda_damp);
btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
if (!close_to_flat)
{
df_on_node123 = psb->m_tetraScratches[j].m_corotation * df_on_node123;
}
btVector3 df_on_node0 = df_on_node123 * grad_N_hat_1st_col;
// damping force differential
btScalar scale1 = scale * tetra.m_element_measure;
force[id0] -= scale1 * df_on_node0;
@@ -89,6 +139,15 @@ public:
force[id2] -= scale1 * df_on_node123.getColumn(1);
force[id3] -= scale1 * df_on_node123.getColumn(2);
}
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
const btSoftBody::Node& node = psb->m_nodes[j];
size_t id = node.index;
if (node.m_im > 0)
{
force[id] -= scale * node.m_v / node.m_im * m_damping_alpha;
}
}
}
}
@@ -201,7 +260,7 @@ public:
}
#endif
// btVector3 force_on_node0 = P * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
btMatrix3x3 force_on_node123 = P * tetra.m_Dm_inverse.transpose();
btMatrix3x3 force_on_node123 = psb->m_tetraScratches[j].m_corotation * P * tetra.m_Dm_inverse.transpose();
btVector3 force_on_node0 = force_on_node123 * grad_N_hat_1st_col;
btSoftBody::Node* node0 = tetra.m_n[0];
@@ -223,11 +282,15 @@ public:
}
}
virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA) {}
// The damping matrix is calculated using the time n state as described in https://www.math.ucla.edu/~jteran/papers/GSSJT15.pdf to allow line search
virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df)
{
if (m_mu_damp == 0 && m_lambda_damp == 0)
if (m_damping_alpha == 0 && m_damping_beta == 0)
return;
btScalar mu_damp = m_damping_beta * m_mu;
btScalar lambda_damp = m_damping_beta * m_lambda;
int numNodes = getNumNodes();
btAssert(numNodes <= df.size());
btVector3 grad_N_hat_1st_col = btVector3(-1, -1, -1);
@@ -240,6 +303,7 @@ public:
}
for (int j = 0; j < psb->m_tetras.size(); ++j)
{
bool close_to_flat = (psb->m_tetraScratches[j].m_J < TETRA_FLAT_THRESHOLD);
btSoftBody::Tetra& tetra = psb->m_tetras[j];
btSoftBody::Node* node0 = tetra.m_n[0];
btSoftBody::Node* node1 = tetra.m_n[1];
@@ -250,12 +314,18 @@ public:
size_t id2 = node2->index;
size_t id3 = node3->index;
btMatrix3x3 dF = Ds(id0, id1, id2, id3, dv) * tetra.m_Dm_inverse;
if (!close_to_flat)
{
dF = psb->m_tetraScratches[j].m_corotation.transpose() * dF;
}
btMatrix3x3 I;
I.setIdentity();
btMatrix3x3 dP = (dF + dF.transpose()) * m_mu_damp + I * (dF[0][0] + dF[1][1] + dF[2][2]) * m_lambda_damp;
// firstPiolaDampingDifferential(psb->m_tetraScratchesTn[j], dF, dP);
// btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
btMatrix3x3 dP = (dF + dF.transpose()) * mu_damp + I * ((dF[0][0] + dF[1][1] + dF[2][2]) * lambda_damp);
btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
if (!close_to_flat)
{
df_on_node123 = psb->m_tetraScratches[j].m_corotation * df_on_node123;
}
btVector3 df_on_node0 = df_on_node123 * grad_N_hat_1st_col;
// damping force differential
@@ -265,6 +335,15 @@ public:
df[id2] -= scale1 * df_on_node123.getColumn(1);
df[id3] -= scale1 * df_on_node123.getColumn(2);
}
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
const btSoftBody::Node& node = psb->m_nodes[j];
size_t id = node.index;
if (node.m_im > 0)
{
df[id] -= scale * dv[id] / node.m_im * m_damping_alpha;
}
}
}
}
@@ -291,11 +370,11 @@ public:
size_t id1 = node1->index;
size_t id2 = node2->index;
size_t id3 = node3->index;
btMatrix3x3 dF = Ds(id0, id1, id2, id3, dx) * tetra.m_Dm_inverse;
btMatrix3x3 dF = psb->m_tetraScratches[j].m_corotation.transpose() * Ds(id0, id1, id2, id3, dx) * tetra.m_Dm_inverse;
btMatrix3x3 dP;
firstPiolaDifferential(psb->m_tetraScratches[j], dF, dP);
// btVector3 df_on_node0 = dP * (tetra.m_Dm_inverse.transpose()*grad_N_hat_1st_col);
btMatrix3x3 df_on_node123 = dP * tetra.m_Dm_inverse.transpose();
btMatrix3x3 df_on_node123 = psb->m_tetraScratches[j].m_corotation * dP * tetra.m_Dm_inverse.transpose();
btVector3 df_on_node0 = df_on_node123 * grad_N_hat_1st_col;
// elastic force differential
@@ -310,7 +389,9 @@ public:
void firstPiola(const btSoftBody::TetraScratch& s, btMatrix3x3& P)
{
btMatrix3x3 epsilon = (s.m_F + s.m_F.transpose()) * 0.5 - btMatrix3x3::getIdentity();
btMatrix3x3 corotated_F = s.m_corotation.transpose() * s.m_F;
btMatrix3x3 epsilon = (corotated_F + corotated_F.transpose()) * 0.5 - btMatrix3x3::getIdentity();
btScalar trace = epsilon[0][0] + epsilon[1][1] + epsilon[2][2];
P = epsilon * btScalar(2) * m_mu + btMatrix3x3::getIdentity() * m_lambda * trace;
}
@@ -327,8 +408,50 @@ public:
// This function calculates the dP = dQ/dF * dF
void firstPiolaDampingDifferential(const btSoftBody::TetraScratch& s, const btMatrix3x3& dF, btMatrix3x3& dP)
{
btScalar mu_damp = m_damping_beta * m_mu;
btScalar lambda_damp = m_damping_beta * m_lambda;
btScalar trace = (dF[0][0] + dF[1][1] + dF[2][2]);
dP = (dF + dF.transpose()) * m_mu_damp + btMatrix3x3::getIdentity() * m_lambda_damp * trace;
dP = (dF + dF.transpose()) * mu_damp + btMatrix3x3::getIdentity() * lambda_damp * trace;
}
virtual void addScaledHessian(btScalar scale)
{
btVector3 grad_N_hat_1st_col = btVector3(-1, -1, -1);
for (int i = 0; i < m_softBodies.size(); ++i)
{
btSoftBody* psb = m_softBodies[i];
if (!psb->isActive())
{
continue;
}
for (int j = 0; j < psb->m_tetras.size(); ++j)
{
btSoftBody::Tetra& tetra = psb->m_tetras[j];
btMatrix3x3 P;
firstPiola(psb->m_tetraScratches[j], P); // make sure scratch is evaluated at x_n + dt * vn
btMatrix3x3 force_on_node123 = psb->m_tetraScratches[j].m_corotation * P * tetra.m_Dm_inverse.transpose();
btVector3 force_on_node0 = force_on_node123 * grad_N_hat_1st_col;
btSoftBody::Node* node0 = tetra.m_n[0];
btSoftBody::Node* node1 = tetra.m_n[1];
btSoftBody::Node* node2 = tetra.m_n[2];
btSoftBody::Node* node3 = tetra.m_n[3];
btScalar scale1 = scale * (scale + m_damping_beta) * tetra.m_element_measure; // stiff and stiffness-damping terms;
node0->m_effectiveMass += OuterProduct(force_on_node0, force_on_node0) * scale1;
node1->m_effectiveMass += OuterProduct(force_on_node123.getColumn(0), force_on_node123.getColumn(0)) * scale1;
node2->m_effectiveMass += OuterProduct(force_on_node123.getColumn(1), force_on_node123.getColumn(1)) * scale1;
node3->m_effectiveMass += OuterProduct(force_on_node123.getColumn(2), force_on_node123.getColumn(2)) * scale1;
}
for (int j = 0; j < psb->m_nodes.size(); ++j)
{
btSoftBody::Node& node = psb->m_nodes[j];
if (node.m_im > 0)
{
btMatrix3x3 I;
I.setIdentity();
node.m_effectiveMass += I * (scale * (1.0 / node.m_im) * m_damping_alpha);
}
}
}
}
virtual btDeformableLagrangianForceType getForceType()
@@ -128,7 +128,24 @@ public:
virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df)
{
//TODO
btScalar scaled_stiffness = scale * m_elasticStiffness;
for (int i = 0; i < 3; ++i)
{
btVector3 dir = (m_face.m_n[i]->m_q - m_mouse_pos);
btScalar dir_norm = dir.norm();
btVector3 dir_normalized = (dir_norm > SIMD_EPSILON) ? dir.normalized() : btVector3(0, 0, 0);
int id = m_face.m_n[i]->index;
btVector3 dx_diff = dx[id];
btScalar r = 0; // rest length is 0 for picking spring
btVector3 scaled_df = btVector3(0, 0, 0);
if (dir_norm > SIMD_EPSILON)
{
scaled_df -= scaled_stiffness * dir_normalized.dot(dx_diff) * dir_normalized;
scaled_df += scaled_stiffness * dir_normalized.dot(dx_diff) * ((dir_norm - r) / dir_norm) * dir_normalized;
scaled_df -= scaled_stiffness * ((dir_norm - r) / dir_norm) * dx_diff;
}
df[id] += scaled_df;
}
}
void setMousePos(const btVector3& p)
@@ -162,6 +162,11 @@ public:
m_lineSearch = lineSearch;
}
void setUseProjection(bool useProjection)
{
m_useProjection = useProjection;
}
void applyRepulsionForce(btScalar timeStep);
void performGeometricCollisions(btScalar timeStep);
+52
View File
@@ -900,6 +900,7 @@ void btSoftBody::setVelocity(const btVector3& velocity)
if (n.m_im > 0)
{
n.m_v = velocity;
n.m_vn = velocity;
}
}
}
@@ -2772,6 +2773,7 @@ bool btSoftBody::checkDeformableContact(const btCollisionObjectWrapper* colObjWr
shp,
nrm,
margin);
if (!predict)
{
cti.m_colObj = colObjWrap->getCollisionObject();
@@ -3462,11 +3464,46 @@ void btSoftBody::initializeDmInverse()
c1.getZ(), c2.getZ(), c3.getZ());
t.m_element_measure = Dm.determinant() * unit_simplex_measure;
t.m_Dm_inverse = Dm.inverse();
// calculate the first three columns of P^{-1}
btVector3 a = t.m_n[0]->m_x;
btVector3 b = t.m_n[1]->m_x;
btVector3 c = t.m_n[2]->m_x;
btVector3 d = t.m_n[3]->m_x;
btScalar det = 1 / (a[0] * b[1] * c[2] - a[0] * b[1] * d[2] - a[0] * b[2] * c[1] + a[0] * b[2] * d[1] + a[0] * c[1] * d[2] - a[0] * c[2] * d[1] + a[1] * (-b[0] * c[2] + b[0] * d[2] + b[2] * c[0] - b[2] * d[0] - c[0] * d[2] + c[2] * d[0]) + a[2] * (b[0] * c[1] - b[0] * d[1] + b[1] * (d[0] - c[0]) + c[0] * d[1] - c[1] * d[0]) - b[0] * c[1] * d[2] + b[0] * c[2] * d[1] + b[1] * c[0] * d[2] - b[1] * c[2] * d[0] - b[2] * c[0] * d[1] + b[2] * c[1] * d[0]);
btScalar P11 = -b[2] * c[1] + d[2] * c[1] + b[1] * c[2] + b[2] * d[1] - c[2] * d[1] - b[1] * d[2];
btScalar P12 = b[2] * c[0] - d[2] * c[0] - b[0] * c[2] - b[2] * d[0] + c[2] * d[0] + b[0] * d[2];
btScalar P13 = -b[1] * c[0] + d[1] * c[0] + b[0] * c[1] + b[1] * d[0] - c[1] * d[0] - b[0] * d[1];
btScalar P21 = a[2] * c[1] - d[2] * c[1] - a[1] * c[2] - a[2] * d[1] + c[2] * d[1] + a[1] * d[2];
btScalar P22 = -a[2] * c[0] + d[2] * c[0] + a[0] * c[2] + a[2] * d[0] - c[2] * d[0] - a[0] * d[2];
btScalar P23 = a[1] * c[0] - d[1] * c[0] - a[0] * c[1] - a[1] * d[0] + c[1] * d[0] + a[0] * d[1];
btScalar P31 = -a[2] * b[1] + d[2] * b[1] + a[1] * b[2] + a[2] * d[1] - b[2] * d[1] - a[1] * d[2];
btScalar P32 = a[2] * b[0] - d[2] * b[0] - a[0] * b[2] - a[2] * d[0] + b[2] * d[0] + a[0] * d[2];
btScalar P33 = -a[1] * b[0] + d[1] * b[0] + a[0] * b[1] + a[1] * d[0] - b[1] * d[0] - a[0] * d[1];
btScalar P41 = a[2] * b[1] - c[2] * b[1] - a[1] * b[2] - a[2] * c[1] + b[2] * c[1] + a[1] * c[2];
btScalar P42 = -a[2] * b[0] + c[2] * b[0] + a[0] * b[2] + a[2] * c[0] - b[2] * c[0] - a[0] * c[2];
btScalar P43 = a[1] * b[0] - c[1] * b[0] - a[0] * b[1] - a[1] * c[0] + b[1] * c[0] + a[0] * c[1];
btVector4 p1(P11 * det, P21 * det, P31 * det, P41 * det);
btVector4 p2(P12 * det, P22 * det, P32 * det, P42 * det);
btVector4 p3(P13 * det, P23 * det, P33 * det, P43 * det);
t.m_P_inv[0] = p1;
t.m_P_inv[1] = p2;
t.m_P_inv[2] = p3;
}
}
static btScalar Dot4(const btVector4& a, const btVector4& b)
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
}
void btSoftBody::updateDeformation()
{
btQuaternion q;
for (int i = 0; i < m_tetras.size(); ++i)
{
btSoftBody::Tetra& t = m_tetras[i];
@@ -3484,6 +3521,21 @@ void btSoftBody::updateDeformation()
btMatrix3x3 C = t.m_F.transpose() * t.m_F;
s.m_trace = C[0].getX() + C[1].getY() + C[2].getZ();
s.m_cofF = t.m_F.adjoint().transpose();
btVector3 a = t.m_n[0]->m_q;
btVector3 b = t.m_n[1]->m_q;
btVector3 c = t.m_n[2]->m_q;
btVector3 d = t.m_n[3]->m_q;
btVector4 q1(a[0], b[0], c[0], d[0]);
btVector4 q2(a[1], b[1], c[1], d[1]);
btVector4 q3(a[2], b[2], c[2], d[2]);
btMatrix3x3 B(Dot4(q1, t.m_P_inv[0]), Dot4(q1, t.m_P_inv[1]), Dot4(q1, t.m_P_inv[2]),
Dot4(q2, t.m_P_inv[0]), Dot4(q2, t.m_P_inv[1]), Dot4(q2, t.m_P_inv[2]),
Dot4(q3, t.m_P_inv[0]), Dot4(q3, t.m_P_inv[1]), Dot4(q3, t.m_P_inv[2]));
q.setRotation(btVector3(0, 0, 1), 0);
B.extractRotation(q, 0.01); // precision of the rotation is not very important for visual correctness.
btMatrix3x3 Q(q);
s.m_corotation = Q;
}
}
+14 -9
View File
@@ -272,7 +272,9 @@ public:
int m_constrained; // depth of penetration
int m_battach : 1; // Attached
int index;
btVector3 m_splitv; // velocity associated with split impulse
btVector3 m_splitv; // velocity associated with split impulse
btMatrix3x3 m_effectiveMass; // effective mass in contact
btMatrix3x3 m_effectiveMass_inv; // inverse of effective mass
};
/* Link */
ATTRIBUTE_ALIGNED16(struct)
@@ -311,15 +313,17 @@ public:
btMatrix3x3 m_Dm_inverse; // rest Dm^-1
btMatrix3x3 m_F;
btScalar m_element_measure;
btVector4 m_P_inv[3]; // first three columns of P_inv matrix
};
/* TetraScratch */
struct TetraScratch
{
btMatrix3x3 m_F; // deformation gradient F
btScalar m_trace; // trace of F^T * F
btScalar m_J; // det(F)
btMatrix3x3 m_cofF; // cofactor of F
btMatrix3x3 m_F; // deformation gradient F
btScalar m_trace; // trace of F^T * F
btScalar m_J; // det(F)
btMatrix3x3 m_cofF; // cofactor of F
btMatrix3x3 m_corotation; // corotatio of the tetra
};
/* RContact */
@@ -350,6 +354,7 @@ public:
btScalar m_c2; // inverse mass of node/face
btScalar m_c3; // Friction
btScalar m_c4; // Hardness
btMatrix3x3 m_c5; // inverse effective mass
// jacobians and unit impulse responses for multibody
btMultiBodyJacobianData jacobianData_normal;
@@ -1323,7 +1328,7 @@ public:
int face_penetration = 0, node_penetration = node->m_constrained;
for (int i = 0; i < 3; ++i)
face_penetration |= face->m_n[i]->m_constrained;
btScalar I_tilde = .5 * I / (1.0 + w.length2());
btScalar I_tilde = 2.0 * I / (1.0 + w.length2());
// double the impulse if node or face is constrained.
if (face_penetration > 0 || node_penetration > 0)
@@ -1349,10 +1354,10 @@ public:
btScalar vt_new = btMax(btScalar(1) - mu * delta_vn / (vt_norm + SIMD_EPSILON), btScalar(0)) * vt_norm;
I = 0.5 * mass * (vt_norm - vt_new);
vt.safeNormalize();
I_tilde = .5 * I / (1.0 + w.length2());
I_tilde = 2.0 * I / (1.0 + w.length2());
// double the impulse if node or face is constrained.
// if (face_penetration > 0 || node_penetration > 0)
// I_tilde *= 2.0;
if (face_penetration > 0 || node_penetration > 0)
I_tilde *= 2.0;
if (face_penetration <= 0)
{
for (int j = 0; j < 3; ++j)
+19 -4
View File
@@ -1010,6 +1010,20 @@ static inline btMatrix3x3 ImpulseMatrix(btScalar dt,
return (Diagonal(1 / dt) * Add(Diagonal(ima), MassMatrix(imb, iwi, r)).inverse());
}
//
static inline btMatrix3x3 ImpulseMatrix(btScalar dt,
const btMatrix3x3& effective_mass_inv,
btScalar imb,
const btMatrix3x3& iwi,
const btVector3& r)
{
return (Diagonal(1 / dt) * Add(effective_mass_inv, MassMatrix(imb, iwi, r)).inverse());
// btMatrix3x3 iimb = MassMatrix(imb, iwi, r);
// if (iimb.determinant() == 0)
// return effective_mass_inv.inverse();
// return effective_mass_inv.inverse() * Add(effective_mass_inv.inverse(), iimb.inverse()).inverse() * iimb.inverse();
}
//
static inline btMatrix3x3 ImpulseMatrix(btScalar ima, const btMatrix3x3& iia, const btVector3& ra,
btScalar imb, const btMatrix3x3& iib, const btVector3& rb)
@@ -1132,9 +1146,7 @@ static inline bool lineIntersectsTriangle(const btVector3& rayStart, const btVec
if (dir_norm < SIMD_EPSILON)
return false;
dir.normalize();
btScalar t;
bool ret = rayIntersectsTriangle(rayStart, dir, p1, p2, p3, t);
if (ret)
@@ -1682,7 +1694,9 @@ struct btSoftColliders
const btMatrix3x3& iwi = m_rigidBody ? m_rigidBody->getInvInertiaTensorWorld() : iwiStatic;
const btVector3 ra = n.m_x - wtr.getOrigin();
c.m_c0 = ImpulseMatrix(1, ima, imb, iwi, ra);
c.m_c0 = ImpulseMatrix(1, n.m_effectiveMass_inv, imb, iwi, ra);
c.m_c5 = n.m_effectiveMass_inv;
// c.m_c0 = ImpulseMatrix(1, ima, imb, iwi, ra);
c.m_c1 = ra;
}
else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
@@ -1710,7 +1724,7 @@ struct btSoftColliders
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();
btMatrix3x3 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.jacobianData_normal = jacobianData_normal;
c.jacobianData_t1 = jacobianData_t1;
@@ -1776,6 +1790,7 @@ struct btSoftColliders
c.m_c2 = ima;
c.m_c3 = fc;
c.m_c4 = m_colObj1Wrap->getCollisionObject()->isStaticOrKinematicObject() ? psb->m_cfg.kKHR : psb->m_cfg.kCHR;
c.m_c5 = Diagonal(ima);
if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
{
const btTransform& wtr = m_rigidBody ? m_rigidBody->getWorldTransform() : m_colObj1Wrap->getCollisionObject()->getWorldTransform();