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 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition: boundingBox.h:29
static BulletSoftBodyMaterial empty()
Named constructor intended to be used for asserts which have to return a concrete value.
static BulletSoftBodyNodeElement empty()
Named constructor intended to be used for asserts with have to return a concrete value.
void do_sync_b2p()
Assumes the lock(bullet global lock) is held by the caller.
int get_closest_node_index(LVecBase3 point, bool local)
Returns the index of the node which is closest to the given point.
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
This class defines the physical layout of the vertex data stored within a Geom.
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
int get_data1i()
Returns the data associated with the read row, expressed as a 1-component value, and advances the rea...
This object provides the functionality of both a GeomVertexReader and a GeomVertexWriter,...
bool is_at_end() const
Returns true if the reader or writer is currently at the end of the list of vertices,...
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.
A container for geometry primitives.
Definition: geom.h:54
Similar to MutexHolder, but for a light mutex.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
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
LVecBase3 get_scale() const
Retrieves the scale component of the transform.
Definition: nodePath.cxx:1195
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
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
This class is used to assign the nodes on the mesh.
Definition: meshNode.h:16
This class is an abstraction for evaluating NURBS curves.
get_num_vertices
Returns the number of control vertices in the curve.
This class is an abstraction for evaluating NURBS surfaces.
int get_num_u_vertices() const
Returns the number of control vertices in the U direction on the surface.
int get_num_v_vertices() const
Returns the number of control vertices in the V direction on the surface.
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
A thread; that is, a lightweight process.
Definition: thread.h:46
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
Indicates a coordinate-system transform on vertices.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.