15 #include "bulletWorld.h" 16 #include "bulletPersistentManifold.h" 17 #include "bulletShape.h" 18 #include "bulletSoftBodyWorldInfo.h" 20 #include "collideMask.h" 22 #define clamp(x, x_min, x_max) max(min(x, x_max), x_min) 26 PStatCollector BulletWorld::_pstat_physics(
"App:Bullet:DoPhysics");
27 PStatCollector BulletWorld::_pstat_simulation(
"App:Bullet:DoPhysics:Simulation");
28 PStatCollector BulletWorld::_pstat_debug(
"App:Bullet:DoPhysics:Debug");
29 PStatCollector BulletWorld::_pstat_p2b(
"App:Bullet:DoPhysics:SyncP2B");
30 PStatCollector BulletWorld::_pstat_b2p(
"App:Bullet:DoPhysics:SyncB2P");
43 for (
int i=0; i<32; i++) {
44 _filter_cb2._collide[i].clear();
45 _filter_cb2._collide[i].set_bit(i);
49 btScalar dx(bullet_sap_extents);
50 btVector3 extents(dx, dx, dx);
52 switch (bullet_broadphase_algorithm) {
53 case BA_sweep_and_prune:
54 _broadphase =
new btAxisSweep3(extents, extents, 1024);
56 case BA_dynamic_aabb_tree:
57 _broadphase =
new btDbvtBroadphase();
60 bullet_cat.error() <<
"no proper broadphase algorithm!" << endl;
62 nassertv(_broadphase);
65 _configuration =
new btSoftBodyRigidBodyCollisionConfiguration();
66 nassertv(_configuration);
69 _dispatcher =
new btCollisionDispatcher(_configuration);
70 nassertv(_dispatcher);
73 _solver =
new btSequentialImpulseConstraintSolver;
77 _world =
new btSoftRigidDynamicsWorld(_dispatcher, _broadphase, _solver, _configuration);
79 nassertv(_world->getPairCache());
81 _world->setWorldUserInfo(
this);
82 _world->setGravity(btVector3(0.0f, 0.0f, 0.0f));
85 _world->getPairCache()->setInternalGhostPairCallback(&_ghost_cb);
88 switch (bullet_filter_algorithm) {
90 _filter_cb = &_filter_cb1;
93 _filter_cb = &_filter_cb2;
96 _filter_cb = &_filter_cb3;
99 bullet_cat.error() <<
"no proper filter algorithm!" << endl;
103 _world->getPairCache()->setOverlapFilterCallback(_filter_cb);
106 _tick_callback_obj = NULL;
109 _info.m_dispatcher = _dispatcher;
110 _info.m_broadphase = _broadphase;
111 _info.m_gravity.setValue(0.0f, 0.0f, 0.0f);
112 _info.m_sparsesdf.Initialize();
115 btGImpactCollisionAlgorithm::registerAlgorithm(_dispatcher);
118 _world->getDispatchInfo().m_enableSPU =
true;
119 _world->getDispatchInfo().m_useContinuous =
true;
120 _world->getSolverInfo().m_splitImpulse =
false;
121 _world->getSolverInfo().m_numIterations = bullet_solver_iterations;
141 set_gravity(
const LVector3 &gravity) {
143 _world->setGravity(LVecBase3_to_btVector3(gravity));
144 _info.m_gravity.setValue(gravity.get_x(), gravity.get_y(), gravity.get_z());
153 set_gravity(PN_stdfloat gx, PN_stdfloat gy, PN_stdfloat gz) {
155 _world->setGravity(btVector3((btScalar)gx, (btScalar)gy, (btScalar)gz));
156 _info.m_gravity.setValue((btScalar)gx, (btScalar)gy, (btScalar)gz);
165 get_gravity()
const {
167 return btVector3_to_LVector3(_world->getGravity());
176 do_physics(PN_stdfloat dt,
int max_substeps, PN_stdfloat stepsize) {
178 _pstat_physics.start();
180 int num_substeps = clamp(
int(dt / stepsize), 1, max_substeps);
184 sync_p2b(dt, num_substeps);
188 _pstat_simulation.start();
189 int n = _world->stepSimulation((btScalar)dt, max_substeps, (btScalar)stepsize);
190 _pstat_simulation.stop();
195 _info.m_sparsesdf.GarbageCollect(bullet_gc_lifetime);
200 _pstat_debug.start();
201 _debug->sync_b2p(_world);
205 _pstat_physics.stop();
216 sync_p2b(PN_stdfloat dt,
int num_substeps) {
218 for (
int i=0; i < get_num_rigid_bodies(); i++) {
219 get_rigid_body(i)->sync_p2b();
222 for (
int i=0; i < get_num_soft_bodies(); i++) {
223 get_soft_body(i)->sync_p2b();
226 for (
int i=0; i < get_num_ghosts(); i++) {
227 get_ghost(i)->sync_p2b();
230 for (
int i=0; i < get_num_characters(); i++) {
231 get_character(i)->sync_p2b(dt, num_substeps);
243 for (
int i=0; i < get_num_vehicles(); i++) {
244 get_vehicle(i)->sync_b2p();
247 for (
int i=0; i < get_num_rigid_bodies(); i++) {
248 get_rigid_body(i)->sync_b2p();
251 for (
int i=0; i < get_num_soft_bodies(); i++) {
252 get_soft_body(i)->sync_b2p();
255 for (
int i=0; i < get_num_ghosts(); i++) {
256 get_ghost(i)->sync_b2p();
259 for (
int i=0; i < get_num_characters(); i++) {
260 get_character(i)->sync_b2p();
272 if (object->
is_of_type(BulletGhostNode::get_class_type())) {
275 else if (object->
is_of_type(BulletRigidBodyNode::get_class_type())) {
278 else if (object->
is_of_type(BulletSoftBodyNode::get_class_type())) {
281 else if (object->
is_of_type(BulletBaseCharacterControllerNode::get_class_type())) {
284 else if (object->
is_of_type(BulletVehicle::get_class_type())) {
287 else if (object->
is_of_type(BulletConstraint::get_class_type())) {
291 bullet_cat->error() <<
"not a bullet world object!" << endl;
303 if (object->
is_of_type(BulletGhostNode::get_class_type())) {
306 else if (object->
is_of_type(BulletRigidBodyNode::get_class_type())) {
309 else if (object->
is_of_type(BulletSoftBodyNode::get_class_type())) {
312 else if (object->
is_of_type(BulletBaseCharacterControllerNode::get_class_type())) {
315 else if (object->
is_of_type(BulletVehicle::get_class_type())) {
318 else if (object->
is_of_type(BulletConstraint::get_class_type())) {
322 bullet_cat->error() <<
"not a bullet world object!" << endl;
337 btRigidBody *ptr = btRigidBody::upcast(node->get_object());
339 BulletRigidBodies::iterator found;
341 found = find(_bodies.begin(), _bodies.end(), ptnode);
343 if (found == _bodies.end()) {
344 _bodies.push_back(node);
345 _world->addRigidBody(ptr);
348 bullet_cat.warning() <<
"rigid body already attached" << endl;
363 btRigidBody *ptr = btRigidBody::upcast(node->get_object());
365 BulletRigidBodies::iterator found;
367 found = find(_bodies.begin(), _bodies.end(), ptnode);
369 if (found == _bodies.end()) {
370 bullet_cat.warning() <<
"rigid body not attached" << endl;
373 _bodies.erase(found);
374 _world->removeRigidBody(ptr);
389 btSoftBody *ptr = btSoftBody::upcast(node->get_object());
392 short group = btBroadphaseProxy::DefaultFilter;
393 short mask = btBroadphaseProxy::AllFilter;
395 BulletSoftBodies::iterator found;
397 found = find(_softbodies.begin(), _softbodies.end(), ptnode);
399 if (found == _softbodies.end()) {
400 _softbodies.push_back(node);
401 _world->addSoftBody(ptr, group, mask);
404 bullet_cat.warning() <<
"soft body already attached" << endl;
419 btSoftBody *ptr = btSoftBody::upcast(node->get_object());
421 BulletSoftBodies::iterator found;
423 found = find(_softbodies.begin(), _softbodies.end(), ptnode);
425 if (found == _softbodies.end()) {
426 bullet_cat.warning() <<
"soft body not attached" << endl;
429 _softbodies.erase(found);
430 _world->removeSoftBody(ptr);
458 short group = btBroadphaseProxy::SensorTrigger;
459 short mask = btBroadphaseProxy::AllFilter
460 & ~btBroadphaseProxy::StaticFilter
461 & ~btBroadphaseProxy::SensorTrigger;
463 btGhostObject *ptr = btGhostObject::upcast(node->get_object());
465 BulletGhosts::iterator found;
467 found = find(_ghosts.begin(), _ghosts.end(), ptnode);
469 if (found == _ghosts.end()) {
470 _ghosts.push_back(node);
471 _world->addCollisionObject(ptr, group, mask);
474 bullet_cat.warning() <<
"ghost already attached" << endl;
489 btGhostObject *ptr = btGhostObject::upcast(node->get_object());
491 BulletGhosts::iterator found;
493 found = find(_ghosts.begin(), _ghosts.end(), ptnode);
495 if (found == _ghosts.end()) {
496 bullet_cat.warning() <<
"ghost not attached" << endl;
499 _ghosts.erase(found);
500 _world->removeCollisionObject(ptr);
515 BulletCharacterControllers::iterator found;
517 found = find(_characters.begin(), _characters.end(), ptnode);
519 if (found == _characters.end()) {
520 _characters.push_back(node);
522 _world->addCollisionObject(node->get_ghost(),
523 btBroadphaseProxy::CharacterFilter,
524 btBroadphaseProxy::StaticFilter|btBroadphaseProxy::DefaultFilter);
526 _world->addCharacter(node->get_character());
529 bullet_cat.warning() <<
"character already attached" << endl;
544 BulletCharacterControllers::iterator found;
546 found = find(_characters.begin(), _characters.end(), ptnode);
548 if (found == _characters.end()) {
549 bullet_cat.warning() <<
"character not attached" << endl;
552 _characters.erase(found);
553 _world->removeCollisionObject(node->get_ghost());
554 _world->removeCharacter(node->get_character());
569 BulletVehicles::iterator found;
571 found = find(_vehicles.begin(), _vehicles.end(), ptvehicle);
573 if (found == _vehicles.end()) {
574 _vehicles.push_back(vehicle);
575 _world->addVehicle(vehicle->get_vehicle());
578 bullet_cat.warning() <<
"vehicle already attached" << endl;
595 BulletVehicles::iterator found;
597 found = find(_vehicles.begin(), _vehicles.end(), ptvehicle);
599 if (found == _vehicles.end()) {
600 bullet_cat.warning() <<
"vehicle not attached" << endl;
603 _vehicles.erase(found);
604 _world->removeVehicle(vehicle->get_vehicle());
618 nassertv(constraint);
620 BulletConstraints::iterator found;
622 found = find(_constraints.begin(), _constraints.end(), ptconstraint);
624 if (found == _constraints.end()) {
625 _constraints.push_back(constraint);
626 _world->addConstraint(constraint->ptr(), linked_collision);
629 bullet_cat.warning() <<
"constraint already attached" << endl;
642 nassertv(constraint);
644 BulletConstraints::iterator found;
646 found = find(_constraints.begin(), _constraints.end(), ptconstraint);
648 if (found == _constraints.end()) {
649 bullet_cat.warning() <<
"constraint not attached" << endl;
652 _constraints.erase(found);
653 _world->removeConstraint(constraint->ptr());
668 const btVector3 from = LVecBase3_to_btVector3(from_pos);
669 const btVector3 to = LVecBase3_to_btVector3(to_pos);
672 _world->rayTest(from, to, cb);
687 const btVector3 from = LVecBase3_to_btVector3(from_pos);
688 const btVector3 to = LVecBase3_to_btVector3(to_pos);
691 _world->rayTest(from, to, cb);
701 sweep_test_closest(
BulletShape *shape,
const TransformState &from_ts,
const TransformState &to_ts,
const CollideMask &mask, PN_stdfloat penetration)
const {
708 const btConvexShape *convex = (
const btConvexShape *) shape->ptr();
709 const btVector3 from_pos = LVecBase3_to_btVector3(from_ts.get_pos());
710 const btVector3 to_pos = LVecBase3_to_btVector3(to_ts.get_pos());
711 const btTransform from_trans = LMatrix4_to_btTrans(from_ts.get_mat());
712 const btTransform to_trans = LMatrix4_to_btTrans(to_ts.get_mat());
715 _world->convexSweepTest(convex, from_trans, to_trans, cb, penetration);
728 nassertr(node0,
false);
729 nassertr(node1,
false);
730 nassertr(_filter_cb,
false);
732 btCollisionObject *obj0 = get_collision_object(node0);
733 btCollisionObject *obj1 = get_collision_object(node1);
735 nassertr(obj0,
false);
736 nassertr(obj1,
false);
738 btBroadphaseProxy *proxy0 = obj0->getBroadphaseHandle();
739 btBroadphaseProxy *proxy1 = obj1->getBroadphaseHandle();
741 nassertr(proxy0,
false);
742 nassertr(proxy1,
false);
744 return _filter_cb->needBroadphaseCollision(proxy0, proxy1);
763 btCollisionObject *obj = get_collision_object(node);
768 #if BT_BULLET_VERSION >= 281 770 cb.use_filter(_filter_cb, obj->getBroadphaseHandle());
774 _world->contactTest(obj, cb);
791 btCollisionObject *obj0 = get_collision_object(node0);
792 btCollisionObject *obj1 = get_collision_object(node1);
798 _world->contactPairTest(obj0, obj1, cb);
810 get_manifold(
int idx)
const {
812 nassertr(idx < get_num_manifolds(), NULL);
814 btPersistentManifold *ptr = _dispatcher->getManifoldByIndexInternal(idx);
823 btCollisionObject *BulletWorld::
826 if (node->
is_of_type(BulletRigidBodyNode::get_class_type())) {
829 else if (node->
is_of_type(BulletGhostNode::get_class_type())) {
832 else if (node->
is_of_type(BulletBaseCharacterControllerNode::get_class_type())) {
835 else if (node->
is_of_type(BulletSoftBodyNode::get_class_type())) {
848 set_group_collision_flag(
unsigned int group1,
unsigned int group2,
bool enable) {
850 if (bullet_filter_algorithm != FA_groups_mask) {
851 bullet_cat.warning() <<
"filter algorithm is not 'groups-mask'" << endl;
854 _filter_cb2._collide[group1].set_bit_to(group2, enable);
855 _filter_cb2._collide[group2].set_bit_to(group1, enable);
864 get_group_collision_flag(
unsigned int group1,
unsigned int group2)
const {
866 return _filter_cb2._collide[group1].get_bit(group2);
877 _world->getSolverInfo().m_solverMode |= SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION;
878 _world->getSolverInfo().m_solverMode |= SOLVER_USE_2_FRICTION_DIRECTIONS;
879 _world->getSolverInfo().m_solverMode |= SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
881 bullet_contact_added_callback = obj;
890 clear_contact_added_callback() {
892 _world->getSolverInfo().m_solverMode &= ~SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION;
893 _world->getSolverInfo().m_solverMode &= ~SOLVER_USE_2_FRICTION_DIRECTIONS;
894 _world->getSolverInfo().m_solverMode &= ~SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
896 bullet_contact_added_callback = NULL;
907 nassertv(obj != NULL);
908 _tick_callback_obj = obj;
909 _world->setInternalTickCallback(&BulletWorld::tick_callback,
this, is_pretick);
918 clear_tick_callback() {
920 _tick_callback_obj = NULL;
921 _world->setInternalTickCallback(NULL);
930 tick_callback(btDynamicsWorld *world, btScalar timestep) {
932 nassertv(world->getWorldUserInfo());
950 nassertv(obj != NULL);
952 if (bullet_filter_algorithm != FA_callback) {
953 bullet_cat.warning() <<
"filter algorithm is not 'callback'" << endl;
956 _filter_cb3._filter_callback_obj = obj;
965 clear_filter_callback() {
967 _filter_cb3._filter_callback_obj = NULL;
975 bool BulletWorld::btFilterCallback1::
976 needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1)
const {
978 btCollisionObject *obj0 = (btCollisionObject *) proxy0->m_clientObject;
979 btCollisionObject *obj1 = (btCollisionObject *) proxy1->m_clientObject;
981 nassertr(obj0,
false);
982 nassertr(obj1,
false);
987 nassertr(node0,
false);
988 nassertr(node1,
false);
993 return (mask0 & mask1) != 0;
1001 bool BulletWorld::btFilterCallback2::
1002 needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1)
const {
1004 btCollisionObject *obj0 = (btCollisionObject *) proxy0->m_clientObject;
1005 btCollisionObject *obj1 = (btCollisionObject *) proxy1->m_clientObject;
1007 nassertr(obj0,
false);
1008 nassertr(obj1,
false);
1013 nassertr(node0,
false);
1014 nassertr(node1,
false);
1021 for (
int i=0; i<32; i++) {
1023 if ((_collide[i] & mask1) != 0)
1037 bool BulletWorld::btFilterCallback3::
1038 needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1)
const {
1040 nassertr(_filter_callback_obj,
false);
1042 btCollisionObject *obj0 = (btCollisionObject *) proxy0->m_clientObject;
1043 btCollisionObject *obj1 = (btCollisionObject *) proxy1->m_clientObject;
1045 nassertr(obj0,
false);
1046 nassertr(obj1,
false);
1051 nassertr(node0,
false);
1052 nassertr(node1,
false);
1055 _filter_callback_obj->do_callback(&cbdata);
1056 return cbdata.get_collide();
1064 operator << (ostream &out, BulletWorld::BroadphaseAlgorithm algorithm) {
1066 switch (algorithm) {
1067 case BulletWorld::BA_sweep_and_prune:
1068 return out <<
"sap";
1070 case BulletWorld::BA_dynamic_aabb_tree:
1071 return out <<
"aabb";
1074 return out <<
"**invalid BulletWorld::BroadphaseAlgorithm(" << (int)algorithm <<
")**";
1082 operator >> (istream &in, BulletWorld::BroadphaseAlgorithm &algorithm) {
1086 if (word ==
"sap") {
1087 algorithm = BulletWorld::BA_sweep_and_prune;
1089 else if (word ==
"aabb") {
1090 algorithm = BulletWorld::BA_dynamic_aabb_tree;
1094 <<
"Invalid BulletWorld::BroadphaseAlgorithm: " << word <<
"\n";
1095 algorithm = BulletWorld::BA_dynamic_aabb_tree;
1106 operator << (ostream &out, BulletWorld::FilterAlgorithm algorithm) {
1108 switch (algorithm) {
1109 case BulletWorld::FA_mask:
1110 return out <<
"mask";
1111 case BulletWorld::FA_groups_mask:
1112 return out <<
"groups-mask";
1113 case BulletWorld::FA_callback:
1114 return out <<
"callback";
1116 return out <<
"**invalid BulletWorld::FilterAlgorithm(" << (int)algorithm <<
")**";
1124 operator >> (istream &in, BulletWorld::FilterAlgorithm &algorithm) {
1128 if (word ==
"mask") {
1129 algorithm = BulletWorld::FA_mask;
1131 else if (word ==
"groups-mask") {
1132 algorithm = BulletWorld::FA_groups_mask;
1134 else if (word ==
"callback") {
1135 algorithm = BulletWorld::FA_callback;
1139 <<
"Invalid BulletWorld::FilterAlgorithm: " << word <<
"\n";
1140 algorithm = BulletWorld::FA_mask;
CollideMask get_into_collide_mask() const
Returns the "into" collide mask for this node.
A basic node of the scene graph or data graph.
void remove_soft_body(BulletSoftBodyNode *node)
Deprecated.
void attach_rigid_body(BulletRigidBodyNode *node)
Deprecated! Please use BulletWorld::attach.
void attach_vehicle(BulletVehicle *vehicle)
Deprecated! Please use BulletWorld::attach.
BulletContactResult contact_test_pair(PandaNode *node0, PandaNode *node1) const
Performas a test if the two bodies given as parameters are in contact or not.
BulletContactResult contact_test(PandaNode *node, bool use_filter=false) const
Performas a test for all bodies which are currently in contact with the given body.
static BulletAllHitsRayResult empty()
Named constructor intended to be used for asserts with have to return a concrete value.
void remove_vehicle(BulletVehicle *vehicle)
Deprecated.
This is an abstract class that all classes which use TypeHandle, and also provide virtual functions t...
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
void remove_ghost(BulletGhostNode *node)
Deprecated.
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
void attach_soft_body(BulletSoftBodyNode *node)
Deprecated! Please use BulletWorld::attach.
bool is_nan() const
Returns true if any component of the vector is not-a-number, false otherwise.
void remove_rigid_body(BulletRigidBodyNode *node)
Deprecated.
Simulates a raycast vehicle which casts a ray per wheel at the ground as a cheap replacement for comp...
static BulletClosestHitRayResult empty()
Named constructor intended to be used for asserts with have to return a concrete value.
bool get_bit(int index) const
Returns true if the nth bit is set, false if it is cleared.
A lightweight class that represents a single element that may be timed and/or counted via stats...
virtual void do_callback(CallbackData *cbdata)
This method called when the callback is triggered; it replaces* the original function.
void attach_ghost(BulletGhostNode *node)
Deprecated! Please use BulletWorld::attach.
static BulletClosestHitSweepResult empty()
Named constructor intended to be used for asserts with have to return a concrete value.
This is a generic object that can be assigned to a callback at various points in the rendering proces...
bool filter_test(PandaNode *node0, PandaNode *node1) const
Performs a test if two bodies should collide or not, based on the collision filter setting...
void remove_character(BulletBaseCharacterControllerNode *node)
Deprecated.
void attach_constraint(BulletConstraint *constraint, bool linked_collision=false)
Attaches a single constraint to a world.
BulletRigidBodyNode * get_chassis()
Returns the chassis of this vehicle.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
void attach_character(BulletBaseCharacterControllerNode *node)
Deprecated! Please use BulletWorld::attach.
TypeHandle is the identifier used to differentiate C++ class types.
void remove_constraint(BulletConstraint *constraint)
Deprecated.