Bullet Collision Detection & Physics Library
btDeformableContactProjection.cpp
Go to the documentation of this file.
1/*
2 Written by Xuchen Han <xuchenhan2015@u.northwestern.edu>
3
4 Bullet Continuous Collision Detection and Physics Library
5 Copyright (c) 2019 Google Inc. http://bulletphysics.org
6 This software is provided 'as-is', without any express or implied warranty.
7 In no event will the authors be held liable for any damages arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it freely,
10 subject to the following restrictions:
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15
18#include <algorithm>
19#include <cmath>
20btScalar btDeformableContactProjection::update(btCollisionObject** deformableBodies, int numDeformableBodies, const btContactSolverInfo& infoGlobal)
21{
22 btScalar residualSquare = 0;
23 for (int i = 0; i < numDeformableBodies; ++i)
24 {
25 for (int j = 0; j < m_softBodies.size(); ++j)
26 {
28 if (psb != deformableBodies[i])
29 {
30 continue;
31 }
32 for (int k = 0; k < m_nodeRigidConstraints[j].size(); ++k)
33 {
35 btScalar localResidualSquare = constraint.solveConstraint(infoGlobal);
36 residualSquare = btMax(residualSquare, localResidualSquare);
37 }
38 for (int k = 0; k < m_nodeAnchorConstraints[j].size(); ++k)
39 {
41 btScalar localResidualSquare = constraint.solveConstraint(infoGlobal);
42 residualSquare = btMax(residualSquare, localResidualSquare);
43 }
44 for (int k = 0; k < m_faceRigidConstraints[j].size(); ++k)
45 {
47 btScalar localResidualSquare = constraint.solveConstraint(infoGlobal);
48 residualSquare = btMax(residualSquare, localResidualSquare);
49 }
50 for (int k = 0; k < m_deformableConstraints[j].size(); ++k)
51 {
53 btScalar localResidualSquare = constraint.solveConstraint(infoGlobal);
54 residualSquare = btMax(residualSquare, localResidualSquare);
55 }
56 }
57 }
58 return residualSquare;
59}
60
61btScalar btDeformableContactProjection::solveSplitImpulse(btCollisionObject** deformableBodies, int numDeformableBodies, const btContactSolverInfo& infoGlobal)
62{
63 btScalar residualSquare = 0;
64 for (int i = 0; i < numDeformableBodies; ++i)
65 {
66 for (int j = 0; j < m_softBodies.size(); ++j)
67 {
69 if (psb != deformableBodies[i])
70 {
71 continue;
72 }
73 for (int k = 0; k < m_nodeRigidConstraints[j].size(); ++k)
74 {
76 btScalar localResidualSquare = constraint.solveSplitImpulse(infoGlobal);
77 residualSquare = btMax(residualSquare, localResidualSquare);
78 }
79 for (int k = 0; k < m_faceRigidConstraints[j].size(); ++k)
80 {
82 btScalar localResidualSquare = constraint.solveSplitImpulse(infoGlobal);
83 residualSquare = btMax(residualSquare, localResidualSquare);
84 }
85 }
86 }
87 return residualSquare;
88}
89
91{
92 BT_PROFILE("setConstraints");
93 for (int i = 0; i < m_softBodies.size(); ++i)
94 {
95 btSoftBody* psb = m_softBodies[i];
96 if (!psb->isActive())
97 {
98 continue;
99 }
100
101 // set Dirichlet constraint
102 for (int j = 0; j < psb->m_nodes.size(); ++j)
103 {
104 if (psb->m_nodes[j].m_im == 0)
105 {
106 btDeformableStaticConstraint static_constraint(&psb->m_nodes[j], infoGlobal);
107 m_staticConstraints[i].push_back(static_constraint);
108 }
109 }
110
111 // set up deformable anchors
112 for (int j = 0; j < psb->m_deformableAnchors.size(); ++j)
113 {
115 // skip fixed points
116 if (anchor.m_node->m_im == 0)
117 {
118 continue;
119 }
120 anchor.m_c1 = anchor.m_cti.m_colObj->getWorldTransform().getBasis() * anchor.m_local;
121 btDeformableNodeAnchorConstraint constraint(anchor, infoGlobal);
122 m_nodeAnchorConstraints[i].push_back(constraint);
123 }
124
125 // set Deformable Node vs. Rigid constraint
126 for (int j = 0; j < psb->m_nodeRigidContacts.size(); ++j)
127 {
129 // skip fixed points
130 if (contact.m_node->m_im == 0)
131 {
132 continue;
133 }
134 btDeformableNodeRigidContactConstraint constraint(contact, infoGlobal);
135 m_nodeRigidConstraints[i].push_back(constraint);
136 }
137
138 // set Deformable Face vs. Rigid constraint
139 for (int j = 0; j < psb->m_faceRigidContacts.size(); ++j)
140 {
142 // skip fixed faces
143 if (contact.m_c2 == 0)
144 {
145 continue;
146 }
147 btDeformableFaceRigidContactConstraint constraint(contact, infoGlobal, m_useStrainLimiting);
148 m_faceRigidConstraints[i].push_back(constraint);
149 }
150 }
151}
152
154{
155#ifndef USE_MGS
156 const int dim = 3;
157 for (int index = 0; index < m_projectionsDict.size(); ++index)
158 {
160 size_t i = m_projectionsDict.getKeyAtIndex(index).getUid1();
161 if (projectionDirs.size() >= dim)
162 {
163 // static node
164 x[i].setZero();
165 continue;
166 }
167 else if (projectionDirs.size() == 2)
168 {
169 btVector3 dir0 = projectionDirs[0];
170 btVector3 dir1 = projectionDirs[1];
171 btVector3 free_dir = btCross(dir0, dir1);
172 if (free_dir.safeNorm() < SIMD_EPSILON)
173 {
174 x[i] -= x[i].dot(dir0) * dir0;
175 }
176 else
177 {
178 free_dir.normalize();
179 x[i] = x[i].dot(free_dir) * free_dir;
180 }
181 }
182 else
183 {
184 btAssert(projectionDirs.size() == 1);
185 btVector3 dir0 = projectionDirs[0];
186 x[i] -= x[i].dot(dir0) * dir0;
187 }
188 }
189#else
190 btReducedVector p(x.size());
191 for (int i = 0; i < m_projections.size(); ++i)
192 {
193 p += (m_projections[i].dot(x) * m_projections[i]);
194 }
195 for (int i = 0; i < p.m_indices.size(); ++i)
196 {
197 x[p.m_indices[i]] -= p.m_vecs[i];
198 }
199#endif
200}
201
203{
204#ifndef USE_MGS
205 BT_PROFILE("btDeformableContactProjection::setProjection");
207 units.push_back(btVector3(1, 0, 0));
208 units.push_back(btVector3(0, 1, 0));
209 units.push_back(btVector3(0, 0, 1));
210 for (int i = 0; i < m_softBodies.size(); ++i)
211 {
212 btSoftBody* psb = m_softBodies[i];
213 if (!psb->isActive())
214 {
215 continue;
216 }
217 for (int j = 0; j < m_staticConstraints[i].size(); ++j)
218 {
219 int index = m_staticConstraints[i][j].m_node->index;
220 m_staticConstraints[i][j].m_node->m_constrained = true;
221 if (m_projectionsDict.find(index) == NULL)
222 {
223 m_projectionsDict.insert(index, units);
224 }
225 else
226 {
228 for (int k = 0; k < 3; ++k)
229 {
230 projections.push_back(units[k]);
231 }
232 }
233 }
234 for (int j = 0; j < m_nodeAnchorConstraints[i].size(); ++j)
235 {
236 int index = m_nodeAnchorConstraints[i][j].m_anchor->m_node->index;
237 m_nodeAnchorConstraints[i][j].m_anchor->m_node->m_constrained = true;
238 if (m_projectionsDict.find(index) == NULL)
239 {
240 m_projectionsDict.insert(index, units);
241 }
242 else
243 {
245 for (int k = 0; k < 3; ++k)
246 {
247 projections.push_back(units[k]);
248 }
249 }
250 }
251 for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j)
252 {
253 int index = m_nodeRigidConstraints[i][j].m_node->index;
254 m_nodeRigidConstraints[i][j].m_node->m_constrained = true;
255 if (m_nodeRigidConstraints[i][j].m_binding)
256 {
257 if (m_nodeRigidConstraints[i][j].m_static)
258 {
259 if (m_projectionsDict.find(index) == NULL)
260 {
261 m_projectionsDict.insert(index, units);
262 }
263 else
264 {
266 for (int k = 0; k < 3; ++k)
267 {
268 projections.push_back(units[k]);
269 }
270 }
271 }
272 else
273 {
274 if (m_projectionsDict.find(index) == NULL)
275 {
277 projections.push_back(m_nodeRigidConstraints[i][j].m_normal);
278 m_projectionsDict.insert(index, projections);
279 }
280 else
281 {
283 projections.push_back(m_nodeRigidConstraints[i][j].m_normal);
284 }
285 }
286 }
287 }
288 for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j)
289 {
290 const btSoftBody::Face* face = m_faceRigidConstraints[i][j].m_face;
291 if (m_faceRigidConstraints[i][j].m_binding)
292 {
293 for (int k = 0; k < 3; ++k)
294 {
295 face->m_n[k]->m_constrained = true;
296 }
297 }
298 for (int k = 0; k < 3; ++k)
299 {
300 btSoftBody::Node* node = face->m_n[k];
301 int index = node->index;
302 if (m_faceRigidConstraints[i][j].m_static)
303 {
304 if (m_projectionsDict.find(index) == NULL)
305 {
306 m_projectionsDict.insert(index, units);
307 }
308 else
309 {
311 for (int l = 0; l < 3; ++l)
312 {
313 projections.push_back(units[l]);
314 }
315 }
316 }
317 else
318 {
319 if (m_projectionsDict.find(index) == NULL)
320 {
322 projections.push_back(m_faceRigidConstraints[i][j].m_normal);
323 m_projectionsDict.insert(index, projections);
324 }
325 else
326 {
328 projections.push_back(m_faceRigidConstraints[i][j].m_normal);
329 }
330 }
331 }
332 }
333 }
334#else
335 int dof = 0;
336 for (int i = 0; i < m_softBodies.size(); ++i)
337 {
338 dof += m_softBodies[i]->m_nodes.size();
339 }
340 for (int i = 0; i < m_softBodies.size(); ++i)
341 {
342 btSoftBody* psb = m_softBodies[i];
343 if (!psb->isActive())
344 {
345 continue;
346 }
347 for (int j = 0; j < m_staticConstraints[i].size(); ++j)
348 {
349 int index = m_staticConstraints[i][j].m_node->index;
350 m_staticConstraints[i][j].m_node->m_penetration = SIMD_INFINITY;
352 btAlignedObjectArray<btVector3> vecs1, vecs2, vecs3;
353 indices.push_back(index);
354 vecs1.push_back(btVector3(1, 0, 0));
355 vecs2.push_back(btVector3(0, 1, 0));
356 vecs3.push_back(btVector3(0, 0, 1));
357 m_projections.push_back(btReducedVector(dof, indices, vecs1));
358 m_projections.push_back(btReducedVector(dof, indices, vecs2));
359 m_projections.push_back(btReducedVector(dof, indices, vecs3));
360 }
361
362 for (int j = 0; j < m_nodeAnchorConstraints[i].size(); ++j)
363 {
364 int index = m_nodeAnchorConstraints[i][j].m_anchor->m_node->index;
365 m_nodeAnchorConstraints[i][j].m_anchor->m_node->m_penetration = SIMD_INFINITY;
367 btAlignedObjectArray<btVector3> vecs1, vecs2, vecs3;
368 indices.push_back(index);
369 vecs1.push_back(btVector3(1, 0, 0));
370 vecs2.push_back(btVector3(0, 1, 0));
371 vecs3.push_back(btVector3(0, 0, 1));
372 m_projections.push_back(btReducedVector(dof, indices, vecs1));
373 m_projections.push_back(btReducedVector(dof, indices, vecs2));
374 m_projections.push_back(btReducedVector(dof, indices, vecs3));
375 }
376 for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j)
377 {
378 int index = m_nodeRigidConstraints[i][j].m_node->index;
379 m_nodeRigidConstraints[i][j].m_node->m_penetration = -m_nodeRigidConstraints[i][j].getContact()->m_cti.m_offset;
381 indices.push_back(index);
382 btAlignedObjectArray<btVector3> vecs1, vecs2, vecs3;
383 if (m_nodeRigidConstraints[i][j].m_static)
384 {
385 vecs1.push_back(btVector3(1, 0, 0));
386 vecs2.push_back(btVector3(0, 1, 0));
387 vecs3.push_back(btVector3(0, 0, 1));
388 m_projections.push_back(btReducedVector(dof, indices, vecs1));
389 m_projections.push_back(btReducedVector(dof, indices, vecs2));
390 m_projections.push_back(btReducedVector(dof, indices, vecs3));
391 }
392 else
393 {
394 vecs1.push_back(m_nodeRigidConstraints[i][j].m_normal);
395 m_projections.push_back(btReducedVector(dof, indices, vecs1));
396 }
397 }
398 for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j)
399 {
400 const btSoftBody::Face* face = m_faceRigidConstraints[i][j].m_face;
401 btVector3 bary = m_faceRigidConstraints[i][j].getContact()->m_bary;
402 btScalar penetration = -m_faceRigidConstraints[i][j].getContact()->m_cti.m_offset;
403 for (int k = 0; k < 3; ++k)
404 {
405 face->m_n[k]->m_penetration = btMax(face->m_n[k]->m_penetration, penetration);
406 }
407 if (m_faceRigidConstraints[i][j].m_static)
408 {
409 for (int l = 0; l < 3; ++l)
410 {
411 btReducedVector rv(dof);
412 for (int k = 0; k < 3; ++k)
413 {
414 rv.m_indices.push_back(face->m_n[k]->index);
415 btVector3 v(0, 0, 0);
416 v[l] = bary[k];
417 rv.m_vecs.push_back(v);
418 rv.sort();
419 }
420 m_projections.push_back(rv);
421 }
422 }
423 else
424 {
425 btReducedVector rv(dof);
426 for (int k = 0; k < 3; ++k)
427 {
428 rv.m_indices.push_back(face->m_n[k]->index);
429 rv.m_vecs.push_back(bary[k] * m_faceRigidConstraints[i][j].m_normal);
430 rv.sort();
431 }
432 m_projections.push_back(rv);
433 }
434 }
435 }
437 mgs.solve();
438 m_projections = mgs.m_out;
439#endif
440}
441
443{
444 for (int i = 0; i < m_lagrangeMultipliers.size(); ++i)
445 {
446 btVector3 d(0, 0, 0);
448 for (int j = 0; j < lm.m_num_constraints; ++j)
449 {
450 for (int k = 0; k < lm.m_num_nodes; ++k)
451 {
452 d[j] += lm.m_weights[k] * x[lm.m_indices[k]].dot(lm.m_dirs[j]);
453 }
454 }
455 // printf("d = %f, %f, %f\n", d[0], d[1], d[2]);
456 // printf("val = %f, %f, %f\n", lm.m_vals[0], lm.m_vals[1], lm.m_vals[2]);
457 }
458}
459
461{
462 for (int i = 0; i < m_softBodies.size(); ++i)
463 {
464 btSoftBody* psb = m_softBodies[i];
465 if (!psb->isActive())
466 {
467 continue;
468 }
469 for (int j = 0; j < m_staticConstraints[i].size(); ++j)
470 {
471 int index = m_staticConstraints[i][j].m_node->index;
472 m_staticConstraints[i][j].m_node->m_constrained = true;
474 lm.m_num_nodes = 1;
475 lm.m_indices[0] = index;
476 lm.m_weights[0] = 1.0;
477 lm.m_num_constraints = 3;
478 lm.m_dirs[0] = btVector3(1, 0, 0);
479 lm.m_dirs[1] = btVector3(0, 1, 0);
480 lm.m_dirs[2] = btVector3(0, 0, 1);
482 }
483 for (int j = 0; j < m_nodeAnchorConstraints[i].size(); ++j)
484 {
485 int index = m_nodeAnchorConstraints[i][j].m_anchor->m_node->index;
486 m_nodeAnchorConstraints[i][j].m_anchor->m_node->m_constrained = true;
488 lm.m_num_nodes = 1;
489 lm.m_indices[0] = index;
490 lm.m_weights[0] = 1.0;
491 lm.m_num_constraints = 3;
492 lm.m_dirs[0] = btVector3(1, 0, 0);
493 lm.m_dirs[1] = btVector3(0, 1, 0);
494 lm.m_dirs[2] = btVector3(0, 0, 1);
496 }
497
498 for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j)
499 {
500 if (!m_nodeRigidConstraints[i][j].m_binding)
501 {
502 continue;
503 }
504 int index = m_nodeRigidConstraints[i][j].m_node->index;
505 m_nodeRigidConstraints[i][j].m_node->m_constrained = true;
507 lm.m_num_nodes = 1;
508 lm.m_indices[0] = index;
509 lm.m_weights[0] = 1.0;
510 if (m_nodeRigidConstraints[i][j].m_static)
511 {
512 lm.m_num_constraints = 3;
513 lm.m_dirs[0] = btVector3(1, 0, 0);
514 lm.m_dirs[1] = btVector3(0, 1, 0);
515 lm.m_dirs[2] = btVector3(0, 0, 1);
516 }
517 else
518 {
519 lm.m_num_constraints = 1;
520 lm.m_dirs[0] = m_nodeRigidConstraints[i][j].m_normal;
521 }
523 }
524
525 for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j)
526 {
527 if (!m_faceRigidConstraints[i][j].m_binding)
528 {
529 continue;
530 }
531 btSoftBody::Face* face = m_faceRigidConstraints[i][j].m_face;
532
533 btVector3 bary = m_faceRigidConstraints[i][j].getContact()->m_bary;
535 lm.m_num_nodes = 3;
536
537 for (int k = 0; k < 3; ++k)
538 {
539 face->m_n[k]->m_constrained = true;
540 lm.m_indices[k] = face->m_n[k]->index;
541 lm.m_weights[k] = bary[k];
542 }
543 if (m_faceRigidConstraints[i][j].m_static)
544 {
545 face->m_pcontact[3] = 1;
546 lm.m_num_constraints = 3;
547 lm.m_dirs[0] = btVector3(1, 0, 0);
548 lm.m_dirs[1] = btVector3(0, 1, 0);
549 lm.m_dirs[2] = btVector3(0, 0, 1);
550 }
551 else
552 {
553 face->m_pcontact[3] = 0;
554 lm.m_num_constraints = 1;
555 lm.m_dirs[0] = m_faceRigidConstraints[i][j].m_normal;
556 }
558 }
559 }
560}
561
562//
564{
565 for (int i = 0; i < m_softBodies.size(); ++i)
566 {
567 for (int j = 0; j < m_nodeRigidConstraints[i].size(); ++j)
568 {
570 const btSoftBody::Node* node = constraint.m_node;
571 if (node->m_im != 0)
572 {
573 int index = node->index;
574 f[index] += constraint.getDv(node) * (1. / node->m_im);
575 }
576 }
577 for (int j = 0; j < m_faceRigidConstraints[i].size(); ++j)
578 {
580 const btSoftBody::Face* face = constraint.getContact()->m_face;
581 for (int k = 0; k < 3; ++k)
582 {
583 const btSoftBody::Node* node = face->m_n[k];
584 if (node->m_im != 0)
585 {
586 int index = node->index;
587 f[index] += constraint.getDv(node) * (1. / node->m_im);
588 }
589 }
590 }
591 for (int j = 0; j < m_deformableConstraints[i].size(); ++j)
592 {
594 const btSoftBody::Face* face = constraint.getContact()->m_face;
595 const btSoftBody::Node* node = constraint.getContact()->m_node;
596 if (node->m_im != 0)
597 {
598 int index = node->index;
599 f[index] += constraint.getDv(node) * (1. / node->m_im);
600 }
601 for (int k = 0; k < 3; ++k)
602 {
603 const btSoftBody::Node* node = face->m_n[k];
604 if (node->m_im != 0)
605 {
606 int index = node->index;
607 f[index] += constraint.getDv(node) * (1. / node->m_im);
608 }
609 }
610 }
611 }
612}
613
615{
616 int N = m_softBodies.size();
617 if (nodeUpdated)
618 {
624 }
625 for (int i = 0; i < N; ++i)
626 {
632 }
633#ifndef USE_MGS
635#else
636 m_projections.clear();
637#endif
639}
const T & btMax(const T &a, const T &b)
Definition: btMinMax.h:27
#define BT_PROFILE(name)
Definition: btQuickprof.h:198
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition: btScalar.h:314
#define SIMD_INFINITY
Definition: btScalar.h:544
#define SIMD_EPSILON
Definition: btScalar.h:543
#define btAssert(x)
Definition: btScalar.h:153
btVector3 btCross(const btVector3 &v1, const btVector3 &v2)
Return the cross product of two vectors.
Definition: btVector3.h:918
int size() const
return the number of elements in the array
void resize(int newsize, const T &fillData=T())
void clear()
clear the array, deallocated memory. Generally it is better to use array.resize(0),...
void push_back(const T &_Val)
btCollisionObject can be used to manage collision detection objects.
btTransform & getWorldTransform()
virtual btScalar update(btCollisionObject **deformableBodies, int numDeformableBodies, const btContactSolverInfo &infoGlobal)
btAlignedObjectArray< LagrangeMultiplier > m_lagrangeMultipliers
virtual void setConstraints(const btContactSolverInfo &infoGlobal)
virtual void reinitialize(bool nodeUpdated)
btAlignedObjectArray< btSoftBody * > & m_softBodies
btAlignedObjectArray< btAlignedObjectArray< btDeformableFaceNodeContactConstraint > > m_deformableConstraints
btScalar solveSplitImpulse(btCollisionObject **deformableBodies, int numDeformableBodies, const btContactSolverInfo &infoGlobal)
btAlignedObjectArray< btAlignedObjectArray< btDeformableNodeRigidContactConstraint > > m_nodeRigidConstraints
btHashMap< btHashInt, btAlignedObjectArray< btVector3 > > m_projectionsDict
btAlignedObjectArray< btAlignedObjectArray< btDeformableStaticConstraint > > m_staticConstraints
btAlignedObjectArray< btAlignedObjectArray< btDeformableFaceRigidContactConstraint > > m_faceRigidConstraints
btAlignedObjectArray< btAlignedObjectArray< btDeformableNodeAnchorConstraint > > m_nodeAnchorConstraints
virtual btVector3 getDv(const btSoftBody::Node *) const
const btSoftBody::DeformableFaceNodeContact * getContact() const
virtual btScalar solveConstraint(const btContactSolverInfo &infoGlobal)
const btSoftBody::DeformableFaceRigidContact * getContact() const
virtual btVector3 getDv(const btSoftBody::Node *) const
virtual btScalar solveConstraint(const btContactSolverInfo &infoGlobal)
virtual btVector3 getDv(const btSoftBody::Node *) const
virtual btScalar solveConstraint(const btContactSolverInfo &infoGlobal)
btScalar solveSplitImpulse(const btContactSolverInfo &infoGlobal)
int getUid1() const
Definition: btHashMap.h:77
void insert(const Key &key, const Value &value)
Definition: btHashMap.h:264
Key getKeyAtIndex(int index)
Definition: btHashMap.h:400
void clear()
Definition: btHashMap.h:461
int size() const
Definition: btHashMap.h:373
const Value * getAtIndex(int index) const
Definition: btHashMap.h:378
const Value * find(const Key &key) const
Definition: btHashMap.h:424
btAlignedObjectArray< TV > m_out
btAlignedObjectArray< int > m_indices
btAlignedObjectArray< btVector3 > m_vecs
The btSoftBody is an class to simulate cloth and volumetric soft bodies.
Definition: btSoftBody.h:75
btAlignedObjectArray< DeformableFaceRigidContact > m_faceRigidContacts
Definition: btSoftBody.h:827
btAlignedObjectArray< DeformableNodeRigidAnchor > m_deformableAnchors
Definition: btSoftBody.h:823
btAlignedObjectArray< DeformableNodeRigidContact > m_nodeRigidContacts
Definition: btSoftBody.h:825
tNodeArray m_nodes
Definition: btSoftBody.h:814
btMatrix3x3 & getBasis()
Return the basis matrix for the rotation.
Definition: btTransform.h:109
btVector3 can be used to represent 3D points and vectors.
Definition: btVector3.h:82
btScalar safeNorm() const
Return the norm (length) of the vector.
Definition: btVector3.h:269
btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition: btVector3.h:303
btVector4 m_pcontact
Definition: btSoftBody.h:311
Node * m_n[3]
Definition: btSoftBody.h:307
const btCollisionObject * m_colObj
Definition: btSoftBody.h:226