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  btVector3 origin = _soft->m_initialWorldTransform.getOrigin();
191  btVector3 offset = pos - origin;
192 
193  // Subtract offset to get new transform for the body
194  trans.setOrigin(trans.getOrigin() - offset);
195 
196  // Now apply the new transform
197  _soft->transform(_soft->m_initialWorldTransform.inverse());
198  _soft->transform(trans);
199 
200  if (ts->has_scale()) {
201  btVector3 current_scale = LVecBase3_to_btVector3(_sync->get_scale());
202  btVector3 new_scale = LVecBase3_to_btVector3(ts->get_scale());
203 
204  current_scale.setX(1.0 / current_scale.getX());
205  current_scale.setY(1.0 / current_scale.getY());
206  current_scale.setZ(1.0 / current_scale.getZ());
207 
208  _soft->scale(current_scale);
209  _soft->scale(new_scale);
210  }
211 
212  _sync = std::move(ts);
213  }
214 }
215 
216 /**
217  *
218  */
219 void BulletSoftBodyNode::
220 do_sync_p2b() {
221 
222  // transform_changed(); Disabled for now...
223 }
224 
225 /**
226  * Assumes the lock(bullet global lock) is held by the caller
227  */
230 
231  // Render softbody
232  if (_geom) {
233  btTransform trans = btTransform::getIdentity();
234  get_node_transform(trans, this);
235 
236  PT(GeomVertexData) vdata = _geom->modify_vertex_data();
237 
238  GeomVertexRewriter vertices(vdata, InternalName::get_vertex());
239  GeomVertexRewriter normals(vdata, InternalName::get_normal());
240  GeomVertexReader indices(vdata, BulletHelper::get_sb_index());
241  GeomVertexReader flips(vdata, BulletHelper::get_sb_flip());
242 
243  while (!vertices.is_at_end()) {
244  btSoftBody::Node node = _soft->m_nodes[indices.get_data1i()];
245  btVector3 v = trans.invXform(node.m_x);
246  btVector3 n = node.m_n;
247 
248  if (flips.get_data1i() > 0) n *= -1;
249 
250  vertices.set_data3((PN_stdfloat)v.getX(), (PN_stdfloat)v.getY(), (PN_stdfloat)v.getZ());
251  normals.set_data3((PN_stdfloat)n.getX(), (PN_stdfloat)n.getY(), (PN_stdfloat)n.getZ());
252  }
253  }
254 
255  if (_curve) {
256  btSoftBody::tNodeArray &nodes(_soft->m_nodes);
257 
258  for (int i=0; i < nodes.size(); i++) {
259  btVector3 pos = nodes[i].m_x;
260  _curve->set_vertex(i, btVector3_to_LPoint3(pos));
261  }
262  }
263 
264  if (_surface) {
265  btSoftBody::tNodeArray &nodes(_soft->m_nodes);
266 
267  int num_u = _surface->get_num_u_vertices();
268  int num_v = _surface->get_num_v_vertices();
269  nassertv(num_u * num_v == nodes.size());
270 
271  for (int u=0; u < num_u; u++) {
272  for (int v=0; v < num_v; v++) {
273  btVector3 pos = nodes[u * num_u + v].m_x;
274  _surface->set_vertex(u, v, btVector3_to_LPoint3(pos));
275  }
276  }
277  }
278 
279  // Update the synchronized transform with the current approximate center of
280  // the soft body
281  btVector3 pMin, pMax;
282  _soft->getAabb(pMin, pMax);
283  LPoint3 pos = (btVector3_to_LPoint3(pMin) + btVector3_to_LPoint3(pMax)) * 0.5;
284  CPT(TransformState) ts;
285  if (!pos.is_nan()) {
286  ts = TransformState::make_pos(pos);
287  } else {
288  ts = TransformState::make_identity();
289  }
290 
291  NodePath np = NodePath::any_path((PandaNode *)this);
292  LVecBase3 scale = np.get_net_transform()->get_scale();
293  ts = ts->set_scale(scale);
294 
295  _sync = ts;
296  _sync_disable = true;
297  np.set_transform(NodePath(), ts);
298  _sync_disable = false;
299 /*
300 */
301 
302  Thread *current_thread = Thread::get_current_thread();
303  this->r_mark_geom_bounds_stale(current_thread);
304 }
305 
306 /**
307  * Returns the index of the node which is closest to the given point. The
308  * distance between each node and the given point is computed in world space
309  * if local=false, and in local space if local=true.
310  */
312 get_closest_node_index(LVecBase3 point, bool local) {
313  LightMutexHolder holder(BulletWorld::get_global_lock());
314 
315  return do_get_closest_node_index(point, local);
316 }
317 
318 /**
319  * Returns the index of the node which is closest to the given point. The
320  * distance between each node and the given point is computed in world space
321  * if local=false, and in local space if local=true.
322  * Assumes the lock(bullet global lock) is held by the caller
323  */
324 int BulletSoftBodyNode::
325 do_get_closest_node_index(LVecBase3 point, bool local) {
326 
327  btScalar max_dist_sqr = 1e30;
328  btVector3 point_x = LVecBase3_to_btVector3(point);
329 
330  btTransform trans = btTransform::getIdentity();
331  if (local == true) {
332  get_node_transform(trans, this);
333  }
334 
335  btSoftBody::tNodeArray &nodes(_soft->m_nodes);
336  int node_idx = 0;
337 
338  for (int i=0; i<nodes.size(); ++i) {
339 
340  btVector3 node_x = nodes[i].m_x;
341  btScalar dist_sqr = (trans.invXform(node_x) - point_x).length2();
342 
343  if (dist_sqr < max_dist_sqr) {
344  max_dist_sqr = dist_sqr;
345  node_idx = i;
346  }
347  }
348 
349  return node_idx;
350 }
351 
352 /**
353  *
354  */
355 void BulletSoftBodyNode::
356 link_geom(Geom *geom) {
357  LightMutexHolder holder(BulletWorld::get_global_lock());
358 
359  nassertv(geom->get_vertex_data()->has_column(InternalName::get_vertex()));
360  nassertv(geom->get_vertex_data()->has_column(InternalName::get_normal()));
361 
362  do_sync_p2b();
363 
364  _geom = geom;
365 
366  PT(GeomVertexData) vdata = _geom->modify_vertex_data();
367 
368  if (!vdata->has_column(BulletHelper::get_sb_index())) {
369  CPT(GeomVertexFormat) format = vdata->get_format();
370  format = BulletHelper::add_sb_index_column(format);
371  vdata->set_format(format);
372  }
373 
374  if (!vdata->has_column(BulletHelper::get_sb_flip())) {
375  CPT(GeomVertexFormat) format = vdata->get_format();
376  format = BulletHelper::add_sb_flip_column(format);
377  vdata->set_format(format);
378  }
379 
380  GeomVertexReader vertices(vdata, InternalName::get_vertex());
381  GeomVertexRewriter indices(vdata, BulletHelper::get_sb_index());
382 
383  while (!vertices.is_at_end()) {
384  LVecBase3 point = vertices.get_data3();
385  int node_idx = do_get_closest_node_index(point, true);
386  indices.set_data1i(node_idx);
387  }
388 }
389 
390 /**
391  *
392  */
393 void BulletSoftBodyNode::
394 unlink_geom() {
395  LightMutexHolder holder(BulletWorld::get_global_lock());
396 
397  _geom = nullptr;
398 }
399 
400 /**
401  *
402  */
403 void BulletSoftBodyNode::
404 link_curve(NurbsCurveEvaluator *curve) {
405  LightMutexHolder holder(BulletWorld::get_global_lock());
406 
407  nassertv(curve->get_num_vertices() == _soft->m_nodes.size());
408 
409  _curve = curve;
410 }
411 
412 /**
413  *
414  */
415 void BulletSoftBodyNode::
416 unlink_curve() {
417  LightMutexHolder holder(BulletWorld::get_global_lock());
418 
419  _curve = nullptr;
420 }
421 
422 /**
423  *
424  */
425 void BulletSoftBodyNode::
426 link_surface(NurbsSurfaceEvaluator *surface) {
427  LightMutexHolder holder(BulletWorld::get_global_lock());
428 
429  nassertv(surface->get_num_u_vertices() * surface->get_num_v_vertices() == _soft->m_nodes.size());
430 
431  _surface = surface;
432 }
433 
434 /**
435  *
436  */
437 void BulletSoftBodyNode::
438 unlink_surface() {
439  LightMutexHolder holder(BulletWorld::get_global_lock());
440 
441  _surface = nullptr;
442 }
443 
444 /**
445  *
446  */
447 BoundingBox BulletSoftBodyNode::
448 get_aabb() const {
449  LightMutexHolder holder(BulletWorld::get_global_lock());
450 
451  return do_get_aabb();
452 }
453 
454 /**
455  *
456  */
457 BoundingBox BulletSoftBodyNode::
458 do_get_aabb() const {
459 
460  btVector3 pMin;
461  btVector3 pMax;
462 
463  _soft->getAabb(pMin, pMax);
464 
465  return BoundingBox(
466  btVector3_to_LPoint3(pMin),
467  btVector3_to_LPoint3(pMax)
468  );
469 }
470 
471 /**
472  *
473  */
474 void BulletSoftBodyNode::
475 set_volume_mass(PN_stdfloat mass) {
476  LightMutexHolder holder(BulletWorld::get_global_lock());
477 
478  _soft->setVolumeMass(mass);
479 }
480 
481 /**
482  *
483  */
484 void BulletSoftBodyNode::
485 set_total_mass(PN_stdfloat mass, bool fromfaces) {
486  LightMutexHolder holder(BulletWorld::get_global_lock());
487 
488  _soft->setTotalMass(mass, fromfaces);
489 }
490 
491 /**
492  *
493  */
494 void BulletSoftBodyNode::
495 set_volume_density(PN_stdfloat density) {
496  LightMutexHolder holder(BulletWorld::get_global_lock());
497 
498  _soft->setVolumeDensity(density);
499 }
500 
501 /**
502  *
503  */
504 void BulletSoftBodyNode::
505 set_total_density(PN_stdfloat density) {
506  LightMutexHolder holder(BulletWorld::get_global_lock());
507 
508  _soft->setTotalDensity(density);
509 }
510 
511 /**
512  *
513  */
514 void BulletSoftBodyNode::
515 set_mass(int node, PN_stdfloat mass) {
516  LightMutexHolder holder(BulletWorld::get_global_lock());
517 
518  _soft->setMass(node, mass);
519 }
520 
521 /**
522  *
523  */
524 PN_stdfloat BulletSoftBodyNode::
525 get_mass(int node) const {
526  LightMutexHolder holder(BulletWorld::get_global_lock());
527 
528  return _soft->getMass(node);
529 }
530 
531 /**
532  *
533  */
534 PN_stdfloat BulletSoftBodyNode::
535 get_total_mass() const {
536  LightMutexHolder holder(BulletWorld::get_global_lock());
537 
538  return _soft->getTotalMass();
539 }
540 
541 /**
542  *
543  */
544 PN_stdfloat BulletSoftBodyNode::
545 get_volume() const {
546  LightMutexHolder holder(BulletWorld::get_global_lock());
547 
548  return _soft->getVolume();
549 }
550 
551 /**
552  *
553  */
554 void BulletSoftBodyNode::
555 add_force(const LVector3 &force) {
556  LightMutexHolder holder(BulletWorld::get_global_lock());
557 
558  nassertv(!force.is_nan());
559  _soft->addForce(LVecBase3_to_btVector3(force));
560 }
561 
562 /**
563  *
564  */
565 void BulletSoftBodyNode::
566 add_force(const LVector3 &force, int node) {
567  LightMutexHolder holder(BulletWorld::get_global_lock());
568 
569  nassertv(!force.is_nan());
570  _soft->addForce(LVecBase3_to_btVector3(force), node);
571 }
572 
573 /**
574  *
575  */
576 void BulletSoftBodyNode::
577 set_velocity(const LVector3 &velocity) {
578  LightMutexHolder holder(BulletWorld::get_global_lock());
579 
580  nassertv(!velocity.is_nan());
581  _soft->setVelocity(LVecBase3_to_btVector3(velocity));
582 }
583 
584 /**
585  *
586  */
587 void BulletSoftBodyNode::
588 add_velocity(const LVector3 &velocity) {
589  LightMutexHolder holder(BulletWorld::get_global_lock());
590 
591  nassertv(!velocity.is_nan());
592  _soft->addVelocity(LVecBase3_to_btVector3(velocity));
593 }
594 
595 /**
596  *
597  */
598 void BulletSoftBodyNode::
599 add_velocity(const LVector3 &velocity, int node) {
600  LightMutexHolder holder(BulletWorld::get_global_lock());
601 
602  nassertv(!velocity.is_nan());
603  _soft->addVelocity(LVecBase3_to_btVector3(velocity), node);
604 }
605 
606 /**
607  *
608  */
609 void BulletSoftBodyNode::
610 generate_clusters(int k, int maxiterations) {
611  LightMutexHolder holder(BulletWorld::get_global_lock());
612 
613  _soft->generateClusters(k, maxiterations);
614 }
615 
616 /**
617  *
618  */
619 void BulletSoftBodyNode::
620 release_clusters() {
621  LightMutexHolder holder(BulletWorld::get_global_lock());
622 
623  _soft->releaseClusters();
624 }
625 
626 /**
627  *
628  */
629 void BulletSoftBodyNode::
630 release_cluster(int index) {
631  LightMutexHolder holder(BulletWorld::get_global_lock());
632 
633  _soft->releaseCluster(index);
634 }
635 
636 /**
637  *
638  */
639 int BulletSoftBodyNode::
640 get_num_clusters() const {
641  LightMutexHolder holder(BulletWorld::get_global_lock());
642 
643  return _soft->clusterCount();
644 }
645 
646 /**
647  *
648  */
649 LVecBase3 BulletSoftBodyNode::
650 cluster_com(int cluster) const {
651  LightMutexHolder holder(BulletWorld::get_global_lock());
652 
653  return btVector3_to_LVecBase3(_soft->clusterCom(cluster));
654 }
655 
656 /**
657  *
658  */
659 void BulletSoftBodyNode::
660 set_pose(bool bvolume, bool bframe) {
661  LightMutexHolder holder(BulletWorld::get_global_lock());
662 
663  _soft->setPose(bvolume, bframe);
664 }
665 
666 /**
667  *
668  */
669 void BulletSoftBodyNode::
670 append_anchor(int node, BulletRigidBodyNode *body, bool disable) {
671  LightMutexHolder holder(BulletWorld::get_global_lock());
672 
673  nassertv(node < _soft->m_nodes.size())
674  nassertv(body);
675 
676  body->do_sync_p2b();
677 
678  btRigidBody *ptr = (btRigidBody *)body->get_object();
679  _soft->appendAnchor(node, ptr, disable);
680 }
681 
682 /**
683  *
684  */
685 void BulletSoftBodyNode::
686 append_anchor(int node, BulletRigidBodyNode *body, const LVector3 &pivot, bool disable) {
687  LightMutexHolder holder(BulletWorld::get_global_lock());
688 
689  nassertv(node < _soft->m_nodes.size())
690  nassertv(body);
691  nassertv(!pivot.is_nan());
692 
693  body->do_sync_p2b();
694 
695  btRigidBody *ptr = (btRigidBody *)body->get_object();
696  _soft->appendAnchor(node, ptr, LVecBase3_to_btVector3(pivot), disable);
697 }
698 
699 /**
700  *
701  */
703 BulletSoftBodyNodeElement(btSoftBody::Node &node) : _node(node) {
704 
705 }
706 
707 /**
708  * Returns the index of the first point within an array of points which has
709  * about the same coordinates as the given point. If no points is found -1 is
710  * returned.
711  */
712 int BulletSoftBodyNode::
713 get_point_index(LVecBase3 p, PTA_LVecBase3 points) {
714  LightMutexHolder holder(BulletWorld::get_global_lock());
715 
716  PN_stdfloat eps = 1.0e-6f; // TODO make this a config option
717 
718  for (PTA_LVecBase3::size_type i=0; i<points.size(); i++) {
719  if (points[i].almost_equal(p, eps)) {
720  return i; // Found
721  }
722  }
723 
724  return -1; // Not found
725 }
726 
727 /**
728  * Read on until the next linebreak is detected, or the end of file has been
729  * reached.
730  */
731 int BulletSoftBodyNode::
732 next_line(const char* buffer) {
733 
734  int num_bytes_read = 0;
735 
736  while (*buffer != '\n') {
737  buffer++;
738  num_bytes_read++;
739  }
740 
741  if (buffer[0] == 0x0a) {
742  buffer++;
743  num_bytes_read++;
744  }
745 
746  return num_bytes_read;
747 }
748 
749 /**
750  *
751  */
752 PT(BulletSoftBodyNode) BulletSoftBodyNode::
753 make_rope(BulletSoftBodyWorldInfo &info, const LPoint3 &from, const LPoint3 &to, int res, int fixeds) {
754 
755  btSoftBody *body = btSoftBodyHelpers::CreateRope(
756  info.get_info(),
757  LVecBase3_to_btVector3(from),
758  LVecBase3_to_btVector3(to),
759  res,
760  fixeds);
761 
762  PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
763 
764  return node;
765 }
766 
767 /**
768  *
769  */
770 PT(BulletSoftBodyNode) BulletSoftBodyNode::
771 make_patch(BulletSoftBodyWorldInfo &info, const LPoint3 &corner00, const LPoint3 &corner10, const LPoint3 &corner01, const LPoint3 &corner11, int resx, int resy, int fixeds, bool gendiags) {
772 
773  btSoftBody *body = btSoftBodyHelpers::CreatePatch(
774  info.get_info(),
775  LVecBase3_to_btVector3(corner00),
776  LVecBase3_to_btVector3(corner10),
777  LVecBase3_to_btVector3(corner01),
778  LVecBase3_to_btVector3(corner11),
779  resx,
780  resy,
781  fixeds,
782  gendiags);
783 
784  PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
785 
786  return node;
787 }
788 
789 /**
790  *
791  */
792 PT(BulletSoftBodyNode) BulletSoftBodyNode::
793 make_ellipsoid(BulletSoftBodyWorldInfo &info, const LPoint3 &center, const LVecBase3 &radius, int res) {
794 
795  btSoftBody *body = btSoftBodyHelpers::CreateEllipsoid(
796  info.get_info(),
797  LVecBase3_to_btVector3(center),
798  LVecBase3_to_btVector3(radius),
799  res);
800 
801  PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
802 
803  return node;
804 }
805 
806 /**
807  *
808  */
809 PT(BulletSoftBodyNode) BulletSoftBodyNode::
810 make_tri_mesh(BulletSoftBodyWorldInfo &info, PTA_LVecBase3 points, PTA_int indices, bool randomizeConstraints) {
811 
812  // Eliminate duplicate vertices
813  PTA_LVecBase3 mapped_points;
814  PTA_int mapped_indices;
815 
816  pmap<int, int> mapping;
817 
818  for (PTA_LVecBase3::size_type i=0; i<points.size(); i++) {
819  LVecBase3 p = points[i];
820  int j = get_point_index(p, mapped_points);
821  if (j < 0) {
822  mapping[i] = mapped_points.size();
823  mapped_points.push_back(p);
824  }
825  else {
826  mapping[i] = j;
827  }
828  }
829 
830  for (PTA_int::size_type i=0; i<indices.size(); i++) {
831  int idx = indices[i];
832  int mapped_idx = mapping[idx];
833  mapped_indices.push_back(mapped_idx);
834  }
835 
836  points = mapped_points;
837  indices = mapped_indices;
838 
839  // Convert arrays
840  int num_vertices = points.size();
841  int num_triangles = indices.size() / 3;
842 
843  btScalar *vertices = new btScalar[num_vertices * 3];
844  for (int i=0; i < num_vertices; i++) {
845  vertices[3*i] = points[i].get_x();
846  vertices[3*i+1] = points[i].get_y();
847  vertices[3*i+2] = points[i].get_z();
848  }
849 
850  int *triangles = new int[num_triangles * 3];
851  for (int i=0; i < num_triangles * 3; i++) {
852  triangles[i] = indices[i];
853  }
854 
855  // Create body
856  btSoftBody *body = btSoftBodyHelpers::CreateFromTriMesh(
857  info.get_info(),
858  vertices,
859  triangles,
860  num_triangles,
861  randomizeConstraints);
862 
863  nassertr(body, nullptr);
864 
865  delete[] vertices;
866  delete[] triangles;
867 
868  PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
869 
870  return node;
871 }
872 
873 /**
874  *
875  */
876 PT(BulletSoftBodyNode) BulletSoftBodyNode::
877 make_tri_mesh(BulletSoftBodyWorldInfo &info, const Geom *geom, bool randomizeConstraints) {
878 
879  // Read vertex data
880  PTA_LVecBase3 points;
881  PTA_int indices;
882 
883  CPT(GeomVertexData) vdata = geom->get_vertex_data();
884 
885  nassertr(vdata->has_column(InternalName::get_vertex()), nullptr);
886 
887  GeomVertexReader vreader(vdata, InternalName::get_vertex());
888 
889  while (!vreader.is_at_end()) {
890  LVecBase3 v = vreader.get_data3();
891  points.push_back(v);
892  }
893 
894  // Read indices
895  for (size_t i = 0; i < geom->get_num_primitives(); ++i) {
896 
897  CPT(GeomPrimitive) prim = geom->get_primitive(i);
898  prim = prim->decompose();
899 
900  for (int j=0; j<prim->get_num_primitives(); j++) {
901 
902  int s = prim->get_primitive_start(j);
903  int e = prim->get_primitive_end(j);
904 
905  for (int k=s; k<e; k++) {
906  indices.push_back(prim->get_vertex(k));
907  }
908  }
909  }
910 
911  // Create body
912  return make_tri_mesh(info, points, indices, randomizeConstraints);
913 }
914 
915 /**
916  *
917  */
918 PT(BulletSoftBodyNode) BulletSoftBodyNode::
919 make_tet_mesh(BulletSoftBodyWorldInfo &info, PTA_LVecBase3 points, PTA_int indices, bool tetralinks) {
920 
921  // Points
922  btAlignedObjectArray<btVector3> pos;
923  pos.resize(points.size());
924  for (PTA_LVecBase3::size_type i=0; i<points.size(); i++) {
925  LVecBase3 point = points[i];
926  pos[i] = LVecBase3_to_btVector3(point);
927  }
928 
929  // Body
930  btSoftBody* body = new btSoftBody(&info.get_info(), pos.size(), &pos[0], 0);
931 
932  // Indices
933  for (PTA_int::size_type i=0; i<indices.size() / 4; i++) {
934  int ni[4];
935 
936  ni[0] = indices[4*i];
937  ni[1] = indices[4*i+1];
938  ni[2] = indices[4*i+2];
939  ni[3] = indices[4*i+3];
940 
941  body->appendTetra(ni[0],ni[1],ni[2],ni[3]);
942 
943  if (tetralinks) {
944  body->appendLink(ni[0], ni[1], 0, true);
945  body->appendLink(ni[1], ni[2], 0, true);
946  body->appendLink(ni[2], ni[0], 0, true);
947  body->appendLink(ni[0], ni[3], 0, true);
948  body->appendLink(ni[1], ni[3], 0, true);
949  body->appendLink(ni[2], ni[3], 0, true);
950  }
951  }
952 
953  // Node
954  PT(BulletSoftBodyNode) node = new BulletSoftBodyNode(body);
955 
956  return node;
957 }
958 
959 /**
960  *
961  */
962 PT(BulletSoftBodyNode) BulletSoftBodyNode::
963 make_tet_mesh(BulletSoftBodyWorldInfo &info, const char *ele, const char *face, const char *node) {
964 
965  nassertr(node && node[0], nullptr);
966 
967  // Nodes
968  btAlignedObjectArray<btVector3> pos;
969 
970  int npos = 0;
971  int ndims = 0; // not used
972  int nattrb = 0; // not used
973  int hasbounds = 0; // not used
974 
975  sscanf(node, "%d %d %d %d", &npos, &ndims, &nattrb, &hasbounds);
976  node += next_line(node);
977 
978  pos.resize(npos);
979 
980  for (int i=0; i<pos.size(); ++i) {
981  int index = 0;
982  float x, y, z;
983 
984  sscanf(node, "%d %f %f %f", &index, &x, &y, &z);
985  node += next_line(node);
986 
987  pos[index].setX(btScalar(x));
988  pos[index].setY(btScalar(y));
989  pos[index].setZ(btScalar(z));
990  }
991 
992  // Body
993  btSoftBody *body = new btSoftBody(&info.get_info(), npos, &pos[0], 0);
994 
995  // Faces
996  if (face && face[0]) {
997  int nface = 0;
998  int hasbounds = 0; // not used
999 
1000  sscanf(face, "%d %d", &nface, &hasbounds);
1001  face += next_line(face);
1002 
1003  for (int i=0; i<nface; ++i) {
1004  int index = 0;
1005  int ni[3];
1006 
1007  sscanf(face, "%d %d %d %d", &index, &ni[0], &ni[1], &ni[2]);
1008  face += next_line(face);
1009 
1010  body->appendFace(ni[0], ni[1], ni[2]);
1011  }
1012  }
1013 
1014  // Links
1015  if (ele && ele[0]) {
1016  int ntetra = 0;
1017  int ncorner = 0;
1018  int neattrb = 0;
1019 
1020  sscanf(ele, "%d %d %d", &ntetra, &ncorner, &neattrb);
1021  ele += next_line(ele);
1022 
1023  for (int i=0; i<ntetra; ++i) {
1024  int index = 0;
1025  int ni[4];
1026 
1027  sscanf(ele, "%d %d %d %d %d", &index, &ni[0], &ni[1], &ni[2], &ni[3]);
1028  ele += next_line(ele);
1029 
1030  body->appendTetra(ni[0], ni[1], ni[2], ni[3]);
1031 
1032  body->appendLink(ni[0], ni[1], 0, true);
1033  body->appendLink(ni[1], ni[2], 0, true);
1034  body->appendLink(ni[2], ni[0], 0, true);
1035  body->appendLink(ni[0], ni[3], 0, true);
1036  body->appendLink(ni[1], ni[3], 0, true);
1037  body->appendLink(ni[2], ni[3], 0, true);
1038  }
1039  }
1040 
1041  // Node
1042  PT(BulletSoftBodyNode) sbnode = new BulletSoftBodyNode(body);
1043 
1044  return sbnode;
1045 }
1046 
1047 /**
1048  *
1049  */
1050 void BulletSoftBodyNode::
1051 append_linear_joint(BulletBodyNode *body, int cluster, PN_stdfloat erp, PN_stdfloat cfm, PN_stdfloat split) {
1052  LightMutexHolder holder(BulletWorld::get_global_lock());
1053 
1054  nassertv(body);
1055 
1056  btCollisionObject *ptr = body->get_object();
1057 
1058  btSoftBody::LJoint::Specs ls;
1059  ls.erp = erp;
1060  ls.cfm = cfm;
1061  ls.split = split;
1062  ls.position = _soft->clusterCom(cluster);
1063 
1064  _soft->appendLinearJoint(ls, ptr);
1065 }
1066 
1067 /**
1068  *
1069  */
1070 void BulletSoftBodyNode::
1071 append_linear_joint(BulletBodyNode *body, const LPoint3 &pos, PN_stdfloat erp, PN_stdfloat cfm, PN_stdfloat split) {
1072  LightMutexHolder holder(BulletWorld::get_global_lock());
1073 
1074  nassertv(body);
1075 
1076  btCollisionObject *ptr = body->get_object();
1077 
1078  btSoftBody::LJoint::Specs ls;
1079  ls.erp = erp;
1080  ls.cfm = cfm;
1081  ls.split = split;
1082  ls.position = LVecBase3_to_btVector3(pos);
1083 
1084  _soft->appendLinearJoint(ls, ptr);
1085 }
1086 
1087 /**
1088  *
1089  */
1090 void BulletSoftBodyNode::
1091 append_angular_joint(BulletBodyNode *body, const LVector3 &axis, PN_stdfloat erp, PN_stdfloat cfm, PN_stdfloat split, BulletSoftBodyControl *control) {
1092  LightMutexHolder holder(BulletWorld::get_global_lock());
1093 
1094  nassertv(body);
1095 
1096  btCollisionObject *ptr = body->get_object();
1097 
1098  btSoftBody::AJoint::Specs as;
1099  as.erp = erp;
1100  as.cfm = cfm;
1101  as.split = split;
1102  as.axis = LVecBase3_to_btVector3(axis);
1103  as.icontrol = control ? control : btSoftBody::AJoint::IControl::Default();
1104 
1105  _soft->appendAngularJoint(as, ptr);
1106 }
1107 
1108 /**
1109  *
1110  */
1111 void BulletSoftBodyNode::
1112 set_wind_velocity(const LVector3 &velocity) {
1113  LightMutexHolder holder(BulletWorld::get_global_lock());
1114 
1115  nassertv(!velocity.is_nan());
1116  _soft->setWindVelocity(LVecBase3_to_btVector3(velocity));
1117 }
1118 
1119 /**
1120  *
1121  */
1122 LVector3 BulletSoftBodyNode::
1123 get_wind_velocity() const {
1124  LightMutexHolder holder(BulletWorld::get_global_lock());
1125 
1126  return btVector3_to_LVector3(_soft->getWindVelocity());
1127 }
1128 
1129 /**
1130  *
1131  */
1132 LPoint3 BulletSoftBodyNodeElement::
1133 get_pos() const {
1134  LightMutexHolder holder(BulletWorld::get_global_lock());
1135 
1136  return btVector3_to_LPoint3(_node.m_x);
1137 }
1138 
1139 /**
1140  *
1141  */
1142 LVector3 BulletSoftBodyNodeElement::
1143 get_normal() const {
1144  LightMutexHolder holder(BulletWorld::get_global_lock());
1145 
1146  return btVector3_to_LVector3(_node.m_n);
1147 }
1148 
1149 /**
1150  *
1151  */
1152 LVector3 BulletSoftBodyNodeElement::
1153 get_velocity() const {
1154  LightMutexHolder holder(BulletWorld::get_global_lock());
1155 
1156  return btVector3_to_LVector3(_node.m_v);
1157 }
1158 
1159 /**
1160  *
1161  */
1162 PN_stdfloat BulletSoftBodyNodeElement::
1163 get_inv_mass() const {
1164  LightMutexHolder holder(BulletWorld::get_global_lock());
1165 
1166  return (PN_stdfloat)_node.m_im;
1167 }
1168 
1169 /**
1170  *
1171  */
1172 PN_stdfloat BulletSoftBodyNodeElement::
1173 get_area() const {
1174  LightMutexHolder holder(BulletWorld::get_global_lock());
1175 
1176  return (PN_stdfloat)_node.m_area;
1177 }
1178 
1179 /**
1180  *
1181  */
1182 int BulletSoftBodyNodeElement::
1183 is_attached() const {
1184  LightMutexHolder holder(BulletWorld::get_global_lock());
1185 
1186  return (PN_stdfloat)_node.m_battach;
1187 }
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:229
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:1128
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:312
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:64
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