3710 lines
92 KiB
C++
3710 lines
92 KiB
C++
/*
|
||
Bullet Continuous Collision Detection and Physics Library
|
||
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||
|
||
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.
|
||
*/
|
||
///btSoftBody implementation by Nathanael Presson
|
||
|
||
#include "btSoftBodyInternals.h"
|
||
#include "BulletSoftBody/btSoftBodySolvers.h"
|
||
#include "btSoftBodyData.h"
|
||
#include "LinearMath/btSerializer.h"
|
||
#include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h"
|
||
#include "BulletDynamics/Featherstone/btMultiBodyConstraint.h"
|
||
|
||
|
||
//
|
||
btSoftBody::btSoftBody(btSoftBodyWorldInfo* worldInfo,int node_count, const btVector3* x, const btScalar* m)
|
||
:m_softBodySolver(0),m_worldInfo(worldInfo)
|
||
{
|
||
/* Init */
|
||
initDefaults();
|
||
|
||
/* Default material */
|
||
Material* pm=appendMaterial();
|
||
pm->m_kLST = 1;
|
||
pm->m_kAST = 1;
|
||
pm->m_kVST = 1;
|
||
pm->m_flags = fMaterial::Default;
|
||
|
||
/* Nodes */
|
||
const btScalar margin=getCollisionShape()->getMargin();
|
||
m_nodes.resize(node_count);
|
||
for(int i=0,ni=node_count;i<ni;++i)
|
||
{
|
||
Node& n=m_nodes[i];
|
||
ZeroInitialize(n);
|
||
n.m_x = x?*x++:btVector3(0,0,0);
|
||
n.m_q = n.m_x;
|
||
n.m_im = m?*m++:1;
|
||
n.m_im = n.m_im>0?1/n.m_im:0;
|
||
n.m_leaf = m_ndbvt.insert(btDbvtVolume::FromCR(n.m_x,margin),&n);
|
||
n.m_material= pm;
|
||
}
|
||
updateBounds();
|
||
|
||
}
|
||
|
||
btSoftBody::btSoftBody(btSoftBodyWorldInfo* worldInfo)
|
||
:m_worldInfo(worldInfo)
|
||
{
|
||
initDefaults();
|
||
}
|
||
|
||
|
||
void btSoftBody::initDefaults()
|
||
{
|
||
m_internalType = CO_SOFT_BODY;
|
||
m_cfg.aeromodel = eAeroModel::V_Point;
|
||
m_cfg.kVCF = 1;
|
||
m_cfg.kDG = 0;
|
||
m_cfg.kLF = 0;
|
||
m_cfg.kDP = 0;
|
||
m_cfg.kPR = 0;
|
||
m_cfg.kVC = 0;
|
||
m_cfg.kDF = (btScalar)0.2;
|
||
m_cfg.kMT = 0;
|
||
m_cfg.kCHR = (btScalar)1.0;
|
||
m_cfg.kKHR = (btScalar)0.1;
|
||
m_cfg.kSHR = (btScalar)1.0;
|
||
m_cfg.kAHR = (btScalar)0.7;
|
||
m_cfg.kSRHR_CL = (btScalar)0.1;
|
||
m_cfg.kSKHR_CL = (btScalar)1;
|
||
m_cfg.kSSHR_CL = (btScalar)0.5;
|
||
m_cfg.kSR_SPLT_CL = (btScalar)0.5;
|
||
m_cfg.kSK_SPLT_CL = (btScalar)0.5;
|
||
m_cfg.kSS_SPLT_CL = (btScalar)0.5;
|
||
m_cfg.maxvolume = (btScalar)1;
|
||
m_cfg.timescale = 1;
|
||
m_cfg.viterations = 0;
|
||
m_cfg.piterations = 1;
|
||
m_cfg.diterations = 0;
|
||
m_cfg.citerations = 4;
|
||
m_cfg.collisions = fCollision::Default;
|
||
m_pose.m_bvolume = false;
|
||
m_pose.m_bframe = false;
|
||
m_pose.m_volume = 0;
|
||
m_pose.m_com = btVector3(0,0,0);
|
||
m_pose.m_rot.setIdentity();
|
||
m_pose.m_scl.setIdentity();
|
||
m_tag = 0;
|
||
m_timeacc = 0;
|
||
m_bUpdateRtCst = true;
|
||
m_bounds[0] = btVector3(0,0,0);
|
||
m_bounds[1] = btVector3(0,0,0);
|
||
m_worldTransform.setIdentity();
|
||
setSolver(eSolverPresets::Positions);
|
||
|
||
/* Collision shape */
|
||
///for now, create a collision shape internally
|
||
m_collisionShape = new btSoftBodyCollisionShape(this);
|
||
m_collisionShape->setMargin(0.25f);
|
||
|
||
m_initialWorldTransform.setIdentity();
|
||
|
||
m_windVelocity = btVector3(0,0,0);
|
||
m_restLengthScale = btScalar(1.0);
|
||
}
|
||
|
||
//
|
||
btSoftBody::~btSoftBody()
|
||
{
|
||
//for now, delete the internal shape
|
||
delete m_collisionShape;
|
||
int i;
|
||
|
||
releaseClusters();
|
||
for(i=0;i<m_materials.size();++i)
|
||
btAlignedFree(m_materials[i]);
|
||
for(i=0;i<m_joints.size();++i)
|
||
btAlignedFree(m_joints[i]);
|
||
}
|
||
|
||
//
|
||
bool btSoftBody::checkLink(int node0,int node1) const
|
||
{
|
||
return(checkLink(&m_nodes[node0],&m_nodes[node1]));
|
||
}
|
||
|
||
//
|
||
bool btSoftBody::checkLink(const Node* node0,const Node* node1) const
|
||
{
|
||
const Node* n[]={node0,node1};
|
||
for(int i=0,ni=m_links.size();i<ni;++i)
|
||
{
|
||
const Link& l=m_links[i];
|
||
if( (l.m_n[0]==n[0]&&l.m_n[1]==n[1])||
|
||
(l.m_n[0]==n[1]&&l.m_n[1]==n[0]))
|
||
{
|
||
return(true);
|
||
}
|
||
}
|
||
return(false);
|
||
}
|
||
|
||
//
|
||
bool btSoftBody::checkFace(int node0,int node1,int node2) const
|
||
{
|
||
const Node* n[]={ &m_nodes[node0],
|
||
&m_nodes[node1],
|
||
&m_nodes[node2]};
|
||
for(int i=0,ni=m_faces.size();i<ni;++i)
|
||
{
|
||
const Face& f=m_faces[i];
|
||
int c=0;
|
||
for(int j=0;j<3;++j)
|
||
{
|
||
if( (f.m_n[j]==n[0])||
|
||
(f.m_n[j]==n[1])||
|
||
(f.m_n[j]==n[2])) c|=1<<j; else break;
|
||
}
|
||
if(c==7) return(true);
|
||
}
|
||
return(false);
|
||
}
|
||
|
||
//
|
||
btSoftBody::Material* btSoftBody::appendMaterial()
|
||
{
|
||
Material* pm=new(btAlignedAlloc(sizeof(Material),16)) Material();
|
||
if(m_materials.size()>0)
|
||
*pm=*m_materials[0];
|
||
else
|
||
ZeroInitialize(*pm);
|
||
m_materials.push_back(pm);
|
||
return(pm);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendNote( const char* text,
|
||
const btVector3& o,
|
||
const btVector4& c,
|
||
Node* n0,
|
||
Node* n1,
|
||
Node* n2,
|
||
Node* n3)
|
||
{
|
||
Note n;
|
||
ZeroInitialize(n);
|
||
n.m_rank = 0;
|
||
n.m_text = text;
|
||
n.m_offset = o;
|
||
n.m_coords[0] = c.x();
|
||
n.m_coords[1] = c.y();
|
||
n.m_coords[2] = c.z();
|
||
n.m_coords[3] = c.w();
|
||
n.m_nodes[0] = n0;n.m_rank+=n0?1:0;
|
||
n.m_nodes[1] = n1;n.m_rank+=n1?1:0;
|
||
n.m_nodes[2] = n2;n.m_rank+=n2?1:0;
|
||
n.m_nodes[3] = n3;n.m_rank+=n3?1:0;
|
||
m_notes.push_back(n);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendNote( const char* text,
|
||
const btVector3& o,
|
||
Node* feature)
|
||
{
|
||
appendNote(text,o,btVector4(1,0,0,0),feature);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendNote( const char* text,
|
||
const btVector3& o,
|
||
Link* feature)
|
||
{
|
||
static const btScalar w=1/(btScalar)2;
|
||
appendNote(text,o,btVector4(w,w,0,0), feature->m_n[0],
|
||
feature->m_n[1]);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendNote( const char* text,
|
||
const btVector3& o,
|
||
Face* feature)
|
||
{
|
||
static const btScalar w=1/(btScalar)3;
|
||
appendNote(text,o,btVector4(w,w,w,0), feature->m_n[0],
|
||
feature->m_n[1],
|
||
feature->m_n[2]);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendNode( const btVector3& x,btScalar m)
|
||
{
|
||
if(m_nodes.capacity()==m_nodes.size())
|
||
{
|
||
pointersToIndices();
|
||
m_nodes.reserve(m_nodes.size()*2+1);
|
||
indicesToPointers();
|
||
}
|
||
const btScalar margin=getCollisionShape()->getMargin();
|
||
m_nodes.push_back(Node());
|
||
Node& n=m_nodes[m_nodes.size()-1];
|
||
ZeroInitialize(n);
|
||
n.m_x = x;
|
||
n.m_q = n.m_x;
|
||
n.m_im = m>0?1/m:0;
|
||
n.m_material = m_materials[0];
|
||
n.m_leaf = m_ndbvt.insert(btDbvtVolume::FromCR(n.m_x,margin),&n);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendLink(int model,Material* mat)
|
||
{
|
||
Link l;
|
||
if(model>=0)
|
||
l=m_links[model];
|
||
else
|
||
{ ZeroInitialize(l);l.m_material=mat?mat:m_materials[0]; }
|
||
m_links.push_back(l);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendLink( int node0,
|
||
int node1,
|
||
Material* mat,
|
||
bool bcheckexist)
|
||
{
|
||
appendLink(&m_nodes[node0],&m_nodes[node1],mat,bcheckexist);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendLink( Node* node0,
|
||
Node* node1,
|
||
Material* mat,
|
||
bool bcheckexist)
|
||
{
|
||
if((!bcheckexist)||(!checkLink(node0,node1)))
|
||
{
|
||
appendLink(-1,mat);
|
||
Link& l=m_links[m_links.size()-1];
|
||
l.m_n[0] = node0;
|
||
l.m_n[1] = node1;
|
||
l.m_rl = (l.m_n[0]->m_x-l.m_n[1]->m_x).length();
|
||
m_bUpdateRtCst=true;
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendFace(int model,Material* mat)
|
||
{
|
||
Face f;
|
||
if(model>=0)
|
||
{ f=m_faces[model]; }
|
||
else
|
||
{ ZeroInitialize(f);f.m_material=mat?mat:m_materials[0]; }
|
||
m_faces.push_back(f);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendFace(int node0,int node1,int node2,Material* mat)
|
||
{
|
||
if (node0==node1)
|
||
return;
|
||
if (node1==node2)
|
||
return;
|
||
if (node2==node0)
|
||
return;
|
||
|
||
appendFace(-1,mat);
|
||
Face& f=m_faces[m_faces.size()-1];
|
||
btAssert(node0!=node1);
|
||
btAssert(node1!=node2);
|
||
btAssert(node2!=node0);
|
||
f.m_n[0] = &m_nodes[node0];
|
||
f.m_n[1] = &m_nodes[node1];
|
||
f.m_n[2] = &m_nodes[node2];
|
||
f.m_ra = AreaOf( f.m_n[0]->m_x,
|
||
f.m_n[1]->m_x,
|
||
f.m_n[2]->m_x);
|
||
m_bUpdateRtCst=true;
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendTetra(int model,Material* mat)
|
||
{
|
||
Tetra t;
|
||
if(model>=0)
|
||
t=m_tetras[model];
|
||
else
|
||
{ ZeroInitialize(t);t.m_material=mat?mat:m_materials[0]; }
|
||
m_tetras.push_back(t);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendTetra(int node0,
|
||
int node1,
|
||
int node2,
|
||
int node3,
|
||
Material* mat)
|
||
{
|
||
appendTetra(-1,mat);
|
||
Tetra& t=m_tetras[m_tetras.size()-1];
|
||
t.m_n[0] = &m_nodes[node0];
|
||
t.m_n[1] = &m_nodes[node1];
|
||
t.m_n[2] = &m_nodes[node2];
|
||
t.m_n[3] = &m_nodes[node3];
|
||
t.m_rv = VolumeOf(t.m_n[0]->m_x,t.m_n[1]->m_x,t.m_n[2]->m_x,t.m_n[3]->m_x);
|
||
m_bUpdateRtCst=true;
|
||
}
|
||
|
||
//
|
||
|
||
void btSoftBody::appendAnchor(int node,btRigidBody* body, bool disableCollisionBetweenLinkedBodies,btScalar influence)
|
||
{
|
||
btVector3 local = body->getWorldTransform().inverse()*m_nodes[node].m_x;
|
||
appendAnchor(node,body,local,disableCollisionBetweenLinkedBodies,influence);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendAnchor(int node,btRigidBody* body, const btVector3& localPivot,bool disableCollisionBetweenLinkedBodies,btScalar influence)
|
||
{
|
||
if (disableCollisionBetweenLinkedBodies)
|
||
{
|
||
if (m_collisionDisabledObjects.findLinearSearch(body)==m_collisionDisabledObjects.size())
|
||
{
|
||
m_collisionDisabledObjects.push_back(body);
|
||
}
|
||
}
|
||
|
||
Anchor a;
|
||
a.m_node = &m_nodes[node];
|
||
a.m_body = body;
|
||
a.m_local = localPivot;
|
||
a.m_node->m_battach = 1;
|
||
a.m_influence = influence;
|
||
m_anchors.push_back(a);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendLinearJoint(const LJoint::Specs& specs,Cluster* body0,Body body1)
|
||
{
|
||
LJoint* pj = new(btAlignedAlloc(sizeof(LJoint),16)) LJoint();
|
||
pj->m_bodies[0] = body0;
|
||
pj->m_bodies[1] = body1;
|
||
pj->m_refs[0] = pj->m_bodies[0].xform().inverse()*specs.position;
|
||
pj->m_refs[1] = pj->m_bodies[1].xform().inverse()*specs.position;
|
||
pj->m_cfm = specs.cfm;
|
||
pj->m_erp = specs.erp;
|
||
pj->m_split = specs.split;
|
||
m_joints.push_back(pj);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendLinearJoint(const LJoint::Specs& specs,Body body)
|
||
{
|
||
appendLinearJoint(specs,m_clusters[0],body);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendLinearJoint(const LJoint::Specs& specs,btSoftBody* body)
|
||
{
|
||
appendLinearJoint(specs,m_clusters[0],body->m_clusters[0]);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendAngularJoint(const AJoint::Specs& specs,Cluster* body0,Body body1)
|
||
{
|
||
AJoint* pj = new(btAlignedAlloc(sizeof(AJoint),16)) AJoint();
|
||
pj->m_bodies[0] = body0;
|
||
pj->m_bodies[1] = body1;
|
||
pj->m_refs[0] = pj->m_bodies[0].xform().inverse().getBasis()*specs.axis;
|
||
pj->m_refs[1] = pj->m_bodies[1].xform().inverse().getBasis()*specs.axis;
|
||
pj->m_cfm = specs.cfm;
|
||
pj->m_erp = specs.erp;
|
||
pj->m_split = specs.split;
|
||
pj->m_icontrol = specs.icontrol;
|
||
m_joints.push_back(pj);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendAngularJoint(const AJoint::Specs& specs,Body body)
|
||
{
|
||
appendAngularJoint(specs,m_clusters[0],body);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::appendAngularJoint(const AJoint::Specs& specs,btSoftBody* body)
|
||
{
|
||
appendAngularJoint(specs,m_clusters[0],body->m_clusters[0]);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::addForce(const btVector3& force)
|
||
{
|
||
for(int i=0,ni=m_nodes.size();i<ni;++i) addForce(force,i);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::addForce(const btVector3& force,int node)
|
||
{
|
||
Node& n=m_nodes[node];
|
||
if(n.m_im>0)
|
||
{
|
||
n.m_f += force;
|
||
}
|
||
}
|
||
|
||
void btSoftBody::addAeroForceToNode(const btVector3& windVelocity,int nodeIndex)
|
||
{
|
||
btAssert(nodeIndex >= 0 && nodeIndex < m_nodes.size());
|
||
|
||
const btScalar dt = m_sst.sdt;
|
||
const btScalar kLF = m_cfg.kLF;
|
||
const btScalar kDG = m_cfg.kDG;
|
||
//const btScalar kPR = m_cfg.kPR;
|
||
//const btScalar kVC = m_cfg.kVC;
|
||
const bool as_lift = kLF>0;
|
||
const bool as_drag = kDG>0;
|
||
const bool as_aero = as_lift || as_drag;
|
||
const bool as_vaero = as_aero && (m_cfg.aeromodel < btSoftBody::eAeroModel::F_TwoSided);
|
||
|
||
Node& n = m_nodes[nodeIndex];
|
||
|
||
if( n.m_im>0 )
|
||
{
|
||
btSoftBody::sMedium medium;
|
||
|
||
EvaluateMedium(m_worldInfo, n.m_x, medium);
|
||
medium.m_velocity = windVelocity;
|
||
medium.m_density = m_worldInfo->air_density;
|
||
|
||
/* Aerodynamics */
|
||
if(as_vaero)
|
||
{
|
||
const btVector3 rel_v = n.m_v - medium.m_velocity;
|
||
const btScalar rel_v_len = rel_v.length();
|
||
const btScalar rel_v2 = rel_v.length2();
|
||
|
||
if(rel_v2>SIMD_EPSILON)
|
||
{
|
||
const btVector3 rel_v_nrm = rel_v.normalized();
|
||
btVector3 nrm = n.m_n;
|
||
|
||
if (m_cfg.aeromodel == btSoftBody::eAeroModel::V_TwoSidedLiftDrag)
|
||
{
|
||
nrm *= (btScalar)( (btDot(nrm,rel_v) < 0) ? -1 : +1);
|
||
btVector3 fDrag(0, 0, 0);
|
||
btVector3 fLift(0, 0, 0);
|
||
|
||
btScalar n_dot_v = nrm.dot(rel_v_nrm);
|
||
btScalar tri_area = 0.5f * n.m_area;
|
||
|
||
fDrag = 0.5f * kDG * medium.m_density * rel_v2 * tri_area * n_dot_v * (-rel_v_nrm);
|
||
|
||
// Check angle of attack
|
||
// cos(10<31>) = 0.98480
|
||
if ( 0 < n_dot_v && n_dot_v < 0.98480f)
|
||
fLift = 0.5f * kLF * medium.m_density * rel_v_len * tri_area * btSqrt(1.0f-n_dot_v*n_dot_v) * (nrm.cross(rel_v_nrm).cross(rel_v_nrm));
|
||
|
||
// Check if the velocity change resulted by aero drag force exceeds the current velocity of the node.
|
||
btVector3 del_v_by_fDrag = fDrag*n.m_im*m_sst.sdt;
|
||
btScalar del_v_by_fDrag_len2 = del_v_by_fDrag.length2();
|
||
btScalar v_len2 = n.m_v.length2();
|
||
|
||
if (del_v_by_fDrag_len2 >= v_len2 && del_v_by_fDrag_len2 > 0)
|
||
{
|
||
btScalar del_v_by_fDrag_len = del_v_by_fDrag.length();
|
||
btScalar v_len = n.m_v.length();
|
||
fDrag *= btScalar(0.8)*(v_len / del_v_by_fDrag_len);
|
||
}
|
||
|
||
n.m_f += fDrag;
|
||
n.m_f += fLift;
|
||
}
|
||
else if (m_cfg.aeromodel == btSoftBody::eAeroModel::V_Point || m_cfg.aeromodel == btSoftBody::eAeroModel::V_OneSided || m_cfg.aeromodel == btSoftBody::eAeroModel::V_TwoSided)
|
||
{
|
||
if (m_cfg.aeromodel == btSoftBody::eAeroModel::V_TwoSided)
|
||
nrm *= (btScalar)( (btDot(nrm,rel_v) < 0) ? -1 : +1);
|
||
|
||
const btScalar dvn = btDot(rel_v,nrm);
|
||
/* Compute forces */
|
||
if(dvn>0)
|
||
{
|
||
btVector3 force(0,0,0);
|
||
const btScalar c0 = n.m_area * dvn * rel_v2/2;
|
||
const btScalar c1 = c0 * medium.m_density;
|
||
force += nrm*(-c1*kLF);
|
||
force += rel_v.normalized() * (-c1 * kDG);
|
||
ApplyClampedForce(n, force, dt);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void btSoftBody::addAeroForceToFace(const btVector3& windVelocity,int faceIndex)
|
||
{
|
||
const btScalar dt = m_sst.sdt;
|
||
const btScalar kLF = m_cfg.kLF;
|
||
const btScalar kDG = m_cfg.kDG;
|
||
// const btScalar kPR = m_cfg.kPR;
|
||
// const btScalar kVC = m_cfg.kVC;
|
||
const bool as_lift = kLF>0;
|
||
const bool as_drag = kDG>0;
|
||
const bool as_aero = as_lift || as_drag;
|
||
const bool as_faero = as_aero && (m_cfg.aeromodel >= btSoftBody::eAeroModel::F_TwoSided);
|
||
|
||
if(as_faero)
|
||
{
|
||
btSoftBody::Face& f=m_faces[faceIndex];
|
||
|
||
btSoftBody::sMedium medium;
|
||
|
||
const btVector3 v=(f.m_n[0]->m_v+f.m_n[1]->m_v+f.m_n[2]->m_v)/3;
|
||
const btVector3 x=(f.m_n[0]->m_x+f.m_n[1]->m_x+f.m_n[2]->m_x)/3;
|
||
EvaluateMedium(m_worldInfo,x,medium);
|
||
medium.m_velocity = windVelocity;
|
||
medium.m_density = m_worldInfo->air_density;
|
||
const btVector3 rel_v=v-medium.m_velocity;
|
||
const btScalar rel_v_len = rel_v.length();
|
||
const btScalar rel_v2=rel_v.length2();
|
||
|
||
if(rel_v2>SIMD_EPSILON)
|
||
{
|
||
const btVector3 rel_v_nrm = rel_v.normalized();
|
||
btVector3 nrm = f.m_normal;
|
||
|
||
if (m_cfg.aeromodel == btSoftBody::eAeroModel::F_TwoSidedLiftDrag)
|
||
{
|
||
nrm *= (btScalar)( (btDot(nrm,rel_v) < 0) ? -1 : +1);
|
||
|
||
btVector3 fDrag(0, 0, 0);
|
||
btVector3 fLift(0, 0, 0);
|
||
|
||
btScalar n_dot_v = nrm.dot(rel_v_nrm);
|
||
btScalar tri_area = 0.5f * f.m_ra;
|
||
|
||
fDrag = 0.5f * kDG * medium.m_density * rel_v2 * tri_area * n_dot_v * (-rel_v_nrm);
|
||
|
||
// Check angle of attack
|
||
// cos(10<31>) = 0.98480
|
||
if ( 0 < n_dot_v && n_dot_v < 0.98480f)
|
||
fLift = 0.5f * kLF * medium.m_density * rel_v_len * tri_area * btSqrt(1.0f-n_dot_v*n_dot_v) * (nrm.cross(rel_v_nrm).cross(rel_v_nrm));
|
||
|
||
fDrag /= 3;
|
||
fLift /= 3;
|
||
|
||
for(int j=0;j<3;++j)
|
||
{
|
||
if (f.m_n[j]->m_im>0)
|
||
{
|
||
// Check if the velocity change resulted by aero drag force exceeds the current velocity of the node.
|
||
btVector3 del_v_by_fDrag = fDrag*f.m_n[j]->m_im*m_sst.sdt;
|
||
btScalar del_v_by_fDrag_len2 = del_v_by_fDrag.length2();
|
||
btScalar v_len2 = f.m_n[j]->m_v.length2();
|
||
|
||
if (del_v_by_fDrag_len2 >= v_len2 && del_v_by_fDrag_len2 > 0)
|
||
{
|
||
btScalar del_v_by_fDrag_len = del_v_by_fDrag.length();
|
||
btScalar v_len = f.m_n[j]->m_v.length();
|
||
fDrag *= btScalar(0.8)*(v_len / del_v_by_fDrag_len);
|
||
}
|
||
|
||
f.m_n[j]->m_f += fDrag;
|
||
f.m_n[j]->m_f += fLift;
|
||
}
|
||
}
|
||
}
|
||
else if (m_cfg.aeromodel == btSoftBody::eAeroModel::F_OneSided || m_cfg.aeromodel == btSoftBody::eAeroModel::F_TwoSided)
|
||
{
|
||
if (m_cfg.aeromodel == btSoftBody::eAeroModel::F_TwoSided)
|
||
nrm *= (btScalar)( (btDot(nrm,rel_v) < 0) ? -1 : +1);
|
||
|
||
const btScalar dvn=btDot(rel_v,nrm);
|
||
/* Compute forces */
|
||
if(dvn>0)
|
||
{
|
||
btVector3 force(0,0,0);
|
||
const btScalar c0 = f.m_ra*dvn*rel_v2;
|
||
const btScalar c1 = c0*medium.m_density;
|
||
force += nrm*(-c1*kLF);
|
||
force += rel_v.normalized()*(-c1*kDG);
|
||
force /= 3;
|
||
for(int j=0;j<3;++j) ApplyClampedForce(*f.m_n[j],force,dt);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
void btSoftBody::addVelocity(const btVector3& velocity)
|
||
{
|
||
for(int i=0,ni=m_nodes.size();i<ni;++i) addVelocity(velocity,i);
|
||
}
|
||
|
||
/* Set velocity for the entire body */
|
||
void btSoftBody::setVelocity( const btVector3& velocity)
|
||
{
|
||
for(int i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
Node& n=m_nodes[i];
|
||
if(n.m_im>0)
|
||
{
|
||
n.m_v = velocity;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
void btSoftBody::addVelocity(const btVector3& velocity,int node)
|
||
{
|
||
Node& n=m_nodes[node];
|
||
if(n.m_im>0)
|
||
{
|
||
n.m_v += velocity;
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::setMass(int node,btScalar mass)
|
||
{
|
||
m_nodes[node].m_im=mass>0?1/mass:0;
|
||
m_bUpdateRtCst=true;
|
||
}
|
||
|
||
//
|
||
btScalar btSoftBody::getMass(int node) const
|
||
{
|
||
return(m_nodes[node].m_im>0?1/m_nodes[node].m_im:0);
|
||
}
|
||
|
||
//
|
||
btScalar btSoftBody::getTotalMass() const
|
||
{
|
||
btScalar mass=0;
|
||
for(int i=0;i<m_nodes.size();++i)
|
||
{
|
||
mass+=getMass(i);
|
||
}
|
||
return(mass);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::setTotalMass(btScalar mass,bool fromfaces)
|
||
{
|
||
int i;
|
||
|
||
if(fromfaces)
|
||
{
|
||
|
||
for(i=0;i<m_nodes.size();++i)
|
||
{
|
||
m_nodes[i].m_im=0;
|
||
}
|
||
for(i=0;i<m_faces.size();++i)
|
||
{
|
||
const Face& f=m_faces[i];
|
||
const btScalar twicearea=AreaOf( f.m_n[0]->m_x,
|
||
f.m_n[1]->m_x,
|
||
f.m_n[2]->m_x);
|
||
for(int j=0;j<3;++j)
|
||
{
|
||
f.m_n[j]->m_im+=twicearea;
|
||
}
|
||
}
|
||
for( i=0;i<m_nodes.size();++i)
|
||
{
|
||
m_nodes[i].m_im=1/m_nodes[i].m_im;
|
||
}
|
||
}
|
||
const btScalar tm=getTotalMass();
|
||
const btScalar itm=1/tm;
|
||
for( i=0;i<m_nodes.size();++i)
|
||
{
|
||
m_nodes[i].m_im/=itm*mass;
|
||
}
|
||
m_bUpdateRtCst=true;
|
||
}
|
||
|
||
//
|
||
void btSoftBody::setTotalDensity(btScalar density)
|
||
{
|
||
setTotalMass(getVolume()*density,true);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::setVolumeMass(btScalar mass)
|
||
{
|
||
btAlignedObjectArray<btScalar> ranks;
|
||
ranks.resize(m_nodes.size(),0);
|
||
int i;
|
||
|
||
for(i=0;i<m_nodes.size();++i)
|
||
{
|
||
m_nodes[i].m_im=0;
|
||
}
|
||
for(i=0;i<m_tetras.size();++i)
|
||
{
|
||
const Tetra& t=m_tetras[i];
|
||
for(int j=0;j<4;++j)
|
||
{
|
||
t.m_n[j]->m_im+=btFabs(t.m_rv);
|
||
ranks[int(t.m_n[j]-&m_nodes[0])]+=1;
|
||
}
|
||
}
|
||
for( i=0;i<m_nodes.size();++i)
|
||
{
|
||
if(m_nodes[i].m_im>0)
|
||
{
|
||
m_nodes[i].m_im=ranks[i]/m_nodes[i].m_im;
|
||
}
|
||
}
|
||
setTotalMass(mass,false);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::setVolumeDensity(btScalar density)
|
||
{
|
||
btScalar volume=0;
|
||
for(int i=0;i<m_tetras.size();++i)
|
||
{
|
||
const Tetra& t=m_tetras[i];
|
||
for(int j=0;j<4;++j)
|
||
{
|
||
volume+=btFabs(t.m_rv);
|
||
}
|
||
}
|
||
setVolumeMass(volume*density/6);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::transform(const btTransform& trs)
|
||
{
|
||
const btScalar margin=getCollisionShape()->getMargin();
|
||
ATTRIBUTE_ALIGNED16(btDbvtVolume) vol;
|
||
|
||
for(int i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
Node& n=m_nodes[i];
|
||
n.m_x=trs*n.m_x;
|
||
n.m_q=trs*n.m_q;
|
||
n.m_n=trs.getBasis()*n.m_n;
|
||
vol = btDbvtVolume::FromCR(n.m_x,margin);
|
||
|
||
m_ndbvt.update(n.m_leaf,vol);
|
||
}
|
||
updateNormals();
|
||
updateBounds();
|
||
updateConstants();
|
||
m_initialWorldTransform = trs;
|
||
}
|
||
|
||
//
|
||
void btSoftBody::translate(const btVector3& trs)
|
||
{
|
||
btTransform t;
|
||
t.setIdentity();
|
||
t.setOrigin(trs);
|
||
transform(t);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::rotate( const btQuaternion& rot)
|
||
{
|
||
btTransform t;
|
||
t.setIdentity();
|
||
t.setRotation(rot);
|
||
transform(t);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::scale(const btVector3& scl)
|
||
{
|
||
|
||
const btScalar margin=getCollisionShape()->getMargin();
|
||
ATTRIBUTE_ALIGNED16(btDbvtVolume) vol;
|
||
|
||
for(int i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
Node& n=m_nodes[i];
|
||
n.m_x*=scl;
|
||
n.m_q*=scl;
|
||
vol = btDbvtVolume::FromCR(n.m_x,margin);
|
||
m_ndbvt.update(n.m_leaf,vol);
|
||
}
|
||
updateNormals();
|
||
updateBounds();
|
||
updateConstants();
|
||
}
|
||
|
||
//
|
||
btScalar btSoftBody::getRestLengthScale()
|
||
{
|
||
return m_restLengthScale;
|
||
}
|
||
|
||
//
|
||
void btSoftBody::setRestLengthScale(btScalar restLengthScale)
|
||
{
|
||
for(int i=0, ni=m_links.size(); i<ni; ++i)
|
||
{
|
||
Link& l=m_links[i];
|
||
l.m_rl = l.m_rl / m_restLengthScale * restLengthScale;
|
||
l.m_c1 = l.m_rl*l.m_rl;
|
||
}
|
||
m_restLengthScale = restLengthScale;
|
||
|
||
if (getActivationState() == ISLAND_SLEEPING)
|
||
activate();
|
||
}
|
||
|
||
//
|
||
void btSoftBody::setPose(bool bvolume,bool bframe)
|
||
{
|
||
m_pose.m_bvolume = bvolume;
|
||
m_pose.m_bframe = bframe;
|
||
int i,ni;
|
||
|
||
/* Weights */
|
||
const btScalar omass=getTotalMass();
|
||
const btScalar kmass=omass*m_nodes.size()*1000;
|
||
btScalar tmass=omass;
|
||
m_pose.m_wgh.resize(m_nodes.size());
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
if(m_nodes[i].m_im<=0) tmass+=kmass;
|
||
}
|
||
for( i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
Node& n=m_nodes[i];
|
||
m_pose.m_wgh[i]= n.m_im>0 ?
|
||
1/(m_nodes[i].m_im*tmass) :
|
||
kmass/tmass;
|
||
}
|
||
/* Pos */
|
||
const btVector3 com=evaluateCom();
|
||
m_pose.m_pos.resize(m_nodes.size());
|
||
for( i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
m_pose.m_pos[i]=m_nodes[i].m_x-com;
|
||
}
|
||
m_pose.m_volume = bvolume?getVolume():0;
|
||
m_pose.m_com = com;
|
||
m_pose.m_rot.setIdentity();
|
||
m_pose.m_scl.setIdentity();
|
||
/* Aqq */
|
||
m_pose.m_aqq[0] =
|
||
m_pose.m_aqq[1] =
|
||
m_pose.m_aqq[2] = btVector3(0,0,0);
|
||
for( i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
const btVector3& q=m_pose.m_pos[i];
|
||
const btVector3 mq=m_pose.m_wgh[i]*q;
|
||
m_pose.m_aqq[0]+=mq.x()*q;
|
||
m_pose.m_aqq[1]+=mq.y()*q;
|
||
m_pose.m_aqq[2]+=mq.z()*q;
|
||
}
|
||
m_pose.m_aqq=m_pose.m_aqq.inverse();
|
||
|
||
updateConstants();
|
||
}
|
||
|
||
void btSoftBody::resetLinkRestLengths()
|
||
{
|
||
for(int i=0, ni=m_links.size();i<ni;++i)
|
||
{
|
||
Link& l = m_links[i];
|
||
l.m_rl = (l.m_n[0]->m_x-l.m_n[1]->m_x).length();
|
||
l.m_c1 = l.m_rl*l.m_rl;
|
||
}
|
||
}
|
||
|
||
//
|
||
btScalar btSoftBody::getVolume() const
|
||
{
|
||
btScalar vol=0;
|
||
if(m_nodes.size()>0)
|
||
{
|
||
int i,ni;
|
||
|
||
const btVector3 org=m_nodes[0].m_x;
|
||
for(i=0,ni=m_faces.size();i<ni;++i)
|
||
{
|
||
const Face& f=m_faces[i];
|
||
vol+=btDot(f.m_n[0]->m_x-org,btCross(f.m_n[1]->m_x-org,f.m_n[2]->m_x-org));
|
||
}
|
||
vol/=(btScalar)6;
|
||
}
|
||
return(vol);
|
||
}
|
||
|
||
//
|
||
int btSoftBody::clusterCount() const
|
||
{
|
||
return(m_clusters.size());
|
||
}
|
||
|
||
//
|
||
btVector3 btSoftBody::clusterCom(const Cluster* cluster)
|
||
{
|
||
btVector3 com(0,0,0);
|
||
for(int i=0,ni=cluster->m_nodes.size();i<ni;++i)
|
||
{
|
||
com+=cluster->m_nodes[i]->m_x*cluster->m_masses[i];
|
||
}
|
||
return(com*cluster->m_imass);
|
||
}
|
||
|
||
//
|
||
btVector3 btSoftBody::clusterCom(int cluster) const
|
||
{
|
||
return(clusterCom(m_clusters[cluster]));
|
||
}
|
||
|
||
//
|
||
btVector3 btSoftBody::clusterVelocity(const Cluster* cluster,const btVector3& rpos)
|
||
{
|
||
return(cluster->m_lv+btCross(cluster->m_av,rpos));
|
||
}
|
||
|
||
//
|
||
void btSoftBody::clusterVImpulse(Cluster* cluster,const btVector3& rpos,const btVector3& impulse)
|
||
{
|
||
const btVector3 li=cluster->m_imass*impulse;
|
||
const btVector3 ai=cluster->m_invwi*btCross(rpos,impulse);
|
||
cluster->m_vimpulses[0]+=li;cluster->m_lv+=li;
|
||
cluster->m_vimpulses[1]+=ai;cluster->m_av+=ai;
|
||
cluster->m_nvimpulses++;
|
||
}
|
||
|
||
//
|
||
void btSoftBody::clusterDImpulse(Cluster* cluster,const btVector3& rpos,const btVector3& impulse)
|
||
{
|
||
const btVector3 li=cluster->m_imass*impulse;
|
||
const btVector3 ai=cluster->m_invwi*btCross(rpos,impulse);
|
||
cluster->m_dimpulses[0]+=li;
|
||
cluster->m_dimpulses[1]+=ai;
|
||
cluster->m_ndimpulses++;
|
||
}
|
||
|
||
//
|
||
void btSoftBody::clusterImpulse(Cluster* cluster,const btVector3& rpos,const Impulse& impulse)
|
||
{
|
||
if(impulse.m_asVelocity) clusterVImpulse(cluster,rpos,impulse.m_velocity);
|
||
if(impulse.m_asDrift) clusterDImpulse(cluster,rpos,impulse.m_drift);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::clusterVAImpulse(Cluster* cluster,const btVector3& impulse)
|
||
{
|
||
const btVector3 ai=cluster->m_invwi*impulse;
|
||
cluster->m_vimpulses[1]+=ai;cluster->m_av+=ai;
|
||
cluster->m_nvimpulses++;
|
||
}
|
||
|
||
//
|
||
void btSoftBody::clusterDAImpulse(Cluster* cluster,const btVector3& impulse)
|
||
{
|
||
const btVector3 ai=cluster->m_invwi*impulse;
|
||
cluster->m_dimpulses[1]+=ai;
|
||
cluster->m_ndimpulses++;
|
||
}
|
||
|
||
//
|
||
void btSoftBody::clusterAImpulse(Cluster* cluster,const Impulse& impulse)
|
||
{
|
||
if(impulse.m_asVelocity) clusterVAImpulse(cluster,impulse.m_velocity);
|
||
if(impulse.m_asDrift) clusterDAImpulse(cluster,impulse.m_drift);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::clusterDCImpulse(Cluster* cluster,const btVector3& impulse)
|
||
{
|
||
cluster->m_dimpulses[0]+=impulse*cluster->m_imass;
|
||
cluster->m_ndimpulses++;
|
||
}
|
||
|
||
struct NodeLinks
|
||
{
|
||
btAlignedObjectArray<int> m_links;
|
||
};
|
||
|
||
|
||
|
||
//
|
||
int btSoftBody::generateBendingConstraints(int distance,Material* mat)
|
||
{
|
||
int i,j;
|
||
|
||
if(distance>1)
|
||
{
|
||
/* Build graph */
|
||
const int n=m_nodes.size();
|
||
const unsigned inf=(~(unsigned)0)>>1;
|
||
unsigned* adj=new unsigned[n*n];
|
||
|
||
|
||
#define IDX(_x_,_y_) ((_y_)*n+(_x_))
|
||
for(j=0;j<n;++j)
|
||
{
|
||
for(i=0;i<n;++i)
|
||
{
|
||
if(i!=j)
|
||
{
|
||
adj[IDX(i,j)]=adj[IDX(j,i)]=inf;
|
||
}
|
||
else
|
||
{
|
||
adj[IDX(i,j)]=adj[IDX(j,i)]=0;
|
||
}
|
||
}
|
||
}
|
||
for( i=0;i<m_links.size();++i)
|
||
{
|
||
const int ia=(int)(m_links[i].m_n[0]-&m_nodes[0]);
|
||
const int ib=(int)(m_links[i].m_n[1]-&m_nodes[0]);
|
||
adj[IDX(ia,ib)]=1;
|
||
adj[IDX(ib,ia)]=1;
|
||
}
|
||
|
||
|
||
//special optimized case for distance == 2
|
||
if (distance == 2)
|
||
{
|
||
|
||
btAlignedObjectArray<NodeLinks> nodeLinks;
|
||
|
||
|
||
/* Build node links */
|
||
nodeLinks.resize(m_nodes.size());
|
||
|
||
for( i=0;i<m_links.size();++i)
|
||
{
|
||
const int ia=(int)(m_links[i].m_n[0]-&m_nodes[0]);
|
||
const int ib=(int)(m_links[i].m_n[1]-&m_nodes[0]);
|
||
if (nodeLinks[ia].m_links.findLinearSearch(ib)==nodeLinks[ia].m_links.size())
|
||
nodeLinks[ia].m_links.push_back(ib);
|
||
|
||
if (nodeLinks[ib].m_links.findLinearSearch(ia)==nodeLinks[ib].m_links.size())
|
||
nodeLinks[ib].m_links.push_back(ia);
|
||
}
|
||
for (int ii=0;ii<nodeLinks.size();ii++)
|
||
{
|
||
int i=ii;
|
||
|
||
for (int jj=0;jj<nodeLinks[ii].m_links.size();jj++)
|
||
{
|
||
int k = nodeLinks[ii].m_links[jj];
|
||
for (int kk=0;kk<nodeLinks[k].m_links.size();kk++)
|
||
{
|
||
int j = nodeLinks[k].m_links[kk];
|
||
if (i!=j)
|
||
{
|
||
const unsigned sum=adj[IDX(i,k)]+adj[IDX(k,j)];
|
||
btAssert(sum==2);
|
||
if(adj[IDX(i,j)]>sum)
|
||
{
|
||
adj[IDX(i,j)]=adj[IDX(j,i)]=sum;
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
} else
|
||
{
|
||
///generic Floyd's algorithm
|
||
for(int k=0;k<n;++k)
|
||
{
|
||
for(j=0;j<n;++j)
|
||
{
|
||
for(i=j+1;i<n;++i)
|
||
{
|
||
const unsigned sum=adj[IDX(i,k)]+adj[IDX(k,j)];
|
||
if(adj[IDX(i,j)]>sum)
|
||
{
|
||
adj[IDX(i,j)]=adj[IDX(j,i)]=sum;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* Build links */
|
||
int nlinks=0;
|
||
for(j=0;j<n;++j)
|
||
{
|
||
for(i=j+1;i<n;++i)
|
||
{
|
||
if(adj[IDX(i,j)]==(unsigned)distance)
|
||
{
|
||
appendLink(i,j,mat);
|
||
m_links[m_links.size()-1].m_bbending=1;
|
||
++nlinks;
|
||
}
|
||
}
|
||
}
|
||
delete[] adj;
|
||
return(nlinks);
|
||
}
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::randomizeConstraints()
|
||
{
|
||
unsigned long seed=243703;
|
||
#define NEXTRAND (seed=(1664525L*seed+1013904223L)&0xffffffff)
|
||
int i,ni;
|
||
|
||
for(i=0,ni=m_links.size();i<ni;++i)
|
||
{
|
||
btSwap(m_links[i],m_links[NEXTRAND%ni]);
|
||
}
|
||
for(i=0,ni=m_faces.size();i<ni;++i)
|
||
{
|
||
btSwap(m_faces[i],m_faces[NEXTRAND%ni]);
|
||
}
|
||
#undef NEXTRAND
|
||
}
|
||
|
||
//
|
||
void btSoftBody::releaseCluster(int index)
|
||
{
|
||
Cluster* c=m_clusters[index];
|
||
if(c->m_leaf) m_cdbvt.remove(c->m_leaf);
|
||
c->~Cluster();
|
||
btAlignedFree(c);
|
||
m_clusters.remove(c);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::releaseClusters()
|
||
{
|
||
while(m_clusters.size()>0) releaseCluster(0);
|
||
}
|
||
|
||
//
|
||
int btSoftBody::generateClusters(int k,int maxiterations)
|
||
{
|
||
int i;
|
||
releaseClusters();
|
||
m_clusters.resize(btMin(k,m_nodes.size()));
|
||
for(i=0;i<m_clusters.size();++i)
|
||
{
|
||
m_clusters[i] = new(btAlignedAlloc(sizeof(Cluster),16)) Cluster();
|
||
m_clusters[i]->m_collide= true;
|
||
}
|
||
k=m_clusters.size();
|
||
if(k>0)
|
||
{
|
||
/* Initialize */
|
||
btAlignedObjectArray<btVector3> centers;
|
||
btVector3 cog(0,0,0);
|
||
int i;
|
||
for(i=0;i<m_nodes.size();++i)
|
||
{
|
||
cog+=m_nodes[i].m_x;
|
||
m_clusters[(i*29873)%m_clusters.size()]->m_nodes.push_back(&m_nodes[i]);
|
||
}
|
||
cog/=(btScalar)m_nodes.size();
|
||
centers.resize(k,cog);
|
||
/* Iterate */
|
||
const btScalar slope=16;
|
||
bool changed;
|
||
int iterations=0;
|
||
do {
|
||
const btScalar w=2-btMin<btScalar>(1,iterations/slope);
|
||
changed=false;
|
||
iterations++;
|
||
int i;
|
||
|
||
for(i=0;i<k;++i)
|
||
{
|
||
btVector3 c(0,0,0);
|
||
for(int j=0;j<m_clusters[i]->m_nodes.size();++j)
|
||
{
|
||
c+=m_clusters[i]->m_nodes[j]->m_x;
|
||
}
|
||
if(m_clusters[i]->m_nodes.size())
|
||
{
|
||
c /= (btScalar)m_clusters[i]->m_nodes.size();
|
||
c = centers[i]+(c-centers[i])*w;
|
||
changed |= ((c-centers[i]).length2()>SIMD_EPSILON);
|
||
centers[i] = c;
|
||
m_clusters[i]->m_nodes.resize(0);
|
||
}
|
||
}
|
||
for(i=0;i<m_nodes.size();++i)
|
||
{
|
||
const btVector3 nx=m_nodes[i].m_x;
|
||
int kbest=0;
|
||
btScalar kdist=ClusterMetric(centers[0],nx);
|
||
for(int j=1;j<k;++j)
|
||
{
|
||
const btScalar d=ClusterMetric(centers[j],nx);
|
||
if(d<kdist)
|
||
{
|
||
kbest=j;
|
||
kdist=d;
|
||
}
|
||
}
|
||
m_clusters[kbest]->m_nodes.push_back(&m_nodes[i]);
|
||
}
|
||
} while(changed&&(iterations<maxiterations));
|
||
/* Merge */
|
||
btAlignedObjectArray<int> cids;
|
||
cids.resize(m_nodes.size(),-1);
|
||
for(i=0;i<m_clusters.size();++i)
|
||
{
|
||
for(int j=0;j<m_clusters[i]->m_nodes.size();++j)
|
||
{
|
||
cids[int(m_clusters[i]->m_nodes[j]-&m_nodes[0])]=i;
|
||
}
|
||
}
|
||
for(i=0;i<m_faces.size();++i)
|
||
{
|
||
const int idx[]={ int(m_faces[i].m_n[0]-&m_nodes[0]),
|
||
int(m_faces[i].m_n[1]-&m_nodes[0]),
|
||
int(m_faces[i].m_n[2]-&m_nodes[0])};
|
||
for(int j=0;j<3;++j)
|
||
{
|
||
const int cid=cids[idx[j]];
|
||
for(int q=1;q<3;++q)
|
||
{
|
||
const int kid=idx[(j+q)%3];
|
||
if(cids[kid]!=cid)
|
||
{
|
||
if(m_clusters[cid]->m_nodes.findLinearSearch(&m_nodes[kid])==m_clusters[cid]->m_nodes.size())
|
||
{
|
||
m_clusters[cid]->m_nodes.push_back(&m_nodes[kid]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/* Master */
|
||
if(m_clusters.size()>1)
|
||
{
|
||
Cluster* pmaster=new(btAlignedAlloc(sizeof(Cluster),16)) Cluster();
|
||
pmaster->m_collide = false;
|
||
pmaster->m_nodes.reserve(m_nodes.size());
|
||
for(int i=0;i<m_nodes.size();++i) pmaster->m_nodes.push_back(&m_nodes[i]);
|
||
m_clusters.push_back(pmaster);
|
||
btSwap(m_clusters[0],m_clusters[m_clusters.size()-1]);
|
||
}
|
||
/* Terminate */
|
||
for(i=0;i<m_clusters.size();++i)
|
||
{
|
||
if(m_clusters[i]->m_nodes.size()==0)
|
||
{
|
||
releaseCluster(i--);
|
||
}
|
||
}
|
||
} else
|
||
{
|
||
//create a cluster for each tetrahedron (if tetrahedra exist) or each face
|
||
if (m_tetras.size())
|
||
{
|
||
m_clusters.resize(m_tetras.size());
|
||
for(i=0;i<m_clusters.size();++i)
|
||
{
|
||
m_clusters[i] = new(btAlignedAlloc(sizeof(Cluster),16)) Cluster();
|
||
m_clusters[i]->m_collide= true;
|
||
}
|
||
for (i=0;i<m_tetras.size();i++)
|
||
{
|
||
for (int j=0;j<4;j++)
|
||
{
|
||
m_clusters[i]->m_nodes.push_back(m_tetras[i].m_n[j]);
|
||
}
|
||
}
|
||
|
||
} else
|
||
{
|
||
m_clusters.resize(m_faces.size());
|
||
for(i=0;i<m_clusters.size();++i)
|
||
{
|
||
m_clusters[i] = new(btAlignedAlloc(sizeof(Cluster),16)) Cluster();
|
||
m_clusters[i]->m_collide= true;
|
||
}
|
||
|
||
for(i=0;i<m_faces.size();++i)
|
||
{
|
||
for(int j=0;j<3;++j)
|
||
{
|
||
m_clusters[i]->m_nodes.push_back(m_faces[i].m_n[j]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (m_clusters.size())
|
||
{
|
||
initializeClusters();
|
||
updateClusters();
|
||
|
||
|
||
//for self-collision
|
||
m_clusterConnectivity.resize(m_clusters.size()*m_clusters.size());
|
||
{
|
||
for (int c0=0;c0<m_clusters.size();c0++)
|
||
{
|
||
m_clusters[c0]->m_clusterIndex=c0;
|
||
for (int c1=0;c1<m_clusters.size();c1++)
|
||
{
|
||
|
||
bool connected=false;
|
||
Cluster* cla = m_clusters[c0];
|
||
Cluster* clb = m_clusters[c1];
|
||
for (int i=0;!connected&&i<cla->m_nodes.size();i++)
|
||
{
|
||
for (int j=0;j<clb->m_nodes.size();j++)
|
||
{
|
||
if (cla->m_nodes[i] == clb->m_nodes[j])
|
||
{
|
||
connected=true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
m_clusterConnectivity[c0+c1*m_clusters.size()]=connected;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return(m_clusters.size());
|
||
}
|
||
|
||
//
|
||
void btSoftBody::refine(ImplicitFn* ifn,btScalar accurary,bool cut)
|
||
{
|
||
const Node* nbase = &m_nodes[0];
|
||
int ncount = m_nodes.size();
|
||
btSymMatrix<int> edges(ncount,-2);
|
||
int newnodes=0;
|
||
int i,j,k,ni;
|
||
|
||
/* Filter out */
|
||
for(i=0;i<m_links.size();++i)
|
||
{
|
||
Link& l=m_links[i];
|
||
if(l.m_bbending)
|
||
{
|
||
if(!SameSign(ifn->Eval(l.m_n[0]->m_x),ifn->Eval(l.m_n[1]->m_x)))
|
||
{
|
||
btSwap(m_links[i],m_links[m_links.size()-1]);
|
||
m_links.pop_back();--i;
|
||
}
|
||
}
|
||
}
|
||
/* Fill edges */
|
||
for(i=0;i<m_links.size();++i)
|
||
{
|
||
Link& l=m_links[i];
|
||
edges(int(l.m_n[0]-nbase),int(l.m_n[1]-nbase))=-1;
|
||
}
|
||
for(i=0;i<m_faces.size();++i)
|
||
{
|
||
Face& f=m_faces[i];
|
||
edges(int(f.m_n[0]-nbase),int(f.m_n[1]-nbase))=-1;
|
||
edges(int(f.m_n[1]-nbase),int(f.m_n[2]-nbase))=-1;
|
||
edges(int(f.m_n[2]-nbase),int(f.m_n[0]-nbase))=-1;
|
||
}
|
||
/* Intersect */
|
||
for(i=0;i<ncount;++i)
|
||
{
|
||
for(j=i+1;j<ncount;++j)
|
||
{
|
||
if(edges(i,j)==-1)
|
||
{
|
||
Node& a=m_nodes[i];
|
||
Node& b=m_nodes[j];
|
||
const btScalar t=ImplicitSolve(ifn,a.m_x,b.m_x,accurary);
|
||
if(t>0)
|
||
{
|
||
const btVector3 x=Lerp(a.m_x,b.m_x,t);
|
||
const btVector3 v=Lerp(a.m_v,b.m_v,t);
|
||
btScalar m=0;
|
||
if(a.m_im>0)
|
||
{
|
||
if(b.m_im>0)
|
||
{
|
||
const btScalar ma=1/a.m_im;
|
||
const btScalar mb=1/b.m_im;
|
||
const btScalar mc=Lerp(ma,mb,t);
|
||
const btScalar f=(ma+mb)/(ma+mb+mc);
|
||
a.m_im=1/(ma*f);
|
||
b.m_im=1/(mb*f);
|
||
m=mc*f;
|
||
}
|
||
else
|
||
{ a.m_im/=0.5f;m=1/a.m_im; }
|
||
}
|
||
else
|
||
{
|
||
if(b.m_im>0)
|
||
{ b.m_im/=0.5f;m=1/b.m_im; }
|
||
else
|
||
m=0;
|
||
}
|
||
appendNode(x,m);
|
||
edges(i,j)=m_nodes.size()-1;
|
||
m_nodes[edges(i,j)].m_v=v;
|
||
++newnodes;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
nbase=&m_nodes[0];
|
||
/* Refine links */
|
||
for(i=0,ni=m_links.size();i<ni;++i)
|
||
{
|
||
Link& feat=m_links[i];
|
||
const int idx[]={ int(feat.m_n[0]-nbase),
|
||
int(feat.m_n[1]-nbase)};
|
||
if((idx[0]<ncount)&&(idx[1]<ncount))
|
||
{
|
||
const int ni=edges(idx[0],idx[1]);
|
||
if(ni>0)
|
||
{
|
||
appendLink(i);
|
||
Link* pft[]={ &m_links[i],
|
||
&m_links[m_links.size()-1]};
|
||
pft[0]->m_n[0]=&m_nodes[idx[0]];
|
||
pft[0]->m_n[1]=&m_nodes[ni];
|
||
pft[1]->m_n[0]=&m_nodes[ni];
|
||
pft[1]->m_n[1]=&m_nodes[idx[1]];
|
||
}
|
||
}
|
||
}
|
||
/* Refine faces */
|
||
for(i=0;i<m_faces.size();++i)
|
||
{
|
||
const Face& feat=m_faces[i];
|
||
const int idx[]={ int(feat.m_n[0]-nbase),
|
||
int(feat.m_n[1]-nbase),
|
||
int(feat.m_n[2]-nbase)};
|
||
for(j=2,k=0;k<3;j=k++)
|
||
{
|
||
if((idx[j]<ncount)&&(idx[k]<ncount))
|
||
{
|
||
const int ni=edges(idx[j],idx[k]);
|
||
if(ni>0)
|
||
{
|
||
appendFace(i);
|
||
const int l=(k+1)%3;
|
||
Face* pft[]={ &m_faces[i],
|
||
&m_faces[m_faces.size()-1]};
|
||
pft[0]->m_n[0]=&m_nodes[idx[l]];
|
||
pft[0]->m_n[1]=&m_nodes[idx[j]];
|
||
pft[0]->m_n[2]=&m_nodes[ni];
|
||
pft[1]->m_n[0]=&m_nodes[ni];
|
||
pft[1]->m_n[1]=&m_nodes[idx[k]];
|
||
pft[1]->m_n[2]=&m_nodes[idx[l]];
|
||
appendLink(ni,idx[l],pft[0]->m_material);
|
||
--i;break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/* Cut */
|
||
if(cut)
|
||
{
|
||
btAlignedObjectArray<int> cnodes;
|
||
const int pcount=ncount;
|
||
int i;
|
||
ncount=m_nodes.size();
|
||
cnodes.resize(ncount,0);
|
||
/* Nodes */
|
||
for(i=0;i<ncount;++i)
|
||
{
|
||
const btVector3 x=m_nodes[i].m_x;
|
||
if((i>=pcount)||(btFabs(ifn->Eval(x))<accurary))
|
||
{
|
||
const btVector3 v=m_nodes[i].m_v;
|
||
btScalar m=getMass(i);
|
||
if(m>0) { m*=0.5f;m_nodes[i].m_im/=0.5f; }
|
||
appendNode(x,m);
|
||
cnodes[i]=m_nodes.size()-1;
|
||
m_nodes[cnodes[i]].m_v=v;
|
||
}
|
||
}
|
||
nbase=&m_nodes[0];
|
||
/* Links */
|
||
for(i=0,ni=m_links.size();i<ni;++i)
|
||
{
|
||
const int id[]={ int(m_links[i].m_n[0]-nbase),
|
||
int(m_links[i].m_n[1]-nbase)};
|
||
int todetach=0;
|
||
if(cnodes[id[0]]&&cnodes[id[1]])
|
||
{
|
||
appendLink(i);
|
||
todetach=m_links.size()-1;
|
||
}
|
||
else
|
||
{
|
||
if(( (ifn->Eval(m_nodes[id[0]].m_x)<accurary)&&
|
||
(ifn->Eval(m_nodes[id[1]].m_x)<accurary)))
|
||
todetach=i;
|
||
}
|
||
if(todetach)
|
||
{
|
||
Link& l=m_links[todetach];
|
||
for(int j=0;j<2;++j)
|
||
{
|
||
int cn=cnodes[int(l.m_n[j]-nbase)];
|
||
if(cn) l.m_n[j]=&m_nodes[cn];
|
||
}
|
||
}
|
||
}
|
||
/* Faces */
|
||
for(i=0,ni=m_faces.size();i<ni;++i)
|
||
{
|
||
Node** n= m_faces[i].m_n;
|
||
if( (ifn->Eval(n[0]->m_x)<accurary)&&
|
||
(ifn->Eval(n[1]->m_x)<accurary)&&
|
||
(ifn->Eval(n[2]->m_x)<accurary))
|
||
{
|
||
for(int j=0;j<3;++j)
|
||
{
|
||
int cn=cnodes[int(n[j]-nbase)];
|
||
if(cn) n[j]=&m_nodes[cn];
|
||
}
|
||
}
|
||
}
|
||
/* Clean orphans */
|
||
int nnodes=m_nodes.size();
|
||
btAlignedObjectArray<int> ranks;
|
||
btAlignedObjectArray<int> todelete;
|
||
ranks.resize(nnodes,0);
|
||
for(i=0,ni=m_links.size();i<ni;++i)
|
||
{
|
||
for(int j=0;j<2;++j) ranks[int(m_links[i].m_n[j]-nbase)]++;
|
||
}
|
||
for(i=0,ni=m_faces.size();i<ni;++i)
|
||
{
|
||
for(int j=0;j<3;++j) ranks[int(m_faces[i].m_n[j]-nbase)]++;
|
||
}
|
||
for(i=0;i<m_links.size();++i)
|
||
{
|
||
const int id[]={ int(m_links[i].m_n[0]-nbase),
|
||
int(m_links[i].m_n[1]-nbase)};
|
||
const bool sg[]={ ranks[id[0]]==1,
|
||
ranks[id[1]]==1};
|
||
if(sg[0]||sg[1])
|
||
{
|
||
--ranks[id[0]];
|
||
--ranks[id[1]];
|
||
btSwap(m_links[i],m_links[m_links.size()-1]);
|
||
m_links.pop_back();--i;
|
||
}
|
||
}
|
||
#if 0
|
||
for(i=nnodes-1;i>=0;--i)
|
||
{
|
||
if(!ranks[i]) todelete.push_back(i);
|
||
}
|
||
if(todelete.size())
|
||
{
|
||
btAlignedObjectArray<int>& map=ranks;
|
||
for(int i=0;i<nnodes;++i) map[i]=i;
|
||
PointersToIndices(this);
|
||
for(int i=0,ni=todelete.size();i<ni;++i)
|
||
{
|
||
int j=todelete[i];
|
||
int& a=map[j];
|
||
int& b=map[--nnodes];
|
||
m_ndbvt.remove(m_nodes[a].m_leaf);m_nodes[a].m_leaf=0;
|
||
btSwap(m_nodes[a],m_nodes[b]);
|
||
j=a;a=b;b=j;
|
||
}
|
||
IndicesToPointers(this,&map[0]);
|
||
m_nodes.resize(nnodes);
|
||
}
|
||
#endif
|
||
}
|
||
m_bUpdateRtCst=true;
|
||
}
|
||
|
||
//
|
||
bool btSoftBody::cutLink(const Node* node0,const Node* node1,btScalar position)
|
||
{
|
||
return(cutLink(int(node0-&m_nodes[0]),int(node1-&m_nodes[0]),position));
|
||
}
|
||
|
||
//
|
||
bool btSoftBody::cutLink(int node0,int node1,btScalar position)
|
||
{
|
||
bool done=false;
|
||
int i,ni;
|
||
// const btVector3 d=m_nodes[node0].m_x-m_nodes[node1].m_x;
|
||
const btVector3 x=Lerp(m_nodes[node0].m_x,m_nodes[node1].m_x,position);
|
||
const btVector3 v=Lerp(m_nodes[node0].m_v,m_nodes[node1].m_v,position);
|
||
const btScalar m=1;
|
||
appendNode(x,m);
|
||
appendNode(x,m);
|
||
Node* pa=&m_nodes[node0];
|
||
Node* pb=&m_nodes[node1];
|
||
Node* pn[2]={ &m_nodes[m_nodes.size()-2],
|
||
&m_nodes[m_nodes.size()-1]};
|
||
pn[0]->m_v=v;
|
||
pn[1]->m_v=v;
|
||
for(i=0,ni=m_links.size();i<ni;++i)
|
||
{
|
||
const int mtch=MatchEdge(m_links[i].m_n[0],m_links[i].m_n[1],pa,pb);
|
||
if(mtch!=-1)
|
||
{
|
||
appendLink(i);
|
||
Link* pft[]={&m_links[i],&m_links[m_links.size()-1]};
|
||
pft[0]->m_n[1]=pn[mtch];
|
||
pft[1]->m_n[0]=pn[1-mtch];
|
||
done=true;
|
||
}
|
||
}
|
||
for(i=0,ni=m_faces.size();i<ni;++i)
|
||
{
|
||
for(int k=2,l=0;l<3;k=l++)
|
||
{
|
||
const int mtch=MatchEdge(m_faces[i].m_n[k],m_faces[i].m_n[l],pa,pb);
|
||
if(mtch!=-1)
|
||
{
|
||
appendFace(i);
|
||
Face* pft[]={&m_faces[i],&m_faces[m_faces.size()-1]};
|
||
pft[0]->m_n[l]=pn[mtch];
|
||
pft[1]->m_n[k]=pn[1-mtch];
|
||
appendLink(pn[0],pft[0]->m_n[(l+1)%3],pft[0]->m_material,true);
|
||
appendLink(pn[1],pft[0]->m_n[(l+1)%3],pft[0]->m_material,true);
|
||
}
|
||
}
|
||
}
|
||
if(!done)
|
||
{
|
||
m_ndbvt.remove(pn[0]->m_leaf);
|
||
m_ndbvt.remove(pn[1]->m_leaf);
|
||
m_nodes.pop_back();
|
||
m_nodes.pop_back();
|
||
}
|
||
return(done);
|
||
}
|
||
|
||
//
|
||
bool btSoftBody::rayTest(const btVector3& rayFrom,
|
||
const btVector3& rayTo,
|
||
sRayCast& results)
|
||
{
|
||
if(m_faces.size()&&m_fdbvt.empty())
|
||
initializeFaceTree();
|
||
|
||
results.body = this;
|
||
results.fraction = 1.f;
|
||
results.feature = eFeature::None;
|
||
results.index = -1;
|
||
|
||
return(rayTest(rayFrom,rayTo,results.fraction,results.feature,results.index,false)!=0);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::setSolver(eSolverPresets::_ preset)
|
||
{
|
||
m_cfg.m_vsequence.clear();
|
||
m_cfg.m_psequence.clear();
|
||
m_cfg.m_dsequence.clear();
|
||
switch(preset)
|
||
{
|
||
case eSolverPresets::Positions:
|
||
m_cfg.m_psequence.push_back(ePSolver::Anchors);
|
||
m_cfg.m_psequence.push_back(ePSolver::RContacts);
|
||
m_cfg.m_psequence.push_back(ePSolver::SContacts);
|
||
m_cfg.m_psequence.push_back(ePSolver::Linear);
|
||
break;
|
||
case eSolverPresets::Velocities:
|
||
m_cfg.m_vsequence.push_back(eVSolver::Linear);
|
||
|
||
m_cfg.m_psequence.push_back(ePSolver::Anchors);
|
||
m_cfg.m_psequence.push_back(ePSolver::RContacts);
|
||
m_cfg.m_psequence.push_back(ePSolver::SContacts);
|
||
|
||
m_cfg.m_dsequence.push_back(ePSolver::Linear);
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::predictMotion(btScalar dt)
|
||
{
|
||
|
||
int i,ni;
|
||
|
||
/* Update */
|
||
if(m_bUpdateRtCst)
|
||
{
|
||
m_bUpdateRtCst=false;
|
||
updateConstants();
|
||
m_fdbvt.clear();
|
||
if(m_cfg.collisions&fCollision::VF_SS)
|
||
{
|
||
initializeFaceTree();
|
||
}
|
||
}
|
||
|
||
/* Prepare */
|
||
m_sst.sdt = dt*m_cfg.timescale;
|
||
m_sst.isdt = 1/m_sst.sdt;
|
||
m_sst.velmrg = m_sst.sdt*3;
|
||
m_sst.radmrg = getCollisionShape()->getMargin();
|
||
m_sst.updmrg = m_sst.radmrg*(btScalar)0.25;
|
||
/* Forces */
|
||
addVelocity(m_worldInfo->m_gravity*m_sst.sdt);
|
||
applyForces();
|
||
/* Integrate */
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
Node& n=m_nodes[i];
|
||
n.m_q = n.m_x;
|
||
btVector3 deltaV = n.m_f*n.m_im*m_sst.sdt;
|
||
{
|
||
btScalar maxDisplacement = m_worldInfo->m_maxDisplacement;
|
||
btScalar clampDeltaV = maxDisplacement/m_sst.sdt;
|
||
for (int c=0;c<3;c++)
|
||
{
|
||
if (deltaV[c]>clampDeltaV)
|
||
{
|
||
deltaV[c] = clampDeltaV;
|
||
}
|
||
if (deltaV[c]<-clampDeltaV)
|
||
{
|
||
deltaV[c]=-clampDeltaV;
|
||
}
|
||
}
|
||
}
|
||
n.m_v += deltaV;
|
||
n.m_x += n.m_v*m_sst.sdt;
|
||
n.m_f = btVector3(0,0,0);
|
||
}
|
||
/* Clusters */
|
||
updateClusters();
|
||
/* Bounds */
|
||
updateBounds();
|
||
/* Nodes */
|
||
ATTRIBUTE_ALIGNED16(btDbvtVolume) vol;
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
Node& n=m_nodes[i];
|
||
vol = btDbvtVolume::FromCR(n.m_x,m_sst.radmrg);
|
||
m_ndbvt.update( n.m_leaf,
|
||
vol,
|
||
n.m_v*m_sst.velmrg,
|
||
m_sst.updmrg);
|
||
}
|
||
/* Faces */
|
||
if(!m_fdbvt.empty())
|
||
{
|
||
for(int i=0;i<m_faces.size();++i)
|
||
{
|
||
Face& f=m_faces[i];
|
||
const btVector3 v=( f.m_n[0]->m_v+
|
||
f.m_n[1]->m_v+
|
||
f.m_n[2]->m_v)/3;
|
||
vol = VolumeOf(f,m_sst.radmrg);
|
||
m_fdbvt.update( f.m_leaf,
|
||
vol,
|
||
v*m_sst.velmrg,
|
||
m_sst.updmrg);
|
||
}
|
||
}
|
||
/* Pose */
|
||
updatePose();
|
||
/* Match */
|
||
if(m_pose.m_bframe&&(m_cfg.kMT>0))
|
||
{
|
||
const btMatrix3x3 posetrs=m_pose.m_rot;
|
||
for(int i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
Node& n=m_nodes[i];
|
||
if(n.m_im>0)
|
||
{
|
||
const btVector3 x=posetrs*m_pose.m_pos[i]+m_pose.m_com;
|
||
n.m_x=Lerp(n.m_x,x,m_cfg.kMT);
|
||
}
|
||
}
|
||
}
|
||
/* Clear contacts */
|
||
m_rcontacts.resize(0);
|
||
m_scontacts.resize(0);
|
||
/* Optimize dbvt's */
|
||
m_ndbvt.optimizeIncremental(1);
|
||
m_fdbvt.optimizeIncremental(1);
|
||
m_cdbvt.optimizeIncremental(1);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::solveConstraints()
|
||
{
|
||
|
||
/* Apply clusters */
|
||
applyClusters(false);
|
||
/* Prepare links */
|
||
|
||
int i,ni;
|
||
|
||
for(i=0,ni=m_links.size();i<ni;++i)
|
||
{
|
||
Link& l=m_links[i];
|
||
l.m_c3 = l.m_n[1]->m_q-l.m_n[0]->m_q;
|
||
l.m_c2 = 1/(l.m_c3.length2()*l.m_c0);
|
||
}
|
||
/* Prepare anchors */
|
||
for(i=0,ni=m_anchors.size();i<ni;++i)
|
||
{
|
||
Anchor& a=m_anchors[i];
|
||
const btVector3 ra=a.m_body->getWorldTransform().getBasis()*a.m_local;
|
||
a.m_c0 = ImpulseMatrix( m_sst.sdt,
|
||
a.m_node->m_im,
|
||
a.m_body->getInvMass(),
|
||
a.m_body->getInvInertiaTensorWorld(),
|
||
ra);
|
||
a.m_c1 = ra;
|
||
a.m_c2 = m_sst.sdt*a.m_node->m_im;
|
||
a.m_body->activate();
|
||
}
|
||
/* Solve velocities */
|
||
if(m_cfg.viterations>0)
|
||
{
|
||
/* Solve */
|
||
for(int isolve=0;isolve<m_cfg.viterations;++isolve)
|
||
{
|
||
for(int iseq=0;iseq<m_cfg.m_vsequence.size();++iseq)
|
||
{
|
||
getSolver(m_cfg.m_vsequence[iseq])(this,1);
|
||
}
|
||
}
|
||
/* Update */
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
Node& n=m_nodes[i];
|
||
n.m_x = n.m_q+n.m_v*m_sst.sdt;
|
||
}
|
||
}
|
||
/* Solve positions */
|
||
if(m_cfg.piterations>0)
|
||
{
|
||
for(int isolve=0;isolve<m_cfg.piterations;++isolve)
|
||
{
|
||
const btScalar ti=isolve/(btScalar)m_cfg.piterations;
|
||
for(int iseq=0;iseq<m_cfg.m_psequence.size();++iseq)
|
||
{
|
||
getSolver(m_cfg.m_psequence[iseq])(this,1,ti);
|
||
}
|
||
}
|
||
const btScalar vc=m_sst.isdt*(1-m_cfg.kDP);
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
Node& n=m_nodes[i];
|
||
n.m_v = (n.m_x-n.m_q)*vc;
|
||
n.m_f = btVector3(0,0,0);
|
||
}
|
||
}
|
||
/* Solve drift */
|
||
if(m_cfg.diterations>0)
|
||
{
|
||
const btScalar vcf=m_cfg.kVCF*m_sst.isdt;
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
Node& n=m_nodes[i];
|
||
n.m_q = n.m_x;
|
||
}
|
||
for(int idrift=0;idrift<m_cfg.diterations;++idrift)
|
||
{
|
||
for(int iseq=0;iseq<m_cfg.m_dsequence.size();++iseq)
|
||
{
|
||
getSolver(m_cfg.m_dsequence[iseq])(this,1,0);
|
||
}
|
||
}
|
||
for(int i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
Node& n=m_nodes[i];
|
||
n.m_v += (n.m_x-n.m_q)*vcf;
|
||
}
|
||
}
|
||
/* Apply clusters */
|
||
dampClusters();
|
||
applyClusters(true);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::staticSolve(int iterations)
|
||
{
|
||
for(int isolve=0;isolve<iterations;++isolve)
|
||
{
|
||
for(int iseq=0;iseq<m_cfg.m_psequence.size();++iseq)
|
||
{
|
||
getSolver(m_cfg.m_psequence[iseq])(this,1,0);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::solveCommonConstraints(btSoftBody** /*bodies*/,int /*count*/,int /*iterations*/)
|
||
{
|
||
/// placeholder
|
||
}
|
||
|
||
//
|
||
void btSoftBody::solveClusters(const btAlignedObjectArray<btSoftBody*>& bodies)
|
||
{
|
||
const int nb=bodies.size();
|
||
int iterations=0;
|
||
int i;
|
||
|
||
for(i=0;i<nb;++i)
|
||
{
|
||
iterations=btMax(iterations,bodies[i]->m_cfg.citerations);
|
||
}
|
||
for(i=0;i<nb;++i)
|
||
{
|
||
bodies[i]->prepareClusters(iterations);
|
||
}
|
||
for(i=0;i<iterations;++i)
|
||
{
|
||
const btScalar sor=1;
|
||
for(int j=0;j<nb;++j)
|
||
{
|
||
bodies[j]->solveClusters(sor);
|
||
}
|
||
}
|
||
for(i=0;i<nb;++i)
|
||
{
|
||
bodies[i]->cleanupClusters();
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::integrateMotion()
|
||
{
|
||
/* Update */
|
||
updateNormals();
|
||
}
|
||
|
||
//
|
||
btSoftBody::RayFromToCaster::RayFromToCaster(const btVector3& rayFrom,const btVector3& rayTo,btScalar mxt)
|
||
{
|
||
m_rayFrom = rayFrom;
|
||
m_rayNormalizedDirection = (rayTo-rayFrom);
|
||
m_rayTo = rayTo;
|
||
m_mint = mxt;
|
||
m_face = 0;
|
||
m_tests = 0;
|
||
}
|
||
|
||
//
|
||
void btSoftBody::RayFromToCaster::Process(const btDbvtNode* leaf)
|
||
{
|
||
btSoftBody::Face& f=*(btSoftBody::Face*)leaf->data;
|
||
const btScalar t=rayFromToTriangle( m_rayFrom,m_rayTo,m_rayNormalizedDirection,
|
||
f.m_n[0]->m_x,
|
||
f.m_n[1]->m_x,
|
||
f.m_n[2]->m_x,
|
||
m_mint);
|
||
if((t>0)&&(t<m_mint))
|
||
{
|
||
m_mint=t;m_face=&f;
|
||
}
|
||
++m_tests;
|
||
}
|
||
|
||
//
|
||
btScalar btSoftBody::RayFromToCaster::rayFromToTriangle( const btVector3& rayFrom,
|
||
const btVector3& rayTo,
|
||
const btVector3& rayNormalizedDirection,
|
||
const btVector3& a,
|
||
const btVector3& b,
|
||
const btVector3& c,
|
||
btScalar maxt)
|
||
{
|
||
static const btScalar ceps=-SIMD_EPSILON*10;
|
||
static const btScalar teps=SIMD_EPSILON*10;
|
||
|
||
const btVector3 n=btCross(b-a,c-a);
|
||
const btScalar d=btDot(a,n);
|
||
const btScalar den=btDot(rayNormalizedDirection,n);
|
||
if(!btFuzzyZero(den))
|
||
{
|
||
const btScalar num=btDot(rayFrom,n)-d;
|
||
const btScalar t=-num/den;
|
||
if((t>teps)&&(t<maxt))
|
||
{
|
||
const btVector3 hit=rayFrom+rayNormalizedDirection*t;
|
||
if( (btDot(n,btCross(a-hit,b-hit))>ceps) &&
|
||
(btDot(n,btCross(b-hit,c-hit))>ceps) &&
|
||
(btDot(n,btCross(c-hit,a-hit))>ceps))
|
||
{
|
||
return(t);
|
||
}
|
||
}
|
||
}
|
||
return(-1);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::pointersToIndices()
|
||
{
|
||
#define PTR2IDX(_p_,_b_) reinterpret_cast<btSoftBody::Node*>((_p_)-(_b_))
|
||
btSoftBody::Node* base=m_nodes.size() ? &m_nodes[0] : 0;
|
||
int i,ni;
|
||
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
if(m_nodes[i].m_leaf)
|
||
{
|
||
m_nodes[i].m_leaf->data=*(void**)&i;
|
||
}
|
||
}
|
||
for(i=0,ni=m_links.size();i<ni;++i)
|
||
{
|
||
m_links[i].m_n[0]=PTR2IDX(m_links[i].m_n[0],base);
|
||
m_links[i].m_n[1]=PTR2IDX(m_links[i].m_n[1],base);
|
||
}
|
||
for(i=0,ni=m_faces.size();i<ni;++i)
|
||
{
|
||
m_faces[i].m_n[0]=PTR2IDX(m_faces[i].m_n[0],base);
|
||
m_faces[i].m_n[1]=PTR2IDX(m_faces[i].m_n[1],base);
|
||
m_faces[i].m_n[2]=PTR2IDX(m_faces[i].m_n[2],base);
|
||
if(m_faces[i].m_leaf)
|
||
{
|
||
m_faces[i].m_leaf->data=*(void**)&i;
|
||
}
|
||
}
|
||
for(i=0,ni=m_anchors.size();i<ni;++i)
|
||
{
|
||
m_anchors[i].m_node=PTR2IDX(m_anchors[i].m_node,base);
|
||
}
|
||
for(i=0,ni=m_notes.size();i<ni;++i)
|
||
{
|
||
for(int j=0;j<m_notes[i].m_rank;++j)
|
||
{
|
||
m_notes[i].m_nodes[j]=PTR2IDX(m_notes[i].m_nodes[j],base);
|
||
}
|
||
}
|
||
#undef PTR2IDX
|
||
}
|
||
|
||
//
|
||
void btSoftBody::indicesToPointers(const int* map)
|
||
{
|
||
#define IDX2PTR(_p_,_b_) map?(&(_b_)[map[(((char*)_p_)-(char*)0)]]): \
|
||
(&(_b_)[(((char*)_p_)-(char*)0)])
|
||
btSoftBody::Node* base=m_nodes.size() ? &m_nodes[0]:0;
|
||
int i,ni;
|
||
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
if(m_nodes[i].m_leaf)
|
||
{
|
||
m_nodes[i].m_leaf->data=&m_nodes[i];
|
||
}
|
||
}
|
||
for(i=0,ni=m_links.size();i<ni;++i)
|
||
{
|
||
m_links[i].m_n[0]=IDX2PTR(m_links[i].m_n[0],base);
|
||
m_links[i].m_n[1]=IDX2PTR(m_links[i].m_n[1],base);
|
||
}
|
||
for(i=0,ni=m_faces.size();i<ni;++i)
|
||
{
|
||
m_faces[i].m_n[0]=IDX2PTR(m_faces[i].m_n[0],base);
|
||
m_faces[i].m_n[1]=IDX2PTR(m_faces[i].m_n[1],base);
|
||
m_faces[i].m_n[2]=IDX2PTR(m_faces[i].m_n[2],base);
|
||
if(m_faces[i].m_leaf)
|
||
{
|
||
m_faces[i].m_leaf->data=&m_faces[i];
|
||
}
|
||
}
|
||
for(i=0,ni=m_anchors.size();i<ni;++i)
|
||
{
|
||
m_anchors[i].m_node=IDX2PTR(m_anchors[i].m_node,base);
|
||
}
|
||
for(i=0,ni=m_notes.size();i<ni;++i)
|
||
{
|
||
for(int j=0;j<m_notes[i].m_rank;++j)
|
||
{
|
||
m_notes[i].m_nodes[j]=IDX2PTR(m_notes[i].m_nodes[j],base);
|
||
}
|
||
}
|
||
#undef IDX2PTR
|
||
}
|
||
|
||
//
|
||
int btSoftBody::rayTest(const btVector3& rayFrom,const btVector3& rayTo,
|
||
btScalar& mint,eFeature::_& feature,int& index,bool bcountonly) const
|
||
{
|
||
int cnt=0;
|
||
btVector3 dir = rayTo-rayFrom;
|
||
|
||
|
||
if(bcountonly||m_fdbvt.empty())
|
||
{/* Full search */
|
||
|
||
for(int i=0,ni=m_faces.size();i<ni;++i)
|
||
{
|
||
const btSoftBody::Face& f=m_faces[i];
|
||
|
||
const btScalar t=RayFromToCaster::rayFromToTriangle( rayFrom,rayTo,dir,
|
||
f.m_n[0]->m_x,
|
||
f.m_n[1]->m_x,
|
||
f.m_n[2]->m_x,
|
||
mint);
|
||
if(t>0)
|
||
{
|
||
++cnt;
|
||
if(!bcountonly)
|
||
{
|
||
feature=btSoftBody::eFeature::Face;
|
||
index=i;
|
||
mint=t;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{/* Use dbvt */
|
||
RayFromToCaster collider(rayFrom,rayTo,mint);
|
||
|
||
btDbvt::rayTest(m_fdbvt.m_root,rayFrom,rayTo,collider);
|
||
if(collider.m_face)
|
||
{
|
||
mint=collider.m_mint;
|
||
feature=btSoftBody::eFeature::Face;
|
||
index=(int)(collider.m_face-&m_faces[0]);
|
||
cnt=1;
|
||
}
|
||
}
|
||
|
||
for (int i=0;i<m_tetras.size();i++)
|
||
{
|
||
const btSoftBody::Tetra& tet = m_tetras[i];
|
||
int tetfaces[4][3] = {{0,1,2},{0,1,3},{1,2,3},{0,2,3}};
|
||
for (int f=0;f<4;f++)
|
||
{
|
||
|
||
int index0=tetfaces[f][0];
|
||
int index1=tetfaces[f][1];
|
||
int index2=tetfaces[f][2];
|
||
btVector3 v0=tet.m_n[index0]->m_x;
|
||
btVector3 v1=tet.m_n[index1]->m_x;
|
||
btVector3 v2=tet.m_n[index2]->m_x;
|
||
|
||
|
||
const btScalar t=RayFromToCaster::rayFromToTriangle( rayFrom,rayTo,dir,
|
||
v0,v1,v2,
|
||
mint);
|
||
if(t>0)
|
||
{
|
||
++cnt;
|
||
if(!bcountonly)
|
||
{
|
||
feature=btSoftBody::eFeature::Tetra;
|
||
index=i;
|
||
mint=t;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return(cnt);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::initializeFaceTree()
|
||
{
|
||
m_fdbvt.clear();
|
||
for(int i=0;i<m_faces.size();++i)
|
||
{
|
||
Face& f=m_faces[i];
|
||
f.m_leaf=m_fdbvt.insert(VolumeOf(f,0),&f);
|
||
}
|
||
}
|
||
|
||
//
|
||
btVector3 btSoftBody::evaluateCom() const
|
||
{
|
||
btVector3 com(0,0,0);
|
||
if(m_pose.m_bframe)
|
||
{
|
||
for(int i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
com+=m_nodes[i].m_x*m_pose.m_wgh[i];
|
||
}
|
||
}
|
||
return(com);
|
||
}
|
||
|
||
//
|
||
bool btSoftBody::checkContact( const btCollisionObjectWrapper* colObjWrap,
|
||
const btVector3& x,
|
||
btScalar margin,
|
||
btSoftBody::sCti& cti) const
|
||
{
|
||
btVector3 nrm;
|
||
const btCollisionShape *shp = colObjWrap->getCollisionShape();
|
||
// const btRigidBody *tmpRigid = btRigidBody::upcast(colObjWrap->getCollisionObject());
|
||
//const btTransform &wtr = tmpRigid ? tmpRigid->getWorldTransform() : colObjWrap->getWorldTransform();
|
||
const btTransform &wtr = colObjWrap->getWorldTransform();
|
||
//todo: check which transform is needed here
|
||
|
||
btScalar dst =
|
||
m_worldInfo->m_sparsesdf.Evaluate(
|
||
wtr.invXform(x),
|
||
shp,
|
||
nrm,
|
||
margin);
|
||
if(dst<0)
|
||
{
|
||
cti.m_colObj = colObjWrap->getCollisionObject();
|
||
cti.m_normal = wtr.getBasis()*nrm;
|
||
cti.m_offset = -btDot( cti.m_normal, x - cti.m_normal * dst );
|
||
return(true);
|
||
}
|
||
return(false);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::updateNormals()
|
||
{
|
||
|
||
const btVector3 zv(0,0,0);
|
||
int i,ni;
|
||
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
m_nodes[i].m_n=zv;
|
||
}
|
||
for(i=0,ni=m_faces.size();i<ni;++i)
|
||
{
|
||
btSoftBody::Face& f=m_faces[i];
|
||
const btVector3 n=btCross(f.m_n[1]->m_x-f.m_n[0]->m_x,
|
||
f.m_n[2]->m_x-f.m_n[0]->m_x);
|
||
f.m_normal=n.normalized();
|
||
f.m_n[0]->m_n+=n;
|
||
f.m_n[1]->m_n+=n;
|
||
f.m_n[2]->m_n+=n;
|
||
}
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
btScalar len = m_nodes[i].m_n.length();
|
||
if (len>SIMD_EPSILON)
|
||
m_nodes[i].m_n /= len;
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::updateBounds()
|
||
{
|
||
/*if( m_acceleratedSoftBody )
|
||
{
|
||
// If we have an accelerated softbody we need to obtain the bounds correctly
|
||
// For now (slightly hackily) just have a very large AABB
|
||
// TODO: Write get bounds kernel
|
||
// If that is updating in place, atomic collisions might be low (when the cloth isn't perfectly aligned to an axis) and we could
|
||
// probably do a test and exchange reasonably efficiently.
|
||
|
||
m_bounds[0] = btVector3(-1000, -1000, -1000);
|
||
m_bounds[1] = btVector3(1000, 1000, 1000);
|
||
|
||
} else {*/
|
||
if(m_ndbvt.m_root)
|
||
{
|
||
const btVector3& mins=m_ndbvt.m_root->volume.Mins();
|
||
const btVector3& maxs=m_ndbvt.m_root->volume.Maxs();
|
||
const btScalar csm=getCollisionShape()->getMargin();
|
||
const btVector3 mrg=btVector3( csm,
|
||
csm,
|
||
csm)*1; // ??? to investigate...
|
||
m_bounds[0]=mins-mrg;
|
||
m_bounds[1]=maxs+mrg;
|
||
if(0!=getBroadphaseHandle())
|
||
{
|
||
m_worldInfo->m_broadphase->setAabb( getBroadphaseHandle(),
|
||
m_bounds[0],
|
||
m_bounds[1],
|
||
m_worldInfo->m_dispatcher);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
m_bounds[0]=
|
||
m_bounds[1]=btVector3(0,0,0);
|
||
}
|
||
//}
|
||
}
|
||
|
||
|
||
//
|
||
void btSoftBody::updatePose()
|
||
{
|
||
if(m_pose.m_bframe)
|
||
{
|
||
btSoftBody::Pose& pose=m_pose;
|
||
const btVector3 com=evaluateCom();
|
||
/* Com */
|
||
pose.m_com = com;
|
||
/* Rotation */
|
||
btMatrix3x3 Apq;
|
||
const btScalar eps=SIMD_EPSILON;
|
||
Apq[0]=Apq[1]=Apq[2]=btVector3(0,0,0);
|
||
Apq[0].setX(eps);Apq[1].setY(eps*2);Apq[2].setZ(eps*3);
|
||
for(int i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
const btVector3 a=pose.m_wgh[i]*(m_nodes[i].m_x-com);
|
||
const btVector3& b=pose.m_pos[i];
|
||
Apq[0]+=a.x()*b;
|
||
Apq[1]+=a.y()*b;
|
||
Apq[2]+=a.z()*b;
|
||
}
|
||
btMatrix3x3 r,s;
|
||
PolarDecompose(Apq,r,s);
|
||
pose.m_rot=r;
|
||
pose.m_scl=pose.m_aqq*r.transpose()*Apq;
|
||
if(m_cfg.maxvolume>1)
|
||
{
|
||
const btScalar idet=Clamp<btScalar>( 1/pose.m_scl.determinant(),
|
||
1,m_cfg.maxvolume);
|
||
pose.m_scl=Mul(pose.m_scl,idet);
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::updateArea(bool averageArea)
|
||
{
|
||
int i,ni;
|
||
|
||
/* Face area */
|
||
for(i=0,ni=m_faces.size();i<ni;++i)
|
||
{
|
||
Face& f=m_faces[i];
|
||
f.m_ra = AreaOf(f.m_n[0]->m_x,f.m_n[1]->m_x,f.m_n[2]->m_x);
|
||
}
|
||
|
||
/* Node area */
|
||
|
||
if (averageArea)
|
||
{
|
||
btAlignedObjectArray<int> counts;
|
||
counts.resize(m_nodes.size(),0);
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
m_nodes[i].m_area = 0;
|
||
}
|
||
for(i=0,ni=m_faces.size();i<ni;++i)
|
||
{
|
||
btSoftBody::Face& f=m_faces[i];
|
||
for(int j=0;j<3;++j)
|
||
{
|
||
const int index=(int)(f.m_n[j]-&m_nodes[0]);
|
||
counts[index]++;
|
||
f.m_n[j]->m_area+=btFabs(f.m_ra);
|
||
}
|
||
}
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
if(counts[i]>0)
|
||
m_nodes[i].m_area/=(btScalar)counts[i];
|
||
else
|
||
m_nodes[i].m_area=0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// initialize node area as zero
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
m_nodes[i].m_area=0;
|
||
}
|
||
|
||
for(i=0,ni=m_faces.size();i<ni;++i)
|
||
{
|
||
btSoftBody::Face& f=m_faces[i];
|
||
|
||
for(int j=0;j<3;++j)
|
||
{
|
||
f.m_n[j]->m_area += f.m_ra;
|
||
}
|
||
}
|
||
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
m_nodes[i].m_area *= 0.3333333f;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void btSoftBody::updateLinkConstants()
|
||
{
|
||
int i,ni;
|
||
|
||
/* Links */
|
||
for(i=0,ni=m_links.size();i<ni;++i)
|
||
{
|
||
Link& l=m_links[i];
|
||
Material& m=*l.m_material;
|
||
l.m_c0 = (l.m_n[0]->m_im+l.m_n[1]->m_im)/m.m_kLST;
|
||
}
|
||
}
|
||
|
||
void btSoftBody::updateConstants()
|
||
{
|
||
resetLinkRestLengths();
|
||
updateLinkConstants();
|
||
updateArea();
|
||
}
|
||
|
||
|
||
|
||
//
|
||
void btSoftBody::initializeClusters()
|
||
{
|
||
int i;
|
||
|
||
for( i=0;i<m_clusters.size();++i)
|
||
{
|
||
Cluster& c=*m_clusters[i];
|
||
c.m_imass=0;
|
||
c.m_masses.resize(c.m_nodes.size());
|
||
for(int j=0;j<c.m_nodes.size();++j)
|
||
{
|
||
if (c.m_nodes[j]->m_im==0)
|
||
{
|
||
c.m_containsAnchor = true;
|
||
c.m_masses[j] = BT_LARGE_FLOAT;
|
||
} else
|
||
{
|
||
c.m_masses[j] = btScalar(1.)/c.m_nodes[j]->m_im;
|
||
}
|
||
c.m_imass += c.m_masses[j];
|
||
}
|
||
c.m_imass = btScalar(1.)/c.m_imass;
|
||
c.m_com = btSoftBody::clusterCom(&c);
|
||
c.m_lv = btVector3(0,0,0);
|
||
c.m_av = btVector3(0,0,0);
|
||
c.m_leaf = 0;
|
||
/* Inertia */
|
||
btMatrix3x3& ii=c.m_locii;
|
||
ii[0]=ii[1]=ii[2]=btVector3(0,0,0);
|
||
{
|
||
int i,ni;
|
||
|
||
for(i=0,ni=c.m_nodes.size();i<ni;++i)
|
||
{
|
||
const btVector3 k=c.m_nodes[i]->m_x-c.m_com;
|
||
const btVector3 q=k*k;
|
||
const btScalar m=c.m_masses[i];
|
||
ii[0][0] += m*(q[1]+q[2]);
|
||
ii[1][1] += m*(q[0]+q[2]);
|
||
ii[2][2] += m*(q[0]+q[1]);
|
||
ii[0][1] -= m*k[0]*k[1];
|
||
ii[0][2] -= m*k[0]*k[2];
|
||
ii[1][2] -= m*k[1]*k[2];
|
||
}
|
||
}
|
||
ii[1][0]=ii[0][1];
|
||
ii[2][0]=ii[0][2];
|
||
ii[2][1]=ii[1][2];
|
||
|
||
ii = ii.inverse();
|
||
|
||
/* Frame */
|
||
c.m_framexform.setIdentity();
|
||
c.m_framexform.setOrigin(c.m_com);
|
||
c.m_framerefs.resize(c.m_nodes.size());
|
||
{
|
||
int i;
|
||
for(i=0;i<c.m_framerefs.size();++i)
|
||
{
|
||
c.m_framerefs[i]=c.m_nodes[i]->m_x-c.m_com;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::updateClusters()
|
||
{
|
||
BT_PROFILE("UpdateClusters");
|
||
int i;
|
||
|
||
for(i=0;i<m_clusters.size();++i)
|
||
{
|
||
btSoftBody::Cluster& c=*m_clusters[i];
|
||
const int n=c.m_nodes.size();
|
||
//const btScalar invn=1/(btScalar)n;
|
||
if(n)
|
||
{
|
||
/* Frame */
|
||
const btScalar eps=btScalar(0.0001);
|
||
btMatrix3x3 m,r,s;
|
||
m[0]=m[1]=m[2]=btVector3(0,0,0);
|
||
m[0][0]=eps*1;
|
||
m[1][1]=eps*2;
|
||
m[2][2]=eps*3;
|
||
c.m_com=clusterCom(&c);
|
||
for(int i=0;i<c.m_nodes.size();++i)
|
||
{
|
||
const btVector3 a=c.m_nodes[i]->m_x-c.m_com;
|
||
const btVector3& b=c.m_framerefs[i];
|
||
m[0]+=a[0]*b;m[1]+=a[1]*b;m[2]+=a[2]*b;
|
||
}
|
||
PolarDecompose(m,r,s);
|
||
c.m_framexform.setOrigin(c.m_com);
|
||
c.m_framexform.setBasis(r);
|
||
/* Inertia */
|
||
#if 1/* Constant */
|
||
c.m_invwi=c.m_framexform.getBasis()*c.m_locii*c.m_framexform.getBasis().transpose();
|
||
#else
|
||
#if 0/* Sphere */
|
||
const btScalar rk=(2*c.m_extents.length2())/(5*c.m_imass);
|
||
const btVector3 inertia(rk,rk,rk);
|
||
const btVector3 iin(btFabs(inertia[0])>SIMD_EPSILON?1/inertia[0]:0,
|
||
btFabs(inertia[1])>SIMD_EPSILON?1/inertia[1]:0,
|
||
btFabs(inertia[2])>SIMD_EPSILON?1/inertia[2]:0);
|
||
|
||
c.m_invwi=c.m_xform.getBasis().scaled(iin)*c.m_xform.getBasis().transpose();
|
||
#else/* Actual */
|
||
c.m_invwi[0]=c.m_invwi[1]=c.m_invwi[2]=btVector3(0,0,0);
|
||
for(int i=0;i<n;++i)
|
||
{
|
||
const btVector3 k=c.m_nodes[i]->m_x-c.m_com;
|
||
const btVector3 q=k*k;
|
||
const btScalar m=1/c.m_nodes[i]->m_im;
|
||
c.m_invwi[0][0] += m*(q[1]+q[2]);
|
||
c.m_invwi[1][1] += m*(q[0]+q[2]);
|
||
c.m_invwi[2][2] += m*(q[0]+q[1]);
|
||
c.m_invwi[0][1] -= m*k[0]*k[1];
|
||
c.m_invwi[0][2] -= m*k[0]*k[2];
|
||
c.m_invwi[1][2] -= m*k[1]*k[2];
|
||
}
|
||
c.m_invwi[1][0]=c.m_invwi[0][1];
|
||
c.m_invwi[2][0]=c.m_invwi[0][2];
|
||
c.m_invwi[2][1]=c.m_invwi[1][2];
|
||
c.m_invwi=c.m_invwi.inverse();
|
||
#endif
|
||
#endif
|
||
/* Velocities */
|
||
c.m_lv=btVector3(0,0,0);
|
||
c.m_av=btVector3(0,0,0);
|
||
{
|
||
int i;
|
||
|
||
for(i=0;i<n;++i)
|
||
{
|
||
const btVector3 v=c.m_nodes[i]->m_v*c.m_masses[i];
|
||
c.m_lv += v;
|
||
c.m_av += btCross(c.m_nodes[i]->m_x-c.m_com,v);
|
||
}
|
||
}
|
||
c.m_lv=c.m_imass*c.m_lv*(1-c.m_ldamping);
|
||
c.m_av=c.m_invwi*c.m_av*(1-c.m_adamping);
|
||
c.m_vimpulses[0] =
|
||
c.m_vimpulses[1] = btVector3(0,0,0);
|
||
c.m_dimpulses[0] =
|
||
c.m_dimpulses[1] = btVector3(0,0,0);
|
||
c.m_nvimpulses = 0;
|
||
c.m_ndimpulses = 0;
|
||
/* Matching */
|
||
if(c.m_matching>0)
|
||
{
|
||
for(int j=0;j<c.m_nodes.size();++j)
|
||
{
|
||
Node& n=*c.m_nodes[j];
|
||
const btVector3 x=c.m_framexform*c.m_framerefs[j];
|
||
n.m_x=Lerp(n.m_x,x,c.m_matching);
|
||
}
|
||
}
|
||
/* Dbvt */
|
||
if(c.m_collide)
|
||
{
|
||
btVector3 mi=c.m_nodes[0]->m_x;
|
||
btVector3 mx=mi;
|
||
for(int j=1;j<n;++j)
|
||
{
|
||
mi.setMin(c.m_nodes[j]->m_x);
|
||
mx.setMax(c.m_nodes[j]->m_x);
|
||
}
|
||
ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds=btDbvtVolume::FromMM(mi,mx);
|
||
if(c.m_leaf)
|
||
m_cdbvt.update(c.m_leaf,bounds,c.m_lv*m_sst.sdt*3,m_sst.radmrg);
|
||
else
|
||
c.m_leaf=m_cdbvt.insert(bounds,&c);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
void btSoftBody::cleanupClusters()
|
||
{
|
||
for(int i=0;i<m_joints.size();++i)
|
||
{
|
||
m_joints[i]->Terminate(m_sst.sdt);
|
||
if(m_joints[i]->m_delete)
|
||
{
|
||
btAlignedFree(m_joints[i]);
|
||
m_joints.remove(m_joints[i--]);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::prepareClusters(int iterations)
|
||
{
|
||
for(int i=0;i<m_joints.size();++i)
|
||
{
|
||
m_joints[i]->Prepare(m_sst.sdt,iterations);
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
void btSoftBody::solveClusters(btScalar sor)
|
||
{
|
||
for(int i=0,ni=m_joints.size();i<ni;++i)
|
||
{
|
||
m_joints[i]->Solve(m_sst.sdt,sor);
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::applyClusters(bool drift)
|
||
{
|
||
BT_PROFILE("ApplyClusters");
|
||
// const btScalar f0=m_sst.sdt;
|
||
//const btScalar f1=f0/2;
|
||
btAlignedObjectArray<btVector3> deltas;
|
||
btAlignedObjectArray<btScalar> weights;
|
||
deltas.resize(m_nodes.size(),btVector3(0,0,0));
|
||
weights.resize(m_nodes.size(),0);
|
||
int i;
|
||
|
||
if(drift)
|
||
{
|
||
for(i=0;i<m_clusters.size();++i)
|
||
{
|
||
Cluster& c=*m_clusters[i];
|
||
if(c.m_ndimpulses)
|
||
{
|
||
c.m_dimpulses[0]/=(btScalar)c.m_ndimpulses;
|
||
c.m_dimpulses[1]/=(btScalar)c.m_ndimpulses;
|
||
}
|
||
}
|
||
}
|
||
|
||
for(i=0;i<m_clusters.size();++i)
|
||
{
|
||
Cluster& c=*m_clusters[i];
|
||
if(0<(drift?c.m_ndimpulses:c.m_nvimpulses))
|
||
{
|
||
const btVector3 v=(drift?c.m_dimpulses[0]:c.m_vimpulses[0])*m_sst.sdt;
|
||
const btVector3 w=(drift?c.m_dimpulses[1]:c.m_vimpulses[1])*m_sst.sdt;
|
||
for(int j=0;j<c.m_nodes.size();++j)
|
||
{
|
||
const int idx=int(c.m_nodes[j]-&m_nodes[0]);
|
||
const btVector3& x=c.m_nodes[j]->m_x;
|
||
const btScalar q=c.m_masses[j];
|
||
deltas[idx] += (v+btCross(w,x-c.m_com))*q;
|
||
weights[idx] += q;
|
||
}
|
||
}
|
||
}
|
||
for(i=0;i<deltas.size();++i)
|
||
{
|
||
if(weights[i]>0)
|
||
{
|
||
m_nodes[i].m_x+=deltas[i]/weights[i];
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::dampClusters()
|
||
{
|
||
int i;
|
||
|
||
for(i=0;i<m_clusters.size();++i)
|
||
{
|
||
Cluster& c=*m_clusters[i];
|
||
if(c.m_ndamping>0)
|
||
{
|
||
for(int j=0;j<c.m_nodes.size();++j)
|
||
{
|
||
Node& n=*c.m_nodes[j];
|
||
if(n.m_im>0)
|
||
{
|
||
const btVector3 vx=c.m_lv+btCross(c.m_av,c.m_nodes[j]->m_q-c.m_com);
|
||
if(vx.length2()<=n.m_v.length2())
|
||
{
|
||
n.m_v += c.m_ndamping*(vx-n.m_v);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::Joint::Prepare(btScalar dt,int)
|
||
{
|
||
m_bodies[0].activate();
|
||
m_bodies[1].activate();
|
||
}
|
||
|
||
//
|
||
void btSoftBody::LJoint::Prepare(btScalar dt,int iterations)
|
||
{
|
||
static const btScalar maxdrift=4;
|
||
Joint::Prepare(dt,iterations);
|
||
m_rpos[0] = m_bodies[0].xform()*m_refs[0];
|
||
m_rpos[1] = m_bodies[1].xform()*m_refs[1];
|
||
m_drift = Clamp(m_rpos[0]-m_rpos[1],maxdrift)*m_erp/dt;
|
||
m_rpos[0] -= m_bodies[0].xform().getOrigin();
|
||
m_rpos[1] -= m_bodies[1].xform().getOrigin();
|
||
m_massmatrix = ImpulseMatrix( m_bodies[0].invMass(),m_bodies[0].invWorldInertia(),m_rpos[0],
|
||
m_bodies[1].invMass(),m_bodies[1].invWorldInertia(),m_rpos[1]);
|
||
if(m_split>0)
|
||
{
|
||
m_sdrift = m_massmatrix*(m_drift*m_split);
|
||
m_drift *= 1-m_split;
|
||
}
|
||
m_drift /=(btScalar)iterations;
|
||
}
|
||
|
||
//
|
||
void btSoftBody::LJoint::Solve(btScalar dt,btScalar sor)
|
||
{
|
||
const btVector3 va=m_bodies[0].velocity(m_rpos[0]);
|
||
const btVector3 vb=m_bodies[1].velocity(m_rpos[1]);
|
||
const btVector3 vr=va-vb;
|
||
btSoftBody::Impulse impulse;
|
||
impulse.m_asVelocity = 1;
|
||
impulse.m_velocity = m_massmatrix*(m_drift+vr*m_cfm)*sor;
|
||
m_bodies[0].applyImpulse(-impulse,m_rpos[0]);
|
||
m_bodies[1].applyImpulse( impulse,m_rpos[1]);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::LJoint::Terminate(btScalar dt)
|
||
{
|
||
if(m_split>0)
|
||
{
|
||
m_bodies[0].applyDImpulse(-m_sdrift,m_rpos[0]);
|
||
m_bodies[1].applyDImpulse( m_sdrift,m_rpos[1]);
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::AJoint::Prepare(btScalar dt,int iterations)
|
||
{
|
||
static const btScalar maxdrift=SIMD_PI/16;
|
||
m_icontrol->Prepare(this);
|
||
Joint::Prepare(dt,iterations);
|
||
m_axis[0] = m_bodies[0].xform().getBasis()*m_refs[0];
|
||
m_axis[1] = m_bodies[1].xform().getBasis()*m_refs[1];
|
||
m_drift = NormalizeAny(btCross(m_axis[1],m_axis[0]));
|
||
m_drift *= btMin(maxdrift,btAcos(Clamp<btScalar>(btDot(m_axis[0],m_axis[1]),-1,+1)));
|
||
m_drift *= m_erp/dt;
|
||
m_massmatrix= AngularImpulseMatrix(m_bodies[0].invWorldInertia(),m_bodies[1].invWorldInertia());
|
||
if(m_split>0)
|
||
{
|
||
m_sdrift = m_massmatrix*(m_drift*m_split);
|
||
m_drift *= 1-m_split;
|
||
}
|
||
m_drift /=(btScalar)iterations;
|
||
}
|
||
|
||
//
|
||
void btSoftBody::AJoint::Solve(btScalar dt,btScalar sor)
|
||
{
|
||
const btVector3 va=m_bodies[0].angularVelocity();
|
||
const btVector3 vb=m_bodies[1].angularVelocity();
|
||
const btVector3 vr=va-vb;
|
||
const btScalar sp=btDot(vr,m_axis[0]);
|
||
const btVector3 vc=vr-m_axis[0]*m_icontrol->Speed(this,sp);
|
||
btSoftBody::Impulse impulse;
|
||
impulse.m_asVelocity = 1;
|
||
impulse.m_velocity = m_massmatrix*(m_drift+vc*m_cfm)*sor;
|
||
m_bodies[0].applyAImpulse(-impulse);
|
||
m_bodies[1].applyAImpulse( impulse);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::AJoint::Terminate(btScalar dt)
|
||
{
|
||
if(m_split>0)
|
||
{
|
||
m_bodies[0].applyDAImpulse(-m_sdrift);
|
||
m_bodies[1].applyDAImpulse( m_sdrift);
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::CJoint::Prepare(btScalar dt,int iterations)
|
||
{
|
||
Joint::Prepare(dt,iterations);
|
||
const bool dodrift=(m_life==0);
|
||
m_delete=(++m_life)>m_maxlife;
|
||
if(dodrift)
|
||
{
|
||
m_drift=m_drift*m_erp/dt;
|
||
if(m_split>0)
|
||
{
|
||
m_sdrift = m_massmatrix*(m_drift*m_split);
|
||
m_drift *= 1-m_split;
|
||
}
|
||
m_drift/=(btScalar)iterations;
|
||
}
|
||
else
|
||
{
|
||
m_drift=m_sdrift=btVector3(0,0,0);
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::CJoint::Solve(btScalar dt,btScalar sor)
|
||
{
|
||
const btVector3 va=m_bodies[0].velocity(m_rpos[0]);
|
||
const btVector3 vb=m_bodies[1].velocity(m_rpos[1]);
|
||
const btVector3 vrel=va-vb;
|
||
const btScalar rvac=btDot(vrel,m_normal);
|
||
btSoftBody::Impulse impulse;
|
||
impulse.m_asVelocity = 1;
|
||
impulse.m_velocity = m_drift;
|
||
if(rvac<0)
|
||
{
|
||
const btVector3 iv=m_normal*rvac;
|
||
const btVector3 fv=vrel-iv;
|
||
impulse.m_velocity += iv+fv*m_friction;
|
||
}
|
||
impulse.m_velocity=m_massmatrix*impulse.m_velocity*sor;
|
||
|
||
if (m_bodies[0].m_soft==m_bodies[1].m_soft)
|
||
{
|
||
if ((impulse.m_velocity.getX() ==impulse.m_velocity.getX())&&(impulse.m_velocity.getY() ==impulse.m_velocity.getY())&&
|
||
(impulse.m_velocity.getZ() ==impulse.m_velocity.getZ()))
|
||
{
|
||
if (impulse.m_asVelocity)
|
||
{
|
||
if (impulse.m_velocity.length() <m_bodies[0].m_soft->m_maxSelfCollisionImpulse)
|
||
{
|
||
|
||
} else
|
||
{
|
||
m_bodies[0].applyImpulse(-impulse*m_bodies[0].m_soft->m_selfCollisionImpulseFactor,m_rpos[0]);
|
||
m_bodies[1].applyImpulse( impulse*m_bodies[0].m_soft->m_selfCollisionImpulseFactor,m_rpos[1]);
|
||
}
|
||
}
|
||
}
|
||
} else
|
||
{
|
||
m_bodies[0].applyImpulse(-impulse,m_rpos[0]);
|
||
m_bodies[1].applyImpulse( impulse,m_rpos[1]);
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::CJoint::Terminate(btScalar dt)
|
||
{
|
||
if(m_split>0)
|
||
{
|
||
m_bodies[0].applyDImpulse(-m_sdrift,m_rpos[0]);
|
||
m_bodies[1].applyDImpulse( m_sdrift,m_rpos[1]);
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::applyForces()
|
||
{
|
||
|
||
BT_PROFILE("SoftBody applyForces");
|
||
// const btScalar dt = m_sst.sdt;
|
||
const btScalar kLF = m_cfg.kLF;
|
||
const btScalar kDG = m_cfg.kDG;
|
||
const btScalar kPR = m_cfg.kPR;
|
||
const btScalar kVC = m_cfg.kVC;
|
||
const bool as_lift = kLF>0;
|
||
const bool as_drag = kDG>0;
|
||
const bool as_pressure = kPR!=0;
|
||
const bool as_volume = kVC>0;
|
||
const bool as_aero = as_lift ||
|
||
as_drag ;
|
||
//const bool as_vaero = as_aero &&
|
||
// (m_cfg.aeromodel < btSoftBody::eAeroModel::F_TwoSided);
|
||
//const bool as_faero = as_aero &&
|
||
// (m_cfg.aeromodel >= btSoftBody::eAeroModel::F_TwoSided);
|
||
const bool use_medium = as_aero;
|
||
const bool use_volume = as_pressure ||
|
||
as_volume ;
|
||
btScalar volume = 0;
|
||
btScalar ivolumetp = 0;
|
||
btScalar dvolumetv = 0;
|
||
btSoftBody::sMedium medium;
|
||
if(use_volume)
|
||
{
|
||
volume = getVolume();
|
||
ivolumetp = 1/btFabs(volume)*kPR;
|
||
dvolumetv = (m_pose.m_volume-volume)*kVC;
|
||
}
|
||
/* Per vertex forces */
|
||
int i,ni;
|
||
|
||
for(i=0,ni=m_nodes.size();i<ni;++i)
|
||
{
|
||
btSoftBody::Node& n=m_nodes[i];
|
||
if(n.m_im>0)
|
||
{
|
||
if(use_medium)
|
||
{
|
||
/* Aerodynamics */
|
||
addAeroForceToNode(m_windVelocity, i);
|
||
}
|
||
/* Pressure */
|
||
if(as_pressure)
|
||
{
|
||
n.m_f += n.m_n*(n.m_area*ivolumetp);
|
||
}
|
||
/* Volume */
|
||
if(as_volume)
|
||
{
|
||
n.m_f += n.m_n*(n.m_area*dvolumetv);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Per face forces */
|
||
for(i=0,ni=m_faces.size();i<ni;++i)
|
||
{
|
||
// btSoftBody::Face& f=m_faces[i];
|
||
|
||
/* Aerodynamics */
|
||
addAeroForceToFace(m_windVelocity, i);
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::PSolve_Anchors(btSoftBody* psb,btScalar kst,btScalar ti)
|
||
{
|
||
BT_PROFILE("PSolve_Anchors");
|
||
const btScalar kAHR=psb->m_cfg.kAHR*kst;
|
||
const btScalar dt=psb->m_sst.sdt;
|
||
for(int i=0,ni=psb->m_anchors.size();i<ni;++i)
|
||
{
|
||
const Anchor& a=psb->m_anchors[i];
|
||
const btTransform& t=a.m_body->getWorldTransform();
|
||
Node& n=*a.m_node;
|
||
const btVector3 wa=t*a.m_local;
|
||
const btVector3 va=a.m_body->getVelocityInLocalPoint(a.m_c1)*dt;
|
||
const btVector3 vb=n.m_x-n.m_q;
|
||
const btVector3 vr=(va-vb)+(wa-n.m_x)*kAHR;
|
||
const btVector3 impulse=a.m_c0*vr*a.m_influence;
|
||
n.m_x+=impulse*a.m_c2;
|
||
a.m_body->applyImpulse(-impulse,a.m_c1);
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
void btSoftBody::PSolve_RContacts(btSoftBody* psb, btScalar kst, btScalar ti)
|
||
{
|
||
BT_PROFILE("PSolve_RContacts");
|
||
const btScalar dt = psb->m_sst.sdt;
|
||
const btScalar mrg = psb->getCollisionShape()->getMargin();
|
||
btMultiBodyJacobianData jacobianData;
|
||
for(int i=0,ni=psb->m_rcontacts.size();i<ni;++i)
|
||
{
|
||
const RContact& c = psb->m_rcontacts[i];
|
||
const sCti& cti = c.m_cti;
|
||
if (cti.m_colObj->hasContactResponse())
|
||
{
|
||
btVector3 va(0,0,0);
|
||
btRigidBody* rigidCol=0;
|
||
btMultiBodyLinkCollider* multibodyLinkCol=0;
|
||
btScalar* deltaV;
|
||
|
||
if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
|
||
{
|
||
rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj);
|
||
va = rigidCol ? rigidCol->getVelocityInLocalPoint(c.m_c1)*dt : btVector3(0,0,0);
|
||
}
|
||
else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
|
||
{
|
||
multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
|
||
if (multibodyLinkCol)
|
||
{
|
||
const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
|
||
jacobianData.m_jacobians.resize(ndof);
|
||
jacobianData.m_deltaVelocitiesUnitImpulse.resize(ndof);
|
||
btScalar* jac=&jacobianData.m_jacobians[0];
|
||
|
||
multibodyLinkCol->m_multiBody->fillContactJacobianMultiDof(multibodyLinkCol->m_link, c.m_node->m_x, cti.m_normal, jac, jacobianData.scratch_r, jacobianData.scratch_v, jacobianData.scratch_m);
|
||
deltaV = &jacobianData.m_deltaVelocitiesUnitImpulse[0];
|
||
multibodyLinkCol->m_multiBody->calcAccelerationDeltasMultiDof(&jacobianData.m_jacobians[0],deltaV,jacobianData.scratch_r, jacobianData.scratch_v);
|
||
|
||
btScalar vel = 0.0;
|
||
for (int j = 0; j < ndof ; ++j) {
|
||
vel += multibodyLinkCol->m_multiBody->getVelocityVector()[j] * jac[j];
|
||
}
|
||
va = cti.m_normal*vel*dt;
|
||
}
|
||
}
|
||
|
||
const btVector3 vb = c.m_node->m_x-c.m_node->m_q;
|
||
const btVector3 vr = vb-va;
|
||
const btScalar dn = btDot(vr, cti.m_normal);
|
||
if(dn<=SIMD_EPSILON)
|
||
{
|
||
const btScalar dp = btMin( (btDot(c.m_node->m_x, cti.m_normal) + cti.m_offset), mrg );
|
||
const btVector3 fv = vr - (cti.m_normal * dn);
|
||
// c0 is the impulse matrix, c3 is 1 - the friction coefficient or 0, c4 is the contact hardness coefficient
|
||
const btVector3 impulse = c.m_c0 * ( (vr - (fv * c.m_c3) + (cti.m_normal * (dp * c.m_c4))) * kst );
|
||
c.m_node->m_x -= impulse * c.m_c2;
|
||
|
||
if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
|
||
{
|
||
if (rigidCol)
|
||
rigidCol->applyImpulse(impulse,c.m_c1);
|
||
}
|
||
else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
|
||
{
|
||
if (multibodyLinkCol)
|
||
{
|
||
double multiplier = 0.5;
|
||
multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof(deltaV,-impulse.length()*multiplier);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::PSolve_SContacts(btSoftBody* psb,btScalar,btScalar ti)
|
||
{
|
||
BT_PROFILE("PSolve_SContacts");
|
||
|
||
for(int i=0,ni=psb->m_scontacts.size();i<ni;++i)
|
||
{
|
||
const SContact& c=psb->m_scontacts[i];
|
||
const btVector3& nr=c.m_normal;
|
||
Node& n=*c.m_node;
|
||
Face& f=*c.m_face;
|
||
const btVector3 p=BaryEval( f.m_n[0]->m_x,
|
||
f.m_n[1]->m_x,
|
||
f.m_n[2]->m_x,
|
||
c.m_weights);
|
||
const btVector3 q=BaryEval( f.m_n[0]->m_q,
|
||
f.m_n[1]->m_q,
|
||
f.m_n[2]->m_q,
|
||
c.m_weights);
|
||
const btVector3 vr=(n.m_x-n.m_q)-(p-q);
|
||
btVector3 corr(0,0,0);
|
||
btScalar dot = btDot(vr,nr);
|
||
if(dot<0)
|
||
{
|
||
const btScalar j=c.m_margin-(btDot(nr,n.m_x)-btDot(nr,p));
|
||
corr+=c.m_normal*j;
|
||
}
|
||
corr -= ProjectOnPlane(vr,nr)*c.m_friction;
|
||
n.m_x += corr*c.m_cfm[0];
|
||
f.m_n[0]->m_x -= corr*(c.m_cfm[1]*c.m_weights.x());
|
||
f.m_n[1]->m_x -= corr*(c.m_cfm[1]*c.m_weights.y());
|
||
f.m_n[2]->m_x -= corr*(c.m_cfm[1]*c.m_weights.z());
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::PSolve_Links(btSoftBody* psb,btScalar kst,btScalar ti)
|
||
{
|
||
BT_PROFILE("PSolve_Links");
|
||
for(int i=0,ni=psb->m_links.size();i<ni;++i)
|
||
{
|
||
Link& l=psb->m_links[i];
|
||
if(l.m_c0>0)
|
||
{
|
||
Node& a=*l.m_n[0];
|
||
Node& b=*l.m_n[1];
|
||
const btVector3 del=b.m_x-a.m_x;
|
||
const btScalar len=del.length2();
|
||
if (l.m_c1+len > SIMD_EPSILON)
|
||
{
|
||
const btScalar k=((l.m_c1-len)/(l.m_c0*(l.m_c1+len)))*kst;
|
||
a.m_x-=del*(k*a.m_im);
|
||
b.m_x+=del*(k*b.m_im);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::VSolve_Links(btSoftBody* psb,btScalar kst)
|
||
{
|
||
BT_PROFILE("VSolve_Links");
|
||
for(int i=0,ni=psb->m_links.size();i<ni;++i)
|
||
{
|
||
Link& l=psb->m_links[i];
|
||
Node** n=l.m_n;
|
||
const btScalar j=-btDot(l.m_c3,n[0]->m_v-n[1]->m_v)*l.m_c2*kst;
|
||
n[0]->m_v+= l.m_c3*(j*n[0]->m_im);
|
||
n[1]->m_v-= l.m_c3*(j*n[1]->m_im);
|
||
}
|
||
}
|
||
|
||
//
|
||
btSoftBody::psolver_t btSoftBody::getSolver(ePSolver::_ solver)
|
||
{
|
||
switch(solver)
|
||
{
|
||
case ePSolver::Anchors:
|
||
return(&btSoftBody::PSolve_Anchors);
|
||
case ePSolver::Linear:
|
||
return(&btSoftBody::PSolve_Links);
|
||
case ePSolver::RContacts:
|
||
return(&btSoftBody::PSolve_RContacts);
|
||
case ePSolver::SContacts:
|
||
return(&btSoftBody::PSolve_SContacts);
|
||
default:
|
||
{
|
||
}
|
||
}
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
btSoftBody::vsolver_t btSoftBody::getSolver(eVSolver::_ solver)
|
||
{
|
||
switch(solver)
|
||
{
|
||
case eVSolver::Linear: return(&btSoftBody::VSolve_Links);
|
||
default:
|
||
{
|
||
}
|
||
}
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
void btSoftBody::defaultCollisionHandler(const btCollisionObjectWrapper* pcoWrap)
|
||
{
|
||
|
||
switch(m_cfg.collisions&fCollision::RVSmask)
|
||
{
|
||
case fCollision::SDF_RS:
|
||
{
|
||
btSoftColliders::CollideSDF_RS docollide;
|
||
btRigidBody* prb1=(btRigidBody*) btRigidBody::upcast(pcoWrap->getCollisionObject());
|
||
btTransform wtr=pcoWrap->getWorldTransform();
|
||
|
||
const btTransform ctr=pcoWrap->getWorldTransform();
|
||
const btScalar timemargin=(wtr.getOrigin()-ctr.getOrigin()).length();
|
||
const btScalar basemargin=getCollisionShape()->getMargin();
|
||
btVector3 mins;
|
||
btVector3 maxs;
|
||
ATTRIBUTE_ALIGNED16(btDbvtVolume) volume;
|
||
pcoWrap->getCollisionShape()->getAabb( pcoWrap->getWorldTransform(),
|
||
mins,
|
||
maxs);
|
||
volume=btDbvtVolume::FromMM(mins,maxs);
|
||
volume.Expand(btVector3(basemargin,basemargin,basemargin));
|
||
docollide.psb = this;
|
||
docollide.m_colObj1Wrap = pcoWrap;
|
||
docollide.m_rigidBody = prb1;
|
||
|
||
docollide.dynmargin = basemargin+timemargin;
|
||
docollide.stamargin = basemargin;
|
||
m_ndbvt.collideTV(m_ndbvt.m_root,volume,docollide);
|
||
}
|
||
break;
|
||
case fCollision::CL_RS:
|
||
{
|
||
btSoftColliders::CollideCL_RS collider;
|
||
collider.ProcessColObj(this,pcoWrap);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
void btSoftBody::defaultCollisionHandler(btSoftBody* psb)
|
||
{
|
||
const int cf=m_cfg.collisions&psb->m_cfg.collisions;
|
||
switch(cf&fCollision::SVSmask)
|
||
{
|
||
case fCollision::CL_SS:
|
||
{
|
||
|
||
//support self-collision if CL_SELF flag set
|
||
if (this!=psb || psb->m_cfg.collisions&fCollision::CL_SELF)
|
||
{
|
||
btSoftColliders::CollideCL_SS docollide;
|
||
docollide.ProcessSoftSoft(this,psb);
|
||
}
|
||
|
||
}
|
||
break;
|
||
case fCollision::VF_SS:
|
||
{
|
||
//only self-collision for Cluster, not Vertex-Face yet
|
||
if (this!=psb)
|
||
{
|
||
btSoftColliders::CollideVF_SS docollide;
|
||
/* common */
|
||
docollide.mrg= getCollisionShape()->getMargin()+
|
||
psb->getCollisionShape()->getMargin();
|
||
/* psb0 nodes vs psb1 faces */
|
||
docollide.psb[0]=this;
|
||
docollide.psb[1]=psb;
|
||
docollide.psb[0]->m_ndbvt.collideTT( docollide.psb[0]->m_ndbvt.m_root,
|
||
docollide.psb[1]->m_fdbvt.m_root,
|
||
docollide);
|
||
/* psb1 nodes vs psb0 faces */
|
||
docollide.psb[0]=psb;
|
||
docollide.psb[1]=this;
|
||
docollide.psb[0]->m_ndbvt.collideTT( docollide.psb[0]->m_ndbvt.m_root,
|
||
docollide.psb[1]->m_fdbvt.m_root,
|
||
docollide);
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
{
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void btSoftBody::setWindVelocity( const btVector3 &velocity )
|
||
{
|
||
m_windVelocity = velocity;
|
||
}
|
||
|
||
|
||
const btVector3& btSoftBody::getWindVelocity()
|
||
{
|
||
return m_windVelocity;
|
||
}
|
||
|
||
|
||
|
||
int btSoftBody::calculateSerializeBufferSize() const
|
||
{
|
||
int sz = sizeof(btSoftBodyData);
|
||
return sz;
|
||
}
|
||
|
||
///fills the dataBuffer and returns the struct name (and 0 on failure)
|
||
const char* btSoftBody::serialize(void* dataBuffer, class btSerializer* serializer) const
|
||
{
|
||
btSoftBodyData* sbd = (btSoftBodyData*) dataBuffer;
|
||
|
||
btCollisionObject::serialize(&sbd->m_collisionObjectData, serializer);
|
||
|
||
btHashMap<btHashPtr,int> m_nodeIndexMap;
|
||
|
||
sbd->m_numMaterials = m_materials.size();
|
||
sbd->m_materials = sbd->m_numMaterials? (SoftBodyMaterialData**) serializer->getUniquePointer((void*)&m_materials): 0;
|
||
|
||
if (sbd->m_materials)
|
||
{
|
||
int sz = sizeof(SoftBodyMaterialData*);
|
||
int numElem = sbd->m_numMaterials;
|
||
btChunk* chunk = serializer->allocate(sz,numElem);
|
||
//SoftBodyMaterialData** memPtr = chunk->m_oldPtr;
|
||
SoftBodyMaterialData** memPtr = (SoftBodyMaterialData**)chunk->m_oldPtr;
|
||
for (int i=0;i<numElem;i++,memPtr++)
|
||
{
|
||
btSoftBody::Material* mat = m_materials[i];
|
||
*memPtr = mat ? (SoftBodyMaterialData*)serializer->getUniquePointer((void*)mat) : 0;
|
||
if (!serializer->findPointer(mat))
|
||
{
|
||
//serialize it here
|
||
btChunk* chunk = serializer->allocate(sizeof(SoftBodyMaterialData),1);
|
||
SoftBodyMaterialData* memPtr = (SoftBodyMaterialData*)chunk->m_oldPtr;
|
||
memPtr->m_flags = mat->m_flags;
|
||
memPtr->m_angularStiffness = mat->m_kAST;
|
||
memPtr->m_linearStiffness = mat->m_kLST;
|
||
memPtr->m_volumeStiffness = mat->m_kVST;
|
||
serializer->finalizeChunk(chunk,"SoftBodyMaterialData",BT_SBMATERIAL_CODE,mat);
|
||
}
|
||
}
|
||
serializer->finalizeChunk(chunk,"SoftBodyMaterialData",BT_ARRAY_CODE,(void*) &m_materials);
|
||
}
|
||
|
||
|
||
|
||
|
||
sbd->m_numNodes = m_nodes.size();
|
||
sbd->m_nodes = sbd->m_numNodes ? (SoftBodyNodeData*)serializer->getUniquePointer((void*)&m_nodes): 0;
|
||
if (sbd->m_nodes)
|
||
{
|
||
int sz = sizeof(SoftBodyNodeData);
|
||
int numElem = sbd->m_numNodes;
|
||
btChunk* chunk = serializer->allocate(sz,numElem);
|
||
SoftBodyNodeData* memPtr = (SoftBodyNodeData*)chunk->m_oldPtr;
|
||
for (int i=0;i<numElem;i++,memPtr++)
|
||
{
|
||
m_nodes[i].m_f.serializeFloat( memPtr->m_accumulatedForce);
|
||
memPtr->m_area = m_nodes[i].m_area;
|
||
memPtr->m_attach = m_nodes[i].m_battach;
|
||
memPtr->m_inverseMass = m_nodes[i].m_im;
|
||
memPtr->m_material = m_nodes[i].m_material? (SoftBodyMaterialData*)serializer->getUniquePointer((void*) m_nodes[i].m_material):0;
|
||
m_nodes[i].m_n.serializeFloat(memPtr->m_normal);
|
||
m_nodes[i].m_x.serializeFloat(memPtr->m_position);
|
||
m_nodes[i].m_q.serializeFloat(memPtr->m_previousPosition);
|
||
m_nodes[i].m_v.serializeFloat(memPtr->m_velocity);
|
||
m_nodeIndexMap.insert(&m_nodes[i],i);
|
||
}
|
||
serializer->finalizeChunk(chunk,"SoftBodyNodeData",BT_SBNODE_CODE,(void*) &m_nodes);
|
||
}
|
||
|
||
sbd->m_numLinks = m_links.size();
|
||
sbd->m_links = sbd->m_numLinks? (SoftBodyLinkData*) serializer->getUniquePointer((void*)&m_links[0]):0;
|
||
if (sbd->m_links)
|
||
{
|
||
int sz = sizeof(SoftBodyLinkData);
|
||
int numElem = sbd->m_numLinks;
|
||
btChunk* chunk = serializer->allocate(sz,numElem);
|
||
SoftBodyLinkData* memPtr = (SoftBodyLinkData*)chunk->m_oldPtr;
|
||
for (int i=0;i<numElem;i++,memPtr++)
|
||
{
|
||
memPtr->m_bbending = m_links[i].m_bbending;
|
||
memPtr->m_material = m_links[i].m_material? (SoftBodyMaterialData*)serializer->getUniquePointer((void*) m_links[i].m_material):0;
|
||
memPtr->m_nodeIndices[0] = m_links[i].m_n[0] ? m_links[i].m_n[0] - &m_nodes[0]: -1;
|
||
memPtr->m_nodeIndices[1] = m_links[i].m_n[1] ? m_links[i].m_n[1] - &m_nodes[0]: -1;
|
||
btAssert(memPtr->m_nodeIndices[0]<m_nodes.size());
|
||
btAssert(memPtr->m_nodeIndices[1]<m_nodes.size());
|
||
memPtr->m_restLength = m_links[i].m_rl;
|
||
}
|
||
serializer->finalizeChunk(chunk,"SoftBodyLinkData",BT_ARRAY_CODE,(void*) &m_links[0]);
|
||
|
||
}
|
||
|
||
|
||
sbd->m_numFaces = m_faces.size();
|
||
sbd->m_faces = sbd->m_numFaces? (SoftBodyFaceData*) serializer->getUniquePointer((void*)&m_faces[0]):0;
|
||
if (sbd->m_faces)
|
||
{
|
||
int sz = sizeof(SoftBodyFaceData);
|
||
int numElem = sbd->m_numFaces;
|
||
btChunk* chunk = serializer->allocate(sz,numElem);
|
||
SoftBodyFaceData* memPtr = (SoftBodyFaceData*)chunk->m_oldPtr;
|
||
for (int i=0;i<numElem;i++,memPtr++)
|
||
{
|
||
memPtr->m_material = m_faces[i].m_material ? (SoftBodyMaterialData*) serializer->getUniquePointer((void*)m_faces[i].m_material): 0;
|
||
m_faces[i].m_normal.serializeFloat( memPtr->m_normal);
|
||
for (int j=0;j<3;j++)
|
||
{
|
||
memPtr->m_nodeIndices[j] = m_faces[i].m_n[j]? m_faces[i].m_n[j] - &m_nodes[0]: -1;
|
||
}
|
||
memPtr->m_restArea = m_faces[i].m_ra;
|
||
}
|
||
serializer->finalizeChunk(chunk,"SoftBodyFaceData",BT_ARRAY_CODE,(void*) &m_faces[0]);
|
||
}
|
||
|
||
|
||
sbd->m_numTetrahedra = m_tetras.size();
|
||
sbd->m_tetrahedra = sbd->m_numTetrahedra ? (SoftBodyTetraData*) serializer->getUniquePointer((void*)&m_tetras[0]):0;
|
||
if (sbd->m_tetrahedra)
|
||
{
|
||
int sz = sizeof(SoftBodyTetraData);
|
||
int numElem = sbd->m_numTetrahedra;
|
||
btChunk* chunk = serializer->allocate(sz,numElem);
|
||
SoftBodyTetraData* memPtr = (SoftBodyTetraData*)chunk->m_oldPtr;
|
||
for (int i=0;i<numElem;i++,memPtr++)
|
||
{
|
||
for (int j=0;j<4;j++)
|
||
{
|
||
m_tetras[i].m_c0[j].serializeFloat( memPtr->m_c0[j] );
|
||
memPtr->m_nodeIndices[j] = m_tetras[j].m_n[j]? m_tetras[j].m_n[j]-&m_nodes[0] : -1;
|
||
}
|
||
memPtr->m_c1 = m_tetras[i].m_c1;
|
||
memPtr->m_c2 = m_tetras[i].m_c2;
|
||
memPtr->m_material = m_tetras[i].m_material ? (SoftBodyMaterialData*)serializer->getUniquePointer((void*) m_tetras[i].m_material): 0;
|
||
memPtr->m_restVolume = m_tetras[i].m_rv;
|
||
}
|
||
serializer->finalizeChunk(chunk,"SoftBodyTetraData",BT_ARRAY_CODE,(void*) &m_tetras[0]);
|
||
}
|
||
|
||
sbd->m_numAnchors = m_anchors.size();
|
||
sbd->m_anchors = sbd->m_numAnchors ? (SoftRigidAnchorData*) serializer->getUniquePointer((void*)&m_anchors[0]):0;
|
||
if (sbd->m_anchors)
|
||
{
|
||
int sz = sizeof(SoftRigidAnchorData);
|
||
int numElem = sbd->m_numAnchors;
|
||
btChunk* chunk = serializer->allocate(sz,numElem);
|
||
SoftRigidAnchorData* memPtr = (SoftRigidAnchorData*)chunk->m_oldPtr;
|
||
for (int i=0;i<numElem;i++,memPtr++)
|
||
{
|
||
m_anchors[i].m_c0.serializeFloat(memPtr->m_c0);
|
||
m_anchors[i].m_c1.serializeFloat(memPtr->m_c1);
|
||
memPtr->m_c2 = m_anchors[i].m_c2;
|
||
m_anchors[i].m_local.serializeFloat(memPtr->m_localFrame);
|
||
memPtr->m_nodeIndex = m_anchors[i].m_node? m_anchors[i].m_node-&m_nodes[0]: -1;
|
||
|
||
memPtr->m_rigidBody = m_anchors[i].m_body? (btRigidBodyData*) serializer->getUniquePointer((void*)m_anchors[i].m_body): 0;
|
||
btAssert(memPtr->m_nodeIndex < m_nodes.size());
|
||
}
|
||
serializer->finalizeChunk(chunk,"SoftRigidAnchorData",BT_ARRAY_CODE,(void*) &m_anchors[0]);
|
||
}
|
||
|
||
|
||
sbd->m_config.m_dynamicFriction = m_cfg.kDF;
|
||
sbd->m_config.m_baumgarte = m_cfg.kVCF;
|
||
sbd->m_config.m_pressure = m_cfg.kPR;
|
||
sbd->m_config.m_aeroModel = this->m_cfg.aeromodel;
|
||
sbd->m_config.m_lift = m_cfg.kLF;
|
||
sbd->m_config.m_drag = m_cfg.kDG;
|
||
sbd->m_config.m_positionIterations = m_cfg.piterations;
|
||
sbd->m_config.m_driftIterations = m_cfg.diterations;
|
||
sbd->m_config.m_clusterIterations = m_cfg.citerations;
|
||
sbd->m_config.m_velocityIterations = m_cfg.viterations;
|
||
sbd->m_config.m_maxVolume = m_cfg.maxvolume;
|
||
sbd->m_config.m_damping = m_cfg.kDP;
|
||
sbd->m_config.m_poseMatch = m_cfg.kMT;
|
||
sbd->m_config.m_collisionFlags = m_cfg.collisions;
|
||
sbd->m_config.m_volume = m_cfg.kVC;
|
||
sbd->m_config.m_rigidContactHardness = m_cfg.kCHR;
|
||
sbd->m_config.m_kineticContactHardness = m_cfg.kKHR;
|
||
sbd->m_config.m_softContactHardness = m_cfg.kSHR;
|
||
sbd->m_config.m_anchorHardness = m_cfg.kAHR;
|
||
sbd->m_config.m_timeScale = m_cfg.timescale;
|
||
sbd->m_config.m_maxVolume = m_cfg.maxvolume;
|
||
sbd->m_config.m_softRigidClusterHardness = m_cfg.kSRHR_CL;
|
||
sbd->m_config.m_softKineticClusterHardness = m_cfg.kSKHR_CL;
|
||
sbd->m_config.m_softSoftClusterHardness = m_cfg.kSSHR_CL;
|
||
sbd->m_config.m_softRigidClusterImpulseSplit = m_cfg.kSR_SPLT_CL;
|
||
sbd->m_config.m_softKineticClusterImpulseSplit = m_cfg.kSK_SPLT_CL;
|
||
sbd->m_config.m_softSoftClusterImpulseSplit = m_cfg.kSS_SPLT_CL;
|
||
|
||
//pose for shape matching
|
||
{
|
||
sbd->m_pose = (SoftBodyPoseData*)serializer->getUniquePointer((void*)&m_pose);
|
||
|
||
int sz = sizeof(SoftBodyPoseData);
|
||
btChunk* chunk = serializer->allocate(sz,1);
|
||
SoftBodyPoseData* memPtr = (SoftBodyPoseData*)chunk->m_oldPtr;
|
||
|
||
m_pose.m_aqq.serializeFloat(memPtr->m_aqq);
|
||
memPtr->m_bframe = m_pose.m_bframe;
|
||
memPtr->m_bvolume = m_pose.m_bvolume;
|
||
m_pose.m_com.serializeFloat(memPtr->m_com);
|
||
|
||
memPtr->m_numPositions = m_pose.m_pos.size();
|
||
memPtr->m_positions = memPtr->m_numPositions ? (btVector3FloatData*)serializer->getUniquePointer((void*)&m_pose.m_pos[0]): 0;
|
||
if (memPtr->m_numPositions)
|
||
{
|
||
int numElem = memPtr->m_numPositions;
|
||
int sz = sizeof(btVector3Data);
|
||
btChunk* chunk = serializer->allocate(sz,numElem);
|
||
btVector3FloatData* memPtr = (btVector3FloatData*)chunk->m_oldPtr;
|
||
for (int i=0;i<numElem;i++,memPtr++)
|
||
{
|
||
m_pose.m_pos[i].serializeFloat(*memPtr);
|
||
}
|
||
serializer->finalizeChunk(chunk,"btVector3FloatData",BT_ARRAY_CODE,(void*)&m_pose.m_pos[0]);
|
||
}
|
||
memPtr->m_restVolume = m_pose.m_volume;
|
||
m_pose.m_rot.serializeFloat(memPtr->m_rot);
|
||
m_pose.m_scl.serializeFloat(memPtr->m_scale);
|
||
|
||
memPtr->m_numWeigts = m_pose.m_wgh.size();
|
||
memPtr->m_weights = memPtr->m_numWeigts? (float*) serializer->getUniquePointer((void*) &m_pose.m_wgh[0]) : 0;
|
||
if (memPtr->m_numWeigts)
|
||
{
|
||
|
||
int numElem = memPtr->m_numWeigts;
|
||
int sz = sizeof(float);
|
||
btChunk* chunk = serializer->allocate(sz,numElem);
|
||
float* memPtr = (float*) chunk->m_oldPtr;
|
||
for (int i=0;i<numElem;i++,memPtr++)
|
||
{
|
||
*memPtr = m_pose.m_wgh[i];
|
||
}
|
||
serializer->finalizeChunk(chunk,"float",BT_ARRAY_CODE,(void*)&m_pose.m_wgh[0]);
|
||
}
|
||
|
||
serializer->finalizeChunk(chunk,"SoftBodyPoseData",BT_ARRAY_CODE,(void*)&m_pose);
|
||
}
|
||
|
||
//clusters for convex-cluster collision detection
|
||
|
||
sbd->m_numClusters = m_clusters.size();
|
||
sbd->m_clusters = sbd->m_numClusters? (SoftBodyClusterData*) serializer->getUniquePointer((void*)m_clusters[0]) : 0;
|
||
if (sbd->m_numClusters)
|
||
{
|
||
int numElem = sbd->m_numClusters;
|
||
int sz = sizeof(SoftBodyClusterData);
|
||
btChunk* chunk = serializer->allocate(sz,numElem);
|
||
SoftBodyClusterData* memPtr = (SoftBodyClusterData*) chunk->m_oldPtr;
|
||
for (int i=0;i<numElem;i++,memPtr++)
|
||
{
|
||
memPtr->m_adamping= m_clusters[i]->m_adamping;
|
||
m_clusters[i]->m_av.serializeFloat(memPtr->m_av);
|
||
memPtr->m_clusterIndex = m_clusters[i]->m_clusterIndex;
|
||
memPtr->m_collide = m_clusters[i]->m_collide;
|
||
m_clusters[i]->m_com.serializeFloat(memPtr->m_com);
|
||
memPtr->m_containsAnchor = m_clusters[i]->m_containsAnchor;
|
||
m_clusters[i]->m_dimpulses[0].serializeFloat(memPtr->m_dimpulses[0]);
|
||
m_clusters[i]->m_dimpulses[1].serializeFloat(memPtr->m_dimpulses[1]);
|
||
m_clusters[i]->m_framexform.serializeFloat(memPtr->m_framexform);
|
||
memPtr->m_idmass = m_clusters[i]->m_idmass;
|
||
memPtr->m_imass = m_clusters[i]->m_imass;
|
||
m_clusters[i]->m_invwi.serializeFloat(memPtr->m_invwi);
|
||
memPtr->m_ldamping = m_clusters[i]->m_ldamping;
|
||
m_clusters[i]->m_locii.serializeFloat(memPtr->m_locii);
|
||
m_clusters[i]->m_lv.serializeFloat(memPtr->m_lv);
|
||
memPtr->m_matching = m_clusters[i]->m_matching;
|
||
memPtr->m_maxSelfCollisionImpulse = m_clusters[i]->m_maxSelfCollisionImpulse;
|
||
memPtr->m_ndamping = m_clusters[i]->m_ndamping;
|
||
memPtr->m_ldamping = m_clusters[i]->m_ldamping;
|
||
memPtr->m_adamping = m_clusters[i]->m_adamping;
|
||
memPtr->m_selfCollisionImpulseFactor = m_clusters[i]->m_selfCollisionImpulseFactor;
|
||
|
||
memPtr->m_numFrameRefs = m_clusters[i]->m_framerefs.size();
|
||
memPtr->m_numMasses = m_clusters[i]->m_masses.size();
|
||
memPtr->m_numNodes = m_clusters[i]->m_nodes.size();
|
||
|
||
memPtr->m_nvimpulses = m_clusters[i]->m_nvimpulses;
|
||
m_clusters[i]->m_vimpulses[0].serializeFloat(memPtr->m_vimpulses[0]);
|
||
m_clusters[i]->m_vimpulses[1].serializeFloat(memPtr->m_vimpulses[1]);
|
||
memPtr->m_ndimpulses = m_clusters[i]->m_ndimpulses;
|
||
|
||
|
||
|
||
memPtr->m_framerefs = memPtr->m_numFrameRefs? (btVector3FloatData*)serializer->getUniquePointer((void*)&m_clusters[i]->m_framerefs[0]) : 0;
|
||
if (memPtr->m_framerefs)
|
||
{
|
||
int numElem = memPtr->m_numFrameRefs;
|
||
int sz = sizeof(btVector3FloatData);
|
||
btChunk* chunk = serializer->allocate(sz,numElem);
|
||
btVector3FloatData* memPtr = (btVector3FloatData*) chunk->m_oldPtr;
|
||
for (int j=0;j<numElem;j++,memPtr++)
|
||
{
|
||
m_clusters[i]->m_framerefs[j].serializeFloat(*memPtr);
|
||
}
|
||
serializer->finalizeChunk(chunk,"btVector3FloatData",BT_ARRAY_CODE,(void*)&m_clusters[i]->m_framerefs[0]);
|
||
}
|
||
|
||
memPtr->m_masses = memPtr->m_numMasses ? (float*) serializer->getUniquePointer((void*)&m_clusters[i]->m_masses[0]): 0;
|
||
if (memPtr->m_masses)
|
||
{
|
||
int numElem = memPtr->m_numMasses;
|
||
int sz = sizeof(float);
|
||
btChunk* chunk = serializer->allocate(sz,numElem);
|
||
float* memPtr = (float*) chunk->m_oldPtr;
|
||
for (int j=0;j<numElem;j++,memPtr++)
|
||
{
|
||
*memPtr = m_clusters[i]->m_masses[j];
|
||
}
|
||
serializer->finalizeChunk(chunk,"float",BT_ARRAY_CODE,(void*)&m_clusters[i]->m_masses[0]);
|
||
}
|
||
|
||
memPtr->m_nodeIndices = memPtr->m_numNodes ? (int*) serializer->getUniquePointer((void*) &m_clusters[i]->m_nodes) : 0;
|
||
if (memPtr->m_nodeIndices )
|
||
{
|
||
int numElem = memPtr->m_numMasses;
|
||
int sz = sizeof(int);
|
||
btChunk* chunk = serializer->allocate(sz,numElem);
|
||
int* memPtr = (int*) chunk->m_oldPtr;
|
||
for (int j=0;j<numElem;j++,memPtr++)
|
||
{
|
||
int* indexPtr = m_nodeIndexMap.find(m_clusters[i]->m_nodes[j]);
|
||
btAssert(indexPtr);
|
||
*memPtr = *indexPtr;
|
||
}
|
||
serializer->finalizeChunk(chunk,"int",BT_ARRAY_CODE,(void*)&m_clusters[i]->m_nodes);
|
||
}
|
||
}
|
||
serializer->finalizeChunk(chunk,"SoftBodyClusterData",BT_ARRAY_CODE,(void*)m_clusters[0]);
|
||
|
||
}
|
||
|
||
|
||
|
||
sbd->m_numJoints = m_joints.size();
|
||
sbd->m_joints = m_joints.size()? (btSoftBodyJointData*) serializer->getUniquePointer((void*)&m_joints[0]) : 0;
|
||
|
||
if (sbd->m_joints)
|
||
{
|
||
int sz = sizeof(btSoftBodyJointData);
|
||
int numElem = m_joints.size();
|
||
btChunk* chunk = serializer->allocate(sz,numElem);
|
||
btSoftBodyJointData* memPtr = (btSoftBodyJointData*)chunk->m_oldPtr;
|
||
|
||
for (int i=0;i<numElem;i++,memPtr++)
|
||
{
|
||
memPtr->m_jointType = (int)m_joints[i]->Type();
|
||
m_joints[i]->m_refs[0].serializeFloat(memPtr->m_refs[0]);
|
||
m_joints[i]->m_refs[1].serializeFloat(memPtr->m_refs[1]);
|
||
memPtr->m_cfm = m_joints[i]->m_cfm;
|
||
memPtr->m_erp = float(m_joints[i]->m_erp);
|
||
memPtr->m_split = float(m_joints[i]->m_split);
|
||
memPtr->m_delete = m_joints[i]->m_delete;
|
||
|
||
for (int j=0;j<4;j++)
|
||
{
|
||
memPtr->m_relPosition[0].m_floats[j] = 0.f;
|
||
memPtr->m_relPosition[1].m_floats[j] = 0.f;
|
||
}
|
||
memPtr->m_bodyA = 0;
|
||
memPtr->m_bodyB = 0;
|
||
if (m_joints[i]->m_bodies[0].m_soft)
|
||
{
|
||
memPtr->m_bodyAtype = BT_JOINT_SOFT_BODY_CLUSTER;
|
||
memPtr->m_bodyA = serializer->getUniquePointer((void*)m_joints[i]->m_bodies[0].m_soft);
|
||
}
|
||
if (m_joints[i]->m_bodies[0].m_collisionObject)
|
||
{
|
||
memPtr->m_bodyAtype = BT_JOINT_COLLISION_OBJECT;
|
||
memPtr->m_bodyA = serializer->getUniquePointer((void*)m_joints[i]->m_bodies[0].m_collisionObject);
|
||
}
|
||
if (m_joints[i]->m_bodies[0].m_rigid)
|
||
{
|
||
memPtr->m_bodyAtype = BT_JOINT_RIGID_BODY;
|
||
memPtr->m_bodyA = serializer->getUniquePointer((void*)m_joints[i]->m_bodies[0].m_rigid);
|
||
}
|
||
|
||
if (m_joints[i]->m_bodies[1].m_soft)
|
||
{
|
||
memPtr->m_bodyBtype = BT_JOINT_SOFT_BODY_CLUSTER;
|
||
memPtr->m_bodyB = serializer->getUniquePointer((void*)m_joints[i]->m_bodies[1].m_soft);
|
||
}
|
||
if (m_joints[i]->m_bodies[1].m_collisionObject)
|
||
{
|
||
memPtr->m_bodyBtype = BT_JOINT_COLLISION_OBJECT;
|
||
memPtr->m_bodyB = serializer->getUniquePointer((void*)m_joints[i]->m_bodies[1].m_collisionObject);
|
||
}
|
||
if (m_joints[i]->m_bodies[1].m_rigid)
|
||
{
|
||
memPtr->m_bodyBtype = BT_JOINT_RIGID_BODY;
|
||
memPtr->m_bodyB = serializer->getUniquePointer((void*)m_joints[i]->m_bodies[1].m_rigid);
|
||
}
|
||
}
|
||
serializer->finalizeChunk(chunk,"btSoftBodyJointData",BT_ARRAY_CODE,(void*) &m_joints[0]);
|
||
}
|
||
|
||
|
||
return btSoftBodyDataName;
|
||
}
|
||
|