Bullet Collision Detection & Physics Library
btSoftBodyHelpers.cpp
Go to the documentation of this file.
1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
4 
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:
10 
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.
14 */
16 
17 #include "btSoftBodyInternals.h"
18 #include <stdio.h>
19 #include <string>
20 #include <iostream>
21 #include <sstream>
22 #include <string.h>
23 #include <algorithm>
24 #include "btSoftBodyHelpers.h"
27 #include <map>
28 #include <vector>
29 
30 static void drawVertex(btIDebugDraw* idraw,
31  const btVector3& x, btScalar s, const btVector3& c)
32 {
33  idraw->drawLine(x - btVector3(s, 0, 0), x + btVector3(s, 0, 0), c);
34  idraw->drawLine(x - btVector3(0, s, 0), x + btVector3(0, s, 0), c);
35  idraw->drawLine(x - btVector3(0, 0, s), x + btVector3(0, 0, s), c);
36 }
37 
38 //
39 static void drawBox(btIDebugDraw* idraw,
40  const btVector3& mins,
41  const btVector3& maxs,
42  const btVector3& color)
43 {
44  const btVector3 c[] = {btVector3(mins.x(), mins.y(), mins.z()),
45  btVector3(maxs.x(), mins.y(), mins.z()),
46  btVector3(maxs.x(), maxs.y(), mins.z()),
47  btVector3(mins.x(), maxs.y(), mins.z()),
48  btVector3(mins.x(), mins.y(), maxs.z()),
49  btVector3(maxs.x(), mins.y(), maxs.z()),
50  btVector3(maxs.x(), maxs.y(), maxs.z()),
51  btVector3(mins.x(), maxs.y(), maxs.z())};
52  idraw->drawLine(c[0], c[1], color);
53  idraw->drawLine(c[1], c[2], color);
54  idraw->drawLine(c[2], c[3], color);
55  idraw->drawLine(c[3], c[0], color);
56  idraw->drawLine(c[4], c[5], color);
57  idraw->drawLine(c[5], c[6], color);
58  idraw->drawLine(c[6], c[7], color);
59  idraw->drawLine(c[7], c[4], color);
60  idraw->drawLine(c[0], c[4], color);
61  idraw->drawLine(c[1], c[5], color);
62  idraw->drawLine(c[2], c[6], color);
63  idraw->drawLine(c[3], c[7], color);
64 }
65 
66 //
67 static void drawTree(btIDebugDraw* idraw,
68  const btDbvtNode* node,
69  int depth,
70  const btVector3& ncolor,
71  const btVector3& lcolor,
72  int mindepth,
73  int maxdepth)
74 {
75  if (node)
76  {
77  if (node->isinternal() && ((depth < maxdepth) || (maxdepth < 0)))
78  {
79  drawTree(idraw, node->childs[0], depth + 1, ncolor, lcolor, mindepth, maxdepth);
80  drawTree(idraw, node->childs[1], depth + 1, ncolor, lcolor, mindepth, maxdepth);
81  }
82  if (depth >= mindepth)
83  {
84  const btScalar scl = (btScalar)(node->isinternal() ? 1 : 1);
85  const btVector3 mi = node->volume.Center() - node->volume.Extents() * scl;
86  const btVector3 mx = node->volume.Center() + node->volume.Extents() * scl;
87  drawBox(idraw, mi, mx, node->isleaf() ? lcolor : ncolor);
88  }
89  }
90 }
91 
92 //
93 template <typename T>
94 static inline T sum(const btAlignedObjectArray<T>& items)
95 {
96  T v;
97  if (items.size())
98  {
99  v = items[0];
100  for (int i = 1, ni = items.size(); i < ni; ++i)
101  {
102  v += items[i];
103  }
104  }
105  return (v);
106 }
107 
108 //
109 template <typename T, typename Q>
110 static inline void add(btAlignedObjectArray<T>& items, const Q& value)
111 {
112  for (int i = 0, ni = items.size(); i < ni; ++i)
113  {
114  items[i] += value;
115  }
116 }
117 
118 //
119 template <typename T, typename Q>
120 static inline void mul(btAlignedObjectArray<T>& items, const Q& value)
121 {
122  for (int i = 0, ni = items.size(); i < ni; ++i)
123  {
124  items[i] *= value;
125  }
126 }
127 
128 //
129 template <typename T>
130 static inline T average(const btAlignedObjectArray<T>& items)
131 {
132  const btScalar n = (btScalar)(items.size() > 0 ? items.size() : 1);
133  return (sum(items) / n);
134 }
135 
136 #if 0
137 //
138  inline static btScalar tetravolume(const btVector3& x0,
139  const btVector3& x1,
140  const btVector3& x2,
141  const btVector3& x3)
142 {
143  const btVector3 a=x1-x0;
144  const btVector3 b=x2-x0;
145  const btVector3 c=x3-x0;
146  return(btDot(a,btCross(b,c)));
147 }
148 #endif
149 
150 //
151 #if 0
152 static btVector3 stresscolor(btScalar stress)
153 {
154  static const btVector3 spectrum[]= { btVector3(1,0,1),
155  btVector3(0,0,1),
156  btVector3(0,1,1),
157  btVector3(0,1,0),
158  btVector3(1,1,0),
159  btVector3(1,0,0),
160  btVector3(1,0,0)};
161  static const int ncolors=sizeof(spectrum)/sizeof(spectrum[0])-1;
162  static const btScalar one=1;
163  stress=btMax<btScalar>(0,btMin<btScalar>(1,stress))*ncolors;
164  const int sel=(int)stress;
165  const btScalar frc=stress-sel;
166  return(spectrum[sel]+(spectrum[sel+1]-spectrum[sel])*frc);
167 }
168 #endif
169 
170 //
172  btIDebugDraw* idraw,
173  int drawflags)
174 {
175  const btScalar scl = (btScalar)0.1;
176  const btScalar nscl = scl * 5;
177  const btVector3 lcolor = btVector3(0, 0, 0);
178  const btVector3 ncolor = btVector3(1, 1, 1);
179  const btVector3 ccolor = btVector3(1, 0, 0);
180  int i, j, nj;
181 
182  /* Clusters */
183  if (0 != (drawflags & fDrawFlags::Clusters))
184  {
185  srand(1806);
186  for (i = 0; i < psb->m_clusters.size(); ++i)
187  {
188  if (psb->m_clusters[i]->m_collide)
189  {
190  btVector3 color(rand() / (btScalar)RAND_MAX,
191  rand() / (btScalar)RAND_MAX,
192  rand() / (btScalar)RAND_MAX);
193  color = color.normalized() * 0.75;
195  vertices.resize(psb->m_clusters[i]->m_nodes.size());
196  for (j = 0, nj = vertices.size(); j < nj; ++j)
197  {
198  vertices[j] = psb->m_clusters[i]->m_nodes[j]->m_x;
199  }
200 #define USE_NEW_CONVEX_HULL_COMPUTER
201 #ifdef USE_NEW_CONVEX_HULL_COMPUTER
202  btConvexHullComputer computer;
203  int stride = sizeof(btVector3);
204  int count = vertices.size();
205  btScalar shrink = 0.f;
206  btScalar shrinkClamp = 0.f;
207  computer.compute(&vertices[0].getX(), stride, count, shrink, shrinkClamp);
208  for (int i = 0; i < computer.faces.size(); i++)
209  {
210  int face = computer.faces[i];
211  //printf("face=%d\n",face);
212  const btConvexHullComputer::Edge* firstEdge = &computer.edges[face];
213  const btConvexHullComputer::Edge* edge = firstEdge->getNextEdgeOfFace();
214 
215  int v0 = firstEdge->getSourceVertex();
216  int v1 = firstEdge->getTargetVertex();
217  while (edge != firstEdge)
218  {
219  int v2 = edge->getTargetVertex();
220  idraw->drawTriangle(computer.vertices[v0], computer.vertices[v1], computer.vertices[v2], color, 1);
221  edge = edge->getNextEdgeOfFace();
222  v0 = v1;
223  v1 = v2;
224  };
225  }
226 #else
227 
228  HullDesc hdsc(QF_TRIANGLES, vertices.size(), &vertices[0]);
229  HullResult hres;
230  HullLibrary hlib;
231  hdsc.mMaxVertices = vertices.size();
232  hlib.CreateConvexHull(hdsc, hres);
233  const btVector3 center = average(hres.m_OutputVertices);
234  add(hres.m_OutputVertices, -center);
235  mul(hres.m_OutputVertices, (btScalar)1);
236  add(hres.m_OutputVertices, center);
237  for (j = 0; j < (int)hres.mNumFaces; ++j)
238  {
239  const int idx[] = {hres.m_Indices[j * 3 + 0], hres.m_Indices[j * 3 + 1], hres.m_Indices[j * 3 + 2]};
240  idraw->drawTriangle(hres.m_OutputVertices[idx[0]],
241  hres.m_OutputVertices[idx[1]],
242  hres.m_OutputVertices[idx[2]],
243  color, 1);
244  }
245  hlib.ReleaseResult(hres);
246 #endif
247  }
248  /* Velocities */
249 #if 0
250  for(int j=0;j<psb->m_clusters[i].m_nodes.size();++j)
251  {
252  const btSoftBody::Cluster& c=psb->m_clusters[i];
253  const btVector3 r=c.m_nodes[j]->m_x-c.m_com;
254  const btVector3 v=c.m_lv+btCross(c.m_av,r);
255  idraw->drawLine(c.m_nodes[j]->m_x,c.m_nodes[j]->m_x+v,btVector3(1,0,0));
256  }
257 #endif
258  /* Frame */
259  // btSoftBody::Cluster& c=*psb->m_clusters[i];
260  // idraw->drawLine(c.m_com,c.m_framexform*btVector3(10,0,0),btVector3(1,0,0));
261  // idraw->drawLine(c.m_com,c.m_framexform*btVector3(0,10,0),btVector3(0,1,0));
262  // idraw->drawLine(c.m_com,c.m_framexform*btVector3(0,0,10),btVector3(0,0,1));
263  }
264  }
265  else
266  {
267  /* Nodes */
268  if (0 != (drawflags & fDrawFlags::Nodes))
269  {
270  for (i = 0; i < psb->m_nodes.size(); ++i)
271  {
272  const btSoftBody::Node& n = psb->m_nodes[i];
273  if (0 == (n.m_material->m_flags & btSoftBody::fMaterial::DebugDraw)) continue;
274  idraw->drawLine(n.m_x - btVector3(scl, 0, 0), n.m_x + btVector3(scl, 0, 0), btVector3(1, 0, 0));
275  idraw->drawLine(n.m_x - btVector3(0, scl, 0), n.m_x + btVector3(0, scl, 0), btVector3(0, 1, 0));
276  idraw->drawLine(n.m_x - btVector3(0, 0, scl), n.m_x + btVector3(0, 0, scl), btVector3(0, 0, 1));
277  }
278  }
279  /* Links */
280  if (0 != (drawflags & fDrawFlags::Links))
281  {
282  for (i = 0; i < psb->m_links.size(); ++i)
283  {
284  const btSoftBody::Link& l = psb->m_links[i];
285  if (0 == (l.m_material->m_flags & btSoftBody::fMaterial::DebugDraw)) continue;
286  idraw->drawLine(l.m_n[0]->m_x, l.m_n[1]->m_x, lcolor);
287  }
288  }
289  /* Normals */
290  if (0 != (drawflags & fDrawFlags::Normals))
291  {
292  for (i = 0; i < psb->m_nodes.size(); ++i)
293  {
294  const btSoftBody::Node& n = psb->m_nodes[i];
295  if (0 == (n.m_material->m_flags & btSoftBody::fMaterial::DebugDraw)) continue;
296  const btVector3 d = n.m_n * nscl;
297  idraw->drawLine(n.m_x, n.m_x + d, ncolor);
298  idraw->drawLine(n.m_x, n.m_x - d, ncolor * 0.5);
299  }
300  }
301  /* Contacts */
302  if (0 != (drawflags & fDrawFlags::Contacts))
303  {
304  static const btVector3 axis[] = {btVector3(1, 0, 0),
305  btVector3(0, 1, 0),
306  btVector3(0, 0, 1)};
307  for (i = 0; i < psb->m_rcontacts.size(); ++i)
308  {
309  const btSoftBody::RContact& c = psb->m_rcontacts[i];
310  const btVector3 o = c.m_node->m_x - c.m_cti.m_normal *
311  (btDot(c.m_node->m_x, c.m_cti.m_normal) + c.m_cti.m_offset);
312  const btVector3 x = btCross(c.m_cti.m_normal, axis[c.m_cti.m_normal.minAxis()]).normalized();
313  const btVector3 y = btCross(x, c.m_cti.m_normal).normalized();
314  idraw->drawLine(o - x * nscl, o + x * nscl, ccolor);
315  idraw->drawLine(o - y * nscl, o + y * nscl, ccolor);
316  idraw->drawLine(o, o + c.m_cti.m_normal * nscl * 3, btVector3(1, 1, 0));
317  }
318  }
319  /* Faces */
320  if (0 != (drawflags & fDrawFlags::Faces))
321  {
322  const btScalar scl = (btScalar)0.8;
323  const btScalar alp = (btScalar)1;
324  const btVector3 col(0, (btScalar)0.7, 0);
325  for (i = 0; i < psb->m_faces.size(); ++i)
326  {
327  const btSoftBody::Face& f = psb->m_faces[i];
328  if (0 == (f.m_material->m_flags & btSoftBody::fMaterial::DebugDraw)) continue;
329  const btVector3 x[] = {f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x};
330  const btVector3 c = (x[0] + x[1] + x[2]) / 3;
331  idraw->drawTriangle((x[0] - c) * scl + c,
332  (x[1] - c) * scl + c,
333  (x[2] - c) * scl + c,
334  col, alp);
335  }
336  }
337  /* Tetras */
338  if (0 != (drawflags & fDrawFlags::Tetras))
339  {
340  const btScalar scl = (btScalar)0.8;
341  const btScalar alp = (btScalar)1;
342  const btVector3 col((btScalar)0.3, (btScalar)0.3, (btScalar)0.7);
343  for (int i = 0; i < psb->m_tetras.size(); ++i)
344  {
345  const btSoftBody::Tetra& t = psb->m_tetras[i];
346  if (0 == (t.m_material->m_flags & btSoftBody::fMaterial::DebugDraw)) continue;
347  const btVector3 x[] = {t.m_n[0]->m_x, t.m_n[1]->m_x, t.m_n[2]->m_x, t.m_n[3]->m_x};
348  const btVector3 c = (x[0] + x[1] + x[2] + x[3]) / 4;
349  idraw->drawTriangle((x[0] - c) * scl + c, (x[1] - c) * scl + c, (x[2] - c) * scl + c, col, alp);
350  idraw->drawTriangle((x[0] - c) * scl + c, (x[1] - c) * scl + c, (x[3] - c) * scl + c, col, alp);
351  idraw->drawTriangle((x[1] - c) * scl + c, (x[2] - c) * scl + c, (x[3] - c) * scl + c, col, alp);
352  idraw->drawTriangle((x[2] - c) * scl + c, (x[0] - c) * scl + c, (x[3] - c) * scl + c, col, alp);
353  }
354  }
355  }
356  /* Anchors */
357  if (0 != (drawflags & fDrawFlags::Anchors))
358  {
359  for (i = 0; i < psb->m_anchors.size(); ++i)
360  {
361  const btSoftBody::Anchor& a = psb->m_anchors[i];
362  const btVector3 q = a.m_body->getWorldTransform() * a.m_local;
363  drawVertex(idraw, a.m_node->m_x, 0.25, btVector3(1, 0, 0));
364  drawVertex(idraw, q, 0.25, btVector3(0, 1, 0));
365  idraw->drawLine(a.m_node->m_x, q, btVector3(1, 1, 1));
366  }
367  for (i = 0; i < psb->m_nodes.size(); ++i)
368  {
369  const btSoftBody::Node& n = psb->m_nodes[i];
370  if (0 == (n.m_material->m_flags & btSoftBody::fMaterial::DebugDraw)) continue;
371  if (n.m_im <= 0)
372  {
373  drawVertex(idraw, n.m_x, 0.25, btVector3(1, 0, 0));
374  }
375  }
376  }
377 
378  /* Notes */
379  if (0 != (drawflags & fDrawFlags::Notes))
380  {
381  for (i = 0; i < psb->m_notes.size(); ++i)
382  {
383  const btSoftBody::Note& n = psb->m_notes[i];
384  btVector3 p = n.m_offset;
385  for (int j = 0; j < n.m_rank; ++j)
386  {
387  p += n.m_nodes[j]->m_x * n.m_coords[j];
388  }
389  idraw->draw3dText(p, n.m_text);
390  }
391  }
392  /* Node tree */
393  if (0 != (drawflags & fDrawFlags::NodeTree)) DrawNodeTree(psb, idraw);
394  /* Face tree */
395  if (0 != (drawflags & fDrawFlags::FaceTree)) DrawFaceTree(psb, idraw);
396  /* Cluster tree */
397  if (0 != (drawflags & fDrawFlags::ClusterTree)) DrawClusterTree(psb, idraw);
398  /* Joints */
399  if (0 != (drawflags & fDrawFlags::Joints))
400  {
401  for (i = 0; i < psb->m_joints.size(); ++i)
402  {
403  const btSoftBody::Joint* pj = psb->m_joints[i];
404  switch (pj->Type())
405  {
407  {
408  const btSoftBody::LJoint* pjl = (const btSoftBody::LJoint*)pj;
409  const btVector3 a0 = pj->m_bodies[0].xform() * pjl->m_refs[0];
410  const btVector3 a1 = pj->m_bodies[1].xform() * pjl->m_refs[1];
411  idraw->drawLine(pj->m_bodies[0].xform().getOrigin(), a0, btVector3(1, 1, 0));
412  idraw->drawLine(pj->m_bodies[1].xform().getOrigin(), a1, btVector3(0, 1, 1));
413  drawVertex(idraw, a0, 0.25, btVector3(1, 1, 0));
414  drawVertex(idraw, a1, 0.25, btVector3(0, 1, 1));
415  }
416  break;
418  {
419  //const btSoftBody::AJoint* pja=(const btSoftBody::AJoint*)pj;
420  const btVector3 o0 = pj->m_bodies[0].xform().getOrigin();
421  const btVector3 o1 = pj->m_bodies[1].xform().getOrigin();
422  const btVector3 a0 = pj->m_bodies[0].xform().getBasis() * pj->m_refs[0];
423  const btVector3 a1 = pj->m_bodies[1].xform().getBasis() * pj->m_refs[1];
424  idraw->drawLine(o0, o0 + a0 * 10, btVector3(1, 1, 0));
425  idraw->drawLine(o0, o0 + a1 * 10, btVector3(1, 1, 0));
426  idraw->drawLine(o1, o1 + a0 * 10, btVector3(0, 1, 1));
427  idraw->drawLine(o1, o1 + a1 * 10, btVector3(0, 1, 1));
428  break;
429  }
430  default:
431  {
432  }
433  }
434  }
435  }
436 }
437 
438 //
440  btIDebugDraw* idraw,
441  bool masses,
442  bool areas,
443  bool /*stress*/)
444 {
445  for (int i = 0; i < psb->m_nodes.size(); ++i)
446  {
447  const btSoftBody::Node& n = psb->m_nodes[i];
448  char text[2048] = {0};
449  char buff[1024];
450  if (masses)
451  {
452  sprintf(buff, " M(%.2f)", 1 / n.m_im);
453  strcat(text, buff);
454  }
455  if (areas)
456  {
457  sprintf(buff, " A(%.2f)", n.m_area);
458  strcat(text, buff);
459  }
460  if (text[0]) idraw->draw3dText(n.m_x, text);
461  }
462 }
463 
464 //
466  btIDebugDraw* idraw,
467  int mindepth,
468  int maxdepth)
469 {
470  drawTree(idraw, psb->m_ndbvt.m_root, 0, btVector3(1, 0, 1), btVector3(1, 1, 1), mindepth, maxdepth);
471 }
472 
473 //
475  btIDebugDraw* idraw,
476  int mindepth,
477  int maxdepth)
478 {
479  drawTree(idraw, psb->m_fdbvt.m_root, 0, btVector3(0, 1, 0), btVector3(1, 0, 0), mindepth, maxdepth);
480 }
481 
482 //
484  btIDebugDraw* idraw,
485  int mindepth,
486  int maxdepth)
487 {
488  drawTree(idraw, psb->m_cdbvt.m_root, 0, btVector3(0, 1, 1), btVector3(1, 0, 0), mindepth, maxdepth);
489 }
490 
491 //The btSoftBody object from the BulletSDK includes an array of Nodes and Links. These links appear
492 // to be first set up to connect a node to between 5 and 6 of its neighbors [480 links],
493 //and then to the rest of the nodes after the execution of the Floyd-Warshall graph algorithm
494 //[another 930 links].
495 //The way the links are stored by default, we have a number of cases where adjacent links share a node in common
496 // - this leads to the creation of a data dependency through memory.
497 //The PSolve_Links() function reads and writes nodes as it iterates over each link.
498 //So, we now have the possibility of a data dependency between iteration X
499 //that processes link L with iteration X+1 that processes link L+1
500 //because L and L+1 have one node in common, and iteration X updates the positions of that node,
501 //and iteration X+1 reads in the position of that shared node.
502 //
503 //Such a memory dependency limits the ability of a modern CPU to speculate beyond
504 //a certain point because it has to respect a possible dependency
505 //- this prevents the CPU from making full use of its out-of-order resources.
506 //If we re-order the links such that we minimize the cases where a link L and L+1 share a common node,
507 //we create a temporal gap between when the node position is written,
508 //and when it is subsequently read. This in turn allows the CPU to continue execution without
509 //risking a dependency violation. Such a reordering would result in significant speedups on
510 //modern CPUs with lots of execution resources.
511 //In our testing, we see it have a tremendous impact not only on the A7,
512 //but also on all x86 cores that ship with modern Macs.
513 //The attached source file includes a single function (ReoptimizeLinkOrder) which can be called on a
514 //btSoftBody object in the solveConstraints() function before the actual solver is invoked,
515 //or right after generateBendingConstraints() once we have all 1410 links.
516 
517 //===================================================================
518 //
519 //
520 // This function takes in a list of interdependent Links and tries
521 // to maximize the distance between calculation
522 // of dependent links. This increases the amount of parallelism that can
523 // be exploited by out-of-order instruction processors with large but
524 // (inevitably) finite instruction windows.
525 //
526 //===================================================================
527 
528 // A small structure to track lists of dependent link calculations
530 {
531 public:
532  int value; // A link calculation that is dependent on this one
533  // Positive values = "input A" while negative values = "input B"
534  LinkDeps_t* next; // Next dependence in the list
535 };
537 
538 // Dependency list constants
539 #define REOP_NOT_DEPENDENT -1
540 #define REOP_NODE_COMPLETE -2 // Must be less than REOP_NOT_DEPENDENT
541 
542 void btSoftBodyHelpers::ReoptimizeLinkOrder(btSoftBody* psb /* This can be replaced by a btSoftBody pointer */)
543 {
544  int i, nLinks = psb->m_links.size(), nNodes = psb->m_nodes.size();
545  btSoftBody::Link* lr;
546  int ar, br;
547  btSoftBody::Node* node0 = &(psb->m_nodes[0]);
548  btSoftBody::Node* node1 = &(psb->m_nodes[1]);
549  LinkDepsPtr_t linkDep;
550  int readyListHead, readyListTail, linkNum, linkDepFrees, depLink;
551 
552  // Allocate temporary buffers
553  int* nodeWrittenAt = new int[nNodes + 1]; // What link calculation produced this node's current values?
554  int* linkDepA = new int[nLinks]; // Link calculation input is dependent upon prior calculation #N
555  int* linkDepB = new int[nLinks];
556  int* readyList = new int[nLinks]; // List of ready-to-process link calculations (# of links, maximum)
557  LinkDeps_t* linkDepFreeList = new LinkDeps_t[2 * nLinks]; // Dependent-on-me list elements (2x# of links, maximum)
558  LinkDepsPtr_t* linkDepListStarts = new LinkDepsPtr_t[nLinks]; // Start nodes of dependent-on-me lists, one for each link
559 
560  // Copy the original, unsorted links to a side buffer
561  btSoftBody::Link* linkBuffer = new btSoftBody::Link[nLinks];
562  memcpy(linkBuffer, &(psb->m_links[0]), sizeof(btSoftBody::Link) * nLinks);
563 
564  // Clear out the node setup and ready list
565  for (i = 0; i < nNodes + 1; i++)
566  {
567  nodeWrittenAt[i] = REOP_NOT_DEPENDENT;
568  }
569  for (i = 0; i < nLinks; i++)
570  {
571  linkDepListStarts[i] = NULL;
572  }
573  readyListHead = readyListTail = linkDepFrees = 0;
574 
575  // Initial link analysis to set up data structures
576  for (i = 0; i < nLinks; i++)
577  {
578  // Note which prior link calculations we are dependent upon & build up dependence lists
579  lr = &(psb->m_links[i]);
580  ar = (lr->m_n[0] - node0) / (node1 - node0);
581  br = (lr->m_n[1] - node0) / (node1 - node0);
582  if (nodeWrittenAt[ar] > REOP_NOT_DEPENDENT)
583  {
584  linkDepA[i] = nodeWrittenAt[ar];
585  linkDep = &linkDepFreeList[linkDepFrees++];
586  linkDep->value = i;
587  linkDep->next = linkDepListStarts[nodeWrittenAt[ar]];
588  linkDepListStarts[nodeWrittenAt[ar]] = linkDep;
589  }
590  else
591  {
592  linkDepA[i] = REOP_NOT_DEPENDENT;
593  }
594  if (nodeWrittenAt[br] > REOP_NOT_DEPENDENT)
595  {
596  linkDepB[i] = nodeWrittenAt[br];
597  linkDep = &linkDepFreeList[linkDepFrees++];
598  linkDep->value = -(i + 1);
599  linkDep->next = linkDepListStarts[nodeWrittenAt[br]];
600  linkDepListStarts[nodeWrittenAt[br]] = linkDep;
601  }
602  else
603  {
604  linkDepB[i] = REOP_NOT_DEPENDENT;
605  }
606 
607  // Add this link to the initial ready list, if it is not dependent on any other links
608  if ((linkDepA[i] == REOP_NOT_DEPENDENT) && (linkDepB[i] == REOP_NOT_DEPENDENT))
609  {
610  readyList[readyListTail++] = i;
611  linkDepA[i] = linkDepB[i] = REOP_NODE_COMPLETE; // Probably not needed now
612  }
613 
614  // Update the nodes to mark which ones are calculated by this link
615  nodeWrittenAt[ar] = nodeWrittenAt[br] = i;
616  }
617 
618  // Process the ready list and create the sorted list of links
619  // -- By treating the ready list as a queue, we maximize the distance between any
620  // inter-dependent node calculations
621  // -- All other (non-related) nodes in the ready list will automatically be inserted
622  // in between each set of inter-dependent link calculations by this loop
623  i = 0;
624  while (readyListHead != readyListTail)
625  {
626  // Use ready list to select the next link to process
627  linkNum = readyList[readyListHead++];
628  // Copy the next-to-calculate link back into the original link array
629  psb->m_links[i++] = linkBuffer[linkNum];
630 
631  // Free up any link inputs that are dependent on this one
632  linkDep = linkDepListStarts[linkNum];
633  while (linkDep)
634  {
635  depLink = linkDep->value;
636  if (depLink >= 0)
637  {
638  linkDepA[depLink] = REOP_NOT_DEPENDENT;
639  }
640  else
641  {
642  depLink = -depLink - 1;
643  linkDepB[depLink] = REOP_NOT_DEPENDENT;
644  }
645  // Add this dependent link calculation to the ready list if *both* inputs are clear
646  if ((linkDepA[depLink] == REOP_NOT_DEPENDENT) && (linkDepB[depLink] == REOP_NOT_DEPENDENT))
647  {
648  readyList[readyListTail++] = depLink;
649  linkDepA[depLink] = linkDepB[depLink] = REOP_NODE_COMPLETE; // Probably not needed now
650  }
651  linkDep = linkDep->next;
652  }
653  }
654 
655  // Delete the temporary buffers
656  delete[] nodeWrittenAt;
657  delete[] linkDepA;
658  delete[] linkDepB;
659  delete[] readyList;
660  delete[] linkDepFreeList;
661  delete[] linkDepListStarts;
662  delete[] linkBuffer;
663 }
664 
665 //
667  btIDebugDraw* idraw)
668 {
669  if (psb->m_pose.m_bframe)
670  {
671  static const btScalar ascl = 10;
672  static const btScalar nscl = (btScalar)0.1;
673  const btVector3 com = psb->m_pose.m_com;
674  const btMatrix3x3 trs = psb->m_pose.m_rot * psb->m_pose.m_scl;
675  const btVector3 Xaxis = (trs * btVector3(1, 0, 0)).normalized();
676  const btVector3 Yaxis = (trs * btVector3(0, 1, 0)).normalized();
677  const btVector3 Zaxis = (trs * btVector3(0, 0, 1)).normalized();
678  idraw->drawLine(com, com + Xaxis * ascl, btVector3(1, 0, 0));
679  idraw->drawLine(com, com + Yaxis * ascl, btVector3(0, 1, 0));
680  idraw->drawLine(com, com + Zaxis * ascl, btVector3(0, 0, 1));
681  for (int i = 0; i < psb->m_pose.m_pos.size(); ++i)
682  {
683  const btVector3 x = com + trs * psb->m_pose.m_pos[i];
684  drawVertex(idraw, x, nscl, btVector3(1, 0, 1));
685  }
686  }
687 }
688 
689 //
691  const btVector3& to,
692  int res,
693  int fixeds)
694 {
695  /* Create nodes */
696  const int r = res + 2;
697  btVector3* x = new btVector3[r];
698  btScalar* m = new btScalar[r];
699  int i;
700 
701  for (i = 0; i < r; ++i)
702  {
703  const btScalar t = i / (btScalar)(r - 1);
704  x[i] = lerp(from, to, t);
705  m[i] = 1;
706  }
707  btSoftBody* psb = new btSoftBody(&worldInfo, r, x, m);
708  if (fixeds & 1) psb->setMass(0, 0);
709  if (fixeds & 2) psb->setMass(r - 1, 0);
710  delete[] x;
711  delete[] m;
712  /* Create links */
713  for (i = 1; i < r; ++i)
714  {
715  psb->appendLink(i - 1, i);
716  }
717  /* Finished */
718  return (psb);
719 }
720 
721 //
723  const btVector3& corner10,
724  const btVector3& corner01,
725  const btVector3& corner11,
726  int resx,
727  int resy,
728  int fixeds,
729  bool gendiags,
730  btScalar perturbation)
731 {
732 #define IDX(_x_, _y_) ((_y_)*rx + (_x_))
733  /* Create nodes */
734  if ((resx < 2) || (resy < 2)) return (0);
735  const int rx = resx;
736  const int ry = resy;
737  const int tot = rx * ry;
738  btVector3* x = new btVector3[tot];
739  btScalar* m = new btScalar[tot];
740  int iy;
741 
742  for (iy = 0; iy < ry; ++iy)
743  {
744  const btScalar ty = iy / (btScalar)(ry - 1);
745  const btVector3 py0 = lerp(corner00, corner01, ty);
746  const btVector3 py1 = lerp(corner10, corner11, ty);
747  for (int ix = 0; ix < rx; ++ix)
748  {
749  const btScalar tx = ix / (btScalar)(rx - 1);
750  btScalar pert = perturbation * btScalar(rand()) / RAND_MAX;
751  btVector3 temp1 = py1;
752  temp1.setY(py1.getY() + pert);
753  btVector3 temp = py0;
754  pert = perturbation * btScalar(rand()) / RAND_MAX;
755  temp.setY(py0.getY() + pert);
756  x[IDX(ix, iy)] = lerp(temp, temp1, tx);
757  m[IDX(ix, iy)] = 1;
758  }
759  }
760  btSoftBody* psb = new btSoftBody(&worldInfo, tot, x, m);
761  if (fixeds & 1) psb->setMass(IDX(0, 0), 0);
762  if (fixeds & 2) psb->setMass(IDX(rx - 1, 0), 0);
763  if (fixeds & 4) psb->setMass(IDX(0, ry - 1), 0);
764  if (fixeds & 8) psb->setMass(IDX(rx - 1, ry - 1), 0);
765  delete[] x;
766  delete[] m;
767  /* Create links and faces */
768  for (iy = 0; iy < ry; ++iy)
769  {
770  for (int ix = 0; ix < rx; ++ix)
771  {
772  const int idx = IDX(ix, iy);
773  const bool mdx = (ix + 1) < rx;
774  const bool mdy = (iy + 1) < ry;
775  if (mdx) psb->appendLink(idx, IDX(ix + 1, iy));
776  if (mdy) psb->appendLink(idx, IDX(ix, iy + 1));
777  if (mdx && mdy)
778  {
779  if ((ix + iy) & 1)
780  {
781  psb->appendFace(IDX(ix, iy), IDX(ix + 1, iy), IDX(ix + 1, iy + 1));
782  psb->appendFace(IDX(ix, iy), IDX(ix + 1, iy + 1), IDX(ix, iy + 1));
783  if (gendiags)
784  {
785  psb->appendLink(IDX(ix, iy), IDX(ix + 1, iy + 1));
786  }
787  }
788  else
789  {
790  psb->appendFace(IDX(ix, iy + 1), IDX(ix, iy), IDX(ix + 1, iy));
791  psb->appendFace(IDX(ix, iy + 1), IDX(ix + 1, iy), IDX(ix + 1, iy + 1));
792  if (gendiags)
793  {
794  psb->appendLink(IDX(ix + 1, iy), IDX(ix, iy + 1));
795  }
796  }
797  }
798  }
799  }
800  /* Finished */
801 #undef IDX
802  return (psb);
803 }
804 
805 //
807  const btVector3& corner00,
808  const btVector3& corner10,
809  const btVector3& corner01,
810  const btVector3& corner11,
811  int resx,
812  int resy,
813  int fixeds,
814  bool gendiags,
815  float* tex_coords)
816 {
817  /*
818  *
819  * corners:
820  *
821  * [0][0] corner00 ------- corner01 [resx][0]
822  * | |
823  * | |
824  * [0][resy] corner10 -------- corner11 [resx][resy]
825  *
826  *
827  *
828  *
829  *
830  *
831  * "fixedgs" map:
832  *
833  * corner00 --> +1
834  * corner01 --> +2
835  * corner10 --> +4
836  * corner11 --> +8
837  * upper middle --> +16
838  * left middle --> +32
839  * right middle --> +64
840  * lower middle --> +128
841  * center --> +256
842  *
843  *
844  * tex_coords size (resx-1)*(resy-1)*12
845  *
846  *
847  *
848  * SINGLE QUAD INTERNALS
849  *
850  * 1) btSoftBody's nodes and links,
851  * diagonal link is optional ("gendiags")
852  *
853  *
854  * node00 ------ node01
855  * | .
856  * | .
857  * | .
858  * | .
859  * | .
860  * node10 node11
861  *
862  *
863  *
864  * 2) Faces:
865  * two triangles,
866  * UV Coordinates (hier example for single quad)
867  *
868  * (0,1) (0,1) (1,1)
869  * 1 |\ 3 \-----| 2
870  * | \ \ |
871  * | \ \ |
872  * | \ \ |
873  * | \ \ |
874  * 2 |-----\ 3 \| 1
875  * (0,0) (1,0) (1,0)
876  *
877  *
878  *
879  *
880  *
881  *
882  */
883 
884 #define IDX(_x_, _y_) ((_y_)*rx + (_x_))
885  /* Create nodes */
886  if ((resx < 2) || (resy < 2)) return (0);
887  const int rx = resx;
888  const int ry = resy;
889  const int tot = rx * ry;
890  btVector3* x = new btVector3[tot];
891  btScalar* m = new btScalar[tot];
892 
893  int iy;
894 
895  for (iy = 0; iy < ry; ++iy)
896  {
897  const btScalar ty = iy / (btScalar)(ry - 1);
898  const btVector3 py0 = lerp(corner00, corner01, ty);
899  const btVector3 py1 = lerp(corner10, corner11, ty);
900  for (int ix = 0; ix < rx; ++ix)
901  {
902  const btScalar tx = ix / (btScalar)(rx - 1);
903  x[IDX(ix, iy)] = lerp(py0, py1, tx);
904  m[IDX(ix, iy)] = 1;
905  }
906  }
907  btSoftBody* psb = new btSoftBody(&worldInfo, tot, x, m);
908  if (fixeds & 1) psb->setMass(IDX(0, 0), 0);
909  if (fixeds & 2) psb->setMass(IDX(rx - 1, 0), 0);
910  if (fixeds & 4) psb->setMass(IDX(0, ry - 1), 0);
911  if (fixeds & 8) psb->setMass(IDX(rx - 1, ry - 1), 0);
912  if (fixeds & 16) psb->setMass(IDX((rx - 1) / 2, 0), 0);
913  if (fixeds & 32) psb->setMass(IDX(0, (ry - 1) / 2), 0);
914  if (fixeds & 64) psb->setMass(IDX(rx - 1, (ry - 1) / 2), 0);
915  if (fixeds & 128) psb->setMass(IDX((rx - 1) / 2, ry - 1), 0);
916  if (fixeds & 256) psb->setMass(IDX((rx - 1) / 2, (ry - 1) / 2), 0);
917  delete[] x;
918  delete[] m;
919 
920  int z = 0;
921  /* Create links and faces */
922  for (iy = 0; iy < ry; ++iy)
923  {
924  for (int ix = 0; ix < rx; ++ix)
925  {
926  const bool mdx = (ix + 1) < rx;
927  const bool mdy = (iy + 1) < ry;
928 
929  int node00 = IDX(ix, iy);
930  int node01 = IDX(ix + 1, iy);
931  int node10 = IDX(ix, iy + 1);
932  int node11 = IDX(ix + 1, iy + 1);
933 
934  if (mdx) psb->appendLink(node00, node01);
935  if (mdy) psb->appendLink(node00, node10);
936  if (mdx && mdy)
937  {
938  psb->appendFace(node00, node10, node11);
939  if (tex_coords)
940  {
941  tex_coords[z + 0] = CalculateUV(resx, resy, ix, iy, 0);
942  tex_coords[z + 1] = CalculateUV(resx, resy, ix, iy, 1);
943  tex_coords[z + 2] = CalculateUV(resx, resy, ix, iy, 0);
944  tex_coords[z + 3] = CalculateUV(resx, resy, ix, iy, 2);
945  tex_coords[z + 4] = CalculateUV(resx, resy, ix, iy, 3);
946  tex_coords[z + 5] = CalculateUV(resx, resy, ix, iy, 2);
947  }
948  psb->appendFace(node11, node01, node00);
949  if (tex_coords)
950  {
951  tex_coords[z + 6] = CalculateUV(resx, resy, ix, iy, 3);
952  tex_coords[z + 7] = CalculateUV(resx, resy, ix, iy, 2);
953  tex_coords[z + 8] = CalculateUV(resx, resy, ix, iy, 3);
954  tex_coords[z + 9] = CalculateUV(resx, resy, ix, iy, 1);
955  tex_coords[z + 10] = CalculateUV(resx, resy, ix, iy, 0);
956  tex_coords[z + 11] = CalculateUV(resx, resy, ix, iy, 1);
957  }
958  if (gendiags) psb->appendLink(node00, node11);
959  z += 12;
960  }
961  }
962  }
963  /* Finished */
964 #undef IDX
965  return (psb);
966 }
967 
968 float btSoftBodyHelpers::CalculateUV(int resx, int resy, int ix, int iy, int id)
969 {
970  /*
971  *
972  *
973  * node00 --- node01
974  * | |
975  * node10 --- node11
976  *
977  *
978  * ID map:
979  *
980  * node00 s --> 0
981  * node00 t --> 1
982  *
983  * node01 s --> 3
984  * node01 t --> 1
985  *
986  * node10 s --> 0
987  * node10 t --> 2
988  *
989  * node11 s --> 3
990  * node11 t --> 2
991  *
992  *
993  */
994 
995  float tc = 0.0f;
996  if (id == 0)
997  {
998  tc = (1.0f / ((resx - 1)) * ix);
999  }
1000  else if (id == 1)
1001  {
1002  tc = (1.0f / ((resy - 1)) * (resy - 1 - iy));
1003  }
1004  else if (id == 2)
1005  {
1006  tc = (1.0f / ((resy - 1)) * (resy - 1 - iy - 1));
1007  }
1008  else if (id == 3)
1009  {
1010  tc = (1.0f / ((resx - 1)) * (ix + 1));
1011  }
1012  return tc;
1013 }
1014 //
1016  const btVector3& radius,
1017  int res)
1018 {
1019  struct Hammersley
1020  {
1021  static void Generate(btVector3* x, int n)
1022  {
1023  for (int i = 0; i < n; i++)
1024  {
1025  btScalar p = 0.5, t = 0;
1026  for (int j = i; j; p *= 0.5, j >>= 1)
1027  if (j & 1) t += p;
1028  btScalar w = 2 * t - 1;
1029  btScalar a = (SIMD_PI + 2 * i * SIMD_PI) / n;
1030  btScalar s = btSqrt(1 - w * w);
1031  *x++ = btVector3(s * btCos(a), s * btSin(a), w);
1032  }
1033  }
1034  };
1036  vtx.resize(3 + res);
1037  Hammersley::Generate(&vtx[0], vtx.size());
1038  for (int i = 0; i < vtx.size(); ++i)
1039  {
1040  vtx[i] = vtx[i] * radius + center;
1041  }
1042  return (CreateFromConvexHull(worldInfo, &vtx[0], vtx.size()));
1043 }
1044 
1045 //
1047  const int* triangles,
1048  int ntriangles, bool randomizeConstraints)
1049 {
1050  int maxidx = 0;
1051  int i, j, ni;
1052 
1053  for (i = 0, ni = ntriangles * 3; i < ni; ++i)
1054  {
1055  maxidx = btMax(triangles[i], maxidx);
1056  }
1057  ++maxidx;
1060  chks.resize(maxidx * maxidx, false);
1061  vtx.resize(maxidx);
1062  for (i = 0, j = 0, ni = maxidx * 3; i < ni; ++j, i += 3)
1063  {
1064  vtx[j] = btVector3(vertices[i], vertices[i + 1], vertices[i + 2]);
1065  }
1066  btSoftBody* psb = new btSoftBody(&worldInfo, vtx.size(), &vtx[0], 0);
1067  for (i = 0, ni = ntriangles * 3; i < ni; i += 3)
1068  {
1069  const int idx[] = {triangles[i], triangles[i + 1], triangles[i + 2]};
1070 #define IDX(_x_, _y_) ((_y_)*maxidx + (_x_))
1071  for (int j = 2, k = 0; k < 3; j = k++)
1072  {
1073  if (!chks[IDX(idx[j], idx[k])])
1074  {
1075  chks[IDX(idx[j], idx[k])] = true;
1076  chks[IDX(idx[k], idx[j])] = true;
1077  psb->appendLink(idx[j], idx[k]);
1078  }
1079  }
1080 #undef IDX
1081  psb->appendFace(idx[0], idx[1], idx[2]);
1082  }
1083 
1084  if (randomizeConstraints)
1085  {
1086  psb->randomizeConstraints();
1087  }
1088 
1089  return (psb);
1090 }
1091 
1092 //
1094  int nvertices, bool randomizeConstraints)
1095 {
1096  HullDesc hdsc(QF_TRIANGLES, nvertices, vertices);
1097  HullResult hres;
1098  HullLibrary hlib; /*??*/
1099  hdsc.mMaxVertices = nvertices;
1100  hlib.CreateConvexHull(hdsc, hres);
1101  btSoftBody* psb = new btSoftBody(&worldInfo, (int)hres.mNumOutputVertices,
1102  &hres.m_OutputVertices[0], 0);
1103  for (int i = 0; i < (int)hres.mNumFaces; ++i)
1104  {
1105  const int idx[] = {static_cast<int>(hres.m_Indices[i * 3 + 0]),
1106  static_cast<int>(hres.m_Indices[i * 3 + 1]),
1107  static_cast<int>(hres.m_Indices[i * 3 + 2])};
1108  if (idx[0] < idx[1]) psb->appendLink(idx[0], idx[1]);
1109  if (idx[1] < idx[2]) psb->appendLink(idx[1], idx[2]);
1110  if (idx[2] < idx[0]) psb->appendLink(idx[2], idx[0]);
1111  psb->appendFace(idx[0], idx[1], idx[2]);
1112  }
1113  hlib.ReleaseResult(hres);
1114  if (randomizeConstraints)
1115  {
1116  psb->randomizeConstraints();
1117  }
1118  return (psb);
1119 }
1120 
1121 static int nextLine(const char* buffer)
1122 {
1123  int numBytesRead = 0;
1124 
1125  while (*buffer != '\n')
1126  {
1127  buffer++;
1128  numBytesRead++;
1129  }
1130 
1131  if (buffer[0] == 0x0a)
1132  {
1133  buffer++;
1134  numBytesRead++;
1135  }
1136  return numBytesRead;
1137 }
1138 
1139 /* Create from TetGen .ele, .face, .node data */
1141  const char* ele,
1142  const char* face,
1143  const char* node,
1144  bool bfacelinks,
1145  bool btetralinks,
1146  bool bfacesfromtetras)
1147 {
1149  int nnode = 0;
1150  int ndims = 0;
1151  int nattrb = 0;
1152  int hasbounds = 0;
1153  int result = sscanf(node, "%d %d %d %d", &nnode, &ndims, &nattrb, &hasbounds);
1154  result = sscanf(node, "%d %d %d %d", &nnode, &ndims, &nattrb, &hasbounds);
1155  node += nextLine(node);
1156 
1157  pos.resize(nnode);
1158  for (int i = 0; i < pos.size(); ++i)
1159  {
1160  int index = 0;
1161  //int bound=0;
1162  float x, y, z;
1163  sscanf(node, "%d %f %f %f", &index, &x, &y, &z);
1164 
1165  // sn>>index;
1166  // sn>>x;sn>>y;sn>>z;
1167  node += nextLine(node);
1168 
1169  //for(int j=0;j<nattrb;++j)
1170  // sn>>a;
1171 
1172  //if(hasbounds)
1173  // sn>>bound;
1174 
1175  pos[index].setX(btScalar(x));
1176  pos[index].setY(btScalar(y));
1177  pos[index].setZ(btScalar(z));
1178  }
1179  btSoftBody* psb = new btSoftBody(&worldInfo, nnode, &pos[0], 0);
1180 #if 0
1181 if(face&&face[0])
1182  {
1183  int nface=0;
1184  sf>>nface;sf>>hasbounds;
1185  for(int i=0;i<nface;++i)
1186  {
1187  int index=0;
1188  int bound=0;
1189  int ni[3];
1190  sf>>index;
1191  sf>>ni[0];sf>>ni[1];sf>>ni[2];
1192  sf>>bound;
1193  psb->appendFace(ni[0],ni[1],ni[2]);
1194  if(btetralinks)
1195  {
1196  psb->appendLink(ni[0],ni[1],0,true);
1197  psb->appendLink(ni[1],ni[2],0,true);
1198  psb->appendLink(ni[2],ni[0],0,true);
1199  }
1200  }
1201  }
1202 #endif
1203 
1204  if (ele && ele[0])
1205  {
1206  int ntetra = 0;
1207  int ncorner = 0;
1208  int neattrb = 0;
1209  sscanf(ele, "%d %d %d", &ntetra, &ncorner, &neattrb);
1210  ele += nextLine(ele);
1211 
1212  //se>>ntetra;se>>ncorner;se>>neattrb;
1213  for (int i = 0; i < ntetra; ++i)
1214  {
1215  int index = 0;
1216  int ni[4];
1217 
1218  //se>>index;
1219  //se>>ni[0];se>>ni[1];se>>ni[2];se>>ni[3];
1220  sscanf(ele, "%d %d %d %d %d", &index, &ni[0], &ni[1], &ni[2], &ni[3]);
1221  ele += nextLine(ele);
1222  //for(int j=0;j<neattrb;++j)
1223  // se>>a;
1224  psb->appendTetra(ni[0], ni[1], ni[2], ni[3]);
1225  if (btetralinks)
1226  {
1227  psb->appendLink(ni[0], ni[1], 0, true);
1228  psb->appendLink(ni[1], ni[2], 0, true);
1229  psb->appendLink(ni[2], ni[0], 0, true);
1230  psb->appendLink(ni[0], ni[3], 0, true);
1231  psb->appendLink(ni[1], ni[3], 0, true);
1232  psb->appendLink(ni[2], ni[3], 0, true);
1233  }
1234  }
1235  }
1236  psb->initializeDmInverse();
1237  psb->m_tetraScratches.resize(psb->m_tetras.size());
1238  psb->m_tetraScratchesTn.resize(psb->m_tetras.size());
1239  printf("Nodes: %u\r\n", psb->m_nodes.size());
1240  printf("Links: %u\r\n", psb->m_links.size());
1241  printf("Faces: %u\r\n", psb->m_faces.size());
1242  printf("Tetras: %u\r\n", psb->m_tetras.size());
1243  return (psb);
1244 }
1245 
1247 {
1248  std::ifstream fs;
1249  fs.open(vtk_file);
1250  btAssert(fs);
1251 
1252  typedef btAlignedObjectArray<int> Index;
1253  std::string line;
1255  btVector3 position;
1257  bool reading_points = false;
1258  bool reading_tets = false;
1259  size_t n_points = 0;
1260  size_t n_tets = 0;
1261  size_t x_count = 0;
1262  size_t indices_count = 0;
1263  while (std::getline(fs, line))
1264  {
1265  std::stringstream ss(line);
1266  if (line.size() == (size_t)(0))
1267  {
1268  }
1269  else if (line.substr(0, 6) == "POINTS")
1270  {
1271  reading_points = true;
1272  reading_tets = false;
1273  ss.ignore(128, ' '); // ignore "POINTS"
1274  ss >> n_points;
1275  X.resize(n_points);
1276  }
1277  else if (line.substr(0, 5) == "CELLS")
1278  {
1279  reading_points = false;
1280  reading_tets = true;
1281  ss.ignore(128, ' '); // ignore "CELLS"
1282  ss >> n_tets;
1283  indices.resize(n_tets);
1284  }
1285  else if (line.substr(0, 10) == "CELL_TYPES")
1286  {
1287  reading_points = false;
1288  reading_tets = false;
1289  }
1290  else if (reading_points)
1291  {
1292  btScalar p;
1293  ss >> p;
1294  position.setX(p);
1295  ss >> p;
1296  position.setY(p);
1297  ss >> p;
1298  position.setZ(p);
1299  //printf("v %f %f %f\n", position.getX(), position.getY(), position.getZ());
1300  X[x_count++] = position;
1301  }
1302  else if (reading_tets)
1303  {
1304  int d;
1305  ss >> d;
1306  if (d != 4)
1307  {
1308  printf("Load deformable failed: Only Tetrahedra are supported in VTK file.\n");
1309  fs.close();
1310  return 0;
1311  }
1312  ss.ignore(128, ' '); // ignore "4"
1313  Index tet;
1314  tet.resize(4);
1315  for (size_t i = 0; i < 4; i++)
1316  {
1317  ss >> tet[i];
1318  //printf("%d ", tet[i]);
1319  }
1320  //printf("\n");
1321  indices[indices_count++] = tet;
1322  }
1323  }
1324  btSoftBody* psb = new btSoftBody(&worldInfo, n_points, &X[0], 0);
1325 
1326  for (int i = 0; i < n_tets; ++i)
1327  {
1328  const Index& ni = indices[i];
1329  psb->appendTetra(ni[0], ni[1], ni[2], ni[3]);
1330  {
1331  psb->appendLink(ni[0], ni[1], 0, true);
1332  psb->appendLink(ni[1], ni[2], 0, true);
1333  psb->appendLink(ni[2], ni[0], 0, true);
1334  psb->appendLink(ni[0], ni[3], 0, true);
1335  psb->appendLink(ni[1], ni[3], 0, true);
1336  psb->appendLink(ni[2], ni[3], 0, true);
1337  }
1338  }
1339 
1340  generateBoundaryFaces(psb);
1341  psb->initializeDmInverse();
1342  psb->m_tetraScratches.resize(psb->m_tetras.size());
1343  psb->m_tetraScratchesTn.resize(psb->m_tetras.size());
1344  printf("Nodes: %u\r\n", psb->m_nodes.size());
1345  printf("Links: %u\r\n", psb->m_links.size());
1346  printf("Faces: %u\r\n", psb->m_faces.size());
1347  printf("Tetras: %u\r\n", psb->m_tetras.size());
1348 
1349  fs.close();
1350  return psb;
1351 }
1352 
1354 {
1355  int counter = 0;
1356  for (int i = 0; i < psb->m_nodes.size(); ++i)
1357  {
1358  psb->m_nodes[i].index = counter++;
1359  }
1360  typedef btAlignedObjectArray<int> Index;
1362  indices.resize(psb->m_tetras.size());
1363  for (int i = 0; i < indices.size(); ++i)
1364  {
1365  Index index;
1366  index.push_back(psb->m_tetras[i].m_n[0]->index);
1367  index.push_back(psb->m_tetras[i].m_n[1]->index);
1368  index.push_back(psb->m_tetras[i].m_n[2]->index);
1369  index.push_back(psb->m_tetras[i].m_n[3]->index);
1370  indices[i] = index;
1371  }
1372 
1373  std::map<std::vector<int>, std::vector<int> > dict;
1374  for (int i = 0; i < indices.size(); ++i)
1375  {
1376  for (int j = 0; j < 4; ++j)
1377  {
1378  std::vector<int> f;
1379  if (j == 0)
1380  {
1381  f.push_back(indices[i][1]);
1382  f.push_back(indices[i][0]);
1383  f.push_back(indices[i][2]);
1384  }
1385  if (j == 1)
1386  {
1387  f.push_back(indices[i][3]);
1388  f.push_back(indices[i][0]);
1389  f.push_back(indices[i][1]);
1390  }
1391  if (j == 2)
1392  {
1393  f.push_back(indices[i][3]);
1394  f.push_back(indices[i][1]);
1395  f.push_back(indices[i][2]);
1396  }
1397  if (j == 3)
1398  {
1399  f.push_back(indices[i][2]);
1400  f.push_back(indices[i][0]);
1401  f.push_back(indices[i][3]);
1402  }
1403  std::vector<int> f_sorted = f;
1404  std::sort(f_sorted.begin(), f_sorted.end());
1405  if (dict.find(f_sorted) != dict.end())
1406  {
1407  dict.erase(f_sorted);
1408  }
1409  else
1410  {
1411  dict.insert(std::make_pair(f_sorted, f));
1412  }
1413  }
1414  }
1415 
1416  for (std::map<std::vector<int>, std::vector<int> >::iterator it = dict.begin(); it != dict.end(); ++it)
1417  {
1418  std::vector<int> f = it->second;
1419  psb->appendFace(f[0], f[1], f[2]);
1420  //printf("f %d %d %d\n", f[0] + 1, f[1] + 1, f[2] + 1);
1421  }
1422 }
1423 
1424 //Write the surface mesh to an obj file.
1425 void btSoftBodyHelpers::writeObj(const char* filename, const btSoftBody* psb)
1426 {
1427  std::ofstream fs;
1428  fs.open(filename);
1429  btAssert(fs);
1430 
1431  if (psb->m_tetras.size() > 0)
1432  {
1433  // For tetrahedron mesh, we need to re-index the surface mesh for it to be in obj file/
1434  std::map<int, int> dict;
1435  for (int i = 0; i < psb->m_faces.size(); i++)
1436  {
1437  for (int d = 0; d < 3; d++)
1438  {
1439  int index = psb->m_faces[i].m_n[d]->index;
1440  if (dict.find(index) == dict.end())
1441  {
1442  int dict_size = dict.size();
1443  dict[index] = dict_size;
1444  fs << "v";
1445  for (int k = 0; k < 3; k++)
1446  {
1447  fs << " " << psb->m_nodes[index].m_x[k];
1448  }
1449  fs << "\n";
1450  }
1451  }
1452  }
1453  // Write surface mesh.
1454  for (int i = 0; i < psb->m_faces.size(); ++i)
1455  {
1456  fs << "f";
1457  for (int n = 0; n < 3; n++)
1458  {
1459  fs << " " << dict[psb->m_faces[i].m_n[n]->index] + 1;
1460  }
1461  fs << "\n";
1462  }
1463  }
1464  else
1465  {
1466  // For trimesh, directly write out all the nodes and faces.xs
1467  for (int i = 0; i < psb->m_nodes.size(); ++i)
1468  {
1469  fs << "v";
1470  for (int d = 0; d < 3; d++)
1471  {
1472  fs << " " << psb->m_nodes[i].m_x[d];
1473  }
1474  fs << "\n";
1475  }
1476 
1477  for (int i = 0; i < psb->m_faces.size(); ++i)
1478  {
1479  fs << "f";
1480  for (int n = 0; n < 3; n++)
1481  {
1482  fs << " " << psb->m_faces[i].m_n[n]->index + 1;
1483  }
1484  fs << "\n";
1485  }
1486  }
1487  fs.close();
1488 }
1489 
1490 void btSoftBodyHelpers::duplicateFaces(const char* filename, const btSoftBody* psb)
1491 {
1492  std::ifstream fs_read;
1493  fs_read.open(filename);
1494  std::string line;
1495  btVector3 pos;
1497  while (std::getline(fs_read, line))
1498  {
1499  std::stringstream ss(line);
1500  if (line[0] == 'v')
1501  {
1502  }
1503  else if (line[0] == 'f')
1504  {
1505  ss.ignore();
1506  int id0, id1, id2;
1507  ss >> id0;
1508  ss >> id1;
1509  ss >> id2;
1510  btAlignedObjectArray<int> new_face;
1511  new_face.push_back(id1);
1512  new_face.push_back(id0);
1513  new_face.push_back(id2);
1514  additional_faces.push_back(new_face);
1515  }
1516  }
1517  fs_read.close();
1518 
1519  std::ofstream fs_write;
1520  fs_write.open(filename, std::ios_base::app);
1521  for (int i = 0; i < additional_faces.size(); ++i)
1522  {
1523  fs_write << "f";
1524  for (int n = 0; n < 3; n++)
1525  {
1526  fs_write << " " << additional_faces[i][n];
1527  }
1528  fs_write << "\n";
1529  }
1530  fs_write.close();
1531 }
1532 
1533 // Given a simplex with vertices a,b,c,d, find the barycentric weights of p in this simplex
1534 void btSoftBodyHelpers::getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, const btVector3& p, btVector4& bary)
1535 {
1536  btVector3 vap = p - a;
1537  btVector3 vbp = p - b;
1538 
1539  btVector3 vab = b - a;
1540  btVector3 vac = c - a;
1541  btVector3 vad = d - a;
1542 
1543  btVector3 vbc = c - b;
1544  btVector3 vbd = d - b;
1545  btScalar va6 = (vbp.cross(vbd)).dot(vbc);
1546  btScalar vb6 = (vap.cross(vac)).dot(vad);
1547  btScalar vc6 = (vap.cross(vad)).dot(vab);
1548  btScalar vd6 = (vap.cross(vab)).dot(vac);
1549  btScalar v6 = btScalar(1) / (vab.cross(vac).dot(vad));
1550  bary = btVector4(va6 * v6, vb6 * v6, vc6 * v6, vd6 * v6);
1551 }
1552 
1553 // Given a simplex with vertices a,b,c, find the barycentric weights of p in this simplex. bary[3] = 0.
1555 {
1556  btVector3 v0 = b - a, v1 = c - a, v2 = p - a;
1557  btScalar d00 = btDot(v0, v0);
1558  btScalar d01 = btDot(v0, v1);
1559  btScalar d11 = btDot(v1, v1);
1560  btScalar d20 = btDot(v2, v0);
1561  btScalar d21 = btDot(v2, v1);
1562  btScalar invDenom = 1.0 / (d00 * d11 - d01 * d01);
1563  bary[1] = (d11 * d20 - d01 * d21) * invDenom;
1564  bary[2] = (d00 * d21 - d01 * d20) * invDenom;
1565  bary[0] = 1.0 - bary[1] - bary[2];
1566  bary[3] = 0;
1567 }
1568 
1569 // Iterate through all render nodes to find the simulation tetrahedron that contains the render node and record the barycentric weights
1570 // If the node is not inside any tetrahedron, assign it to the tetrahedron in which the node has the least negative barycentric weight
1572 {
1573  psb->m_z.resize(0);
1576  for (int i = 0; i < psb->m_renderNodes.size(); ++i)
1577  {
1578  const btVector3& p = psb->m_renderNodes[i].m_x;
1579  btVector4 bary;
1580  btVector4 optimal_bary;
1581  btScalar min_bary_weight = -1e3;
1583  for (int j = 0; j < psb->m_tetras.size(); ++j)
1584  {
1585  const btSoftBody::Tetra& t = psb->m_tetras[j];
1586  getBarycentricWeights(t.m_n[0]->m_x, t.m_n[1]->m_x, t.m_n[2]->m_x, t.m_n[3]->m_x, p, bary);
1587  btScalar new_min_bary_weight = bary[0];
1588  for (int k = 1; k < 4; ++k)
1589  {
1590  new_min_bary_weight = btMin(new_min_bary_weight, bary[k]);
1591  }
1592  if (new_min_bary_weight > min_bary_weight)
1593  {
1595  parents.push_back(t.m_n[0]);
1596  parents.push_back(t.m_n[1]);
1597  parents.push_back(t.m_n[2]);
1598  parents.push_back(t.m_n[3]);
1599  optimal_parents = parents;
1600  optimal_bary = bary;
1601  min_bary_weight = new_min_bary_weight;
1602  // stop searching if p is inside the tetrahedron at hand
1603  if (bary[0] >= 0. && bary[1] >= 0. && bary[2] >= 0. && bary[3] >= 0.)
1604  {
1605  break;
1606  }
1607  }
1608  }
1609  psb->m_renderNodesInterpolationWeights[i] = optimal_bary;
1610  psb->m_renderNodesParents[i] = optimal_parents;
1611  }
1612 }
1613 
1614 // Iterate through all render nodes to find the simulation triangle that's closest to the node in the barycentric sense.
1616 {
1619  psb->m_z.resize(psb->m_renderNodes.size());
1620  for (int i = 0; i < psb->m_renderNodes.size(); ++i)
1621  {
1622  const btVector3& p = psb->m_renderNodes[i].m_x;
1623  btVector4 bary;
1624  btVector4 optimal_bary;
1625  btScalar min_bary_weight = -SIMD_INFINITY;
1627  btScalar dist = 0, optimal_dist = 0;
1628  for (int j = 0; j < psb->m_faces.size(); ++j)
1629  {
1630  const btSoftBody::Face& f = psb->m_faces[j];
1631  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);
1632  btVector3 unit_n = n.normalized();
1633  dist = (p - f.m_n[0]->m_x).dot(unit_n);
1634  btVector3 proj_p = p - dist * unit_n;
1635  getBarycentricWeights(f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, proj_p, bary);
1636  btScalar new_min_bary_weight = bary[0];
1637  for (int k = 1; k < 3; ++k)
1638  {
1639  new_min_bary_weight = btMin(new_min_bary_weight, bary[k]);
1640  }
1641 
1642  // p is out of the current best triangle, we found a traingle that's better
1643  bool better_than_closest_outisde = (new_min_bary_weight > min_bary_weight && min_bary_weight < 0.);
1644  // p is inside of the current best triangle, we found a triangle that's better
1645  bool better_than_best_inside = (new_min_bary_weight >= 0 && min_bary_weight >= 0 && btFabs(dist) < btFabs(optimal_dist));
1646 
1647  if (better_than_closest_outisde || better_than_best_inside)
1648  {
1650  parents.push_back(f.m_n[0]);
1651  parents.push_back(f.m_n[1]);
1652  parents.push_back(f.m_n[2]);
1653  optimal_parents = parents;
1654  optimal_bary = bary;
1655  optimal_dist = dist;
1656  min_bary_weight = new_min_bary_weight;
1657  }
1658  }
1659  psb->m_renderNodesInterpolationWeights[i] = optimal_bary;
1660  psb->m_renderNodesParents[i] = optimal_parents;
1661  psb->m_z[i] = optimal_dist;
1662  }
1663 }
@ QF_TRIANGLES
Definition: btConvexHull.h:50
void sort(btMatrix3x3 &U, btVector3 &sigma, btMatrix3x3 &V, int t)
Helper function of 3X3 SVD for sorting singular values.
const T & btMax(const T &a, const T &b)
Definition: btMinMax.h:27
const T & btMin(const T &a, const T &b)
Definition: btMinMax.h:21
btScalar dot(const btQuaternion &q1, const btQuaternion &q2)
Calculate the dot product between two quaternions.
Definition: btQuaternion.h:888
#define SIMD_PI
Definition: btScalar.h:526
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition: btScalar.h:314
btScalar btSqrt(btScalar y)
Definition: btScalar.h:466
btScalar btSin(btScalar x)
Definition: btScalar.h:499
btScalar btFabs(btScalar x)
Definition: btScalar.h:497
#define SIMD_INFINITY
Definition: btScalar.h:544
btScalar btCos(btScalar x)
Definition: btScalar.h:498
#define btAssert(x)
Definition: btScalar.h:153
static T average(const btAlignedObjectArray< T > &items)
#define REOP_NODE_COMPLETE
static void drawTree(btIDebugDraw *idraw, const btDbvtNode *node, int depth, const btVector3 &ncolor, const btVector3 &lcolor, int mindepth, int maxdepth)
static void mul(btAlignedObjectArray< T > &items, const Q &value)
static int nextLine(const char *buffer)
static void add(btAlignedObjectArray< T > &items, const Q &value)
#define IDX(_x_, _y_)
static T sum(const btAlignedObjectArray< T > &items)
static void drawBox(btIDebugDraw *idraw, const btVector3 &mins, const btVector3 &maxs, const btVector3 &color)
#define REOP_NOT_DEPENDENT
static void drawVertex(btIDebugDraw *idraw, const btVector3 &x, btScalar s, const btVector3 &c)
btSoftBodyHelpers.cpp by Nathanael Presson
LinkDeps_t * LinkDepsPtr_t
btScalar btDot(const btVector3 &v1, const btVector3 &v2)
Return the dot product between two vectors.
Definition: btVector3.h:890
btVector3 btCross(const btVector3 &v1, const btVector3 &v2)
Return the cross product of two vectors.
Definition: btVector3.h:918
btVector3 lerp(const btVector3 &v1, const btVector3 &v2, const btScalar &t)
Return the linear interpolation between two vectors.
Definition: btVector3.h:934
unsigned int mMaxVertices
Definition: btConvexHull.h:103
The HullLibrary class can create a convex hull from a collection of vertices, using the ComputeHull m...
Definition: btConvexHull.h:183
HullError ReleaseResult(HullResult &result)
HullError CreateConvexHull(const HullDesc &desc, HullResult &result)
btAlignedObjectArray< btVector3 > m_OutputVertices
Definition: btConvexHull.h:39
btAlignedObjectArray< unsigned int > m_Indices
Definition: btConvexHull.h:42
unsigned int mNumOutputVertices
Definition: btConvexHull.h:38
unsigned int mNumFaces
Definition: btConvexHull.h:40
LinkDeps_t * next
The btAlignedObjectArray template class uses a subset of the stl::vector interface for its methods It...
int size() const
return the number of elements in the array
void resize(int newsize, const T &fillData=T())
void push_back(const T &_Val)
btTransform & getWorldTransform()
const Edge * getNextEdgeOfFace() const
Convex hull implementation based on Preparata and Hong See http://code.google.com/p/bullet/issues/det...
btScalar compute(const void *coords, bool doubleCoords, int stride, int count, btScalar shrink, btScalar shrinkClamp)
btAlignedObjectArray< btVector3 > vertices
btAlignedObjectArray< int > faces
btAlignedObjectArray< Edge > edges
The btIDebugDraw interface class allows hooking up a debug renderer to visually debug simulations.
Definition: btIDebugDraw.h:27
virtual void drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color)=0
virtual void draw3dText(const btVector3 &location, const char *textString)=0
virtual void drawTriangle(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2, const btVector3 &, const btVector3 &, const btVector3 &, const btVector3 &color, btScalar alpha)
Definition: btIDebugDraw.h:114
The btMatrix3x3 class implements a 3x3 rotation matrix, to perform linear algebra in combination with...
Definition: btMatrix3x3.h:50
The btSoftBody is an class to simulate cloth and volumetric soft bodies.
Definition: btSoftBody.h:75
btDbvt m_cdbvt
Definition: btSoftBody.h:835
void appendFace(int model=-1, Material *mat=0)
Definition: btSoftBody.cpp:429
void setMass(int node, btScalar mass)
Definition: btSoftBody.cpp:920
tJointArray m_joints
Definition: btSoftBody.h:827
btAlignedObjectArray< TetraScratch > m_tetraScratchesTn
Definition: btSoftBody.h:819
Pose m_pose
Definition: btSoftBody.h:808
void appendTetra(int model, Material *mat)
Definition: btSoftBody.cpp:469
tTetraArray m_tetras
Definition: btSoftBody.h:817
btAlignedObjectArray< TetraScratch > m_tetraScratches
Definition: btSoftBody.h:818
btAlignedObjectArray< btVector4 > m_renderNodesInterpolationWeights
Definition: btSoftBody.h:846
tFaceArray m_faces
Definition: btSoftBody.h:815
btAlignedObjectArray< btScalar > m_z
Definition: btSoftBody.h:848
tRContactArray m_rcontacts
Definition: btSoftBody.h:822
tClusterArray m_clusters
Definition: btSoftBody.h:836
btAlignedObjectArray< btAlignedObjectArray< const btSoftBody::Node * > > m_renderNodesParents
Definition: btSoftBody.h:847
tRenderNodeArray m_renderNodes
Definition: btSoftBody.h:813
tNoteArray m_notes
Definition: btSoftBody.h:811
btDbvt m_fdbvt
Definition: btSoftBody.h:833
tLinkArray m_links
Definition: btSoftBody.h:814
tAnchorArray m_anchors
Definition: btSoftBody.h:820
void randomizeConstraints()
tNodeArray m_nodes
Definition: btSoftBody.h:812
void appendLink(int model=-1, Material *mat=0)
Definition: btSoftBody.cpp:389
void initializeDmInverse()
btDbvt m_ndbvt
Definition: btSoftBody.h:832
btMatrix3x3 & getBasis()
Return the basis matrix for the rotation.
Definition: btTransform.h:108
btVector3 & getOrigin()
Return the origin vector translation.
Definition: btTransform.h:113
btVector3 can be used to represent 3D points and vectors.
Definition: btVector3.h:82
const btScalar & y() const
Return the y value.
Definition: btVector3.h:577
void setZ(btScalar _z)
Set the z value.
Definition: btVector3.h:571
const btScalar & z() const
Return the z value.
Definition: btVector3.h:579
btVector3 cross(const btVector3 &v) const
Return the cross product between this and another vector.
Definition: btVector3.h:380
int minAxis() const
Return the axis with the smallest value Note return values are 0,1,2 for x, y, or z.
Definition: btVector3.h:470
btScalar dot(const btVector3 &v) const
Return the dot product.
Definition: btVector3.h:229
btVector3 normalized() const
Return a normalized version of this vector.
Definition: btVector3.h:949
void setY(btScalar _y)
Set the y value.
Definition: btVector3.h:569
const btScalar & x() const
Return the x value.
Definition: btVector3.h:575
void setX(btScalar _x)
Set the x value.
Definition: btVector3.h:567
const btScalar & getY() const
Return the y value.
Definition: btVector3.h:563
DBVT_INLINE btVector3 Extents() const
Definition: btDbvt.h:136
DBVT_INLINE btVector3 Center() const
Definition: btDbvt.h:134
DBVT_INLINE bool isinternal() const
Definition: btDbvt.h:185
btDbvtNode * childs[2]
Definition: btDbvt.h:187
btDbvtVolume volume
Definition: btDbvt.h:182
DBVT_INLINE bool isleaf() const
Definition: btDbvt.h:184
btDbvtNode * m_root
Definition: btDbvt.h:302
static btSoftBody * CreatePatchUV(btSoftBodyWorldInfo &worldInfo, const btVector3 &corner00, const btVector3 &corner10, const btVector3 &corner01, const btVector3 &corner11, int resx, int resy, int fixeds, bool gendiags, float *tex_coords=0)
static void writeObj(const char *file, const btSoftBody *psb)
static btSoftBody * CreateFromTriMesh(btSoftBodyWorldInfo &worldInfo, const btScalar *vertices, const int *triangles, int ntriangles, bool randomizeConstraints=true)
static void extrapolateBarycentricWeights(btSoftBody *psb)
static void DrawNodeTree(btSoftBody *psb, btIDebugDraw *idraw, int mindepth=0, int maxdepth=-1)
static void getBarycentricWeights(const btVector3 &a, const btVector3 &b, const btVector3 &c, const btVector3 &d, const btVector3 &p, btVector4 &bary)
static btSoftBody * CreateFromTetGenData(btSoftBodyWorldInfo &worldInfo, const char *ele, const char *face, const char *node, bool bfacelinks, bool btetralinks, bool bfacesfromtetras)
static btSoftBody * CreateFromConvexHull(btSoftBodyWorldInfo &worldInfo, const btVector3 *vertices, int nvertices, bool randomizeConstraints=true)
static btSoftBody * CreateFromVtkFile(btSoftBodyWorldInfo &worldInfo, const char *vtk_file)
static void ReoptimizeLinkOrder(btSoftBody *psb)
Sort the list of links to move link calculations that are dependent upon earlier ones as far as possi...
static void DrawFaceTree(btSoftBody *psb, btIDebugDraw *idraw, int mindepth=0, int maxdepth=-1)
static void DrawInfos(btSoftBody *psb, btIDebugDraw *idraw, bool masses, bool areas, bool stress)
static btSoftBody * CreateEllipsoid(btSoftBodyWorldInfo &worldInfo, const btVector3 &center, const btVector3 &radius, int res)
static void DrawClusterTree(btSoftBody *psb, btIDebugDraw *idraw, int mindepth=0, int maxdepth=-1)
static float CalculateUV(int resx, int resy, int ix, int iy, int id)
static btSoftBody * CreatePatch(btSoftBodyWorldInfo &worldInfo, const btVector3 &corner00, const btVector3 &corner10, const btVector3 &corner01, const btVector3 &corner11, int resx, int resy, int fixeds, bool gendiags, btScalar perturbation=0.)
static void generateBoundaryFaces(btSoftBody *psb)
static void Draw(btSoftBody *psb, btIDebugDraw *idraw, int drawflags=fDrawFlags::Std)
static void duplicateFaces(const char *filename, const btSoftBody *psb)
static void DrawFrame(btSoftBody *psb, btIDebugDraw *idraw)
static btSoftBody * CreateRope(btSoftBodyWorldInfo &worldInfo, const btVector3 &from, const btVector3 &to, int res, int fixeds)
static void interpolateBarycentricWeights(btSoftBody *psb)
btVector3 m_local
Definition: btSoftBody.h:427
btRigidBody * m_body
Definition: btSoftBody.h:428
const btTransform & xform() const
Definition: btSoftBody.h:545
btAlignedObjectArray< Node * > m_nodes
Definition: btSoftBody.h:460
Node * m_n[3]
Definition: btSoftBody.h:307
Material * m_material
Definition: btSoftBody.h:258
btVector3 m_refs[2]
Definition: btSoftBody.h:638
virtual eType::_ Type() const =0
btScalar m_area
Definition: btSoftBody.h:276
btVector3 m_x
Definition: btSoftBody.h:269
btVector3 m_n
Definition: btSoftBody.h:274
btScalar m_coords[4]
Definition: btSoftBody.h:441
btVector3 m_offset
Definition: btSoftBody.h:438
Node * m_nodes[4]
Definition: btSoftBody.h:440
const char * m_text
Definition: btSoftBody.h:437
btMatrix3x3 m_scl
Definition: btSoftBody.h:453
btVector3 m_com
Definition: btSoftBody.h:451
tVector3Array m_pos
Definition: btSoftBody.h:449
btMatrix3x3 m_rot
Definition: btSoftBody.h:452
btScalar m_offset
Definition: btSoftBody.h:228
btVector3 m_normal
Definition: btSoftBody.h:227