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