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 ///btSoftBodyHelpers.cpp by Nathanael Presson
17 #include "btSoftBodyInternals.h"
20 #include "btSoftBodyHelpers.h"
21 #include "LinearMath/btConvexHull.h"
24 static void drawVertex( btIDebugDraw* idraw,
25 const btVector3& x,btScalar s,const btVector3& c)
27 idraw->drawLine(x-btVector3(s,0,0),x+btVector3(s,0,0),c);
28 idraw->drawLine(x-btVector3(0,s,0),x+btVector3(0,s,0),c);
29 idraw->drawLine(x-btVector3(0,0,s),x+btVector3(0,0,s),c);
33 static void drawBox( btIDebugDraw* idraw,
34 const btVector3& mins,
35 const btVector3& maxs,
36 const btVector3& color)
38 const btVector3 c[]={ btVector3(mins.x(),mins.y(),mins.z()),
39 btVector3(maxs.x(),mins.y(),mins.z()),
40 btVector3(maxs.x(),maxs.y(),mins.z()),
41 btVector3(mins.x(),maxs.y(),mins.z()),
42 btVector3(mins.x(),mins.y(),maxs.z()),
43 btVector3(maxs.x(),mins.y(),maxs.z()),
44 btVector3(maxs.x(),maxs.y(),maxs.z()),
45 btVector3(mins.x(),maxs.y(),maxs.z())};
46 idraw->drawLine(c[0],c[1],color);idraw->drawLine(c[1],c[2],color);
47 idraw->drawLine(c[2],c[3],color);idraw->drawLine(c[3],c[0],color);
48 idraw->drawLine(c[4],c[5],color);idraw->drawLine(c[5],c[6],color);
49 idraw->drawLine(c[6],c[7],color);idraw->drawLine(c[7],c[4],color);
50 idraw->drawLine(c[0],c[4],color);idraw->drawLine(c[1],c[5],color);
51 idraw->drawLine(c[2],c[6],color);idraw->drawLine(c[3],c[7],color);
55 static void drawTree( btIDebugDraw* idraw,
56 const btDbvtNode* node,
58 const btVector3& ncolor,
59 const btVector3& lcolor,
65 if(node->isinternal()&&((depth<maxdepth)||(maxdepth<0)))
67 drawTree(idraw,node->childs[0],depth+1,ncolor,lcolor,mindepth,maxdepth);
68 drawTree(idraw,node->childs[1],depth+1,ncolor,lcolor,mindepth,maxdepth);
72 const btScalar scl=(btScalar)(node->isinternal()?1:1);
73 const btVector3 mi=node->volume.Center()-node->volume.Extents()*scl;
74 const btVector3 mx=node->volume.Center()+node->volume.Extents()*scl;
75 drawBox(idraw,mi,mx,node->isleaf()?lcolor:ncolor);
82 static inline T sum(const btAlignedObjectArray<T>& items)
88 for(int i=1,ni=items.size();i<ni;++i)
97 template <typename T,typename Q>
98 static inline void add(btAlignedObjectArray<T>& items,const Q& value)
100 for(int i=0,ni=items.size();i<ni;++i)
107 template <typename T,typename Q>
108 static inline void mul(btAlignedObjectArray<T>& items,const Q& value)
110 for(int i=0,ni=items.size();i<ni;++i)
117 template <typename T>
118 static inline T average(const btAlignedObjectArray<T>& items)
120 const btScalar n=(btScalar)(items.size()>0?items.size():1);
121 return(sum(items)/n);
125 static inline btScalar tetravolume(const btVector3& x0,
130 const btVector3 a=x1-x0;
131 const btVector3 b=x2-x0;
132 const btVector3 c=x3-x0;
133 return(dot(a,cross(b,c)));
138 static btVector3 stresscolor(btScalar stress)
140 static const btVector3 spectrum[]= { btVector3(1,0,1),
147 static const int ncolors=sizeof(spectrum)/sizeof(spectrum[0])-1;
148 static const btScalar one=1;
149 stress=btMax<btScalar>(0,btMin<btScalar>(1,stress))*ncolors;
150 const int sel=(int)stress;
151 const btScalar frc=stress-sel;
152 return(spectrum[sel]+(spectrum[sel+1]-spectrum[sel])*frc);
157 void btSoftBodyHelpers::Draw( btSoftBody* psb,
161 const btScalar scl=(btScalar)0.1;
162 const btScalar nscl=scl*5;
163 const btVector3 lcolor=btVector3(0,0,0);
164 const btVector3 ncolor=btVector3(1,1,1);
165 const btVector3 ccolor=btVector3(1,0,0);
169 if(0!=(drawflags&fDrawFlags::Nodes))
171 for(i=0;i<psb->m_nodes.size();++i)
173 const btSoftBody::Node& n=psb->m_nodes[i];
174 if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue;
175 idraw->drawLine(n.m_x-btVector3(scl,0,0),n.m_x+btVector3(scl,0,0),btVector3(1,0,0));
176 idraw->drawLine(n.m_x-btVector3(0,scl,0),n.m_x+btVector3(0,scl,0),btVector3(0,1,0));
177 idraw->drawLine(n.m_x-btVector3(0,0,scl),n.m_x+btVector3(0,0,scl),btVector3(0,0,1));
181 if(0!=(drawflags&fDrawFlags::Links))
183 for(i=0;i<psb->m_links.size();++i)
185 const btSoftBody::Link& l=psb->m_links[i];
186 if(0==(l.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue;
187 idraw->drawLine(l.m_n[0]->m_x,l.m_n[1]->m_x,lcolor);
191 if(0!=(drawflags&fDrawFlags::Normals))
193 for(i=0;i<psb->m_nodes.size();++i)
195 const btSoftBody::Node& n=psb->m_nodes[i];
196 if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue;
197 const btVector3 d=n.m_n*nscl;
198 idraw->drawLine(n.m_x,n.m_x+d,ncolor);
199 idraw->drawLine(n.m_x,n.m_x-d,ncolor*0.5);
203 if(0!=(drawflags&fDrawFlags::Contacts))
205 static const btVector3 axis[]={btVector3(1,0,0),
208 for(i=0;i<psb->m_rcontacts.size();++i)
210 const btSoftBody::RContact& c=psb->m_rcontacts[i];
211 const btVector3 o= c.m_node->m_x-c.m_cti.m_normal*
212 (dot(c.m_node->m_x,c.m_cti.m_normal)+c.m_cti.m_offset);
213 const btVector3 x=cross(c.m_cti.m_normal,axis[c.m_cti.m_normal.minAxis()]).normalized();
214 const btVector3 y=cross(x,c.m_cti.m_normal).normalized();
215 idraw->drawLine(o-x*nscl,o+x*nscl,ccolor);
216 idraw->drawLine(o-y*nscl,o+y*nscl,ccolor);
217 idraw->drawLine(o,o+c.m_cti.m_normal*nscl*3,btVector3(1,1,0));
221 if(0!=(drawflags&fDrawFlags::Anchors))
223 for(i=0;i<psb->m_anchors.size();++i)
225 const btSoftBody::Anchor& a=psb->m_anchors[i];
226 const btVector3 q=a.m_body->getWorldTransform()*a.m_local;
227 drawVertex(idraw,a.m_node->m_x,0.25,btVector3(1,0,0));
228 drawVertex(idraw,q,0.25,btVector3(0,1,0));
229 idraw->drawLine(a.m_node->m_x,q,btVector3(1,1,1));
231 for(i=0;i<psb->m_nodes.size();++i)
233 const btSoftBody::Node& n=psb->m_nodes[i];
234 if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue;
237 drawVertex(idraw,n.m_x,0.25,btVector3(1,0,0));
242 if(0!=(drawflags&fDrawFlags::Faces))
244 const btScalar scl=(btScalar)0.8;
245 const btScalar alp=(btScalar)1;
246 const btVector3 col(0,(btScalar)0.7,0);
247 for(i=0;i<psb->m_faces.size();++i)
249 const btSoftBody::Face& f=psb->m_faces[i];
250 if(0==(f.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue;
251 const btVector3 x[]={f.m_n[0]->m_x,f.m_n[1]->m_x,f.m_n[2]->m_x};
252 const btVector3 c=(x[0]+x[1]+x[2])/3;
253 idraw->drawTriangle((x[0]-c)*scl+c,
260 if(0!=(drawflags&fDrawFlags::Clusters))
263 for(i=0;i<psb->m_clusters.size();++i)
265 if(psb->m_clusters[i]->m_collide)
267 btVector3 color( rand()/(btScalar)RAND_MAX,
268 rand()/(btScalar)RAND_MAX,
269 rand()/(btScalar)RAND_MAX);
270 color=color.normalized()*0.75;
271 btAlignedObjectArray<btVector3> vertices;
272 vertices.resize(psb->m_clusters[i]->m_nodes.size());
273 for(j=0,nj=vertices.size();j<nj;++j)
275 vertices[j]=psb->m_clusters[i]->m_nodes[j]->m_x;
277 HullDesc hdsc(QF_TRIANGLES,vertices.size(),&vertices[0]);
280 hdsc.mMaxVertices=vertices.size();
281 hlib.CreateConvexHull(hdsc,hres);
282 const btVector3 center=average(hres.m_OutputVertices);
283 add(hres.m_OutputVertices,-center);
284 mul(hres.m_OutputVertices,(btScalar)1);
285 add(hres.m_OutputVertices,center);
286 for(j=0;j<(int)hres.mNumFaces;++j)
288 const int idx[]={hres.m_Indices[j*3+0],hres.m_Indices[j*3+1],hres.m_Indices[j*3+2]};
289 idraw->drawTriangle(hres.m_OutputVertices[idx[0]],
290 hres.m_OutputVertices[idx[1]],
291 hres.m_OutputVertices[idx[2]],
294 hlib.ReleaseResult(hres);
298 for(int j=0;j<psb->m_clusters[i].m_nodes.size();++j)
300 const btSoftBody::Cluster& c=psb->m_clusters[i];
301 const btVector3 r=c.m_nodes[j]->m_x-c.m_com;
302 const btVector3 v=c.m_lv+cross(c.m_av,r);
303 idraw->drawLine(c.m_nodes[j]->m_x,c.m_nodes[j]->m_x+v,btVector3(1,0,0));
307 btSoftBody::Cluster& c=*psb->m_clusters[i];
308 idraw->drawLine(c.m_com,c.m_framexform*btVector3(10,0,0),btVector3(1,0,0));
309 idraw->drawLine(c.m_com,c.m_framexform*btVector3(0,10,0),btVector3(0,1,0));
310 idraw->drawLine(c.m_com,c.m_framexform*btVector3(0,0,10),btVector3(0,0,1));
314 if(0!=(drawflags&fDrawFlags::Notes))
316 for(i=0;i<psb->m_notes.size();++i)
318 const btSoftBody::Note& n=psb->m_notes[i];
319 btVector3 p=n.m_offset;
320 for(int j=0;j<n.m_rank;++j)
322 p+=n.m_nodes[j]->m_x*n.m_coords[j];
324 idraw->draw3dText(p,n.m_text);
328 if(0!=(drawflags&fDrawFlags::NodeTree)) DrawNodeTree(psb,idraw);
330 if(0!=(drawflags&fDrawFlags::FaceTree)) DrawFaceTree(psb,idraw);
332 if(0!=(drawflags&fDrawFlags::ClusterTree)) DrawClusterTree(psb,idraw);
334 if(0!=(drawflags&fDrawFlags::Joints))
336 for(i=0;i<psb->m_joints.size();++i)
338 const btSoftBody::Joint* pj=psb->m_joints[i];
341 case btSoftBody::Joint::eType::Linear:
343 const btSoftBody::LJoint* pjl=(const btSoftBody::LJoint*)pj;
344 const btVector3 a0=pj->m_bodies[0].xform()*pjl->m_refs[0];
345 const btVector3 a1=pj->m_bodies[1].xform()*pjl->m_refs[1];
346 idraw->drawLine(pj->m_bodies[0].xform().getOrigin(),a0,btVector3(1,1,0));
347 idraw->drawLine(pj->m_bodies[1].xform().getOrigin(),a1,btVector3(0,1,1));
348 drawVertex(idraw,a0,0.25,btVector3(1,1,0));
349 drawVertex(idraw,a1,0.25,btVector3(0,1,1));
352 case btSoftBody::Joint::eType::Angular:
354 const btSoftBody::AJoint* pja=(const btSoftBody::AJoint*)pj;
355 const btVector3 o0=pj->m_bodies[0].xform().getOrigin();
356 const btVector3 o1=pj->m_bodies[1].xform().getOrigin();
357 const btVector3 a0=pj->m_bodies[0].xform().getBasis()*pj->m_refs[0];
358 const btVector3 a1=pj->m_bodies[1].xform().getBasis()*pj->m_refs[1];
359 idraw->drawLine(o0,o0+a0*10,btVector3(1,1,0));
360 idraw->drawLine(o0,o0+a1*10,btVector3(1,1,0));
361 idraw->drawLine(o1,o1+a0*10,btVector3(0,1,1));
362 idraw->drawLine(o1,o1+a1*10,btVector3(0,1,1));
370 void btSoftBodyHelpers::DrawInfos( btSoftBody* psb,
376 for(int i=0;i<psb->m_nodes.size();++i)
378 const btSoftBody::Node& n=psb->m_nodes[i];
383 sprintf(buff," M(%.2f)",1/n.m_im);
388 sprintf(buff," A(%.2f)",n.m_area);
391 if(text[0]) idraw->draw3dText(n.m_x,text);
396 void btSoftBodyHelpers::DrawNodeTree( btSoftBody* psb,
401 drawTree(idraw,psb->m_ndbvt.m_root,0,btVector3(1,0,1),btVector3(1,1,1),mindepth,maxdepth);
405 void btSoftBodyHelpers::DrawFaceTree( btSoftBody* psb,
410 drawTree(idraw,psb->m_fdbvt.m_root,0,btVector3(0,1,0),btVector3(1,0,0),mindepth,maxdepth);
414 void btSoftBodyHelpers::DrawClusterTree( btSoftBody* psb,
419 drawTree(idraw,psb->m_cdbvt.m_root,0,btVector3(0,1,1),btVector3(1,0,0),mindepth,maxdepth);
423 void btSoftBodyHelpers::DrawFrame( btSoftBody* psb,
426 if(psb->m_pose.m_bframe)
428 static const btScalar ascl=10;
429 static const btScalar nscl=(btScalar)0.1;
430 const btVector3 com=psb->m_pose.m_com;
431 const btMatrix3x3 trs=psb->m_pose.m_rot*psb->m_pose.m_scl;
432 const btVector3 Xaxis=(trs*btVector3(1,0,0)).normalized();
433 const btVector3 Yaxis=(trs*btVector3(0,1,0)).normalized();
434 const btVector3 Zaxis=(trs*btVector3(0,0,1)).normalized();
435 idraw->drawLine(com,com+Xaxis*ascl,btVector3(1,0,0));
436 idraw->drawLine(com,com+Yaxis*ascl,btVector3(0,1,0));
437 idraw->drawLine(com,com+Zaxis*ascl,btVector3(0,0,1));
438 for(int i=0;i<psb->m_pose.m_pos.size();++i)
440 const btVector3 x=com+trs*psb->m_pose.m_pos[i];
441 drawVertex(idraw,x,nscl,btVector3(1,0,1));
447 btSoftBody* btSoftBodyHelpers::CreateRope( btSoftBodyWorldInfo& worldInfo, const btVector3& from,
454 btVector3* x=new btVector3[r];
455 btScalar* m=new btScalar[r];
460 const btScalar t=i/(btScalar)(r-1);
461 x[i]=lerp(from,to,t);
464 btSoftBody* psb= new btSoftBody(&worldInfo,r,x,m);
465 if(fixeds&1) psb->setMass(0,0);
466 if(fixeds&2) psb->setMass(r-1,0);
472 psb->appendLink(i-1,i);
479 btSoftBody* btSoftBodyHelpers::CreatePatch(btSoftBodyWorldInfo& worldInfo,const btVector3& corner00,
480 const btVector3& corner10,
481 const btVector3& corner01,
482 const btVector3& corner11,
488 #define IDX(_x_,_y_) ((_y_)*rx+(_x_))
490 if((resx<2)||(resy<2)) return(0);
494 btVector3* x=new btVector3[tot];
495 btScalar* m=new btScalar[tot];
500 const btScalar ty=iy/(btScalar)(ry-1);
501 const btVector3 py0=lerp(corner00,corner01,ty);
502 const btVector3 py1=lerp(corner10,corner11,ty);
503 for(int ix=0;ix<rx;++ix)
505 const btScalar tx=ix/(btScalar)(rx-1);
506 x[IDX(ix,iy)]=lerp(py0,py1,tx);
510 btSoftBody* psb=new btSoftBody(&worldInfo,tot,x,m);
511 if(fixeds&1) psb->setMass(IDX(0,0),0);
512 if(fixeds&2) psb->setMass(IDX(rx-1,0),0);
513 if(fixeds&4) psb->setMass(IDX(0,ry-1),0);
514 if(fixeds&8) psb->setMass(IDX(rx-1,ry-1),0);
517 /* Create links and faces */
520 for(int ix=0;ix<rx;++ix)
522 const int idx=IDX(ix,iy);
523 const bool mdx=(ix+1)<rx;
524 const bool mdy=(iy+1)<ry;
525 if(mdx) psb->appendLink(idx,IDX(ix+1,iy));
526 if(mdy) psb->appendLink(idx,IDX(ix,iy+1));
531 psb->appendFace(IDX(ix,iy),IDX(ix+1,iy),IDX(ix+1,iy+1));
532 psb->appendFace(IDX(ix,iy),IDX(ix+1,iy+1),IDX(ix,iy+1));
535 psb->appendLink(IDX(ix,iy),IDX(ix+1,iy+1));
540 psb->appendFace(IDX(ix,iy+1),IDX(ix,iy),IDX(ix+1,iy));
541 psb->appendFace(IDX(ix,iy+1),IDX(ix+1,iy),IDX(ix+1,iy+1));
544 psb->appendLink(IDX(ix+1,iy),IDX(ix,iy+1));
556 btSoftBody* btSoftBodyHelpers::CreatePatchUV(btSoftBodyWorldInfo& worldInfo,
557 const btVector3& corner00,
558 const btVector3& corner10,
559 const btVector3& corner01,
560 const btVector3& corner11,
572 * [0][0] corner00 ------- corner01 [resx][0]
575 * [0][resy] corner10 -------- corner11 [resx][resy]
588 * upper middle --> +16
589 * left middle --> +32
590 * right middle --> +64
591 * lower middle --> +128
595 * tex_coords size (resx-1)*(resy-1)*12
599 * SINGLE QUAD INTERNALS
601 * 1) btSoftBody's nodes and links,
602 * diagonal link is optional ("gendiags")
605 * node00 ------ node01
617 * UV Coordinates (hier example for single quad)
635 #define IDX(_x_,_y_) ((_y_)*rx+(_x_))
637 if((resx<2)||(resy<2)) return(0);
641 btVector3* x=new btVector3[tot];
642 btScalar* m=new btScalar[tot];
648 const btScalar ty=iy/(btScalar)(ry-1);
649 const btVector3 py0=lerp(corner00,corner01,ty);
650 const btVector3 py1=lerp(corner10,corner11,ty);
651 for(int ix=0;ix<rx;++ix)
653 const btScalar tx=ix/(btScalar)(rx-1);
654 x[IDX(ix,iy)]=lerp(py0,py1,tx);
658 btSoftBody* psb=new btSoftBody(&worldInfo,tot,x,m);
659 if(fixeds&1) psb->setMass(IDX(0,0),0);
660 if(fixeds&2) psb->setMass(IDX(rx-1,0),0);
661 if(fixeds&4) psb->setMass(IDX(0,ry-1),0);
662 if(fixeds&8) psb->setMass(IDX(rx-1,ry-1),0);
663 if(fixeds&16) psb->setMass(IDX((rx-1)/2,0),0);
664 if(fixeds&32) psb->setMass(IDX(0,(ry-1)/2),0);
665 if(fixeds&64) psb->setMass(IDX(rx-1,(ry-1)/2),0);
666 if(fixeds&128) psb->setMass(IDX((rx-1)/2,ry-1),0);
667 if(fixeds&256) psb->setMass(IDX((rx-1)/2,(ry-1)/2),0);
673 /* Create links and faces */
676 for(int ix=0;ix<rx;++ix)
678 const bool mdx=(ix+1)<rx;
679 const bool mdy=(iy+1)<ry;
681 int node00=IDX(ix,iy);
682 int node01=IDX(ix+1,iy);
683 int node10=IDX(ix,iy+1);
684 int node11=IDX(ix+1,iy+1);
686 if(mdx) psb->appendLink(node00,node01);
687 if(mdy) psb->appendLink(node00,node10);
690 psb->appendFace(node00,node10,node11);
692 tex_coords[z+0]=CalculateUV(resx,resy,ix,iy,0);
693 tex_coords[z+1]=CalculateUV(resx,resy,ix,iy,1);
694 tex_coords[z+2]=CalculateUV(resx,resy,ix,iy,0);
695 tex_coords[z+3]=CalculateUV(resx,resy,ix,iy,2);
696 tex_coords[z+4]=CalculateUV(resx,resy,ix,iy,3);
697 tex_coords[z+5]=CalculateUV(resx,resy,ix,iy,2);
699 psb->appendFace(node11,node01,node00);
701 tex_coords[z+6 ]=CalculateUV(resx,resy,ix,iy,3);
702 tex_coords[z+7 ]=CalculateUV(resx,resy,ix,iy,2);
703 tex_coords[z+8 ]=CalculateUV(resx,resy,ix,iy,3);
704 tex_coords[z+9 ]=CalculateUV(resx,resy,ix,iy,1);
705 tex_coords[z+10]=CalculateUV(resx,resy,ix,iy,0);
706 tex_coords[z+11]=CalculateUV(resx,resy,ix,iy,1);
708 if (gendiags) psb->appendLink(node00,node11);
718 float btSoftBodyHelpers::CalculateUV(int resx,int resy,int ix,int iy,int id)
748 tc = (1.0f/((resx-1))*ix);
751 tc = (1.0f/((resy-1))*(resy-1-iy));
754 tc = (1.0f/((resy-1))*(resy-1-iy-1));
757 tc = (1.0f/((resx-1))*(ix+1));
762 btSoftBody* btSoftBodyHelpers::CreateEllipsoid(btSoftBodyWorldInfo& worldInfo,const btVector3& center,
763 const btVector3& radius,
768 static void Generate(btVector3* x,int n)
773 for(int j=i;j;p*=0.5,j>>=1) if(j&1) t+=p;
775 btScalar a=(SIMD_PI+2*i*SIMD_PI)/n;
776 btScalar s=btSqrt(1-w*w);
777 *x++=btVector3(s*btCos(a),s*btSin(a),w);
781 btAlignedObjectArray<btVector3> vtx;
783 Hammersley::Generate(&vtx[0],vtx.size());
784 for(int i=0;i<vtx.size();++i)
786 vtx[i]=vtx[i]*radius+center;
788 return(CreateFromConvexHull(worldInfo,&vtx[0],vtx.size()));
794 btSoftBody* btSoftBodyHelpers::CreateFromTriMesh(btSoftBodyWorldInfo& worldInfo,const btScalar* vertices,
795 const int* triangles,
796 int ntriangles, bool randomizeConstraints)
801 for(i=0,ni=ntriangles*3;i<ni;++i)
803 maxidx=btMax(triangles[i],maxidx);
806 btAlignedObjectArray<bool> chks;
807 btAlignedObjectArray<btVector3> vtx;
808 chks.resize(maxidx*maxidx,false);
810 for(i=0,j=0,ni=maxidx*3;i<ni;++j,i+=3)
812 vtx[j]=btVector3(vertices[i],vertices[i+1],vertices[i+2]);
814 btSoftBody* psb=new btSoftBody(&worldInfo,vtx.size(),&vtx[0],0);
815 for( i=0,ni=ntriangles*3;i<ni;i+=3)
817 const int idx[]={triangles[i],triangles[i+1],triangles[i+2]};
818 #define IDX(_x_,_y_) ((_y_)*maxidx+(_x_))
819 for(int j=2,k=0;k<3;j=k++)
821 if(!chks[IDX(idx[j],idx[k])])
823 chks[IDX(idx[j],idx[k])]=true;
824 chks[IDX(idx[k],idx[j])]=true;
825 psb->appendLink(idx[j],idx[k]);
829 psb->appendFace(idx[0],idx[1],idx[2]);
831 if (randomizeConstraints)
833 psb->randomizeConstraints();
839 btSoftBody* btSoftBodyHelpers::CreateFromConvexHull(btSoftBodyWorldInfo& worldInfo, const btVector3* vertices,
840 int nvertices, bool randomizeConstraints)
842 HullDesc hdsc(QF_TRIANGLES,nvertices,vertices);
844 HullLibrary hlib;/*??*/
845 hdsc.mMaxVertices=nvertices;
846 hlib.CreateConvexHull(hdsc,hres);
847 btSoftBody* psb=new btSoftBody(&worldInfo,(int)hres.mNumOutputVertices,
848 &hres.m_OutputVertices[0],0);
849 for(int i=0;i<(int)hres.mNumFaces;++i)
851 const int idx[]={ hres.m_Indices[i*3+0],
852 hres.m_Indices[i*3+1],
853 hres.m_Indices[i*3+2]};
854 if(idx[0]<idx[1]) psb->appendLink( idx[0],idx[1]);
855 if(idx[1]<idx[2]) psb->appendLink( idx[1],idx[2]);
856 if(idx[2]<idx[0]) psb->appendLink( idx[2],idx[0]);
857 psb->appendFace(idx[0],idx[1],idx[2]);
859 hlib.ReleaseResult(hres);
860 if (randomizeConstraints)
862 psb->randomizeConstraints();