Panda3D
Loading...
Searching...
No Matches
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
19#include "bulletSoftBodyShape.h"
21#include "bulletHelper.h"
22#include "bulletWorld.h"
23
24#include "geomVertexRewriter.h"
25#include "geomVertexReader.h"
26
27TypeHandle BulletSoftBodyNode::_type_handle;
28
29/**
30 *
31 */
32BulletSoftBodyNode::
33BulletSoftBodyNode(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 */
60btCollisionObject *BulletSoftBodyNode::
61get_object() const {
62
63 return _soft;
64}
65
66/**
67 *
68 */
69BulletSoftBodyConfig BulletSoftBodyNode::
70get_cfg() {
71 LightMutexHolder holder(BulletWorld::get_global_lock());
72
73 return BulletSoftBodyConfig(_soft->m_cfg);
74}
75
76/**
77 *
78 */
79BulletSoftBodyWorldInfo BulletSoftBodyNode::
80get_world_info() {
81 LightMutexHolder holder(BulletWorld::get_global_lock());
82
83 return BulletSoftBodyWorldInfo(*(_soft->m_worldInfo));
84}
85
86/**
87 *
88 */
89int BulletSoftBodyNode::
90get_num_materials() const {
91 LightMutexHolder holder(BulletWorld::get_global_lock());
92
93 return _soft->m_materials.size();
94}
95
96/**
97 *
98 */
99BulletSoftBodyMaterial BulletSoftBodyNode::
100get_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 */
112BulletSoftBodyMaterial BulletSoftBodyNode::
113append_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 */
125int BulletSoftBodyNode::
126get_num_nodes() const {
127 LightMutexHolder holder(BulletWorld::get_global_lock());
128
129 return _soft->m_nodes.size();
130}
131
132/**
133 *
134 */
135BulletSoftBodyNodeElement BulletSoftBodyNode::
136get_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 */
146void BulletSoftBodyNode::
147generate_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 */
161void BulletSoftBodyNode::
162randomize_constraints() {
163 LightMutexHolder holder(BulletWorld::get_global_lock());
164
165 _soft->randomizeConstraints();
166}
167
168/**
169 *
170 */
171void BulletSoftBodyNode::
172transform_changed() {
173 if (_sync_disable) return;
174
175 LightMutexHolder holder(BulletWorld::get_global_lock());
176
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 */
227void BulletSoftBodyNode::
228do_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 */
237do_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
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 */
320get_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 */
332int BulletSoftBodyNode::
333do_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 */
363void BulletSoftBodyNode::
364link_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 */
401void BulletSoftBodyNode::
402unlink_geom() {
403 LightMutexHolder holder(BulletWorld::get_global_lock());
404
405 _geom = nullptr;
406}
407
408/**
409 *
410 */
411void BulletSoftBodyNode::
412link_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 */
423void BulletSoftBodyNode::
424unlink_curve() {
425 LightMutexHolder holder(BulletWorld::get_global_lock());
426
427 _curve = nullptr;
428}
429
430/**
431 *
432 */
433void BulletSoftBodyNode::
434link_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 */
445void BulletSoftBodyNode::
446unlink_surface() {
447 LightMutexHolder holder(BulletWorld::get_global_lock());
448
449 _surface = nullptr;
450}
451
452/**
453 *
454 */
455BoundingBox BulletSoftBodyNode::
456get_aabb() const {
457 LightMutexHolder holder(BulletWorld::get_global_lock());
458
459 return do_get_aabb();
460}
461
462/**
463 *
464 */
465BoundingBox BulletSoftBodyNode::
466do_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 */
482void BulletSoftBodyNode::
483set_volume_mass(PN_stdfloat mass) {
484 LightMutexHolder holder(BulletWorld::get_global_lock());
485
486 _soft->setVolumeMass(mass);
487}
488
489/**
490 *
491 */
492void BulletSoftBodyNode::
493set_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 */
502void BulletSoftBodyNode::
503set_volume_density(PN_stdfloat density) {
504 LightMutexHolder holder(BulletWorld::get_global_lock());
505
506 _soft->setVolumeDensity(density);
507}
508
509/**
510 *
511 */
512void BulletSoftBodyNode::
513set_total_density(PN_stdfloat density) {
514 LightMutexHolder holder(BulletWorld::get_global_lock());
515
516 _soft->setTotalDensity(density);
517}
518
519/**
520 *
521 */
522void BulletSoftBodyNode::
523set_mass(int node, PN_stdfloat mass) {
524 LightMutexHolder holder(BulletWorld::get_global_lock());
525
526 _soft->setMass(node, mass);
527}
528
529/**
530 *
531 */
532PN_stdfloat BulletSoftBodyNode::
533get_mass(int node) const {
534 LightMutexHolder holder(BulletWorld::get_global_lock());
535
536 return _soft->getMass(node);
537}
538
539/**
540 *
541 */
542PN_stdfloat BulletSoftBodyNode::
543get_total_mass() const {
544 LightMutexHolder holder(BulletWorld::get_global_lock());
545
546 return _soft->getTotalMass();
547}
548
549/**
550 *
551 */
552PN_stdfloat BulletSoftBodyNode::
553get_volume() const {
554 LightMutexHolder holder(BulletWorld::get_global_lock());
555
556 return _soft->getVolume();
557}
558
559/**
560 *
561 */
562void BulletSoftBodyNode::
563add_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 */
573void BulletSoftBodyNode::
574add_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 */
584void BulletSoftBodyNode::
585set_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 */
595void BulletSoftBodyNode::
596add_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 */
606void BulletSoftBodyNode::
607add_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 */
617void BulletSoftBodyNode::
618generate_clusters(int k, int maxiterations) {
619 LightMutexHolder holder(BulletWorld::get_global_lock());
620
621 _soft->generateClusters(k, maxiterations);
622}
623
624/**
625 *
626 */
627void BulletSoftBodyNode::
628release_clusters() {
629 LightMutexHolder holder(BulletWorld::get_global_lock());
630
631 _soft->releaseClusters();
632}
633
634/**
635 *
636 */
637void BulletSoftBodyNode::
638release_cluster(int index) {
639 LightMutexHolder holder(BulletWorld::get_global_lock());
640
641 _soft->releaseCluster(index);
642}
643
644/**
645 *
646 */
647int BulletSoftBodyNode::
648get_num_clusters() const {
649 LightMutexHolder holder(BulletWorld::get_global_lock());
650
651 return _soft->clusterCount();
652}
653
654/**
655 *
656 */
657LVecBase3 BulletSoftBodyNode::
658cluster_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 */
667void BulletSoftBodyNode::
668set_pose(bool bvolume, bool bframe) {
669 LightMutexHolder holder(BulletWorld::get_global_lock());
670
671 _soft->setPose(bvolume, bframe);
672}
673
674/**
675 *
676 */
677void BulletSoftBodyNode::
678append_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 */
694append_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 */
711BulletSoftBodyNodeElement(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 */
720int BulletSoftBodyNode::
721get_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 */
739int BulletSoftBodyNode::
740next_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 */
760PT(BulletSoftBodyNode) BulletSoftBodyNode::
761make_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 */
778PT(BulletSoftBodyNode) BulletSoftBodyNode::
779make_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 */
800PT(BulletSoftBodyNode) BulletSoftBodyNode::
801make_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 */
817PT(BulletSoftBodyNode) BulletSoftBodyNode::
818make_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 */
884PT(BulletSoftBodyNode) BulletSoftBodyNode::
885make_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 */
926PT(BulletSoftBodyNode) BulletSoftBodyNode::
927make_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 */
970PT(BulletSoftBodyNode) BulletSoftBodyNode::
971make_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 */
1058void BulletSoftBodyNode::
1059append_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 */
1078void BulletSoftBodyNode::
1079append_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 */
1098void BulletSoftBodyNode::
1099append_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 */
1119void BulletSoftBodyNode::
1120set_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 */
1130LVector3 BulletSoftBodyNode::
1131get_wind_velocity() const {
1132 LightMutexHolder holder(BulletWorld::get_global_lock());
1133
1134 return btVector3_to_LVector3(_soft->getWindVelocity());
1135}
1136
1137/**
1138 *
1139 */
1140LPoint3 BulletSoftBodyNodeElement::
1141get_pos() const {
1142 LightMutexHolder holder(BulletWorld::get_global_lock());
1143
1144 return btVector3_to_LPoint3(_node.m_x);
1145}
1146
1147/**
1148 *
1149 */
1150LVector3 BulletSoftBodyNodeElement::
1151get_normal() const {
1152 LightMutexHolder holder(BulletWorld::get_global_lock());
1153
1154 return btVector3_to_LVector3(_node.m_n);
1155}
1156
1157/**
1158 *
1159 */
1160LVector3 BulletSoftBodyNodeElement::
1161get_velocity() const {
1162 LightMutexHolder holder(BulletWorld::get_global_lock());
1163
1164 return btVector3_to_LVector3(_node.m_v);
1165}
1166
1167/**
1168 *
1169 */
1170PN_stdfloat BulletSoftBodyNodeElement::
1171get_inv_mass() const {
1172 LightMutexHolder holder(BulletWorld::get_global_lock());
1173
1174 return (PN_stdfloat)_node.m_im;
1175}
1176
1177/**
1178 *
1179 */
1180PN_stdfloat BulletSoftBodyNodeElement::
1181get_area() const {
1182 LightMutexHolder holder(BulletWorld::get_global_lock());
1183
1184 return (PN_stdfloat)_node.m_area;
1185}
1186
1187/**
1188 *
1189 */
1190int BulletSoftBodyNodeElement::
1191is_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...
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.
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
This is our own Panda specialization on the default STL map.
Definition pmap.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.