27 #define clamp(x, x_min, x_max) std::max(std::min(x, x_max), x_min) 36 PStatCollector BulletWorld::_pstat_physics(
"App:Bullet:DoPhysics");
37 PStatCollector BulletWorld::_pstat_simulation(
"App:Bullet:DoPhysics:Simulation");
38 PStatCollector BulletWorld::_pstat_p2b(
"App:Bullet:DoPhysics:SyncP2B");
39 PStatCollector BulletWorld::_pstat_b2p(
"App:Bullet:DoPhysics:SyncB2P");
50 for (
size_t i = 0; i < 32; ++i) {
51 _filter_cb2._collide[i].clear();
52 _filter_cb2._collide[i].set_bit(i);
56 btScalar dx(bullet_sap_extents);
57 btVector3 extents(dx, dx, dx);
59 switch (bullet_broadphase_algorithm) {
60 case BA_sweep_and_prune:
61 _broadphase =
new btAxisSweep3(extents, extents, 1024);
63 case BA_dynamic_aabb_tree:
64 _broadphase =
new btDbvtBroadphase();
67 bullet_cat.error() <<
"no proper broadphase algorithm!" << endl;
69 nassertv(_broadphase);
72 _configuration =
new btSoftBodyRigidBodyCollisionConfiguration();
73 nassertv(_configuration);
76 _dispatcher =
new btCollisionDispatcher(_configuration);
77 nassertv(_dispatcher);
80 _solver =
new btSequentialImpulseConstraintSolver;
84 _world =
new btSoftRigidDynamicsWorld(_dispatcher, _broadphase, _solver, _configuration);
86 nassertv(_world->getPairCache());
88 _world->setWorldUserInfo(
this);
89 _world->setGravity(btVector3(0.0f, 0.0f, 0.0f));
92 _world->getPairCache()->setInternalGhostPairCallback(&_ghost_cb);
95 _filter_algorithm = bullet_filter_algorithm;
96 switch (_filter_algorithm) {
98 _filter_cb = &_filter_cb1;
101 _filter_cb = &_filter_cb2;
104 _filter_cb = &_filter_cb3;
107 bullet_cat.error() <<
"no proper filter algorithm!" << endl;
108 _filter_cb =
nullptr;
111 _world->getPairCache()->setOverlapFilterCallback(_filter_cb);
114 _tick_callback_obj =
nullptr;
117 _info.m_dispatcher = _dispatcher;
118 _info.m_broadphase = _broadphase;
119 _info.m_gravity.setValue(0.0f, 0.0f, 0.0f);
120 _info.m_sparsesdf.Initialize();
123 btGImpactCollisionAlgorithm::registerAlgorithm(_dispatcher);
126 _world->getDispatchInfo().m_enableSPU =
true;
127 _world->getDispatchInfo().m_useContinuous =
true;
128 _world->getSolverInfo().m_splitImpulse =
false;
129 _world->getSolverInfo().m_numIterations = bullet_solver_iterations;
160 if (node != _debug) {
161 if (_debug !=
nullptr) {
162 _debug->_debug_stale =
false;
163 _debug->_debug_world =
nullptr;
167 _world->setDebugDrawer(&(_debug->_drawer));
178 if (_debug !=
nullptr) {
179 _debug->_debug_stale =
false;
180 _debug->_debug_world =
nullptr;
181 _world->setDebugDrawer(
nullptr);
190 set_gravity(
const LVector3 &gravity) {
193 _world->setGravity(LVecBase3_to_btVector3(gravity));
194 _info.m_gravity.setValue(gravity.get_x(), gravity.get_y(), gravity.get_z());
201 set_gravity(PN_stdfloat gx, PN_stdfloat gy, PN_stdfloat gz) {
204 _world->setGravity(btVector3((btScalar)gx, (btScalar)gy, (btScalar)gz));
205 _info.m_gravity.setValue((btScalar)gx, (btScalar)gy, (btScalar)gz);
211 const LVector3 BulletWorld::
212 get_gravity()
const {
215 return btVector3_to_LVector3(_world->getGravity());
222 do_physics(PN_stdfloat dt,
int max_substeps, PN_stdfloat stepsize) {
225 _pstat_physics.start();
227 int num_substeps = clamp(
int(dt / stepsize), 1, max_substeps);
231 do_sync_p2b(dt, num_substeps);
235 _pstat_simulation.start();
236 int n = _world->stepSimulation((btScalar)dt, max_substeps, (btScalar)stepsize);
237 _pstat_simulation.stop();
242 _info.m_sparsesdf.GarbageCollect(bullet_gc_lifetime);
247 _debug->do_sync_b2p(_world);
250 _pstat_physics.stop();
259 do_sync_p2b(PN_stdfloat dt,
int num_substeps) {
266 softbody->do_sync_p2b();
270 ghost->do_sync_p2b();
274 character->do_sync_p2b(dt, num_substeps);
289 softbody->do_sync_b2p();
293 ghost->do_sync_b2p();
297 character->do_sync_b2p();
301 vehicle->do_sync_b2p();
312 if (object->
is_of_type(BulletGhostNode::get_class_type())) {
315 else if (object->
is_of_type(BulletRigidBodyNode::get_class_type())) {
318 else if (object->
is_of_type(BulletSoftBodyNode::get_class_type())) {
321 else if (object->
is_of_type(BulletBaseCharacterControllerNode::get_class_type())) {
324 else if (object->
is_of_type(BulletVehicle::get_class_type())) {
327 else if (object->
is_of_type(BulletConstraint::get_class_type())) {
331 bullet_cat->error() <<
"not a bullet world object!" << endl;
342 if (object->
is_of_type(BulletGhostNode::get_class_type())) {
345 else if (object->
is_of_type(BulletRigidBodyNode::get_class_type())) {
348 else if (object->
is_of_type(BulletSoftBodyNode::get_class_type())) {
351 else if (object->
is_of_type(BulletBaseCharacterControllerNode::get_class_type())) {
354 else if (object->
is_of_type(BulletVehicle::get_class_type())) {
357 else if (object->
is_of_type(BulletConstraint::get_class_type())) {
361 bullet_cat->error() <<
"not a bullet world object!" << endl;
372 do_attach_rigid_body(node);
382 do_remove_rigid_body(node);
392 do_attach_soft_body(node);
402 do_remove_soft_body(node);
412 do_attach_ghost(node);
422 do_remove_ghost(node);
432 do_attach_character(node);
442 do_remove_character(node);
452 do_attach_vehicle(vehicle);
462 do_remove_vehicle(vehicle);
473 do_attach_constraint(constraint, linked_collision);
483 do_remove_constraint(constraint);
494 btRigidBody *ptr = btRigidBody::upcast(node->get_object());
496 BulletRigidBodies::iterator found;
498 found = find(_bodies.begin(), _bodies.end(), ptnode);
500 if (found == _bodies.end()) {
501 _bodies.push_back(node);
502 _world->addRigidBody(ptr);
505 bullet_cat.warning() <<
"rigid body already attached" << endl;
517 btRigidBody *ptr = btRigidBody::upcast(node->get_object());
519 BulletRigidBodies::iterator found;
521 found = find(_bodies.begin(), _bodies.end(), ptnode);
523 if (found == _bodies.end()) {
524 bullet_cat.warning() <<
"rigid body not attached" << endl;
527 _bodies.erase(found);
528 _world->removeRigidBody(ptr);
540 btSoftBody *ptr = btSoftBody::upcast(node->get_object());
543 short group = btBroadphaseProxy::DefaultFilter;
544 short mask = btBroadphaseProxy::AllFilter;
546 BulletSoftBodies::iterator found;
548 found = find(_softbodies.begin(), _softbodies.end(), ptnode);
550 if (found == _softbodies.end()) {
551 _softbodies.push_back(node);
552 _world->addSoftBody(ptr, group, mask);
555 bullet_cat.warning() <<
"soft body already attached" << endl;
567 btSoftBody *ptr = btSoftBody::upcast(node->get_object());
569 BulletSoftBodies::iterator found;
571 found = find(_softbodies.begin(), _softbodies.end(), ptnode);
573 if (found == _softbodies.end()) {
574 bullet_cat.warning() <<
"soft body not attached" << endl;
577 _softbodies.erase(found);
578 _world->removeSoftBody(ptr);
603 short group = btBroadphaseProxy::SensorTrigger;
604 short mask = btBroadphaseProxy::AllFilter
605 & ~btBroadphaseProxy::StaticFilter
606 & ~btBroadphaseProxy::SensorTrigger;
608 btGhostObject *ptr = btGhostObject::upcast(node->get_object());
610 BulletGhosts::iterator found;
612 found = find(_ghosts.begin(), _ghosts.end(), ptnode);
614 if (found == _ghosts.end()) {
615 _ghosts.push_back(node);
616 _world->addCollisionObject(ptr, group, mask);
619 bullet_cat.warning() <<
"ghost already attached" << endl;
631 btGhostObject *ptr = btGhostObject::upcast(node->get_object());
633 BulletGhosts::iterator found;
635 found = find(_ghosts.begin(), _ghosts.end(), ptnode);
637 if (found == _ghosts.end()) {
638 bullet_cat.warning() <<
"ghost not attached" << endl;
641 _ghosts.erase(found);
642 _world->removeCollisionObject(ptr);
654 BulletCharacterControllers::iterator found;
656 found = find(_characters.begin(), _characters.end(), ptnode);
658 if (found == _characters.end()) {
659 _characters.push_back(node);
661 _world->addCollisionObject(node->get_ghost(),
662 btBroadphaseProxy::CharacterFilter,
663 btBroadphaseProxy::StaticFilter|btBroadphaseProxy::DefaultFilter);
665 _world->addCharacter(node->get_character());
668 bullet_cat.warning() <<
"character already attached" << endl;
680 BulletCharacterControllers::iterator found;
682 found = find(_characters.begin(), _characters.end(), ptnode);
684 if (found == _characters.end()) {
685 bullet_cat.warning() <<
"character not attached" << endl;
688 _characters.erase(found);
689 _world->removeCollisionObject(node->get_ghost());
690 _world->removeCharacter(node->get_character());
702 BulletVehicles::iterator found;
704 found = find(_vehicles.begin(), _vehicles.end(), ptvehicle);
706 if (found == _vehicles.end()) {
707 _vehicles.push_back(vehicle);
708 _world->addVehicle(vehicle->get_vehicle());
711 bullet_cat.warning() <<
"vehicle already attached" << endl;
725 BulletVehicles::iterator found;
727 found = find(_vehicles.begin(), _vehicles.end(), ptvehicle);
729 if (found == _vehicles.end()) {
730 bullet_cat.warning() <<
"vehicle not attached" << endl;
733 _vehicles.erase(found);
734 _world->removeVehicle(vehicle->get_vehicle());
746 nassertv(constraint);
748 BulletConstraints::iterator found;
750 found = find(_constraints.begin(), _constraints.end(), ptconstraint);
752 if (found == _constraints.end()) {
753 _constraints.push_back(constraint);
754 _world->addConstraint(constraint->ptr(), linked_collision);
757 bullet_cat.warning() <<
"constraint already attached" << endl;
767 nassertv(constraint);
769 BulletConstraints::iterator found;
771 found = find(_constraints.begin(), _constraints.end(), ptconstraint);
773 if (found == _constraints.end()) {
774 bullet_cat.warning() <<
"constraint not attached" << endl;
777 _constraints.erase(found);
778 _world->removeConstraint(constraint->ptr());
786 get_num_rigid_bodies()
const {
789 return _bodies.size();
796 get_rigid_body(
int idx)
const {
799 nassertr(idx >= 0 && idx < (
int)_bodies.size(),
nullptr);
807 get_num_soft_bodies()
const {
810 return _softbodies.size();
817 get_soft_body(
int idx)
const {
820 nassertr(idx >= 0 && idx < (
int)_softbodies.size(),
nullptr);
821 return _softbodies[idx];
828 get_num_ghosts()
const {
831 return _ghosts.size();
838 get_ghost(
int idx)
const {
841 nassertr(idx >= 0 && idx < (
int)_ghosts.size(),
nullptr);
849 get_num_characters()
const {
852 return _characters.size();
859 get_character(
int idx)
const {
862 nassertr(idx >= 0 && idx < (
int)_characters.size(),
nullptr);
863 return _characters[idx];
870 get_num_vehicles()
const {
873 return _vehicles.size();
880 get_vehicle(
int idx)
const {
883 nassertr(idx >= 0 && idx < (
int)_vehicles.size(),
nullptr);
884 return _vehicles[idx];
891 get_num_constraints()
const {
894 return _constraints.size();
901 get_constraint(
int idx)
const {
904 nassertr(idx >= 0 && idx < (
int)_constraints.size(),
nullptr);
905 return _constraints[idx];
912 get_num_manifolds()
const {
915 return _world->getDispatcher()->getNumManifolds();
922 ray_test_closest(
const LPoint3 &from_pos,
const LPoint3 &to_pos,
const CollideMask &mask)
const {
928 const btVector3 from = LVecBase3_to_btVector3(from_pos);
929 const btVector3 to = LVecBase3_to_btVector3(to_pos);
932 _world->rayTest(from, to, cb);
940 ray_test_all(
const LPoint3 &from_pos,
const LPoint3 &to_pos,
const CollideMask &mask)
const {
946 const btVector3 from = LVecBase3_to_btVector3(from_pos);
947 const btVector3 to = LVecBase3_to_btVector3(to_pos);
950 _world->rayTest(from, to, cb);
965 const btConvexShape *convex = (
const btConvexShape *) shape->ptr();
971 const btVector3 from_pos = LVecBase3_to_btVector3(from_ts.
get_pos());
972 const btVector3 to_pos = LVecBase3_to_btVector3(to_ts.
get_pos());
973 const btTransform from_trans = LMatrix4_to_btTrans(from_ts.
get_mat());
974 const btTransform to_trans = LMatrix4_to_btTrans(to_ts.
get_mat());
977 _world->convexSweepTest(convex, from_trans, to_trans, cb, penetration);
989 nassertr(node0,
false);
990 nassertr(node1,
false);
991 nassertr(_filter_cb,
false);
993 btCollisionObject *obj0 = get_collision_object(node0);
994 btCollisionObject *obj1 = get_collision_object(node1);
996 nassertr(obj0,
false);
997 nassertr(obj1,
false);
999 btBroadphaseProxy *proxy0 = obj0->getBroadphaseHandle();
1000 btBroadphaseProxy *proxy1 = obj1->getBroadphaseHandle();
1002 nassertr(proxy0,
false);
1003 nassertr(proxy1,
false);
1005 return _filter_cb->needBroadphaseCollision(proxy0, proxy1);
1021 btCollisionObject *obj = get_collision_object(node);
1026 #if BT_BULLET_VERSION >= 281 1028 cb.use_filter(_filter_cb, obj->getBroadphaseHandle());
1032 _world->contactTest(obj, cb);
1047 btCollisionObject *obj0 = get_collision_object(node0);
1048 btCollisionObject *obj1 = get_collision_object(node1);
1054 _world->contactPairTest(obj0, obj1, cb);
1064 get_manifold(
int idx)
const {
1067 nassertr(idx < _dispatcher->getNumManifolds(),
nullptr);
1069 btPersistentManifold *ptr = _dispatcher->getManifoldByIndexInternal(idx);
1076 btCollisionObject *BulletWorld::
1079 if (node->
is_of_type(BulletRigidBodyNode::get_class_type())) {
1082 else if (node->
is_of_type(BulletGhostNode::get_class_type())) {
1085 else if (node->
is_of_type(BulletBaseCharacterControllerNode::get_class_type())) {
1088 else if (node->
is_of_type(BulletSoftBodyNode::get_class_type())) {
1099 set_group_collision_flag(
unsigned int group1,
unsigned int group2,
bool enable) {
1102 if (_filter_algorithm != FA_groups_mask) {
1103 bullet_cat.warning() <<
"filter algorithm is not 'groups-mask'" << endl;
1106 _filter_cb2._collide[group1].set_bit_to(group2, enable);
1107 _filter_cb2._collide[group2].set_bit_to(group1, enable);
1114 get_group_collision_flag(
unsigned int group1,
unsigned int group2)
const {
1117 return _filter_cb2._collide[group1].get_bit(group2);
1124 set_force_update_all_aabbs(
bool force) {
1126 _world->setForceUpdateAllAabbs(force);
1133 get_force_update_all_aabbs()
const {
1135 return _world->getForceUpdateAllAabbs();
1145 _world->getSolverInfo().m_solverMode |= SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION;
1146 _world->getSolverInfo().m_solverMode |= SOLVER_USE_2_FRICTION_DIRECTIONS;
1147 _world->getSolverInfo().m_solverMode |= SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
1149 bullet_contact_added_callback = obj;
1156 clear_contact_added_callback() {
1159 _world->getSolverInfo().m_solverMode &= ~SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION;
1160 _world->getSolverInfo().m_solverMode &= ~SOLVER_USE_2_FRICTION_DIRECTIONS;
1161 _world->getSolverInfo().m_solverMode &= ~SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
1163 bullet_contact_added_callback =
nullptr;
1173 nassertv(obj !=
nullptr);
1174 _tick_callback_obj = obj;
1175 _world->setInternalTickCallback(&BulletWorld::tick_callback,
this, is_pretick);
1182 clear_tick_callback() {
1185 _tick_callback_obj =
nullptr;
1186 _world->setInternalTickCallback(
nullptr);
1193 tick_callback(btDynamicsWorld *world, btScalar timestep) {
1195 nassertv(world->getWorldUserInfo());
1197 BulletWorld *w = static_cast<BulletWorld *>(world->getWorldUserInfo());
1204 obj->do_callback(&cbdata);
1217 nassertv(obj !=
nullptr);
1219 if (_filter_algorithm != FA_callback) {
1220 bullet_cat.warning() <<
"filter algorithm is not 'callback'" << endl;
1223 _filter_cb3._filter_callback_obj = obj;
1230 clear_filter_callback() {
1233 _filter_cb3._filter_callback_obj =
nullptr;
1239 bool BulletWorld::btFilterCallback1::
1240 needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1)
const {
1242 btCollisionObject *obj0 = (btCollisionObject *) proxy0->m_clientObject;
1243 btCollisionObject *obj1 = (btCollisionObject *) proxy1->m_clientObject;
1245 nassertr(obj0,
false);
1246 nassertr(obj1,
false);
1251 nassertr(node0,
false);
1252 nassertr(node1,
false);
1257 return (mask0 & mask1) != 0;
1263 bool BulletWorld::btFilterCallback2::
1264 needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1)
const {
1266 btCollisionObject *obj0 = (btCollisionObject *) proxy0->m_clientObject;
1267 btCollisionObject *obj1 = (btCollisionObject *) proxy1->m_clientObject;
1269 nassertr(obj0,
false);
1270 nassertr(obj1,
false);
1275 nassertr(node0,
false);
1276 nassertr(node1,
false);
1283 for (
size_t i = 0; i < 32; ++i) {
1285 if ((_collide[i] & mask1) != 0)
1297 bool BulletWorld::btFilterCallback3::
1298 needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1)
const {
1300 nassertr(_filter_callback_obj,
false);
1302 btCollisionObject *obj0 = (btCollisionObject *) proxy0->m_clientObject;
1303 btCollisionObject *obj1 = (btCollisionObject *) proxy1->m_clientObject;
1305 nassertr(obj0,
false);
1306 nassertr(obj1,
false);
1311 nassertr(node0,
false);
1312 nassertr(node1,
false);
1315 _filter_callback_obj->do_callback(&cbdata);
1316 return cbdata.get_collide();
1323 operator << (ostream &out, BulletWorld::BroadphaseAlgorithm algorithm) {
1325 switch (algorithm) {
1326 case BulletWorld::BA_sweep_and_prune:
1327 return out <<
"sap";
1329 case BulletWorld::BA_dynamic_aabb_tree:
1330 return out <<
"aabb";
1333 return out <<
"**invalid BulletWorld::BroadphaseAlgorithm(" << (int)algorithm <<
")**";
1340 operator >> (istream &in, BulletWorld::BroadphaseAlgorithm &algorithm) {
1344 if (word ==
"sap") {
1345 algorithm = BulletWorld::BA_sweep_and_prune;
1347 else if (word ==
"aabb") {
1348 algorithm = BulletWorld::BA_dynamic_aabb_tree;
1352 <<
"Invalid BulletWorld::BroadphaseAlgorithm: " << word <<
"\n";
1353 algorithm = BulletWorld::BA_dynamic_aabb_tree;
1363 operator << (ostream &out, BulletWorld::FilterAlgorithm algorithm) {
1365 switch (algorithm) {
1366 case BulletWorld::FA_mask:
1367 return out <<
"mask";
1368 case BulletWorld::FA_groups_mask:
1369 return out <<
"groups-mask";
1370 case BulletWorld::FA_callback:
1371 return out <<
"callback";
1373 return out <<
"**invalid BulletWorld::FilterAlgorithm(" << (int)algorithm <<
")**";
1380 operator >> (istream &in, BulletWorld::FilterAlgorithm &algorithm) {
1384 if (word ==
"mask") {
1385 algorithm = BulletWorld::FA_mask;
1387 else if (word ==
"groups-mask") {
1388 algorithm = BulletWorld::FA_groups_mask;
1390 else if (word ==
"callback") {
1391 algorithm = BulletWorld::FA_callback;
1395 <<
"Invalid BulletWorld::FilterAlgorithm: " << word <<
"\n";
1396 algorithm = BulletWorld::FA_mask;
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A basic node of the scene graph or data graph.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is an abstract class that all classes which use TypeHandle, and also provide virtual functions t...
void remove_ghost(BulletGhostNode *node)
Deprecated.
void attach_soft_body(BulletSoftBodyNode *node)
Deprecated! Please use BulletWorld::attach.
BulletClosestHitSweepResult sweep_test_closest(BulletShape *shape, const TransformState &from_ts, const TransformState &to_ts, const CollideMask &mask=CollideMask::all_on(), PN_stdfloat penetration=0.0f) const
Performs a sweep test against all other shapes that match the given group mask.
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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
Similar to MutexHolder, but for a light mutex.
void acquire() const
Grabs the lightMutex if it is available.
void release() const
Releases the lightMutex.
void attach_ghost(BulletGhostNode *node)
Deprecated! Please use BulletWorld::attach.
BulletRigidBodyNode * do_get_chassis()
Returns the chassis of this vehicle.
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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool filter_test(PandaNode *node0, PandaNode *node1) const
Performs a test if two bodies should collide or not, based on the collision filter setting.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void remove_character(BulletBaseCharacterControllerNode *node)
Deprecated.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void attach_constraint(BulletConstraint *constraint, bool linked_collision=false)
Attaches a single constraint to a world.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
This is a standard, non-reentrant mutex, similar to the Mutex class.
void remove_constraint(BulletConstraint *constraint)
Deprecated.
get_into_collide_mask
Returns the "into" collide mask for this node.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.