Bullet Collision Detection & Physics Library
btReducedDeformableContactConstraint.cpp
Go to the documentation of this file.
2 #include <iostream>
3 
4 // ================= static constraints ===================
7  btSoftBody::Node* node,
8  const btVector3& ri,
9  const btVector3& x0,
10  const btVector3& dir,
11  const btContactSolverInfo& infoGlobal,
12  btScalar dt)
13  : m_rsb(rsb), m_ri(ri), m_targetPos(x0), m_impulseDirection(dir), m_dt(dt), btDeformableStaticConstraint(node, infoGlobal)
14 {
15  m_erp = 0.2;
16  m_appliedImpulse = 0;
17 
18  // get impulse factor
21 
22  btScalar vel_error = btDot(-m_node->m_v, m_impulseDirection);
24 
25  m_rhs = (vel_error + m_erp * pos_error / m_dt) / m_impulseFactor;
26 }
27 
29 {
30  // target velocity of fixed constraint is 0
31  btVector3 deltaVa = getDeltaVa();
32  btScalar deltaV_rel = btDot(deltaVa, m_impulseDirection);
33  btScalar deltaImpulse = m_rhs - deltaV_rel / m_impulseFactor;
34  m_appliedImpulse = m_appliedImpulse + deltaImpulse;
35 
36  btVector3 impulse = deltaImpulse * m_impulseDirection;
37  applyImpulse(impulse);
38 
39  // calculate residual
40  btScalar residualSquare = m_impulseFactor * deltaImpulse;
41  residualSquare *= residualSquare;
42 
43  return residualSquare;
44 }
45 
46 // this calls reduced deformable body's internalApplyFullSpaceImpulse
48 {
49  // apply full space impulse
51 }
52 
54 {
56 }
57 
58 // ================= base contact constraints ===================
62  const btContactSolverInfo& infoGlobal,
63  btScalar dt)
64  : m_rsb(rsb), m_dt(dt), btDeformableRigidContactConstraint(c, infoGlobal)
65 {
66  m_nodeQueryIndex = 0;
69  m_rhs = 0;
70  m_rhs_tangent = 0;
71  m_cfm = infoGlobal.m_deformable_cfm;
72  m_cfm_friction = 0;
73  m_erp = infoGlobal.m_deformable_erp;
74  m_erp_friction = infoGlobal.m_deformable_erp;
75  m_friction = infoGlobal.m_friction;
76 
79 }
80 
82 {
83  if (!m_collideMultibody)
84  {
85  m_solverBodyId = bodyId;
86  m_solverBody = &solver_body;
90 
92  btVector3 torqueAxisTangent = m_relPosA.cross(m_contactTangent);
94  }
95 }
96 
98 {
99  btVector3 Va(0, 0, 0);
100  if (!m_collideStatic)
101  {
103  }
104  return Va;
105 }
106 
108 {
109  // btVector3 Va = getVa();
110  // btVector3 deltaVa = Va - m_bufferVelocityA;
111  // if (!m_collideStatic)
112  // {
113  // std::cout << "moving collision!!!\n";
114  // std::cout << "relPosA: " << m_relPosA[0] << "\t" << m_relPosA[1] << "\t" << m_relPosA[2] << "\n";
115  // std::cout << "moving rigid linear_vel: " << m_solverBody->m_originalBody->getLinearVelocity()[0] << '\t'
116  // << m_solverBody->m_originalBody->getLinearVelocity()[1] << '\t'
117  // << m_solverBody->m_originalBody->getLinearVelocity()[2] << '\n';
118  // }
119  btVector3 deltaVa = getDeltaVa();
120  btVector3 deltaVb = getDeltaVb();
121 
122  // if (!m_collideStatic)
123  // {
124  // std::cout << "deltaVa: " << deltaVa[0] << '\t' << deltaVa[1] << '\t' << deltaVa[2] << '\n';
125  // std::cout << "deltaVb: " << deltaVb[0] << '\t' << deltaVb[1] << '\t' << deltaVb[2] << '\n';
126  // }
127 
128  // get delta relative velocity and magnitude (i.e., how much impulse has been applied?)
129  btVector3 deltaV_rel = deltaVa - deltaVb;
130  btScalar deltaV_rel_normal = -btDot(deltaV_rel, m_contactNormalA);
131 
132  // if (!m_collideStatic)
133  // {
134  // std::cout << "deltaV_rel: " << deltaV_rel[0] << '\t' << deltaV_rel[1] << '\t' << deltaV_rel[2] << "\n";
135  // std::cout << "deltaV_rel_normal: " << deltaV_rel_normal << "\n";
136  // std::cout << "normal_A: " << m_contactNormalA[0] << '\t' << m_contactNormalA[1] << '\t' << m_contactNormalA[2] << '\n';
137  // }
138 
139  // get the normal impulse to be applied
140  btScalar deltaImpulse = m_rhs - m_appliedNormalImpulse * m_cfm - deltaV_rel_normal / m_normalImpulseFactor;
141  // if (!m_collideStatic)
142  // {
143  // std::cout << "m_rhs: " << m_rhs << '\t' << "m_appliedNormalImpulse: " << m_appliedNormalImpulse << "\n";
144  // std::cout << "m_normalImpulseFactor: " << m_normalImpulseFactor << '\n';
145  // }
146 
147  {
148  // cumulative impulse that has been applied
149  btScalar sum = m_appliedNormalImpulse + deltaImpulse;
150  // if the cumulative impulse is pushing the object into the rigid body, set it zero
151  if (sum < 0)
152  {
153  deltaImpulse = -m_appliedNormalImpulse;
155  }
156  else
157  {
159  }
160  }
161 
162  // if (!m_collideStatic)
163  // {
164  // std::cout << "m_appliedNormalImpulse: " << m_appliedNormalImpulse << '\n';
165  // std::cout << "deltaImpulse: " << deltaImpulse << '\n';
166  // }
167 
168  // residual is the nodal normal velocity change in current iteration
169  btScalar residualSquare = deltaImpulse * m_normalImpulseFactor; // get residual
170  residualSquare *= residualSquare;
171 
172 
173  // apply Coulomb friction (based on delta velocity, |dv_t| = |dv_n * friction|)
174  btScalar deltaImpulse_tangent = 0;
175  btScalar deltaImpulse_tangent2 = 0;
176  {
177  // calculate how much impulse is needed
178  // btScalar deltaV_rel_tangent = btDot(deltaV_rel, m_contactTangent);
179  // btScalar impulse_changed = deltaV_rel_tangent * m_tangentImpulseFactorInv;
180  // deltaImpulse_tangent = m_rhs_tangent - impulse_changed;
181 
182  // btScalar sum = m_appliedTangentImpulse + deltaImpulse_tangent;
183  btScalar lower_limit = - m_appliedNormalImpulse * m_friction;
185  // if (sum > upper_limit)
186  // {
187  // deltaImpulse_tangent = upper_limit - m_appliedTangentImpulse;
188  // m_appliedTangentImpulse = upper_limit;
189  // }
190  // else if (sum < lower_limit)
191  // {
192  // deltaImpulse_tangent = lower_limit - m_appliedTangentImpulse;
193  // m_appliedTangentImpulse = lower_limit;
194  // }
195  // else
196  // {
197  // m_appliedTangentImpulse = sum;
198  // }
199  //
201  m_tangentImpulseFactorInv, m_contactTangent, lower_limit, upper_limit, deltaV_rel);
202 
203  if (m_collideMultibody)
204  {
206  m_tangentImpulseFactorInv2, m_contactTangent2, lower_limit, upper_limit, deltaV_rel);
207  }
208 
209 
210  if (!m_collideStatic)
211  {
212  // std::cout << "m_contactTangent: " << m_contactTangent[0] << "\t" << m_contactTangent[1] << "\t" << m_contactTangent[2] << "\n";
213  // std::cout << "deltaV_rel_tangent: " << deltaV_rel_tangent << '\n';
214  // std::cout << "deltaImpulseTangent: " << deltaImpulse_tangent << '\n';
215  // std::cout << "m_appliedTangentImpulse: " << m_appliedTangentImpulse << '\n';
216  }
217  }
218 
219  // get the total impulse vector
220  btVector3 impulse_normal = deltaImpulse * m_contactNormalA;
221  btVector3 impulse_tangent = deltaImpulse_tangent * (-m_contactTangent);
222  btVector3 impulse_tangent2 = deltaImpulse_tangent2 * (-m_contactTangent2);
223  btVector3 impulse = impulse_normal + impulse_tangent + impulse_tangent2;
224 
225  applyImpulse(impulse);
226 
227  // apply impulse to the rigid/multibodies involved and change their velocities
228  if (!m_collideStatic)
229  {
230  // std::cout << "linear_component: " << m_linearComponentNormal[0] << '\t'
231  // << m_linearComponentNormal[1] << '\t'
232  // << m_linearComponentNormal[2] << '\n';
233  // std::cout << "angular_component: " << m_angularComponentNormal[0] << '\t'
234  // << m_angularComponentNormal[1] << '\t'
235  // << m_angularComponentNormal[2] << '\n';
236 
237  if (!m_collideMultibody) // collision with rigid body
238  {
239  // std::cout << "rigid impulse applied!!\n";
240  // std::cout << "delta Linear: " << m_solverBody->getDeltaLinearVelocity()[0] << '\t'
241  // << m_solverBody->getDeltaLinearVelocity()[1] << '\t'
242  // << m_solverBody->getDeltaLinearVelocity()[2] << '\n';
243  // std::cout << "delta Angular: " << m_solverBody->getDeltaAngularVelocity()[0] << '\t'
244  // << m_solverBody->getDeltaAngularVelocity()[1] << '\t'
245  // << m_solverBody->getDeltaAngularVelocity()[2] << '\n';
246 
249 
250  // std::cout << "after\n";
251  // std::cout << "rigid impulse applied!!\n";
252  // std::cout << "delta Linear: " << m_solverBody->getDeltaLinearVelocity()[0] << '\t'
253  // << m_solverBody->getDeltaLinearVelocity()[1] << '\t'
254  // << m_solverBody->getDeltaLinearVelocity()[2] << '\n';
255  // std::cout << "delta Angular: " << m_solverBody->getDeltaAngularVelocity()[0] << '\t'
256  // << m_solverBody->getDeltaAngularVelocity()[1] << '\t'
257  // << m_solverBody->getDeltaAngularVelocity()[2] << '\n';
258  }
259  else // collision with multibody
260  {
261  btMultiBodyLinkCollider* multibodyLinkCol = 0;
263  if (multibodyLinkCol)
264  {
266  // apply normal component of the impulse
267  multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_normal, -deltaImpulse);
268 
269  // const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
270  // std::cout << "deltaV_normal: ";
271  // for (int i = 0; i < ndof; ++i)
272  // {
273  // std::cout << i << "\t" << deltaV_normal[i] << '\n';
274  // }
275 
276  if (impulse_tangent.norm() > SIMD_EPSILON)
277  {
278  // apply tangential component of the impulse
280  multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_t1, deltaImpulse_tangent);
282  multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof2(deltaV_t2, deltaImpulse_tangent2);
283  }
284  }
285  }
286  }
287  return residualSquare;
288 }
289 
291  btScalar& appliedImpulse,
292  const btScalar rhs_tangent,
293  const btScalar tangentImpulseFactorInv,
294  const btVector3& tangent,
295  const btScalar lower_limit,
296  const btScalar upper_limit,
297  const btVector3& deltaV_rel)
298 {
299  btScalar deltaV_rel_tangent = btDot(deltaV_rel, tangent);
300  btScalar impulse_changed = deltaV_rel_tangent * tangentImpulseFactorInv;
301  deltaImpulse_tangent = rhs_tangent - m_cfm_friction * appliedImpulse - impulse_changed;
302 
303  btScalar sum = appliedImpulse + deltaImpulse_tangent;
304  if (sum > upper_limit)
305  {
306  deltaImpulse_tangent = upper_limit - appliedImpulse;
307  appliedImpulse = upper_limit;
308  }
309  else if (sum < lower_limit)
310  {
311  deltaImpulse_tangent = lower_limit - appliedImpulse;
312  appliedImpulse = lower_limit;
313  }
314  else
315  {
316  appliedImpulse = sum;
317  }
318 }
319 
320 // ================= node vs rigid constraints ===================
324  const btContactSolverInfo& infoGlobal,
325  btScalar dt)
326  : m_node(contact.m_node), btReducedDeformableRigidContactConstraint(rsb, contact, infoGlobal, dt)
327 {
328  m_contactNormalA = contact.m_cti.m_normal;
329  m_contactNormalB = -contact.m_cti.m_normal;
330 
331  if (contact.m_node->index < rsb->m_nodes.size())
332  {
333  m_nodeQueryIndex = contact.m_node->index;
334  }
335  else
336  {
338  }
339 
341  {
342  m_relPosA = contact.m_c1;
343  }
344  else
345  {
346  m_relPosA = btVector3(0,0,0);
347  }
349 
350  if (m_collideStatic) // colliding with static object, only consider reduced deformable body's impulse factor
351  {
353  }
354  else // colliding with dynamic object, consider both reduced deformable and rigid body's impulse factors
355  {
357  }
358 
361 
362  warmStarting();
363 }
364 
366 {
367  btVector3 va = getVa();
368  btVector3 vb = getVb();
369  m_bufferVelocityA = va;
370  m_bufferVelocityB = vb;
371 
372  // we define the (+) direction of errors to be the outward surface normal of the rigid object
373  btVector3 v_rel = vb - va;
374  // get tangent direction of the relative velocity
375  btVector3 v_tangent = v_rel - v_rel.dot(m_contactNormalA) * m_contactNormalA;
376  if (v_tangent.norm() < SIMD_EPSILON)
377  {
378  m_contactTangent = btVector3(0, 0, 0);
379  // tangent impulse factor
382  }
383  else
384  {
385  if (!m_collideMultibody)
386  {
387  m_contactTangent = v_tangent.normalized();
389  // tangent impulse factor 1
392  // tangent impulse factor 2
395  }
396  else // multibody requires 2 contact directions
397  {
400 
401  // tangent impulse factor 1
404  // tangent impulse factor 2
407  }
408  }
409 
410 
411  // initial guess for normal impulse
412  {
413  btScalar velocity_error = btDot(v_rel, m_contactNormalA); // magnitude of relative velocity
414  btScalar position_error = 0;
415  if (m_penetration > 0)
416  {
417  velocity_error += m_penetration / m_dt;
418  }
419  else
420  {
421  // add penetration correction vel
422  position_error = m_penetration * m_erp / m_dt;
423  }
424  // get the initial estimate of impulse magnitude to be applied
425  m_rhs = -(velocity_error + position_error) / m_normalImpulseFactor;
426  }
427 
428  // initial guess for tangential impulse
429  {
430  btScalar velocity_error = btDot(v_rel, m_contactTangent);
431  m_rhs_tangent = velocity_error * m_tangentImpulseFactorInv;
432 
433  if (m_collideMultibody)
434  {
435  btScalar velocity_error2 = btDot(v_rel, m_contactTangent2);
436  m_rhs_tangent2 = velocity_error2 * m_tangentImpulseFactorInv2;
437  }
438  }
439 
440  // warm starting
441  // applyImpulse(m_rhs * m_contactNormalA);
442  // if (!m_collideStatic)
443  // {
444  // const btSoftBody::sCti& cti = m_contact->m_cti;
445  // if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
446  // {
447  // m_solverBody->internalApplyImpulse(m_linearComponentNormal, m_angularComponentNormal, -m_rhs);
448  // }
449  // }
450 }
451 
453 {
454  return m_node->m_v;
455 }
456 
458 {
459  btVector3 deltaVa(0, 0, 0);
460  if (!m_collideStatic)
461  {
462  if (!m_collideMultibody) // for rigid body
463  {
465  }
466  else // for multibody
467  {
468  btMultiBodyLinkCollider* multibodyLinkCol = 0;
470  if (multibodyLinkCol)
471  {
472  const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
474  const btScalar* J_t1 = &m_contact->jacobianData_t1.m_jacobians[0];
475  const btScalar* J_t2 = &m_contact->jacobianData_t2.m_jacobians[0];
476  const btScalar* local_dv = multibodyLinkCol->m_multiBody->getDeltaVelocityVector();
477  // add in the normal component of the va
478  btScalar vel = 0;
479  for (int k = 0; k < ndof; ++k)
480  {
481  vel += local_dv[k] * J_n[k];
482  }
483  deltaVa = m_contact->m_cti.m_normal * vel;
484 
485  // add in the tangential components of the va
486  vel = 0;
487  for (int k = 0; k < ndof; ++k)
488  {
489  vel += local_dv[k] * J_t1[k];
490  }
491  deltaVa += m_contact->t1 * vel;
492 
493  vel = 0;
494  for (int k = 0; k < ndof; ++k)
495  {
496  vel += local_dv[k] * J_t2[k];
497  }
498  deltaVa += m_contact->t2 * vel;
499  }
500  }
501  }
502  return deltaVa;
503 }
504 
506 {
507  // std::cout << "node: " << m_node->index << '\n';
509 }
510 
512 {
513  return m_node->m_splitv;
514 }
515 
517 {
519 }
520 
522 {
524  // m_rsb->applyFullSpaceImpulse(impulse, m_relPosB, m_node->index, m_dt);
525  // m_rsb->mapToFullVelocity(m_rsb->getInterpolationWorldTransform());
526  // if (!m_collideStatic)
527  // {
528  // // std::cout << "impulse applied: " << impulse[0] << '\t' << impulse[1] << '\t' << impulse[2] << '\n';
529  // // std::cout << "node: " << m_node->index << " vel: " << m_node->m_v[0] << '\t' << m_node->m_v[1] << '\t' << m_node->m_v[2] << '\n';
530  // btVector3 v_after = getDeltaVb() + m_node->m_v;
531  // // std::cout << "vel after: " << v_after[0] << '\t' << v_after[1] << '\t' << v_after[2] << '\n';
532  // }
533  // std::cout << "node: " << m_node->index << " pos: " << m_node->m_x[0] << '\t' << m_node->m_x[1] << '\t' << m_node->m_x[2] << '\n';
534 }
535 
536 // ================= face vs rigid constraints ===================
540  const btContactSolverInfo& infoGlobal,
541  btScalar dt,
542  bool useStrainLimiting)
543  : m_face(contact.m_face), m_useStrainLimiting(useStrainLimiting), btReducedDeformableRigidContactConstraint(rsb, contact, infoGlobal, dt)
544 {}
545 
547 {
549  btVector3 vb = m_face->m_n[0]->m_v * contact->m_bary[0] + m_face->m_n[1]->m_v * contact->m_bary[1] + m_face->m_n[2]->m_v * contact->m_bary[2];
550  return vb;
551 }
552 
554 {
556  btVector3 vb = (m_face->m_n[0]->m_splitv) * contact->m_bary[0] + (m_face->m_n[1]->m_splitv) * contact->m_bary[1] + (m_face->m_n[2]->m_splitv) * contact->m_bary[2];
557  return vb;
558 }
559 
561 {
564  if (m_face->m_n[0] == node)
565  {
566  return face_dv * contact->m_weights[0];
567  }
568  if (m_face->m_n[1] == node)
569  {
570  return face_dv * contact->m_weights[1];
571  }
572  btAssert(node == m_face->m_n[2]);
573  return face_dv * contact->m_weights[2];
574 }
575 
577 {
578  //
579 }
btScalar dot(const btQuaternion &q1, const btQuaternion &q2)
Calculate the dot product between two quaternions.
Definition: btQuaternion.h:888
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
#define btAssert(x)
Definition: btScalar.h:153
static T sum(const btAlignedObjectArray< T > &items)
btScalar btDot(const btVector3 &v1, const btVector3 &v2)
Return the dot product between two vectors.
Definition: btVector3.h:890
int size() const
return the number of elements in the array
const btTransform & getInterpolationWorldTransform() const
int getInternalType() const
reserved for Bullet internal usage
bool isStaticObject() const
const btSoftBody::DeformableRigidContact * m_contact
static btMultiBodyLinkCollider * upcast(btCollisionObject *colObj)
const btScalar * getDeltaVelocityVector() const
Definition: btMultiBody.h:307
int getNumDofs() const
Definition: btMultiBody.h:167
void applyDeltaVeeMultiDof2(const btScalar *delta_vee, btScalar multiplier)
Definition: btMultiBody.h:428
virtual btMatrix3x3 getImpulseFactor(int n_node)
const btVector3 internalComputeNodeDeltaVelocity(const btTransform &ref_trans, int n_node) const
void internalApplyFullSpaceImpulse(const btVector3 &impulse, const btVector3 &rel_pos, int n_node, btScalar dt)
virtual btVector3 getDv(const btSoftBody::Node *) const
const btSoftBody::DeformableFaceRigidContact * getContact() const
virtual btVector3 getDv(const btSoftBody::Node *) const
virtual btScalar solveConstraint(const btContactSolverInfo &infoGlobal)
void setSolverBody(const int bodyId, btSolverBody &solver_body)
void calculateTangentialImpulse(btScalar &deltaImpulse_tangent, btScalar &appliedImpulse, const btScalar rhs_tangent, const btScalar tangentImpulseFactorInv, const btVector3 &tangent, const btScalar lower_limit, const btScalar upper_limit, const btVector3 &deltaV_rel)
virtual btVector3 getDeltaVb() const =0
virtual btVector3 getDeltaVa() const =0
virtual void applyImpulse(const btVector3 &impulse)
virtual btScalar solveConstraint(const btContactSolverInfo &infoGlobal)
const btMatrix3x3 & getInvInertiaTensorWorld() const
Definition: btRigidBody.h:265
btMultiBodyJacobianData jacobianData_t1
Definition: btSoftBody.h:372
btMultiBodyJacobianData jacobianData_normal
Definition: btSoftBody.h:371
btMultiBodyJacobianData jacobianData_t2
Definition: btSoftBody.h:373
tNodeArray m_nodes
Definition: btSoftBody.h:814
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
btVector3 cross(const btVector3 &v) const
Return the cross product between this and another vector.
Definition: btVector3.h:380
btScalar dot(const btVector3 &v) const
Return the dot product.
Definition: btVector3.h:229
btScalar norm() const
Return the norm (length) of the vector.
Definition: btVector3.h:263
btVector3 normalized() const
Return a normalized version of this vector.
Definition: btVector3.h:949
void setZero()
Definition: btVector3.h:671
btAlignedObjectArray< btScalar > m_deltaVelocitiesUnitImpulse
btAlignedObjectArray< btScalar > m_jacobians
Node * m_n[3]
Definition: btSoftBody.h:307
btVector3 m_x
Definition: btSoftBody.h:269
btVector3 m_splitv
Definition: btSoftBody.h:281
btVector3 m_v
Definition: btSoftBody.h:271
const btCollisionObject * m_colObj
Definition: btSoftBody.h:226
btVector3 m_normal
Definition: btSoftBody.h:227
The btSolverBody is an internal datastructure for the constraint solver. Only necessary data is packe...
Definition: btSolverBody.h:105
btRigidBody * m_originalBody
Definition: btSolverBody.h:120
btVector3 & internalGetDeltaAngularVelocity()
Definition: btSolverBody.h:202
void internalApplyImpulse(const btVector3 &linearComponent, const btVector3 &angularComponent, const btScalar impulseMagnitude)
Definition: btSolverBody.h:243
const btVector3 & internalGetInvMass() const
Definition: btSolverBody.h:212
btVector3 & internalGetDeltaLinearVelocity()
some internal methods, don't use them
Definition: btSolverBody.h:197