Bullet: better performance for rigid body scene graph sync

This commit is contained in:
enn0x 2012-12-10 21:34:30 +00:00
parent 0d43ab3c75
commit ea1a39d123
6 changed files with 156 additions and 49 deletions

View File

@ -21,8 +21,8 @@
INLINE BulletRigidBodyNode::
~BulletRigidBodyNode() {
delete _rigid->getMotionState();
delete _rigid;
delete _motion;
}
////////////////////////////////////////////////////////////////////

View File

@ -25,17 +25,16 @@ TypeHandle BulletRigidBodyNode::_type_handle;
BulletRigidBodyNode::
BulletRigidBodyNode(const char *name) : BulletBodyNode(name) {
// Synchronised transform
// Motion state
_motion = new MotionState();
_sync = TransformState::make_identity();
_sync_disable = false;
// Mass properties
btScalar mass(0.0);
btVector3 inertia(0, 0, 0);
// Motion state and construction info
MotionState *motion = new MotionState(_sync);
btRigidBody::btRigidBodyConstructionInfo ci(mass, motion, _shape, inertia);
// construction info
btRigidBody::btRigidBodyConstructionInfo ci(mass, _motion, _shape, inertia);
// Additional damping
if (bullet_additional_damping) {
@ -268,37 +267,47 @@ apply_central_impulse(const LVector3 &impulse) {
void BulletRigidBodyNode::
transform_changed() {
if (_sync_disable) return;
if (_motion->sync_disabled()) return;
NodePath np = NodePath::any_path((PandaNode *)this);
CPT(TransformState) ts = np.get_net_transform();
LMatrix4 m_sync = _sync->get_mat();
LMatrix4 m_ts = ts->get_mat();
if (!m_sync.almost_equal(m_ts)) {
_sync = ts;
// For kinematic bodies Bullet with collect the transform
// via Motionstate::getWorldTransform. Therefor we need to
// store the new transform within the motion state.
// For dynamic bodies we need to store the net scale within
// the motion state, since Bullet might update the transform
// via MotionState::setWorldTransform.
_motion->set_net_transform(ts);
// For dynamic or static bodies we directly apply the
// new transform.
if (!is_kinematic()) {
btTransform trans = TransformState_to_btTrans(ts);
_rigid->setCenterOfMassTransform(trans);
}
if (ts->has_scale()) {
LVecBase3 scale = ts->get_scale();
if (!scale.almost_equal(LVecBase3(1.0f, 1.0f, 1.0f))) {
for (int i=0; i<get_num_shapes(); i++) {
PT(BulletShape) shape = _shapes[i];
shape->set_local_scale(scale);
}
shape_changed();
// Rescale all shapes, but only if the new transform state
// has a scale
if (ts->has_scale()) {
LVecBase3 scale = ts->get_scale();
if (!scale.almost_equal(LVecBase3(1.0f, 1.0f, 1.0f))) {
for (int i=0; i<get_num_shapes(); i++) {
PT(BulletShape) shape = _shapes[i];
shape->set_local_scale(scale);
}
}
// Activate the body if it has been sleeping
if (!_rigid->isActive()) {
_rigid->activate(true);
shape_changed();
}
}
// Activate the body if it has been sleeping
if (!_rigid->isActive()) {
_rigid->activate(true);
}
// Rememeber current transform (bullet_full_sync)
_sync = ts;
}
////////////////////////////////////////////////////////////////////
@ -309,7 +318,22 @@ transform_changed() {
void BulletRigidBodyNode::
sync_p2b() {
transform_changed();
if (is_kinematic()) {
transform_changed();
}
// Check if net transform has changed (bullet_full_sync)
else if (bullet_full_sync) {
NodePath np = NodePath::any_path((PandaNode *)this);
CPT(TransformState) ts = np.get_net_transform();
LMatrix4 m_sync = _sync->get_mat();
LMatrix4 m_ts = ts->get_mat();
if (!m_sync.almost_equal(m_ts)) {
transform_changed();
}
}
}
////////////////////////////////////////////////////////////////////
@ -320,20 +344,11 @@ sync_p2b() {
void BulletRigidBodyNode::
sync_b2p() {
NodePath np = NodePath::any_path((PandaNode *)this);
LVecBase3 scale = np.get_net_transform()->get_scale();
_motion->sync_b2p((PandaNode *)this);
btTransform trans = _rigid->getWorldTransform();
CPT(TransformState) ts = btTrans_to_TransformState(trans, scale);
LMatrix4 m_sync = _sync->get_mat();
LMatrix4 m_ts = ts->get_mat();
if (!m_sync.almost_equal(m_ts)) {
_sync = ts;
_sync_disable = true;
np.set_transform(NodePath(), ts);
_sync_disable = false;
// Store new transform (bullet_full_sync)
if (bullet_full_sync) {
_motion->get_net_transform(_sync);
}
}
@ -486,6 +501,20 @@ set_angular_factor(const LVector3 &factor) {
_rigid->setAngularFactor(LVecBase3_to_btVector3(factor));
}
////////////////////////////////////////////////////////////////////
// Function: BulletRigidBodyNode::MotionState::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
BulletRigidBodyNode::MotionState::
MotionState() {
_trans.setIdentity();
_scale = LVecBase3(1.0f, 1.0f, 1.0f);
_disabled = false;
_dirty = false;
}
////////////////////////////////////////////////////////////////////
// Function: BulletRigidBodyNode::MotionState::getWorldTransform
// Access: Public
@ -494,7 +523,7 @@ set_angular_factor(const LVector3 &factor) {
void BulletRigidBodyNode::MotionState::
getWorldTransform(btTransform &trans) const {
trans = TransformState_to_btTrans(_sync);
trans = _trans;
}
////////////////////////////////////////////////////////////////////
@ -505,5 +534,65 @@ getWorldTransform(btTransform &trans) const {
void BulletRigidBodyNode::MotionState::
setWorldTransform(const btTransform &trans) {
_trans = trans;
_dirty = true;
}
////////////////////////////////////////////////////////////////////
// Function: BulletRigidBodyNode::MotionState::sync_b2p
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void BulletRigidBodyNode::MotionState::
sync_b2p(PandaNode *node) {
if (!_dirty) return;
NodePath np = NodePath::any_path(node);
CPT(TransformState) ts = btTrans_to_TransformState(_trans, _scale);
_disabled = true;
np.set_transform(NodePath(), ts);
_disabled = false;
_dirty = false;
}
////////////////////////////////////////////////////////////////////
// Function: BulletRigidBodyNode::MotionState::set_net_transform
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void BulletRigidBodyNode::MotionState::
set_net_transform(CPT(TransformState) &ts) {
nassertv(ts);
_trans = TransformState_to_btTrans(ts);
if (ts->has_scale()) {
_scale = ts->get_scale();
}
}
////////////////////////////////////////////////////////////////////
// Function: BulletRigidBodyNode::MotionState::get_net_transform
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void BulletRigidBodyNode::MotionState::
get_net_transform(CPT(TransformState) &ts) const {
ts = btTrans_to_TransformState(_trans, _scale);
}
////////////////////////////////////////////////////////////////////
// Function: BulletRigidBodyNode::MotionState::sync_disabled
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool BulletRigidBodyNode::MotionState::
sync_disabled() const {
return _disabled;
}

View File

@ -91,27 +91,34 @@ protected:
private:
virtual void shape_changed();
// The motion state is required only for kinematic bodies.
// For kinematic nodies getWorldTransform is called each frame, and
// should return the current world transform of the node.
// The motion state is used for syncronisation between Bullet
// and the Panda3D scene graph.
class MotionState : public btMotionState {
public:
MotionState(CPT(TransformState) & sync) : _sync(sync) {};
~MotionState() {};
MotionState();
virtual void getWorldTransform(btTransform &trans) const;
virtual void setWorldTransform(const btTransform &trans);
void set_net_transform(CPT(TransformState) &ts);
void get_net_transform(CPT(TransformState) &ts) const;
void sync_b2p(PandaNode *node);
bool sync_disabled() const;
private:
CPT(TransformState) &_sync;
btTransform _trans;
LVecBase3 _scale;
bool _disabled;
bool _dirty;
};
CPT(TransformState) _sync;
bool _sync_disable;
MotionState *_motion;
btRigidBody *_rigid;
CPT(TransformState) _sync; // only used with bullet_full_sync
////////////////////////////////////////////////////////////////////
public:
static TypeHandle get_class_type() {

View File

@ -987,9 +987,12 @@ needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) co
CollideMask mask0 = node0->get_into_collide_mask();
CollideMask mask1 = node1->get_into_collide_mask();
//cout << mask0 << " " << mask1 << endl;
for (int i=0; i<32; i++) {
if (mask0.get_bit(i)) {
if ((_collide[i] & mask1) != 0)
//cout << "collide: i=" << i << " _collide[i]" << _collide[i] << endl;
return true;
}
}

View File

@ -129,6 +129,13 @@ ConfigVariableDouble bullet_additional_damping_angular_threshold
PRC_DESC("Only used when bullet-additional-damping is set to TRUE. "
"Default value is 0.01."));
ConfigVariableBool bullet_full_sync
("bullet-full-sync", true,
PRC_DESC("Enables optional synchronisation features like checking "
"for changed in a nodes net transform before each simulation "
"step. Disable these features for better performance. "
"Default value is TRUE."));
////////////////////////////////////////////////////////////////////
// Function: init_libbullet
// Description: Initializes the library. This must be called at

View File

@ -40,6 +40,7 @@ extern ConfigVariableDouble bullet_additional_damping_linear_factor;
extern ConfigVariableDouble bullet_additional_damping_angular_factor;
extern ConfigVariableDouble bullet_additional_damping_linear_threshold;
extern ConfigVariableDouble bullet_additional_damping_angular_threshold;
extern ConfigVariableBool bullet_full_sync;
extern EXPCL_PANDABULLET void init_libbullet();