Panda3D
bulletSoftBodyNode.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file bulletSoftBodyNode.cxx
10  * @author enn0x
11  * @date 2010-12-27
12  */
13 
14 #include "bulletSoftBodyNode.h"
15 
16 #include "bulletSoftBodyConfig.h"
17 #include "bulletSoftBodyControl.h"
18 #include "bulletSoftBodyMaterial.h"
19 #include "bulletSoftBodyShape.h"
21 #include "bulletHelper.h"
22 #include "bulletWorld.h"
23 
24 #include "geomVertexRewriter.h"
25 #include "geomVertexReader.h"
26 
27 TypeHandle BulletSoftBodyNode::_type_handle;
28 
29 /**
30  *
31  */
32 BulletSoftBodyNode::
33 BulletSoftBodyNode(btSoftBody *body, const char *name) : BulletBodyNode(name) {
34 
35  // Synchronised transform
36  _sync = TransformState::make_identity();
37  _sync_disable = false;
38 
39  // Softbody
40  _soft = body;
41  _soft->setUserPointer(this);
42 
43  // Shape
44  btCollisionShape *shape_ptr = _soft->getCollisionShape();
45 
46  nassertv(shape_ptr != nullptr);
47  nassertv(shape_ptr->getShapeType() == SOFTBODY_SHAPE_PROXYTYPE);
48 
49  _shapes.push_back(new BulletSoftBodyShape((btSoftBodyCollisionShape *)shape_ptr));
50 
51  // Rendering
52  _geom = nullptr;
53  _curve = nullptr;
54  _surface = nullptr;
55 }
56 
57 /**
58  *
59  */
60 btCollisionObject *BulletSoftBodyNode::
61 get_object() const {
62 
63  return _soft;
64 }
65 
66 /**
67  *
68  */
69 BulletSoftBodyConfig BulletSoftBodyNode::
70 get_cfg() {
71  LightMutexHolder holder(BulletWorld::get_global_lock());
72 
73  return BulletSoftBodyConfig(_soft->m_cfg);
74 }
75 
76 /**
77  *
78  */
79 BulletSoftBodyWorldInfo BulletSoftBodyNode::
80 get_world_info() {
81  LightMutexHolder holder(BulletWorld::get_global_lock());
82 
83  return BulletSoftBodyWorldInfo(*(_soft->m_worldInfo));
84 }
85 
86 /**
87  *
88  */
89 int BulletSoftBodyNode::
90 get_num_materials() const {
91  LightMutexHolder holder(BulletWorld::get_global_lock());
92 
93  return _soft->m_materials.size();
94 }
95 
96 /**
97  *
98  */
99 BulletSoftBodyMaterial BulletSoftBodyNode::
100 get_material(int idx) const {
101  LightMutexHolder holder(BulletWorld::get_global_lock());
102 
103  nassertr(idx >= 0 && idx < _soft->m_materials.size(), BulletSoftBodyMaterial::empty());
104 
105  btSoftBody::Material *material = _soft->m_materials[idx];
106  return BulletSoftBodyMaterial(*material);
107 }
108 
109 /**
110  *
111  */
112 BulletSoftBodyMaterial BulletSoftBodyNode::
113 append_material() {
114  LightMutexHolder holder(BulletWorld::get_global_lock());
115 
116  btSoftBody::Material *material = _soft->appendMaterial();
117  nassertr(material, BulletSoftBodyMaterial::empty());
118 
119  return BulletSoftBodyMaterial(*material);
120 }
121 
122 /**
123  *
124  */
125 int BulletSoftBodyNode::
126 get_num_nodes() const {
127  LightMutexHolder holder(BulletWorld::get_global_lock());
128 
129  return _soft->m_nodes.size();
130 }
131 
132 /**
133  *
134  */
135 BulletSoftBodyNodeElement BulletSoftBodyNode::
136 get_node(int idx) const {
137  LightMutexHolder holder(BulletWorld::get_global_lock());
138 
139  nassertr(idx >= 0 && idx < _soft->m_nodes.size(), BulletSoftBodyNodeElement::empty());
140  return BulletSoftBodyNodeElement(_soft->m_nodes[idx]);
141 }
142 
143 /**
144  *
145  */
146 void BulletSoftBodyNode::
147 generate_bending_constraints(int distance, BulletSoftBodyMaterial *material) {
148  LightMutexHolder holder(BulletWorld::get_global_lock());
149 
150  if (material) {
151  _soft->generateBendingConstraints(distance, &(material->get_material()));
152  }
153  else {
154  _soft->generateBendingConstraints(distance);
155  }
156 }
157 
158 /**
159  *
160  */
161 void BulletSoftBodyNode::
162 randomize_constraints() {
163  LightMutexHolder holder(BulletWorld::get_global_lock());
164 
165  _soft->randomizeConstraints();
166 }
167 
168 /**
169  *
170  */
171 void BulletSoftBodyNode::
172 transform_changed() {
173  if (_sync_disable) return;
174 
175  LightMutexHolder holder(BulletWorld::get_global_lock());
176 
177  NodePath np = NodePath::any_path((PandaNode *)this);
178  CPT(TransformState) ts = np.get_net_transform();
179 
180  LMatrix4 m_sync = _sync->get_mat();
181  LMatrix4 m_ts = ts->get_mat();
182 
183  if (!m_sync.almost_equal(m_ts)) {
184 
185  // New transform for the center
186  btTransform trans = TransformState_to_btTrans(ts);
187 
188  // Offset between current approx center and current initial transform
189  btVector3 pos = LVecBase3_to_btVector3(this->do_get_aabb().get_approx_center());
190 #if BT_BULLET_VERSION >= 290
191  btVector3 origin = _soft->getWorldTransform().getOrigin();
192 #else
193  btVector3 origin = _soft->m_initialWorldTransform.getOrigin();
194 #endif
195  btVector3 offset = pos - origin;
196 
197  // Subtract offset to get new transform for the body
198  trans.setOrigin(trans.getOrigin() - offset);
199 
200  // Now apply the new transform
201 #if BT_BULLET_VERSION >= 290
202  _soft->transform(_soft->getWorldTransform().inverse());
203 #else
204  _soft->transform(_soft->m_initialWorldTransform.inverse());
205 #endif
206  _soft->transform(trans);
207 
208  if (ts->has_scale()) {
209  btVector3 current_scale = LVecBase3_to_btVector3(_sync->get_scale());
210  btVector3 new_scale = LVecBase3_to_btVector3(ts->get_scale());
211 
212  current_scale.setX(1.0 / current_scale.getX());
213  current_scale.setY(1.0 / current_scale.getY());
214  current_scale.setZ(1.0 / current_scale.getZ());
215 
216  _soft->scale(current_scale);
217  _soft->scale(new_scale);
218  }
219 
220  _sync = std::move(ts);
221  }
222 }
223 
224 /**
225  *
226  */
227 void BulletSoftBodyNode::
228 do_sync_p2b() {
229 
230  // transform_changed(); Disabled for now...
231 }
232 
233 /**
234  * Assumes the lock(bullet global lock) is held by the caller
235  */
237 do_sync_b2p() {
238 
239  // Render softbody
240  if (_geom) {
241  btTransform trans = btTransform::getIdentity();
242  get_node_transform(trans, this);
243 
244  PT(GeomVertexData) vdata = _geom->modify_vertex_data();
245 
246  GeomVertexRewriter vertices(vdata, InternalName::get_vertex());
247  GeomVertexRewriter normals(vdata, InternalName::get_normal());
248  GeomVertexReader indices(vdata, BulletHelper::get_sb_index());
249  GeomVertexReader flips(vdata, BulletHelper::get_sb_flip());
250 
251  while (!vertices.is_at_end()) {
252  btSoftBody::Node node = _soft->m_nodes[indices.get_data1i()];
253  btVector3 v = trans.invXform(node.m_x);
254  btVector3 n = node.m_n;
255 
256  if (flips.get_data1i() > 0) n *= -1;
257 
258  vertices.set_data3((PN_stdfloat)v.getX(), (PN_stdfloat)v.getY(), (PN_stdfloat)v.getZ());
259  normals.set_data3((PN_stdfloat)n.getX(), (PN_stdfloat)n.getY(), (PN_stdfloat)n.getZ());
260  }
261  }
262 
263  if (_curve) {
264  btSoftBody::tNodeArray &nodes(_soft->m_nodes);
265 
266  for (int i=0; i < nodes.size(); i++) {
267  btVector3 pos = nodes[i].m_x;
268  _curve->set_vertex(i, btVector3_to_LPoint3(pos));
269  }
270  }
271 
272  if (_surface) {
273  btSoftBody::tNodeArray &nodes(_soft->m_nodes);
274 
275  int num_u = _surface->get_num_u_vertices();
276  int num_v = _surface->get_num_v_vertices();
277  nassertv(num_u * num_v == nodes.size());
278 
279  for (int u=0; u < num_u; u++) {
280  for (int v=0; v < num_v; v++) {
281  btVector3 pos = nodes[u * num_u + v].m_x;
282  _surface->set_vertex(u, v, btVector3_to_LPoint3(pos));
283  }
284  }
285  }
286 
287  // Update the synchronized transform with the current approximate center of
288  // the soft body
289  btVector3 pMin, pMax;
290  _soft->getAabb(pMin, pMax);
291  LPoint3 pos = (btVector3_to_LPoint3(pMin) + btVector3_to_LPoint3(pMax)) * 0.5;
292  CPT(TransformState) ts;
293  if (!pos.is_nan()) {
294  ts = TransformState::make_pos(pos);
295  } else {
296  ts = TransformState::make_identity();
297  }
298 
299  NodePath np = NodePath::any_path((PandaNode *)this);
300  LVecBase3 scale = np.get_net_transform()->get_scale();
301  ts = ts->set_scale(scale);
302 
303  _sync = ts;
304  _sync_disable = true;
305  np.set_transform(NodePath(), ts);
306  _sync_disable = false;
307 /*
308 */
309 
310  Thread *current_thread = Thread::get_current_thread();
311  this->r_mark_geom_bounds_stale(current_thread);
312 }
313 
314 /**
315  * Returns the index of the node which is closest to the given point. The
316  * distance between each node and the given point is computed in world space
317  * if local=false, and in local space if local=true.
318  */
320 get_closest_node_index(LVecBase3 point, bool local) {
321  LightMutexHolder holder(BulletWorld::get_global_lock());
322 
323  return do_get_closest_node_index(point, local);
324 }
325 
326 /**
327  * Returns the index of the node which is closest to the given point. The
328  * distance between each node and the given point is computed in world space
329  * if local=false, and in local space if local=true.
330  * Assumes the lock(bullet global lock) is held by the caller
331  */
332 int BulletSoftBodyNode::
333 do_get_closest_node_index(LVecBase3 point, bool local) {
334 
335  btScalar max_dist_sqr = 1e30;
336  btVector3 point_x = LVecBase3_to_btVector3(point);
337 
338  btTransform trans = btTransform::getIdentity();
339  if (local == true) {
340  get_node_transform(trans, this);
341  }
342 
343  btSoftBody::tNodeArray &nodes(_soft->m_nodes);
344  int node_idx = 0;
345 
346  for (int i=0; i<nodes.size(); ++i) {
347 
348  btVector3 node_x = nodes[i].m_x;
349  btScalar dist_sqr = (trans.invXform(node_x) - point_x).length2();
350 
351  if (dist_sqr < max_dist_sqr) {
352  max_dist_sqr = dist_sqr;
353  node_idx = i;
354  }
355  }
356 
357  return node_idx;
358 }
359 
360 /**
361  *
362  */
363 void BulletSoftBodyNode::
364 link_geom(Geom *geom) {
365  LightMutexHolder holder(BulletWorld::get_global_lock());
366 
367  nassertv(geom->get_vertex_data()->has_column(InternalName::get_vertex()));
368  nassertv(geom->get_vertex_data()->has_column(InternalName::get_normal()));
369 
370  do_sync_p2b();
371 
372  _geom = geom;
373 
374  PT(GeomVertexData) vdata = _geom->modify_vertex_data();
375 
376  if (!vdata->has_column(BulletHelper::get_sb_index())) {
377  CPT(GeomVertexFormat) format = vdata->get_format();
378  format = BulletHelper::add_sb_index_column(format);
379  vdata->set_format(format);
380  }
381 
382  if (!vdata->has_column(BulletHelper::get_sb_flip())) {
383  CPT(GeomVertexFormat) format = vdata->get_format();
384  format = BulletHelper::add_sb_flip_column(format);
385  vdata->set_format(format);
386  }
387 
388  GeomVertexReader vertices(vdata, InternalName::get_vertex());
389  GeomVertexRewriter indices(vdata, BulletHelper::get_sb_index());
390 
391  while (!vertices.is_at_end()) {
392  LVecBase3 point = vertices.get_data3();
393  int node_idx = do_get_closest_node_index(point, true);
394  indices.set_data1i(node_idx);
395  }
396 }
397 
398 /**
399  *
400  */
401 void BulletSoftBodyNode::
402 unlink_geom() {
403  LightMutexHolder holder(BulletWorld::get_global_lock());
404 
405  _geom = nullptr;
406 }
407 
408 /**
409  *
410  */
411 void BulletSoftBodyNode::
412 link_curve(NurbsCurveEvaluator *curve) {
413  LightMutexHolder holder(BulletWorld::get_global_lock());
414 
415  nassertv(curve->get_num_vertices() == _soft->m_nodes.size());
416 
417  _curve = curve;
418 }
419 
420 /**
421  *
422  */
423 void BulletSoftBodyNode::
424 unlink_curve() {
425  LightMutexHolder holder(BulletWorld::get_global_lock());
426 
427  _curve = nullptr;
428 }
429 
430 /**
431  *
432  */
433 void BulletSoftBodyNode::
434 link_surface(NurbsSurfaceEvaluator *surface) {
435  LightMutexHolder holder(BulletWorld::get_global_lock());
436 
437  nassertv(surface->get_num_u_vertices() * surface->get_num_v_vertices() == _soft->m_nodes.size());
438 
439  _surface = surface;
440 }
441 
442 /**
443  *
444  */
445 void BulletSoftBodyNode::
446 unlink_surface() {
447  LightMutexHolder holder(BulletWorld::get_global_lock());
448 
449  _surface = nullptr;
450 }
451 
452 /**
453  *
454  */
455 BoundingBox BulletSoftBodyNode::
456 get_aabb() const {
457  LightMutexHolder holder(BulletWorld::get_global_lock());
458 
459  return do_get_aabb();
460 }
461 
462 /**
463  *
464  */
465 BoundingBox BulletSoftBodyNode::
466 do_get_aabb() const {
467 
468  btVector3 pMin;
469  btVector3 pMax;
470 
471  _soft->getAabb(pMin, pMax);
472 
473  return BoundingBox(
474  btVector3_to_LPoint3(pMin),
475  btVector3_to_LPoint3(pMax)
476  );
477 }
478 
479 /**
480  *
481  */
482 void BulletSoftBodyNode::
483 set_volume_mass(PN_stdfloat mass) {
484  LightMutexHolder holder(BulletWorld::get_global_lock());
485 
486  _soft->setVolumeMass(mass);
487 }
488 
489 /**
490  *
491  */
492 void BulletSoftBodyNode::
493 set_total_mass(PN_stdfloat mass, bool fromfaces) {
494  LightMutexHolder holder(BulletWorld::get_global_lock());
495 
496  _soft->setTotalMass(mass, fromfaces);
497 }
498 
499 /**
500  *
501  */
502 void BulletSoftBodyNode::
503 set_volume_density(PN_stdfloat density) {
504  LightMutexHolder holder(BulletWorld::get_global_lock());
505 
506  _soft->setVolumeDensity(density);
507 }
508 
509 /**
510  *
511  */
512 void BulletSoftBodyNode::
513 set_total_density(PN_stdfloat density) {
514  LightMutexHolder holder(BulletWorld::get_global_lock());
515 
516  _soft->setTotalDensity(density);
517 }
518 
519 /**
520  *
521  */
522 void BulletSoftBodyNode::
523 set_mass(int node, PN_stdfloat mass) {
524  LightMutexHolder holder(BulletWorld::get_global_lock());
525 
526  _soft->setMass(node, mass);
527 }
528 
529 /**
530  *
531  */
532 PN_stdfloat BulletSoftBodyNode::
533 get_mass(int node) const {
534  LightMutexHolder holder(BulletWorld::get_global_lock());
535 
536  return _soft->getMass(node);
537 }
538 
539 /**
540  *
541  */
542 PN_stdfloat BulletSoftBodyNode::
543 get_total_mass() const {
544  LightMutexHolder holder(BulletWorld::get_global_lock());
545 
546  return _soft->getTotalMass();
547 }
548 
549 /**
550  *
551  */
552 PN_stdfloat BulletSoftBodyNode::
553 get_volume() const {
554  LightMutexHolder holder(BulletWorld::get_global_lock());
555 
556  return _soft->getVolume();
557 }
558 
559 /**
560  *
561  */
562 void BulletSoftBodyNode::
563 add_force(const LVector3 &force) {
564  LightMutexHolder holder(BulletWorld::get_global_lock());
565 
566  nassertv(!force.is_nan());
567  _soft->addForce(LVecBase3_to_btVector3(force));
568 }
569 
570 /**
571  *
572  */
573 void BulletSoftBodyNode::
574 add_force(const LVector3 &force, int node) {
575  LightMutexHolder holder(BulletWorld::get_global_lock());
576 
577  nassertv(!force.is_nan());
578  _soft->addForce(LVecBase3_to_btVector3(force), node);
579 }
580 
581 /**
582  *
583  */
584 void BulletSoftBodyNode::
585 set_velocity(const LVector3 &velocity) {
586  LightMutexHolder holder(BulletWorld::get_global_lock());
587 
588  nassertv(!velocity.is_nan());
589  _soft->setVelocity(LVecBase3_to_btVector3(velocity));
590 }
591 
592 /**
593  *
594  */
595 void BulletSoftBodyNode::
596 add_velocity(const LVector3 &velocity) {
597  LightMutexHolder holder(BulletWorld::get_global_lock());
598 
599  nassertv(!velocity.is_nan());
600  _soft->addVelocity(LVecBase3_to_btVector3(velocity));
601 }
602 
603 /**
604  *
605  */
606 void BulletSoftBodyNode::
607 add_velocity(const LVector3 &velocity, int node) {
608  LightMutexHolder holder(BulletWorld::get_global_lock());
609 
610  nassertv(!velocity.is_nan());
611  _soft->addVelocity(LVecBase3_to_btVector3(velocity), node);
612 }
613 
614 /**
615  *
616  */
617 void BulletSoftBodyNode::
618 generate_clusters(int k, int maxiterations) {
619  LightMutexHolder holder(BulletWorld::get_global_lock());
620 
621  _soft->generateClusters(k, maxiterations);
622 }
623 
624 /**
625  *
626  */
627 void BulletSoftBodyNode::
628 release_clusters() {
629  LightMutexHolder holder(BulletWorld::get_global_lock());
630 
631  _soft->releaseClusters();
632 }
633 
634 /**
635  *
636  */
637 void BulletSoftBodyNode::
638 release_cluster(int index) {
639  LightMutexHolder holder(BulletWorld::get_global_lock());
640 
641  _soft->releaseCluster(index);
642 }
643 
644 /**
645  *
646  */
647 int BulletSoftBodyNode::
648 get_num_clusters() const {
649  LightMutexHolder holder(BulletWorld::get_global_lock());
650 
651  return _soft->clusterCount();
652 }
653 
654 /**
655  *
656  */
657 LVecBase3 BulletSoftBodyNode::
658 cluster_com(int cluster) const {
659  LightMutexHolder holder(BulletWorld::get_global_lock());
660 
661  return btVector3_to_LVecBase3(_soft->clusterCom(cluster));
662 }
663 
664 /**
665  *
666  */
667 void BulletSoftBodyNode::
668 set_pose(bool bvolume, bool bframe) {
669  LightMutexHolder holder(BulletWorld::get_global_lock());
670 
671  _soft->setPose(bvolume, bframe);
672 }
673 
674 /**
675  *
676  */
677 void BulletSoftBodyNode::
678 append_anchor(int node, BulletRigidBodyNode *body, bool disable) {
679  LightMutexHolder holder(BulletWorld::get_global_lock());
680 
681  nassertv(node < _soft->m_nodes.size())
682  nassertv(body);
683 
684  body->do_sync_p2b();
685 
686  btRigidBody *ptr = (btRigidBody *)body->get_object();
687  _soft->appendAnchor(node, ptr, disable);
688 }
689 
690 /**
691  *
692  */
693 void BulletSoftBodyNode::
694 append_anchor(int node, BulletRigidBodyNode *body, const LVector3 &pivot, bool disable) {
695  LightMutexHolder holder(BulletWorld::get_global_lock());
696 
697  nassertv(node < _soft->m_nodes.size())
698  nassertv(body);
699  nassertv(!pivot.is_nan());
700 
701  body->do_sync_p2b();
702 
703  btRigidBody *ptr = (btRigidBody *)body->get_object();
704  _soft->appendAnchor(node, ptr, LVecBase3_to_btVector3(pivot), disable);
705 }
706 
707 /**
708  *
709  */
711 BulletSoftBodyNodeElement(btSoftBody::Node &node) : _node(node) {
712 
713 }
714 
715 /**
716  * Returns the index of the first point within an array of points which has
717  * about the same coordinates as the given point. If no points is found -1 is
718  * returned.
719  */
720 int BulletSoftBodyNode::
721 get_point_index(LVecBase3 p, PTA_LVecBase3 points) {
722  LightMutexHolder holder(BulletWorld::get_global_lock());
723 
724  PN_stdfloat eps = 1.0e-6f; // TODO make this a config option
725 
726  for (PTA_LVecBase3::size_type i=0; i<points.size(); i++) {
727  if (points[i].almost_equal(p, eps)) {
728  return i; // Found
729  }
730  }
731 
732  return -1; // Not found
733 }
734 
735 /**
736  * Read on until the next linebreak is detected, or the end of file has been
737  * reached.
738  */
739 int BulletSoftBodyNode::
740 next_line(const char* buffer) {
741 
742  int num_bytes_read = 0;
743 
744  while (*buffer != '\n') {
745  buffer++;
746  num_bytes_read++;
747  }
748 
749  if (buffer[0] == 0x0a) {
750  buffer++;
751  num_bytes_read++;
752  }
753 
754  return num_bytes_read;
755 }
756 
757 /**
758  *
759  */
760 PT(BulletSoftBodyNode) BulletSoftBodyNode::
761 make_rope(BulletSoftBodyWorldInfo &info, const LPoint3 &from, const LPoint3 &to, int res, int fixeds) {
762 
763  btSoftBody *body = btSoftBodyHelpers::CreateRope(
764  info.get_info(),
765  LVecBase3_to_btVector3(from),
766  LVecBase3_to_btVector3(to),
767  res,
768  fixeds);
769 
770  PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
771 
772  return node;
773 }
774 
775 /**
776  *
777  */
778 PT(BulletSoftBodyNode) BulletSoftBodyNode::
779 make_patch(BulletSoftBodyWorldInfo &info, const LPoint3 &corner00, const LPoint3 &corner10, const LPoint3 &corner01, const LPoint3 &corner11, int resx, int resy, int fixeds, bool gendiags) {
780 
781  btSoftBody *body = btSoftBodyHelpers::CreatePatch(
782  info.get_info(),
783  LVecBase3_to_btVector3(corner00),
784  LVecBase3_to_btVector3(corner10),
785  LVecBase3_to_btVector3(corner01),
786  LVecBase3_to_btVector3(corner11),
787  resx,
788  resy,
789  fixeds,
790  gendiags);
791 
792  PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
793 
794  return node;
795 }
796 
797 /**
798  *
799  */
800 PT(BulletSoftBodyNode) BulletSoftBodyNode::
801 make_ellipsoid(BulletSoftBodyWorldInfo &info, const LPoint3 &center, const LVecBase3 &radius, int res) {
802 
803  btSoftBody *body = btSoftBodyHelpers::CreateEllipsoid(
804  info.get_info(),
805  LVecBase3_to_btVector3(center),
806  LVecBase3_to_btVector3(radius),
807  res);
808 
809  PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
810 
811  return node;
812 }
813 
814 /**
815  *
816  */
817 PT(BulletSoftBodyNode) BulletSoftBodyNode::
818 make_tri_mesh(BulletSoftBodyWorldInfo &info, PTA_LVecBase3 points, PTA_int indices, bool randomizeConstraints) {
819 
820  // Eliminate duplicate vertices
821  PTA_LVecBase3 mapped_points;
822  PTA_int mapped_indices;
823 
824  pmap<int, int> mapping;
825 
826  for (PTA_LVecBase3::size_type i=0; i<points.size(); i++) {
827  LVecBase3 p = points[i];
828  int j = get_point_index(p, mapped_points);
829  if (j < 0) {
830  mapping[i] = mapped_points.size();
831  mapped_points.push_back(p);
832  }
833  else {
834  mapping[i] = j;
835  }
836  }
837 
838  for (PTA_int::size_type i=0; i<indices.size(); i++) {
839  int idx = indices[i];
840  int mapped_idx = mapping[idx];
841  mapped_indices.push_back(mapped_idx);
842  }
843 
844  points = mapped_points;
845  indices = mapped_indices;
846 
847  // Convert arrays
848  int num_vertices = points.size();
849  int num_triangles = indices.size() / 3;
850 
851  btScalar *vertices = new btScalar[num_vertices * 3];
852  for (int i=0; i < num_vertices; i++) {
853  vertices[3*i] = points[i].get_x();
854  vertices[3*i+1] = points[i].get_y();
855  vertices[3*i+2] = points[i].get_z();
856  }
857 
858  int *triangles = new int[num_triangles * 3];
859  for (int i=0; i < num_triangles * 3; i++) {
860  triangles[i] = indices[i];
861  }
862 
863  // Create body
864  btSoftBody *body = btSoftBodyHelpers::CreateFromTriMesh(
865  info.get_info(),
866  vertices,
867  triangles,
868  num_triangles,
869  randomizeConstraints);
870 
871  nassertr(body, nullptr);
872 
873  delete[] vertices;
874  delete[] triangles;
875 
876  PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
877 
878  return node;
879 }
880 
881 /**
882  *
883  */
884 PT(BulletSoftBodyNode) BulletSoftBodyNode::
885 make_tri_mesh(BulletSoftBodyWorldInfo &info, const Geom *geom, bool randomizeConstraints) {
886 
887  // Read vertex data
888  PTA_LVecBase3 points;
889  PTA_int indices;
890 
891  CPT(GeomVertexData) vdata = geom->get_vertex_data();
892 
893  nassertr(vdata->has_column(InternalName::get_vertex()), nullptr);
894 
895  GeomVertexReader vreader(vdata, InternalName::get_vertex());
896 
897  while (!vreader.is_at_end()) {
898  LVecBase3 v = vreader.get_data3();
899  points.push_back(v);
900  }
901 
902  // Read indices
903  for (size_t i = 0; i < geom->get_num_primitives(); ++i) {
904 
905  CPT(GeomPrimitive) prim = geom->get_primitive(i);
906  prim = prim->decompose();
907 
908  for (int j=0; j<prim->get_num_primitives(); j++) {
909 
910  int s = prim->get_primitive_start(j);
911  int e = prim->get_primitive_end(j);
912 
913  for (int k=s; k<e; k++) {
914  indices.push_back(prim->get_vertex(k));
915  }
916  }
917  }
918 
919  // Create body
920  return make_tri_mesh(info, points, indices, randomizeConstraints);
921 }
922 
923 /**
924  *
925  */
926 PT(BulletSoftBodyNode) BulletSoftBodyNode::
927 make_tet_mesh(BulletSoftBodyWorldInfo &info, PTA_LVecBase3 points, PTA_int indices, bool tetralinks) {
928 
929  // Points
930  btAlignedObjectArray<btVector3> pos;
931  pos.resize(points.size());
932  for (PTA_LVecBase3::size_type i=0; i<points.size(); i++) {
933  LVecBase3 point = points[i];
934  pos[i] = LVecBase3_to_btVector3(point);
935  }
936 
937  // Body
938  btSoftBody* body = new btSoftBody(&info.get_info(), pos.size(), &pos[0], 0);
939 
940  // Indices
941  for (PTA_int::size_type i=0; i<indices.size() / 4; i++) {
942  int ni[4];
943 
944  ni[0] = indices[4*i];
945  ni[1] = indices[4*i+1];
946  ni[2] = indices[4*i+2];
947  ni[3] = indices[4*i+3];
948 
949  body->appendTetra(ni[0],ni[1],ni[2],ni[3]);
950 
951  if (tetralinks) {
952  body->appendLink(ni[0], ni[1], 0, true);
953  body->appendLink(ni[1], ni[2], 0, true);
954  body->appendLink(ni[2], ni[0], 0, true);
955  body->appendLink(ni[0], ni[3], 0, true);
956  body->appendLink(ni[1], ni[3], 0, true);
957  body->appendLink(ni[2], ni[3], 0, true);
958  }
959  }
960 
961  // Node
962  PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
963 
964  return node;
965 }
966 
967 /**
968  *
969  */
970 PT(BulletSoftBodyNode) BulletSoftBodyNode::
971 make_tet_mesh(BulletSoftBodyWorldInfo &info, const char *ele, const char *face, const char *node) {
972 
973  nassertr(node && node[0], nullptr);
974 
975  // Nodes
976  btAlignedObjectArray<btVector3> pos;
977 
978  int npos = 0;
979  int ndims = 0; // not used
980  int nattrb = 0; // not used
981  int hasbounds = 0; // not used
982 
983  sscanf(node, "%d %d %d %d", &npos, &ndims, &nattrb, &hasbounds);
984  node += next_line(node);
985 
986  pos.resize(npos);
987 
988  for (int i=0; i<pos.size(); ++i) {
989  int index = 0;
990  float x, y, z;
991 
992  sscanf(node, "%d %f %f %f", &index, &x, &y, &z);
993  node += next_line(node);
994 
995  pos[index].setX(btScalar(x));
996  pos[index].setY(btScalar(y));
997  pos[index].setZ(btScalar(z));
998  }
999 
1000  // Body
1001  btSoftBody *body = new btSoftBody(&info.get_info(), npos, &pos[0], 0);
1002 
1003  // Faces
1004  if (face && face[0]) {
1005  int nface = 0;
1006  int hasbounds = 0; // not used
1007 
1008  sscanf(face, "%d %d", &nface, &hasbounds);
1009  face += next_line(face);
1010 
1011  for (int i=0; i<nface; ++i) {
1012  int index = 0;
1013  int ni[3];
1014 
1015  sscanf(face, "%d %d %d %d", &index, &ni[0], &ni[1], &ni[2]);
1016  face += next_line(face);
1017 
1018  body->appendFace(ni[0], ni[1], ni[2]);
1019  }
1020  }
1021 
1022  // Links
1023  if (ele && ele[0]) {
1024  int ntetra = 0;
1025  int ncorner = 0;
1026  int neattrb = 0;
1027 
1028  sscanf(ele, "%d %d %d", &ntetra, &ncorner, &neattrb);
1029  ele += next_line(ele);
1030 
1031  for (int i=0; i<ntetra; ++i) {
1032  int index = 0;
1033  int ni[4];
1034 
1035  sscanf(ele, "%d %d %d %d %d", &index, &ni[0], &ni[1], &ni[2], &ni[3]);
1036  ele += next_line(ele);
1037 
1038  body->appendTetra(ni[0], ni[1], ni[2], ni[3]);
1039 
1040  body->appendLink(ni[0], ni[1], 0, true);
1041  body->appendLink(ni[1], ni[2], 0, true);
1042  body->appendLink(ni[2], ni[0], 0, true);
1043  body->appendLink(ni[0], ni[3], 0, true);
1044  body->appendLink(ni[1], ni[3], 0, true);
1045  body->appendLink(ni[2], ni[3], 0, true);
1046  }
1047  }
1048 
1049  // Node
1050  PT(BulletSoftBodyNode) sbnode = new BulletSoftBodyNode(body);
1051 
1052  return sbnode;
1053 }
1054 
1055 /**
1056  *
1057  */
1058 void BulletSoftBodyNode::
1059 append_linear_joint(BulletBodyNode *body, int cluster, PN_stdfloat erp, PN_stdfloat cfm, PN_stdfloat split) {
1060  LightMutexHolder holder(BulletWorld::get_global_lock());
1061 
1062  nassertv(body);
1063 
1064  btCollisionObject *ptr = body->get_object();
1065 
1066  btSoftBody::LJoint::Specs ls;
1067  ls.erp = erp;
1068  ls.cfm = cfm;
1069  ls.split = split;
1070  ls.position = _soft->clusterCom(cluster);
1071 
1072  _soft->appendLinearJoint(ls, ptr);
1073 }
1074 
1075 /**
1076  *
1077  */
1078 void BulletSoftBodyNode::
1079 append_linear_joint(BulletBodyNode *body, const LPoint3 &pos, PN_stdfloat erp, PN_stdfloat cfm, PN_stdfloat split) {
1080  LightMutexHolder holder(BulletWorld::get_global_lock());
1081 
1082  nassertv(body);
1083 
1084  btCollisionObject *ptr = body->get_object();
1085 
1086  btSoftBody::LJoint::Specs ls;
1087  ls.erp = erp;
1088  ls.cfm = cfm;
1089  ls.split = split;
1090  ls.position = LVecBase3_to_btVector3(pos);
1091 
1092  _soft->appendLinearJoint(ls, ptr);
1093 }
1094 
1095 /**
1096  *
1097  */
1098 void BulletSoftBodyNode::
1099 append_angular_joint(BulletBodyNode *body, const LVector3 &axis, PN_stdfloat erp, PN_stdfloat cfm, PN_stdfloat split, BulletSoftBodyControl *control) {
1100  LightMutexHolder holder(BulletWorld::get_global_lock());
1101 
1102  nassertv(body);
1103 
1104  btCollisionObject *ptr = body->get_object();
1105 
1106  btSoftBody::AJoint::Specs as;
1107  as.erp = erp;
1108  as.cfm = cfm;
1109  as.split = split;
1110  as.axis = LVecBase3_to_btVector3(axis);
1111  as.icontrol = control ? control : btSoftBody::AJoint::IControl::Default();
1112 
1113  _soft->appendAngularJoint(as, ptr);
1114 }
1115 
1116 /**
1117  *
1118  */
1119 void BulletSoftBodyNode::
1120 set_wind_velocity(const LVector3 &velocity) {
1121  LightMutexHolder holder(BulletWorld::get_global_lock());
1122 
1123  nassertv(!velocity.is_nan());
1124  _soft->setWindVelocity(LVecBase3_to_btVector3(velocity));
1125 }
1126 
1127 /**
1128  *
1129  */
1130 LVector3 BulletSoftBodyNode::
1131 get_wind_velocity() const {
1132  LightMutexHolder holder(BulletWorld::get_global_lock());
1133 
1134  return btVector3_to_LVector3(_soft->getWindVelocity());
1135 }
1136 
1137 /**
1138  *
1139  */
1140 LPoint3 BulletSoftBodyNodeElement::
1141 get_pos() const {
1142  LightMutexHolder holder(BulletWorld::get_global_lock());
1143 
1144  return btVector3_to_LPoint3(_node.m_x);
1145 }
1146 
1147 /**
1148  *
1149  */
1150 LVector3 BulletSoftBodyNodeElement::
1151 get_normal() const {
1152  LightMutexHolder holder(BulletWorld::get_global_lock());
1153 
1154  return btVector3_to_LVector3(_node.m_n);
1155 }
1156 
1157 /**
1158  *
1159  */
1160 LVector3 BulletSoftBodyNodeElement::
1161 get_velocity() const {
1162  LightMutexHolder holder(BulletWorld::get_global_lock());
1163 
1164  return btVector3_to_LVector3(_node.m_v);
1165 }
1166 
1167 /**
1168  *
1169  */
1170 PN_stdfloat BulletSoftBodyNodeElement::
1171 get_inv_mass() const {
1172  LightMutexHolder holder(BulletWorld::get_global_lock());
1173 
1174  return (PN_stdfloat)_node.m_im;
1175 }
1176 
1177 /**
1178  *
1179  */
1180 PN_stdfloat BulletSoftBodyNodeElement::
1181 get_area() const {
1182  LightMutexHolder holder(BulletWorld::get_global_lock());
1183 
1184  return (PN_stdfloat)_node.m_area;
1185 }
1186 
1187 /**
1188  *
1189  */
1190 int BulletSoftBodyNodeElement::
1191 is_attached() const {
1192  LightMutexHolder holder(BulletWorld::get_global_lock());
1193 
1194  return (PN_stdfloat)_node.m_battach;
1195 }
Geom
A container for geometry primitives.
Definition: geom.h:54
NodePath::set_transform
void set_transform(const TransformState *transform, Thread *current_thread=Thread::get_current_thread())
Changes the complete transform object on this node.
Definition: nodePath.I:565
LightMutexHolder
Similar to MutexHolder, but for a light mutex.
Definition: lightMutexHolder.h:25
BulletSoftBodyNode::do_sync_b2p
void do_sync_b2p()
Assumes the lock(bullet global lock) is held by the caller.
Definition: bulletSoftBodyNode.cxx:237
BulletSoftBodyNodeElement::empty
static BulletSoftBodyNodeElement empty()
Named constructor intended to be used for asserts with have to return a concrete value.
Definition: bulletSoftBodyNode.I:36
BulletSoftBodyNode
Definition: bulletSoftBodyNode.h:71
BulletRigidBodyNode
Definition: bulletRigidBodyNode.h:31
bulletSoftBodyControl.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletSoftBodyWorldInfo.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexReader::get_data1i
int get_data1i()
Returns the data associated with the read row, expressed as a 1-component value, and advances the rea...
Definition: geomVertexReader.I:631
GeomVertexRewriter
This object provides the functionality of both a GeomVertexReader and a GeomVertexWriter,...
Definition: geomVertexRewriter.h:33
GeomVertexData
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
Definition: geomVertexData.h:68
BulletSoftBodyMaterial
Definition: bulletSoftBodyMaterial.h:26
NurbsCurveEvaluator
This class is an abstraction for evaluating NURBS curves.
Definition: nurbsCurveEvaluator.h:39
NurbsSurfaceEvaluator
This class is an abstraction for evaluating NURBS surfaces.
Definition: nurbsSurfaceEvaluator.h:34
geomVertexReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pmap< int, int >
NodePath::get_scale
LVecBase3 get_scale() const
Retrieves the scale component of the transform.
Definition: nodePath.cxx:1161
BulletSoftBodyNodeElement
Definition: bulletSoftBodyNode.h:41
NurbsSurfaceEvaluator::get_num_v_vertices
int get_num_v_vertices() const
Returns the number of control vertices in the V direction on the surface.
Definition: nurbsSurfaceEvaluator.I:74
GeomVertexReader
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
Definition: geomVertexReader.h:47
BoundingBox
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition: boundingBox.h:29
Thread::get_current_thread
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
GeomVertexRewriter::is_at_end
bool is_at_end() const
Returns true if the reader or writer is currently at the end of the list of vertices,...
Definition: geomVertexRewriter.I:291
BulletBodyNode
Definition: bulletBodyNode.h:33
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
geomVertexRewriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BulletSoftBodyMaterial::empty
static BulletSoftBodyMaterial empty()
Named constructor intended to be used for asserts which have to return a concrete value.
Definition: bulletSoftBodyMaterial.I:27
bulletSoftBodyShape.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletSoftBodyConfig.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletHelper.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BulletSoftBodyWorldInfo
Definition: bulletSoftBodyWorldInfo.h:27
BulletSoftBodyConfig
Definition: bulletSoftBodyConfig.h:26
GeomVertexFormat
This class defines the physical layout of the vertex data stored within a Geom.
Definition: geomVertexFormat.h:55
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
Node
This class is used to assign the nodes on the mesh.
Definition: meshNode.h:16
bulletSoftBodyNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BulletSoftBodyShape
Definition: bulletSoftBodyShape.h:27
NodePath::get_mat
const LMatrix4 & get_mat() const
Returns the transform matrix that has been applied to the referenced node, or the identity matrix if ...
Definition: nodePath.I:776
bulletSoftBodyMaterial.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexWriter::set_data3
void set_data3(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Sets the write row to a particular 3-component value, and advances the write row.
Definition: geomVertexWriter.I:640
bulletWorld.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BulletSoftBodyControl
Definition: bulletSoftBodyControl.h:27
BulletSoftBodyNode::get_closest_node_index
int get_closest_node_index(LVecBase3 point, bool local)
Returns the index of the node which is closest to the given point.
Definition: bulletSoftBodyNode.cxx:320
NurbsSurfaceEvaluator::get_num_u_vertices
int get_num_u_vertices() const
Returns the number of control vertices in the U direction on the surface.
Definition: nurbsSurfaceEvaluator.I:65
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
NurbsCurveEvaluator::get_num_vertices
get_num_vertices
Returns the number of control vertices in the curve.
Definition: nurbsCurveEvaluator.h:54
NodePath::any_path
static NodePath any_path(PandaNode *node, Thread *current_thread=Thread::get_current_thread())
Returns a new NodePath that represents any arbitrary path from the root to the indicated node.
Definition: nodePath.I:62
GeomPrimitive
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56