2
Bullet Continuous Collision Detection and Physics Library
3
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
5
This software is provided 'as-is', without any express or implied warranty.
6
In no event will the authors be held liable for any damages arising from the use of this software.
7
Permission is granted to anyone to use this software for any purpose,
8
including commercial applications, and to alter it and redistribute it freely,
9
subject to the following restrictions:
11
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.
12
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13
3. This notice may not be removed or altered from any source distribution.
15
///btSoftBody implementation by Nathanael Presson
17
#ifndef _BT_SOFT_BODY_INTERNALS_H
18
#define _BT_SOFT_BODY_INTERNALS_H
20
#include "btSoftBody.h"
22
#include "LinearMath/btQuickprof.h"
23
#include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h"
24
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
25
#include "BulletCollision/CollisionShapes/btConvexInternalShape.h"
26
#include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h"
34
btSymMatrix() : dim(0) {}
35
btSymMatrix(int n,const T& init=T()) { resize(n,init); }
36
void resize(int n,const T& init=T()) { dim=n;store.resize((n*(n+1))/2,init); }
37
int index(int c,int r) const { if(c>r) btSwap(c,r);btAssert(r<dim);return((r*(r+1))/2+c); }
38
T& operator()(int c,int r) { return(store[index(c,r)]); }
39
const T& operator()(int c,int r) const { return(store[index(c,r)]); }
40
btAlignedObjectArray<T> store;
45
// btSoftBodyCollisionShape
47
class btSoftBodyCollisionShape : public btConcaveShape
52
btSoftBodyCollisionShape(btSoftBody* backptr)
57
virtual ~btSoftBodyCollisionShape()
62
void processAllTriangles(btTriangleCallback* /*callback*/,const btVector3& /*aabbMin*/,const btVector3& /*aabbMax*/) const
68
///getAabb returns the axis aligned bounding box in the coordinate frame of the given transform t.
69
virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const
71
/* t should be identity, but better be safe than...fast? */
72
const btVector3 mins=m_body->m_bounds[0];
73
const btVector3 maxs=m_body->m_bounds[1];
74
const btVector3 crns[]={t*btVector3(mins.x(),mins.y(),mins.z()),
75
t*btVector3(maxs.x(),mins.y(),mins.z()),
76
t*btVector3(maxs.x(),maxs.y(),mins.z()),
77
t*btVector3(mins.x(),maxs.y(),mins.z()),
78
t*btVector3(mins.x(),mins.y(),maxs.z()),
79
t*btVector3(maxs.x(),mins.y(),maxs.z()),
80
t*btVector3(maxs.x(),maxs.y(),maxs.z()),
81
t*btVector3(mins.x(),maxs.y(),maxs.z())};
82
aabbMin=aabbMax=crns[0];
85
aabbMin.setMin(crns[i]);
86
aabbMax.setMax(crns[i]);
90
virtual int getShapeType() const
92
return SOFTBODY_SHAPE_PROXYTYPE;
94
virtual void setLocalScaling(const btVector3& /*scaling*/)
98
virtual const btVector3& getLocalScaling() const
100
static const btVector3 dummy(1,1,1);
103
virtual void calculateLocalInertia(btScalar /*mass*/,btVector3& /*inertia*/) const
108
virtual const char* getName()const
116
// btSoftClusterCollisionShape
118
class btSoftClusterCollisionShape : public btConvexInternalShape
121
const btSoftBody::Cluster* m_cluster;
123
btSoftClusterCollisionShape (const btSoftBody::Cluster* cluster) : m_cluster(cluster) { setMargin(0); }
126
virtual btVector3 localGetSupportingVertex(const btVector3& vec) const
128
btSoftBody::Node* const * n=&m_cluster->m_nodes[0];
129
btScalar d=dot(vec,n[0]->m_x);
131
for(int i=1,ni=m_cluster->m_nodes.size();i<ni;++i)
133
const btScalar k=dot(vec,n[i]->m_x);
138
virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const
140
return(localGetSupportingVertex(vec));
142
//notice that the vectors should be unit length
143
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const
147
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const
150
virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const
153
virtual int getShapeType() const { return SOFTBODY_SHAPE_PROXYTYPE; }
156
virtual const char* getName()const {return "SOFTCLUSTER";}
158
virtual void setMargin(btScalar margin)
160
btConvexInternalShape::setMargin(margin);
162
virtual btScalar getMargin() const
173
template <typename T>
174
static inline void ZeroInitialize(T& value)
176
static const T zerodummy;
180
template <typename T>
181
static inline bool CompLess(const T& a,const T& b)
184
template <typename T>
185
static inline bool CompGreater(const T& a,const T& b)
188
template <typename T>
189
static inline T Lerp(const T& a,const T& b,btScalar t)
190
{ return(a+(b-a)*t); }
192
template <typename T>
193
static inline T InvLerp(const T& a,const T& b,btScalar t)
194
{ return((b+a*t-b*t)/(a*b)); }
196
static inline btMatrix3x3 Lerp( const btMatrix3x3& a,
197
const btMatrix3x3& b,
201
r[0]=Lerp(a[0],b[0],t);
202
r[1]=Lerp(a[1],b[1],t);
203
r[2]=Lerp(a[2],b[2],t);
207
static inline btVector3 Clamp(const btVector3& v,btScalar maxlength)
209
const btScalar sql=v.length2();
210
if(sql>(maxlength*maxlength))
211
return((v*maxlength)/btSqrt(sql));
216
template <typename T>
217
static inline T Clamp(const T& x,const T& l,const T& h)
218
{ return(x<l?l:x>h?h:x); }
220
template <typename T>
221
static inline T Sq(const T& x)
224
template <typename T>
225
static inline T Cube(const T& x)
228
template <typename T>
229
static inline T Sign(const T& x)
230
{ return((T)(x<0?-1:+1)); }
232
template <typename T>
233
static inline bool SameSign(const T& x,const T& y)
236
static inline btScalar ClusterMetric(const btVector3& x,const btVector3& y)
238
const btVector3 d=x-y;
239
return(btFabs(d[0])+btFabs(d[1])+btFabs(d[2]));
242
static inline btMatrix3x3 ScaleAlongAxis(const btVector3& a,btScalar s)
244
const btScalar xx=a.x()*a.x();
245
const btScalar yy=a.y()*a.y();
246
const btScalar zz=a.z()*a.z();
247
const btScalar xy=a.x()*a.y();
248
const btScalar yz=a.y()*a.z();
249
const btScalar zx=a.z()*a.x();
251
m[0]=btVector3(1-xx+xx*s,xy*s-xy,zx*s-zx);
252
m[1]=btVector3(xy*s-xy,1-yy+yy*s,yz*s-yz);
253
m[2]=btVector3(zx*s-zx,yz*s-yz,1-zz+zz*s);
257
static inline btMatrix3x3 Cross(const btVector3& v)
260
m[0]=btVector3(0,-v.z(),+v.y());
261
m[1]=btVector3(+v.z(),0,-v.x());
262
m[2]=btVector3(-v.y(),+v.x(),0);
266
static inline btMatrix3x3 Diagonal(btScalar x)
269
m[0]=btVector3(x,0,0);
270
m[1]=btVector3(0,x,0);
271
m[2]=btVector3(0,0,x);
275
static inline btMatrix3x3 Add(const btMatrix3x3& a,
276
const btMatrix3x3& b)
279
for(int i=0;i<3;++i) r[i]=a[i]+b[i];
283
static inline btMatrix3x3 Sub(const btMatrix3x3& a,
284
const btMatrix3x3& b)
287
for(int i=0;i<3;++i) r[i]=a[i]-b[i];
291
static inline btMatrix3x3 Mul(const btMatrix3x3& a,
295
for(int i=0;i<3;++i) r[i]=a[i]*b;
299
static inline void Orthogonalize(btMatrix3x3& m)
301
m[2]=cross(m[0],m[1]).normalized();
302
m[1]=cross(m[2],m[0]).normalized();
303
m[0]=cross(m[1],m[2]).normalized();
306
static inline btMatrix3x3 MassMatrix(btScalar im,const btMatrix3x3& iwi,const btVector3& r)
308
const btMatrix3x3 cr=Cross(r);
309
return(Sub(Diagonal(im),cr*iwi*cr));
313
static inline btMatrix3x3 ImpulseMatrix( btScalar dt,
316
const btMatrix3x3& iwi,
319
return(Diagonal(1/dt)*Add(Diagonal(ima),MassMatrix(imb,iwi,r)).inverse());
323
static inline btMatrix3x3 ImpulseMatrix( btScalar ima,const btMatrix3x3& iia,const btVector3& ra,
324
btScalar imb,const btMatrix3x3& iib,const btVector3& rb)
326
return(Add(MassMatrix(ima,iia,ra),MassMatrix(imb,iib,rb)).inverse());
330
static inline btMatrix3x3 AngularImpulseMatrix( const btMatrix3x3& iia,
331
const btMatrix3x3& iib)
333
return(Add(iia,iib).inverse());
337
static inline btVector3 ProjectOnAxis( const btVector3& v,
343
static inline btVector3 ProjectOnPlane( const btVector3& v,
346
return(v-ProjectOnAxis(v,a));
350
static inline void ProjectOrigin( const btVector3& a,
355
const btVector3 d=b-a;
356
const btScalar m2=d.length2();
359
const btScalar t=Clamp<btScalar>(-dot(a,d)/m2,0,1);
360
const btVector3 p=a+d*t;
361
const btScalar l2=p.length2();
370
static inline void ProjectOrigin( const btVector3& a,
376
const btVector3& q=cross(b-a,c-a);
377
const btScalar m2=q.length2();
380
const btVector3 n=q/btSqrt(m2);
381
const btScalar k=dot(a,n);
382
const btScalar k2=k*k;
385
const btVector3 p=n*k;
386
if( (dot(cross(a-p,b-p),q)>0)&&
387
(dot(cross(b-p,c-p),q)>0)&&
388
(dot(cross(c-p,a-p),q)>0))
395
ProjectOrigin(a,b,prj,sqd);
396
ProjectOrigin(b,c,prj,sqd);
397
ProjectOrigin(c,a,prj,sqd);
404
template <typename T>
405
static inline T BaryEval( const T& a,
408
const btVector3& coord)
410
return(a*coord.x()+b*coord.y()+c*coord.z());
413
static inline btVector3 BaryCoord( const btVector3& a,
418
const btScalar w[]={ cross(a-p,b-p).length(),
419
cross(b-p,c-p).length(),
420
cross(c-p,a-p).length()};
421
const btScalar isum=1/(w[0]+w[1]+w[2]);
422
return(btVector3(w[1]*isum,w[2]*isum,w[0]*isum));
426
static btScalar ImplicitSolve( btSoftBody::ImplicitFn* fn,
429
const btScalar accuracy,
430
const int maxiterations=256)
432
btScalar span[2]={0,1};
433
btScalar values[2]={fn->Eval(a),fn->Eval(b)};
434
if(values[0]>values[1])
436
btSwap(span[0],span[1]);
437
btSwap(values[0],values[1]);
439
if(values[0]>-accuracy) return(-1);
440
if(values[1]<+accuracy) return(-1);
441
for(int i=0;i<maxiterations;++i)
443
const btScalar t=Lerp(span[0],span[1],values[0]/(values[0]-values[1]));
444
const btScalar v=fn->Eval(Lerp(a,b,t));
445
if((t<=0)||(t>=1)) break;
446
if(btFabs(v)<accuracy) return(t);
448
{ span[0]=t;values[0]=v; }
450
{ span[1]=t;values[1]=v; }
456
static inline btVector3 NormalizeAny(const btVector3& v)
458
const btScalar l=v.length();
462
return(btVector3(0,0,0));
466
static inline btDbvtVolume VolumeOf( const btSoftBody::Face& f,
469
const btVector3* pts[]={ &f.m_n[0]->m_x,
472
btDbvtVolume vol=btDbvtVolume::FromPoints(pts,3);
473
vol.Expand(btVector3(margin,margin,margin));
478
static inline btVector3 CenterOf( const btSoftBody::Face& f)
480
return((f.m_n[0]->m_x+f.m_n[1]->m_x+f.m_n[2]->m_x)/3);
484
static inline btScalar AreaOf( const btVector3& x0,
488
const btVector3 a=x1-x0;
489
const btVector3 b=x2-x0;
490
const btVector3 cr=cross(a,b);
491
const btScalar area=cr.length();
496
static inline btScalar VolumeOf( const btVector3& x0,
501
const btVector3 a=x1-x0;
502
const btVector3 b=x2-x0;
503
const btVector3 c=x3-x0;
504
return(dot(a,cross(b,c)));
508
static void EvaluateMedium( const btSoftBodyWorldInfo* wfi,
510
btSoftBody::sMedium& medium)
512
medium.m_velocity = btVector3(0,0,0);
513
medium.m_pressure = 0;
514
medium.m_density = wfi->air_density;
515
if(wfi->water_density>0)
517
const btScalar depth=-(dot(x,wfi->water_normal)+wfi->water_offset);
520
medium.m_density = wfi->water_density;
521
medium.m_pressure = depth*wfi->water_density*wfi->m_gravity.length();
527
static inline void ApplyClampedForce( btSoftBody::Node& n,
531
const btScalar dtim=dt*n.m_im;
532
if((f*dtim).length2()>n.m_v.length2())
534
n.m_f-=ProjectOnAxis(n.m_v,f.normalized())/dtim;
543
static inline int MatchEdge( const btSoftBody::Node* a,
544
const btSoftBody::Node* b,
545
const btSoftBody::Node* ma,
546
const btSoftBody::Node* mb)
548
if((a==ma)&&(b==mb)) return(0);
549
if((a==mb)&&(b==ma)) return(1);
554
// btEigen : Extract eigen system,
555
// straitforward implementation of http://math.fullerton.edu/mathews/n2003/JacobiMethodMod.html
556
// outputs are NOT sorted.
560
static int system(btMatrix3x3& a,btMatrix3x3* vectors,btVector3* values=0)
562
static const int maxiterations=16;
563
static const btScalar accuracy=(btScalar)0.0001;
564
btMatrix3x3& v=*vectors;
566
vectors->setIdentity();
569
if(btFabs(a[p][q])<btFabs(a[0][2])) { p=0;q=2; }
570
if(btFabs(a[p][q])<btFabs(a[1][2])) { p=1;q=2; }
571
if(btFabs(a[p][q])>accuracy)
573
const btScalar w=(a[q][q]-a[p][p])/(2*a[p][q]);
574
const btScalar z=btFabs(w);
575
const btScalar t=w/(z*(btSqrt(1+w*w)+z));
576
if(t==t)/* [WARNING] let hope that one does not get thrown aways by some compilers... */
578
const btScalar c=1/btSqrt(t*t+1);
579
const btScalar s=c*t;
585
} while((++iterations)<maxiterations);
588
*values=btVector3(a[0][0],a[1][1],a[2][2]);
593
static inline void mulTPQ(btMatrix3x3& a,btScalar c,btScalar s,int p,int q)
595
const btScalar m[2][3]={ {a[p][0],a[p][1],a[p][2]},
596
{a[q][0],a[q][1],a[q][2]}};
599
for(i=0;i<3;++i) a[p][i]=c*m[0][i]-s*m[1][i];
600
for(i=0;i<3;++i) a[q][i]=c*m[1][i]+s*m[0][i];
602
static inline void mulPQ(btMatrix3x3& a,btScalar c,btScalar s,int p,int q)
604
const btScalar m[2][3]={ {a[0][p],a[1][p],a[2][p]},
605
{a[0][q],a[1][q],a[2][q]}};
608
for(i=0;i<3;++i) a[i][p]=c*m[0][i]-s*m[1][i];
609
for(i=0;i<3;++i) a[i][q]=c*m[1][i]+s*m[0][i];
614
// Polar decomposition,
615
// "Computing the Polar Decomposition with Applications", Nicholas J. Higham, 1986.
617
static inline int PolarDecompose( const btMatrix3x3& m,btMatrix3x3& q,btMatrix3x3& s)
619
static const btScalar half=(btScalar)0.5;
620
static const btScalar accuracy=(btScalar)0.0001;
621
static const int maxiterations=16;
624
q = Mul(m,1/btVector3(m[0][0],m[1][1],m[2][2]).length());
625
det = q.determinant();
626
if(!btFuzzyZero(det))
628
for(;i<maxiterations;++i)
630
q=Mul(Add(q,Mul(q.adjoint(),1/det).transpose()),half);
631
const btScalar ndet=q.determinant();
632
if(Sq(ndet-det)>accuracy) det=ndet; else break;
634
/* Final orthogonalization */
650
struct btSoftColliders
655
struct ClusterBase : btDbvt::ICollide
668
threshold =(btScalar)0;
670
bool SolveContact( const btGjkEpaSolver2::sResults& res,
671
btSoftBody::Body ba,btSoftBody::Body bb,
672
btSoftBody::CJoint& joint)
674
if(res.distance<margin)
676
const btVector3 ra=res.witnesses[0]-ba.xform().getOrigin();
677
const btVector3 rb=res.witnesses[1]-bb.xform().getOrigin();
678
const btVector3 va=ba.velocity(ra);
679
const btVector3 vb=bb.velocity(rb);
680
const btVector3 vrel=va-vb;
681
const btScalar rvac=dot(vrel,res.normal);
682
const btScalar depth=res.distance-margin;
683
const btVector3 iv=res.normal*rvac;
684
const btVector3 fv=vrel-iv;
685
joint.m_bodies[0] = ba;
686
joint.m_bodies[1] = bb;
687
joint.m_refs[0] = ra*ba.xform().getBasis();
688
joint.m_refs[1] = rb*bb.xform().getBasis();
689
joint.m_rpos[0] = ra;
690
joint.m_rpos[1] = rb;
696
joint.m_drift = depth*res.normal;
697
joint.m_normal = res.normal;
698
joint.m_delete = false;
699
joint.m_friction = fv.length2()<(-rvac*friction)?1:friction;
700
joint.m_massmatrix = ImpulseMatrix( ba.invMass(),ba.invWorldInertia(),joint.m_rpos[0],
701
bb.invMass(),bb.invWorldInertia(),joint.m_rpos[1]);
710
struct CollideCL_RS : ClusterBase
714
void Process(const btDbvtNode* leaf)
716
btSoftBody::Cluster* cluster=(btSoftBody::Cluster*)leaf->data;
717
btSoftClusterCollisionShape cshape(cluster);
718
const btConvexShape* rshape=(const btConvexShape*)prb->getCollisionShape();
719
btGjkEpaSolver2::sResults res;
720
if(btGjkEpaSolver2::SignedDistance( &cshape,btTransform::getIdentity(),
721
rshape,prb->getInterpolationWorldTransform(),
722
btVector3(1,0,0),res))
724
btSoftBody::CJoint joint;
725
if(SolveContact(res,cluster,prb,joint))
727
btSoftBody::CJoint* pj=new(btAlignedAlloc(sizeof(btSoftBody::CJoint),16)) btSoftBody::CJoint();
728
*pj=joint;psb->m_joints.push_back(pj);
729
if(prb->isStaticOrKinematicObject())
731
pj->m_erp *= psb->m_cfg.kSKHR_CL;
732
pj->m_split *= psb->m_cfg.kSK_SPLT_CL;
736
pj->m_erp *= psb->m_cfg.kSRHR_CL;
737
pj->m_split *= psb->m_cfg.kSR_SPLT_CL;
742
void Process(btSoftBody* ps,btRigidBody* pr)
746
idt = ps->m_sst.isdt;
747
margin = ps->getCollisionShape()->getMargin()+
748
pr->getCollisionShape()->getMargin();
749
friction = btMin(psb->m_cfg.kDF,prb->getFriction());
753
ATTRIBUTE_ALIGNED16(btDbvtVolume) volume;
754
pr->getCollisionShape()->getAabb(pr->getInterpolationWorldTransform(),mins,maxs);
755
volume=btDbvtVolume::FromMM(mins,maxs);
756
volume.Expand(btVector3(1,1,1)*margin);
757
btDbvt::collideTV(ps->m_cdbvt.m_root,volume,*this);
763
struct CollideCL_SS : ClusterBase
765
btSoftBody* bodies[2];
766
void Process(const btDbvtNode* la,const btDbvtNode* lb)
768
btSoftBody::Cluster* cla=(btSoftBody::Cluster*)la->data;
769
btSoftBody::Cluster* clb=(btSoftBody::Cluster*)lb->data;
770
btSoftClusterCollisionShape csa(cla);
771
btSoftClusterCollisionShape csb(clb);
772
btGjkEpaSolver2::sResults res;
773
if(btGjkEpaSolver2::SignedDistance( &csa,btTransform::getIdentity(),
774
&csb,btTransform::getIdentity(),
775
cla->m_com-clb->m_com,res))
777
btSoftBody::CJoint joint;
778
if(SolveContact(res,cla,clb,joint))
780
btSoftBody::CJoint* pj=new(btAlignedAlloc(sizeof(btSoftBody::CJoint),16)) btSoftBody::CJoint();
781
*pj=joint;bodies[0]->m_joints.push_back(pj);
782
pj->m_erp *= btMax(bodies[0]->m_cfg.kSSHR_CL,bodies[1]->m_cfg.kSSHR_CL);
783
pj->m_split *= (bodies[0]->m_cfg.kSS_SPLT_CL+bodies[1]->m_cfg.kSS_SPLT_CL)/2;
787
void Process(btSoftBody* psa,btSoftBody* psb)
789
idt = psa->m_sst.isdt;
790
margin = (psa->getCollisionShape()->getMargin()+psb->getCollisionShape()->getMargin())/2;
791
friction = btMin(psa->m_cfg.kDF,psb->m_cfg.kDF);
794
btDbvt::collideTT(psa->m_cdbvt.m_root,psb->m_cdbvt.m_root,*this);
800
struct CollideSDF_RS : btDbvt::ICollide
802
void Process(const btDbvtNode* leaf)
804
btSoftBody::Node* node=(btSoftBody::Node*)leaf->data;
807
void DoNode(btSoftBody::Node& n) const
809
const btScalar m=n.m_im>0?dynmargin:stamargin;
810
btSoftBody::RContact c;
812
psb->checkContact(prb,n.m_x,m,c.m_cti))
814
const btScalar ima=n.m_im;
815
const btScalar imb=prb->getInvMass();
816
const btScalar ms=ima+imb;
819
const btTransform& wtr=prb->getInterpolationWorldTransform();
820
const btMatrix3x3& iwi=prb->getInvInertiaTensorWorld();
821
const btVector3 ra=n.m_x-wtr.getOrigin();
822
const btVector3 va=prb->getVelocityInLocalPoint(ra)*psb->m_sst.sdt;
823
const btVector3 vb=n.m_x-n.m_q;
824
const btVector3 vr=vb-va;
825
const btScalar dn=dot(vr,c.m_cti.m_normal);
826
const btVector3 fv=vr-c.m_cti.m_normal*dn;
827
const btScalar fc=psb->m_cfg.kDF*prb->getFriction();
829
c.m_c0 = ImpulseMatrix(psb->m_sst.sdt,ima,imb,iwi,ra);
831
c.m_c2 = ima*psb->m_sst.sdt;
832
c.m_c3 = fv.length2()<(btFabs(dn)*fc)?0:1-fc;
833
c.m_c4 = prb->isStaticOrKinematicObject()?psb->m_cfg.kKHR:psb->m_cfg.kCHR;
834
psb->m_rcontacts.push_back(c);
847
struct CollideVF_SS : btDbvt::ICollide
849
void Process(const btDbvtNode* lnode,
850
const btDbvtNode* lface)
852
btSoftBody::Node* node=(btSoftBody::Node*)lnode->data;
853
btSoftBody::Face* face=(btSoftBody::Face*)lface->data;
854
btVector3 o=node->m_x;
856
btScalar d=SIMD_INFINITY;
857
ProjectOrigin( face->m_n[0]->m_x-o,
861
const btScalar m=mrg+(o-node->m_q).length()*2;
864
const btSoftBody::Node* n[]={face->m_n[0],face->m_n[1],face->m_n[2]};
865
const btVector3 w=BaryCoord(n[0]->m_x,n[1]->m_x,n[2]->m_x,p+o);
866
const btScalar ma=node->m_im;
867
btScalar mb=BaryEval(n[0]->m_im,n[1]->m_im,n[2]->m_im,w);
868
if( (n[0]->m_im<=0)||
874
const btScalar ms=ma+mb;
877
btSoftBody::SContact c;
878
c.m_normal = p/-btSqrt(d);
883
c.m_friction = btMax(psb[0]->m_cfg.kDF,psb[1]->m_cfg.kDF);
884
c.m_cfm[0] = ma/ms*psb[0]->m_cfg.kSHR;
885
c.m_cfm[1] = mb/ms*psb[1]->m_cfg.kSHR;
886
psb[0]->m_scontacts.push_back(c);
895
#endif //_BT_SOFT_BODY_INTERNALS_H