Bullet Collision Detection & Physics Library
btDeformableBodySolver.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 
16 #include <stdio.h>
17 #include <limits>
18 #include "btDeformableBodySolver.h"
19 #include "btSoftBodyInternals.h"
20 #include "LinearMath/btQuickprof.h"
21 static const int kMaxConjugateGradientIterations = 300;
23  : m_numNodes(0), m_cg(kMaxConjugateGradientIterations), m_cr(kMaxConjugateGradientIterations), m_maxNewtonIterations(1), m_newtonTolerance(1e-4), m_lineSearch(false), m_useProjection(false)
24 {
26  m_reducedSolver = false;
27 }
28 
30 {
31  delete m_objective;
32 }
33 
35 {
36  BT_PROFILE("solveDeformableConstraints");
37  if (!m_implicit)
38  {
41  if (m_useProjection)
42  {
44  }
45  else
46  {
47  TVStack rhs, x;
51  computeStep(x, rhs);
52  for (int i = 0; i < m_dv.size(); ++i)
53  {
54  m_dv[i] = x[i];
55  }
56  }
58  }
59  else
60  {
61  for (int i = 0; i < m_maxNewtonIterations; ++i)
62  {
63  updateState();
64  // add the inertia term in the residual
65  int counter = 0;
66  for (int k = 0; k < m_softBodies.size(); ++k)
67  {
68  btSoftBody* psb = m_softBodies[k];
69  for (int j = 0; j < psb->m_nodes.size(); ++j)
70  {
71  if (psb->m_nodes[j].m_im > 0)
72  {
73  m_residual[counter] = (-1. / psb->m_nodes[j].m_im) * m_dv[counter];
74  }
75  ++counter;
76  }
77  }
78 
81  {
82  break;
83  }
84  // todo xuchenhan@: this really only needs to be calculated once
86  if (m_lineSearch)
87  {
88  btScalar inner_product = computeDescentStep(m_ddv, m_residual);
89  btScalar alpha = 0.01, beta = 0.5; // Boyd & Vandenberghe suggested alpha between 0.01 and 0.3, beta between 0.1 to 0.8
90  btScalar scale = 2;
91  btScalar f0 = m_objective->totalEnergy(solverdt) + kineticEnergy(), f1, f2;
92  backupDv();
93  do
94  {
95  scale *= beta;
96  if (scale < 1e-8)
97  {
98  return;
99  }
100  updateEnergy(scale);
101  f1 = m_objective->totalEnergy(solverdt) + kineticEnergy();
102  f2 = f0 - alpha * scale * inner_product;
103  } while (!(f1 < f2 + SIMD_EPSILON)); // if anything here is nan then the search continues
104  revertDv();
105  updateDv(scale);
106  }
107  else
108  {
110  updateDv();
111  }
112  for (int j = 0; j < m_numNodes; ++j)
113  {
114  m_ddv[j].setZero();
115  m_residual[j].setZero();
116  }
117  }
118  updateVelocity();
119  }
120 }
121 
123 {
124  btScalar ke = 0;
125  for (int i = 0; i < m_softBodies.size(); ++i)
126  {
127  btSoftBody* psb = m_softBodies[i];
128  for (int j = 0; j < psb->m_nodes.size(); ++j)
129  {
130  btSoftBody::Node& node = psb->m_nodes[j];
131  if (node.m_im > 0)
132  {
133  ke += m_dv[node.index].length2() * 0.5 / node.m_im;
134  }
135  }
136  }
137  return ke;
138 }
139 
141 {
143  for (int i = 0; i < m_backup_dv.size(); ++i)
144  {
145  m_backup_dv[i] = m_dv[i];
146  }
147 }
148 
150 {
151  for (int i = 0; i < m_backup_dv.size(); ++i)
152  {
153  m_dv[i] = m_backup_dv[i];
154  }
155 }
156 
158 {
159  for (int i = 0; i < m_dv.size(); ++i)
160  {
161  m_dv[i] = m_backup_dv[i] + scale * m_ddv[i];
162  }
163  updateState();
164 }
165 
167 {
168  m_cg.solve(*m_objective, ddv, residual, false);
169  btScalar inner_product = m_cg.dot(residual, m_ddv);
170  btScalar res_norm = m_objective->computeNorm(residual);
171  btScalar tol = 1e-5 * res_norm * m_objective->computeNorm(m_ddv);
172  if (inner_product < -tol)
173  {
174  if (verbose)
175  {
176  std::cout << "Looking backwards!" << std::endl;
177  }
178  for (int i = 0; i < m_ddv.size(); ++i)
179  {
180  m_ddv[i] = -m_ddv[i];
181  }
182  inner_product = -inner_product;
183  }
184  else if (std::abs(inner_product) < tol)
185  {
186  if (verbose)
187  {
188  std::cout << "Gradient Descent!" << std::endl;
189  }
190  btScalar scale = m_objective->computeNorm(m_ddv) / res_norm;
191  for (int i = 0; i < m_ddv.size(); ++i)
192  {
193  m_ddv[i] = scale * residual[i];
194  }
195  inner_product = scale * res_norm * res_norm;
196  }
197  return inner_product;
198 }
199 
201 {
202  updateVelocity();
204 }
205 
207 {
208  for (int i = 0; i < m_numNodes; ++i)
209  {
210  m_dv[i] += scale * m_ddv[i];
211  }
212 }
213 
215 {
216  if (m_useProjection)
217  m_cg.solve(*m_objective, ddv, residual, false);
218  else
219  m_cr.solve(*m_objective, ddv, residual, false);
220 }
221 
223 {
224  m_softBodies.copyFromArray(softBodies);
225  bool nodeUpdated = updateNodes();
226 
227  if (nodeUpdated)
228  {
229  m_dv.resize(m_numNodes, btVector3(0, 0, 0));
230  m_ddv.resize(m_numNodes, btVector3(0, 0, 0));
233  }
234 
235  // need to setZero here as resize only set value for newly allocated items
236  for (int i = 0; i < m_numNodes; ++i)
237  {
238  m_dv[i].setZero();
239  m_ddv[i].setZero();
240  m_residual[i].setZero();
241  }
242 
243  if (dt > 0)
244  {
245  m_dt = dt;
246  }
247  m_objective->reinitialize(nodeUpdated, dt);
249 }
250 
252 {
253  BT_PROFILE("setConstraint");
254  m_objective->setConstraints(infoGlobal);
255 }
256 
257 btScalar btDeformableBodySolver::solveContactConstraints(btCollisionObject** deformableBodies, int numDeformableBodies, const btContactSolverInfo& infoGlobal)
258 {
259  BT_PROFILE("solveContactConstraints");
260  btScalar maxSquaredResidual = m_objective->m_projection.update(deformableBodies, numDeformableBodies, infoGlobal);
261  return maxSquaredResidual;
262 }
263 
265 {
266  int counter = 0;
267  for (int i = 0; i < m_softBodies.size(); ++i)
268  {
269  btSoftBody* psb = m_softBodies[i];
270  psb->m_maxSpeedSquared = 0;
271  if (!psb->isActive())
272  {
273  counter += psb->m_nodes.size();
274  continue;
275  }
276  for (int j = 0; j < psb->m_nodes.size(); ++j)
277  {
278  // set NaN to zero;
279  if (m_dv[counter] != m_dv[counter])
280  {
281  m_dv[counter].setZero();
282  }
283  if (m_implicit)
284  {
285  psb->m_nodes[j].m_v = m_backupVelocity[counter] + m_dv[counter];
286  }
287  else
288  {
289  psb->m_nodes[j].m_v = m_backupVelocity[counter] + m_dv[counter] - psb->m_nodes[j].m_splitv;
290  }
291  psb->m_maxSpeedSquared = btMax(psb->m_maxSpeedSquared, psb->m_nodes[j].m_v.length2());
292  ++counter;
293  }
294  }
295 }
296 
298 {
299  int counter = 0;
300  for (int i = 0; i < m_softBodies.size(); ++i)
301  {
302  btSoftBody* psb = m_softBodies[i];
303  if (!psb->isActive())
304  {
305  counter += psb->m_nodes.size();
306  continue;
307  }
308  for (int j = 0; j < psb->m_nodes.size(); ++j)
309  {
310  psb->m_nodes[j].m_q = psb->m_nodes[j].m_x + m_dt * (psb->m_nodes[j].m_v + psb->m_nodes[j].m_splitv);
311  ++counter;
312  }
313  psb->updateDeformation();
314  }
315 }
316 
318 {
319  int counter = 0;
320  for (int i = 0; i < m_softBodies.size(); ++i)
321  {
322  btSoftBody* psb = m_softBodies[i];
323  for (int j = 0; j < psb->m_nodes.size(); ++j)
324  {
325  m_backupVelocity[counter++] = psb->m_nodes[j].m_v;
326  }
327  }
328 }
329 
331 {
332  int counter = 0;
333  for (int i = 0; i < m_softBodies.size(); ++i)
334  {
335  btSoftBody* psb = m_softBodies[i];
336  if (!psb->isActive())
337  {
338  counter += psb->m_nodes.size();
339  continue;
340  }
341  for (int j = 0; j < psb->m_nodes.size(); ++j)
342  {
343  if (implicit)
344  {
345  // setting the initial guess for newton, need m_dv = v_{n+1} - v_n for dofs that are in constraint.
346  if (psb->m_nodes[j].m_v == m_backupVelocity[counter])
347  m_dv[counter].setZero();
348  else
349  m_dv[counter] = psb->m_nodes[j].m_v - psb->m_nodes[j].m_vn;
350  m_backupVelocity[counter] = psb->m_nodes[j].m_vn;
351  }
352  else
353  {
354  m_dv[counter] = psb->m_nodes[j].m_v + psb->m_nodes[j].m_splitv - m_backupVelocity[counter];
355  }
356  psb->m_nodes[j].m_v = m_backupVelocity[counter];
357  ++counter;
358  }
359  }
360 }
361 
363 {
364  int counter = 0;
365  for (int i = 0; i < m_softBodies.size(); ++i)
366  {
367  btSoftBody* psb = m_softBodies[i];
368  for (int j = 0; j < psb->m_nodes.size(); ++j)
369  {
370  psb->m_nodes[j].m_v = m_backupVelocity[counter++];
371  }
372  }
373 }
374 
376 {
377  int numNodes = 0;
378  for (int i = 0; i < m_softBodies.size(); ++i)
379  numNodes += m_softBodies[i]->m_nodes.size();
380  if (numNodes != m_numNodes)
381  {
382  m_numNodes = numNodes;
383  return true;
384  }
385  return false;
386 }
387 
389 {
390  // apply explicit forces to velocity
391  if (m_implicit)
392  {
393  for (int i = 0; i < m_softBodies.size(); ++i)
394  {
395  btSoftBody* psb = m_softBodies[i];
396  if (psb->isActive())
397  {
398  for (int j = 0; j < psb->m_nodes.size(); ++j)
399  {
400  psb->m_nodes[j].m_q = psb->m_nodes[j].m_x + psb->m_nodes[j].m_v * solverdt;
401  }
402  }
403  }
404  }
406  for (int i = 0; i < m_softBodies.size(); ++i)
407  {
408  btSoftBody* psb = m_softBodies[i];
409  if (psb->isActive())
410  {
411  /* Clear contacts when softbody is active*/
412  psb->m_nodeRigidContacts.resize(0);
413  psb->m_faceRigidContacts.resize(0);
414  psb->m_faceNodeContacts.resize(0);
415  psb->m_faceNodeContactsCCD.resize(0);
416  // predict motion for collision detection
417  predictDeformableMotion(psb, solverdt);
418  }
419  }
420 }
421 
423 {
424  BT_PROFILE("btDeformableBodySolver::predictDeformableMotion");
425  int i, ni;
426 
427  /* Update */
428  if (psb->m_bUpdateRtCst)
429  {
430  psb->m_bUpdateRtCst = false;
431  psb->updateConstants();
432  psb->m_fdbvt.clear();
434  {
435  psb->initializeFaceTree();
436  }
437  }
438 
439  /* Prepare */
440  psb->m_sst.sdt = dt * psb->m_cfg.timescale;
441  psb->m_sst.isdt = 1 / psb->m_sst.sdt;
442  psb->m_sst.velmrg = psb->m_sst.sdt * 3;
443  psb->m_sst.radmrg = psb->getCollisionShape()->getMargin();
444  psb->m_sst.updmrg = psb->m_sst.radmrg * (btScalar)0.25;
445  /* Bounds */
446  psb->updateBounds();
447 
448  /* Integrate */
449  // do not allow particles to move more than the bounding box size
450  btScalar max_v = (psb->m_bounds[1] - psb->m_bounds[0]).norm() / dt;
451  for (i = 0, ni = psb->m_nodes.size(); i < ni; ++i)
452  {
453  btSoftBody::Node& n = psb->m_nodes[i];
454  // apply drag
455  n.m_v *= (1 - psb->m_cfg.drag);
456  // scale velocity back
457  if (m_implicit)
458  {
459  n.m_q = n.m_x;
460  }
461  else
462  {
463  if (n.m_v.norm() > max_v)
464  {
465  n.m_v.safeNormalize();
466  n.m_v *= max_v;
467  }
468  n.m_q = n.m_x + n.m_v * dt;
469  }
470  n.m_splitv.setZero();
471  n.m_constrained = false;
472  }
473 
474  /* Nodes */
475  psb->updateNodeTree(true, true);
476  if (!psb->m_fdbvt.empty())
477  {
478  psb->updateFaceTree(true, true);
479  }
480  /* Optimize dbvt's */
481  // psb->m_ndbvt.optimizeIncremental(1);
482  // psb->m_fdbvt.optimizeIncremental(1);
483 }
484 
486 {
487  BT_PROFILE("updateSoftBodies");
488  for (int i = 0; i < m_softBodies.size(); i++)
489  {
490  btSoftBody* psb = (btSoftBody*)m_softBodies[i];
491  if (psb->isActive())
492  {
493  psb->updateNormals();
494  }
495  }
496 }
497 
499 {
500  m_implicit = implicit;
501  m_objective->setImplicit(implicit);
502 }
503 
505 {
506  m_lineSearch = lineSearch;
507 }
508 
510 {
512 }
513 
515 {
516  for (int i = 0; i < m_softBodies.size(); ++i)
517  {
518  btSoftBody* psb = m_softBodies[i];
519  for (int j = 0; j < psb->m_nodes.size(); ++j)
520  {
521  btSoftBody::Node& node = psb->m_nodes[j];
522  btScalar maxDisplacement = psb->getWorldInfo()->m_maxDisplacement;
523  btScalar clampDeltaV = maxDisplacement / timeStep;
524  for (int c = 0; c < 3; c++)
525  {
526  if (node.m_v[c] > clampDeltaV)
527  {
528  node.m_v[c] = clampDeltaV;
529  }
530  if (node.m_v[c] < -clampDeltaV)
531  {
532  node.m_v[c] = -clampDeltaV;
533  }
534  }
535  node.m_x = node.m_x + timeStep * (node.m_v + node.m_splitv);
536  node.m_q = node.m_x;
537  node.m_vn = node.m_v;
538  }
539  // enforce anchor constraints
540  for (int j = 0; j < psb->m_deformableAnchors.size(); ++j)
541  {
543  btSoftBody::Node* n = a.m_node;
545 
546  // update multibody anchor info
548  {
550  if (multibodyLinkCol)
551  {
552  btVector3 nrm;
553  const btCollisionShape* shp = multibodyLinkCol->getCollisionShape();
554  const btTransform& wtr = multibodyLinkCol->getWorldTransform();
556  wtr.invXform(n->m_x),
557  shp,
558  nrm,
559  0);
560  a.m_cti.m_normal = wtr.getBasis() * nrm;
561  btVector3 normal = a.m_cti.m_normal;
563  btVector3 t2 = btCross(normal, t1);
564  btMultiBodyJacobianData jacobianData_normal, jacobianData_t1, jacobianData_t2;
565  findJacobian(multibodyLinkCol, jacobianData_normal, a.m_node->m_x, normal);
566  findJacobian(multibodyLinkCol, jacobianData_t1, a.m_node->m_x, t1);
567  findJacobian(multibodyLinkCol, jacobianData_t2, a.m_node->m_x, t2);
568 
569  btScalar* J_n = &jacobianData_normal.m_jacobians[0];
570  btScalar* J_t1 = &jacobianData_t1.m_jacobians[0];
571  btScalar* J_t2 = &jacobianData_t2.m_jacobians[0];
572 
573  btScalar* u_n = &jacobianData_normal.m_deltaVelocitiesUnitImpulse[0];
574  btScalar* u_t1 = &jacobianData_t1.m_deltaVelocitiesUnitImpulse[0];
575  btScalar* u_t2 = &jacobianData_t2.m_deltaVelocitiesUnitImpulse[0];
576 
577  btMatrix3x3 rot(normal.getX(), normal.getY(), normal.getZ(),
578  t1.getX(), t1.getY(), t1.getZ(),
579  t2.getX(), t2.getY(), t2.getZ()); // world frame to local frame
580  const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
581  btMatrix3x3 local_impulse_matrix = (Diagonal(n->m_im) + OuterProduct(J_n, J_t1, J_t2, u_n, u_t1, u_t2, ndof)).inverse();
582  a.m_c0 = rot.transpose() * local_impulse_matrix * rot;
583  a.jacobianData_normal = jacobianData_normal;
584  a.jacobianData_t1 = jacobianData_t1;
585  a.jacobianData_t2 = jacobianData_t2;
586  a.t1 = t1;
587  a.t2 = t2;
588  }
589  }
590  }
591  psb->interpolateRenderMesh();
592  }
593 }
static const int kMaxConjugateGradientIterations
const T & btMax(const T &a, const T &b)
Definition: btMinMax.h:27
btQuaternion inverse(const btQuaternion &q)
Return the inverse of a quaternion.
Definition: btQuaternion.h:909
#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_EPSILON
Definition: btScalar.h:543
static btMatrix3x3 OuterProduct(const btScalar *v1, const btScalar *v2, const btScalar *v3, const btScalar *u1, const btScalar *u2, const btScalar *u3, int ndof)
static btVector3 generateUnitOrthogonalVector(const btVector3 &u)
static void findJacobian(const btMultiBodyLinkCollider *multibodyLinkCol, btMultiBodyJacobianData &jacobianData, const btVector3 &contact_point, const btVector3 &dir)
btSoftBody implementation by Nathanael Presson
static btMatrix3x3 Diagonal(btScalar x)
btVector3 btCross(const btVector3 &v1, const btVector3 &v2)
Return the cross product of two vectors.
Definition: btVector3.h:918
virtual void reinitialize(bool nodeUpdated)=0
int size() const
return the number of elements in the array
void copyFromArray(const btAlignedObjectArray &otherArray)
void resize(int newsize, const T &fillData=T())
btCollisionObject can be used to manage collision detection objects.
btTransform & getWorldTransform()
int getInternalType() const
reserved for Bullet internal usage
const btCollisionShape * getCollisionShape() const
The btCollisionShape class provides an interface for collision shapes that can be shared among btColl...
virtual btScalar getMargin() const =0
int solve(MatrixX &A, TVStack &x, const TVStack &b, bool verbose=false)
int solve(MatrixX &A, TVStack &x, const TVStack &b, bool verbose=false)
void setConstraints(const btContactSolverInfo &infoGlobal)
void computeResidual(btScalar dt, TVStack &residual)
void addLagrangeMultiplier(const TVStack &vec, TVStack &extended_vec)
btScalar computeNorm(const TVStack &residual) const
void reinitialize(bool nodeUpdated, btScalar dt)
void addLagrangeMultiplierRHS(const TVStack &residual, const TVStack &m_dv, TVStack &extended_residual)
virtual void updateSoftBodies()
Perform necessary per-step updates of soft bodies such as recomputing normals and bounding boxes.
virtual void solveDeformableConstraints(btScalar solverdt)
void updateEnergy(btScalar scale)
virtual void setConstraints(const btContactSolverInfo &infoGlobal)
btDeformableBackwardEulerObjective * m_objective
virtual void applyTransforms(btScalar timeStep)
btScalar computeDescentStep(TVStack &ddv, const TVStack &residual, bool verbose=false)
void predictDeformableMotion(btSoftBody *psb, btScalar dt)
btConjugateResidual< btDeformableBackwardEulerObjective > m_cr
btConjugateGradient< btDeformableBackwardEulerObjective > m_cg
virtual void reinitialize(const btAlignedObjectArray< btSoftBody * > &softBodies, btScalar dt)
virtual void setupDeformableSolve(bool implicit)
void setLineSearch(bool lineSearch)
btAlignedObjectArray< btSoftBody * > m_softBodies
virtual btScalar solveContactConstraints(btCollisionObject **deformableBodies, int numDeformableBodies, const btContactSolverInfo &infoGlobal)
virtual void predictMotion(btScalar solverdt)
Predict motion of soft bodies into next timestep.
void computeStep(TVStack &ddv, const TVStack &residual)
void updateDv(btScalar scale=1)
virtual btScalar update(btCollisionObject **deformableBodies, int numDeformableBodies, const btContactSolverInfo &infoGlobal)
virtual btScalar dot(const TVStack &a, const TVStack &b)
The btMatrix3x3 class implements a 3x3 rotation matrix, to perform linear algebra in combination with...
Definition: btMatrix3x3.h:50
btMatrix3x3 transpose() const
Return the transpose of the matrix.
Definition: btMatrix3x3.h:1049
static btMultiBodyLinkCollider * upcast(btCollisionObject *colObj)
int getNumDofs() const
Definition: btMultiBody.h:167
btMultiBodyJacobianData jacobianData_t1
Definition: btSoftBody.h:372
btMultiBodyJacobianData jacobianData_normal
Definition: btSoftBody.h:371
btMultiBodyJacobianData jacobianData_t2
Definition: btSoftBody.h:373
The btSoftBody is an class to simulate cloth and volumetric soft bodies.
Definition: btSoftBody.h:75
bool m_bUpdateRtCst
Definition: btSoftBody.h:834
void interpolateRenderMesh()
void updateFaceTree(bool use_velocity, bool margin)
Definition: btSoftBody.h:1300
btSoftBodyWorldInfo * getWorldInfo()
Definition: btSoftBody.h:881
SolverState m_sst
Definition: btSoftBody.h:809
void updateNodeTree(bool use_velocity, bool margin)
Definition: btSoftBody.h:1257
btAlignedObjectArray< DeformableFaceNodeContact > m_faceNodeContactsCCD
Definition: btSoftBody.h:828
btSoftBodyWorldInfo * m_worldInfo
Definition: btSoftBody.h:812
btAlignedObjectArray< DeformableFaceNodeContact > m_faceNodeContacts
Definition: btSoftBody.h:826
Config m_cfg
Definition: btSoftBody.h:808
void updateDeformation()
btVector3 m_bounds[2]
Definition: btSoftBody.h:833
btScalar m_maxSpeedSquared
Definition: btSoftBody.h:842
btAlignedObjectArray< DeformableFaceRigidContact > m_faceRigidContacts
Definition: btSoftBody.h:827
btAlignedObjectArray< DeformableNodeRigidAnchor > m_deformableAnchors
Definition: btSoftBody.h:823
btAlignedObjectArray< DeformableNodeRigidContact > m_nodeRigidContacts
Definition: btSoftBody.h:825
void updateNormals()
btDbvt m_fdbvt
Definition: btSoftBody.h:836
tNodeArray m_nodes
Definition: btSoftBody.h:814
void updateConstants()
void updateBounds()
void initializeFaceTree()
The btTransform class supports rigid transforms with only translation and rotation and no scaling/she...
Definition: btTransform.h:30
btMatrix3x3 & getBasis()
Return the basis matrix for the rotation.
Definition: btTransform.h:109
btVector3 invXform(const btVector3 &inVec) const
Definition: btTransform.h:216
btVector3 can be used to represent 3D points and vectors.
Definition: btVector3.h:82
btVector3 & safeNormalize()
Definition: btVector3.h:286
const btScalar & getX() const
Return the x value.
Definition: btVector3.h:561
btScalar norm() const
Return the norm (length) of the vector.
Definition: btVector3.h:263
const btScalar & getZ() const
Return the z value.
Definition: btVector3.h:565
const btScalar & getY() const
Return the y value.
Definition: btVector3.h:563
void setZero()
Definition: btVector3.h:671
bool empty() const
Definition: btDbvt.h:314
void clear()
Definition: btDbvt.cpp:477
btAlignedObjectArray< btScalar > m_deltaVelocitiesUnitImpulse
btAlignedObjectArray< btScalar > m_jacobians
btSparseSdf< 3 > m_sparsesdf
Definition: btSoftBody.h:57
btScalar m_maxDisplacement
Definition: btSoftBody.h:52
btScalar timescale
Definition: btSoftBody.h:730
btVector3 m_x
Definition: btSoftBody.h:269
btVector3 m_splitv
Definition: btSoftBody.h:281
btVector3 m_vn
Definition: btSoftBody.h:272
btVector3 m_v
Definition: btSoftBody.h:271
btVector3 m_q
Definition: btSoftBody.h:270
@ SDF_RD
Cluster vs convex rigid vs soft.
Definition: btSoftBody.h:166
const btCollisionObject * m_colObj
Definition: btSoftBody.h:226
btVector3 m_normal
Definition: btSoftBody.h:227
btScalar Evaluate(const btVector3 &x, const btCollisionShape *shape, btVector3 &normal, btScalar margin)
Definition: btSparseSDF.h:196