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