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"
20 #include "bulletSoftBodyWorldInfo.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 */
236 void BulletSoftBodyNode::
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 */
319 int BulletSoftBodyNode::
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 */
710 BulletSoftBodyNodeElement::
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 }
bulletHelper.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletSoftBodyConfig.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletSoftBodyControl.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletSoftBodyMaterial.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletSoftBodyNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletSoftBodyShape.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletSoftBodyWorldInfo.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bulletWorld.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BoundingBox
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition: boundingBox.h:29
BulletBodyNode
Definition: bulletBodyNode.h:33
BulletRigidBodyNode
Definition: bulletRigidBodyNode.h:31
BulletSoftBodyConfig
Definition: bulletSoftBodyConfig.h:26
BulletSoftBodyControl
Definition: bulletSoftBodyControl.h:27
BulletSoftBodyMaterial
Definition: bulletSoftBodyMaterial.h:26
BulletSoftBodyMaterial::empty
static BulletSoftBodyMaterial empty()
Named constructor intended to be used for asserts which have to return a concrete value.
Definition: bulletSoftBodyMaterial.I:27
BulletSoftBodyNodeElement
Definition: bulletSoftBodyNode.h:41
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
BulletSoftBodyNode::do_sync_b2p
void do_sync_b2p()
Assumes the lock(bullet global lock) is held by the caller.
Definition: bulletSoftBodyNode.cxx:237
BulletSoftBodyNode::get_closest_node_index
int get_closest_node_index(LVecBase3 point, bool local)
Returns the index of the node which is closest to the given point.
Definition: bulletSoftBodyNode.cxx:320
BulletSoftBodyShape
Definition: bulletSoftBodyShape.h:27
BulletSoftBodyWorldInfo
Definition: bulletSoftBodyWorldInfo.h:27
GeomPrimitive
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
GeomVertexData
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
Definition: geomVertexData.h:68
GeomVertexFormat
This class defines the physical layout of the vertex data stored within a Geom.
Definition: geomVertexFormat.h:55
GeomVertexReader
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
Definition: geomVertexReader.h:47
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
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
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
Geom
A container for geometry primitives.
Definition: geom.h:54
LightMutexHolder
Similar to MutexHolder, but for a light mutex.
Definition: lightMutexHolder.h:25
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
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
NodePath::get_scale
LVecBase3 get_scale() const
Retrieves the scale component of the transform.
Definition: nodePath.cxx:1191
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
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
Node
This class is used to assign the nodes on the mesh.
Definition: meshNode.h:16
NurbsCurveEvaluator
This class is an abstraction for evaluating NURBS curves.
Definition: nurbsCurveEvaluator.h:39
NurbsCurveEvaluator::get_num_vertices
get_num_vertices
Returns the number of control vertices in the curve.
Definition: nurbsCurveEvaluator.h:54
NurbsSurfaceEvaluator
This class is an abstraction for evaluating NURBS surfaces.
Definition: nurbsSurfaceEvaluator.h:34
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
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
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
Thread::get_current_thread
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
pmap< int, int >
geomVertexReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomVertexRewriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.