2 Written by Xuchen Han <xuchenhan2015@u.northwestern.edu>
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.
16 #ifndef BT_DEFORMABLE_LAGRANGIAN_FORCE_H
17 #define BT_DEFORMABLE_LAGRANGIAN_FORCE_H
19 #include "btSoftBody.h"
20 #include <LinearMath/btHashMap.h>
23 enum btDeformableLagrangianForceType
26 BT_MASSSPRING_FORCE = 2,
27 BT_COROTATED_FORCE = 3,
28 BT_NEOHOOKEAN_FORCE = 4,
29 BT_LINEAR_ELASTICITY_FORCE = 5,
30 BT_MOUSE_PICKING_FORCE = 6
33 static inline double randomDouble(double low, double high)
35 return low + static_cast<double>(rand()) / RAND_MAX * (high - low);
38 class btDeformableLagrangianForce
41 typedef btAlignedObjectArray<btVector3> TVStack;
42 btAlignedObjectArray<btSoftBody*> m_softBodies;
43 const btAlignedObjectArray<btSoftBody::Node*>* m_nodes;
45 btDeformableLagrangianForce()
49 virtual ~btDeformableLagrangianForce() {}
52 virtual void addScaledForces(btScalar scale, TVStack& force) = 0;
55 virtual void addScaledDampingForceDifferential(btScalar scale, const TVStack& dv, TVStack& df) = 0;
57 // build diagonal of A matrix
58 virtual void buildDampingForceDifferentialDiagonal(btScalar scale, TVStack& diagA) = 0;
61 virtual void addScaledElasticForceDifferential(btScalar scale, const TVStack& dx, TVStack& df) = 0;
63 // add all forces that are explicit in explicit solve
64 virtual void addScaledExplicitForce(btScalar scale, TVStack& force) = 0;
66 // add all damping forces
67 virtual void addScaledDampingForce(btScalar scale, TVStack& force) = 0;
69 virtual void addScaledHessian(btScalar scale) {}
71 virtual btDeformableLagrangianForceType getForceType() = 0;
73 virtual void reinitialize(bool nodeUpdated)
77 // get number of nodes that have the force
78 virtual int getNumNodes()
81 for (int i = 0; i < m_softBodies.size(); ++i)
83 numNodes += m_softBodies[i]->m_nodes.size();
88 // add a soft body to be affected by the particular lagrangian force
89 virtual void addSoftBody(btSoftBody* psb)
91 m_softBodies.push_back(psb);
94 virtual void removeSoftBody(btSoftBody* psb)
96 m_softBodies.remove(psb);
99 virtual void setIndices(const btAlignedObjectArray<btSoftBody::Node*>* nodes)
104 // Calculate the incremental deformable generated from the input dx
105 virtual btMatrix3x3 Ds(int id0, int id1, int id2, int id3, const TVStack& dx)
107 btVector3 c1 = dx[id1] - dx[id0];
108 btVector3 c2 = dx[id2] - dx[id0];
109 btVector3 c3 = dx[id3] - dx[id0];
110 return btMatrix3x3(c1, c2, c3).transpose();
113 // Calculate the incremental deformable generated from the current velocity
114 virtual btMatrix3x3 DsFromVelocity(const btSoftBody::Node* n0, const btSoftBody::Node* n1, const btSoftBody::Node* n2, const btSoftBody::Node* n3)
116 btVector3 c1 = n1->m_v - n0->m_v;
117 btVector3 c2 = n2->m_v - n0->m_v;
118 btVector3 c3 = n3->m_v - n0->m_v;
119 return btMatrix3x3(c1, c2, c3).transpose();
122 // test for addScaledElasticForce function
123 virtual void testDerivative()
125 for (int i = 0; i < m_softBodies.size(); ++i)
127 btSoftBody* psb = m_softBodies[i];
128 for (int j = 0; j < psb->m_nodes.size(); ++j)
130 psb->m_nodes[j].m_q += btVector3(randomDouble(-.1, .1), randomDouble(-.1, .1), randomDouble(-.1, .1));
132 psb->updateDeformation();
136 dx.resize(getNumNodes());
138 dphi_dx.resize(dx.size());
139 for (int i = 0; i < dphi_dx.size(); ++i)
141 dphi_dx[i].setZero();
143 addScaledForces(-1, dphi_dx);
145 // write down the current position
149 for (int i = 0; i < m_softBodies.size(); ++i)
151 btSoftBody* psb = m_softBodies[i];
152 for (int j = 0; j < psb->m_nodes.size(); ++j)
154 x[counter] = psb->m_nodes[j].m_q;
160 // populate dx with random vectors
161 for (int i = 0; i < dx.size(); ++i)
163 dx[i].setX(randomDouble(-1, 1));
164 dx[i].setY(randomDouble(-1, 1));
165 dx[i].setZ(randomDouble(-1, 1));
168 btAlignedObjectArray<double> errors;
169 for (int it = 0; it < 10; ++it)
171 for (int i = 0; i < dx.size(); ++i)
178 for (int i = 0; i < dx.size(); ++i)
180 dphi += dphi_dx[i].dot(dx[i]);
183 for (int i = 0; i < m_softBodies.size(); ++i)
185 btSoftBody* psb = m_softBodies[i];
186 for (int j = 0; j < psb->m_nodes.size(); ++j)
188 psb->m_nodes[j].m_q = x[counter] + dx[counter];
191 psb->updateDeformation();
194 double f1 = totalElasticEnergy(0);
196 for (int i = 0; i < m_softBodies.size(); ++i)
198 btSoftBody* psb = m_softBodies[i];
199 for (int j = 0; j < psb->m_nodes.size(); ++j)
201 psb->m_nodes[j].m_q = x[counter] - dx[counter];
204 psb->updateDeformation();
208 double f2 = totalElasticEnergy(0);
211 for (int i = 0; i < m_softBodies.size(); ++i)
213 btSoftBody* psb = m_softBodies[i];
214 for (int j = 0; j < psb->m_nodes.size(); ++j)
216 psb->m_nodes[j].m_q = x[counter];
219 psb->updateDeformation();
222 double error = f1 - f2 - 2 * dphi;
223 errors.push_back(error);
224 std::cout << "Iteration = " << it << ", f1 = " << f1 << ", f2 = " << f2 << ", error = " << error << std::endl;
226 for (int i = 1; i < errors.size(); ++i)
228 std::cout << "Iteration = " << i << ", ratio = " << errors[i - 1] / errors[i] << std::endl;
232 // test for addScaledElasticForce function
233 virtual void testHessian()
235 for (int i = 0; i < m_softBodies.size(); ++i)
237 btSoftBody* psb = m_softBodies[i];
238 for (int j = 0; j < psb->m_nodes.size(); ++j)
240 psb->m_nodes[j].m_q += btVector3(randomDouble(-.1, .1), randomDouble(-.1, .1), randomDouble(-.1, .1));
242 psb->updateDeformation();
246 dx.resize(getNumNodes());
248 df.resize(dx.size());
250 f1.resize(dx.size());
252 f2.resize(dx.size());
254 // write down the current position
258 for (int i = 0; i < m_softBodies.size(); ++i)
260 btSoftBody* psb = m_softBodies[i];
261 for (int j = 0; j < psb->m_nodes.size(); ++j)
263 x[counter] = psb->m_nodes[j].m_q;
269 // populate dx with random vectors
270 for (int i = 0; i < dx.size(); ++i)
272 dx[i].setX(randomDouble(-1, 1));
273 dx[i].setY(randomDouble(-1, 1));
274 dx[i].setZ(randomDouble(-1, 1));
277 btAlignedObjectArray<double> errors;
278 for (int it = 0; it < 10; ++it)
280 for (int i = 0; i < dx.size(); ++i)
286 for (int i = 0; i < df.size(); ++i)
294 addScaledElasticForceDifferential(-1, dx, df);
296 for (int i = 0; i < m_softBodies.size(); ++i)
298 btSoftBody* psb = m_softBodies[i];
299 for (int j = 0; j < psb->m_nodes.size(); ++j)
301 psb->m_nodes[j].m_q = x[counter] + dx[counter];
304 psb->updateDeformation();
309 addScaledForces(-1, f1);
311 for (int i = 0; i < m_softBodies.size(); ++i)
313 btSoftBody* psb = m_softBodies[i];
314 for (int j = 0; j < psb->m_nodes.size(); ++j)
316 psb->m_nodes[j].m_q = x[counter] - dx[counter];
319 psb->updateDeformation();
324 addScaledForces(-1, f2);
327 for (int i = 0; i < m_softBodies.size(); ++i)
329 btSoftBody* psb = m_softBodies[i];
330 for (int j = 0; j < psb->m_nodes.size(); ++j)
332 psb->m_nodes[j].m_q = x[counter];
335 psb->updateDeformation();
339 for (int i = 0; i < df.size(); ++i)
341 btVector3 error_vector = f1[i] - f2[i] - 2 * df[i];
342 error += error_vector.length2();
344 error = btSqrt(error);
345 errors.push_back(error);
346 std::cout << "Iteration = " << it << ", error = " << error << std::endl;
348 for (int i = 1; i < errors.size(); ++i)
350 std::cout << "Iteration = " << i << ", ratio = " << errors[i - 1] / errors[i] << std::endl;
355 virtual double totalElasticEnergy(btScalar dt)
361 virtual double totalDampingEnergy(btScalar dt)
366 // total Energy takes dt as input because certain energies depend on dt
367 virtual double totalEnergy(btScalar dt)
369 return totalElasticEnergy(dt) + totalDampingEnergy(dt);
372 #endif /* BT_DEFORMABLE_LAGRANGIAN_FORCE */