4
\$\begingroup\$

In Bullet Physics when I debug draw physics world the graphical mesh lags behind the collsion shape.

m_DynamicsWorld->stepSimulation(1 / 60.0f, 10);

btTransform trans, trans2;
trans2 = m_RigidBodies.at("CubeMesh")->m_Body->getWorldTransform();

m_RigidBodies.at("CubeMesh")->m_Body->getMotionState()->getWorldTransform(trans);
/*
 * using
 * m_RigidBodies.at("CubeMesh")->m_Body->getMotionState()->getWorldTransform(trans);
 *
 * causes the graphical mesh to lag behind the collision shape in DebugDraw call
 * Checking with debugger shows that the lag error keeps on increasing
 * */
//
//
glm::mat4 M;
trans.getOpenGLMatrix(glm::value_ptr(M));
m_RigidBodies.at("CubeMesh")->GetGraphicalObject()->Model = M;

if (m_DebugDraw) {
    m_DynamicsWorld->debugDrawWorld();
}

If I use the OpenGL matrix from trans2 then debug drawing is perferct. But with trans the graphical mesh lags behind the collision shape in debug draw.

I am using btDefaultMotionState when setting the CubeMesh rigid body.

btTransform tr;
    tr.setIdentity();
    tr.setOrigin(btVector3(0.0f, 90.0f, 0.0f));
    cubeMesh->m_PhysicsBody->m_MotionState = new btDefaultMotionState(tr);

Can anyone explain reason for this lag?

\$\endgroup\$
  • \$\begingroup\$ If you test in very slooooowww motion, does any of these manage to get through the ground but not the other? \$\endgroup\$ – Alexandre Vaillancourt May 9 '17 at 11:59
  • \$\begingroup\$ If i test in slow motion then nothing passes through the ground. When box's collision shape hits ground, both graphical mesh and collision shape align perfectly. \$\endgroup\$ – Manmohan Bishnoi May 9 '17 at 15:27
  • \$\begingroup\$ BulletPhysics demo/tutorial code github.com/bulletphysics/bullet3/blob/master/examples/… uses btCollisionObject->getWorldTransforms() to synchronize physical objects to graphical meshes. I have tried to observe bulletPhysics tutorial code in VisualStudio debugger and have found similar behavior. here is a screenshot of bulletPhysics debugging session i.imgur.com/wXXXdwP.png \$\endgroup\$ – Manmohan Bishnoi May 9 '17 at 15:33
3
\$\begingroup\$

Note that this answer could be more complete, but, as I'm not a Bullet/physics engine guru, and that I'm not able to easily set up a project right now, I did not have the chance to try and debug the code to see exactly what was going on.

I have formatted the code a bit from the source to ease the reading.

After digging around a bit in the code, then remembering that something was said about motion states in the documentation, I found this page again that discussed MotionStates in BulletPhysics, which states:

Bullet knows how to interpolate body movement for you. As mentioned, implementation of interpolation is handled through MotionStates.

If you attempt to ask a body for its position, it will return the position at the end of the last physics tick. That's useful for many things, but for rendering you will want some interpolation. Bullet interpolates the transform of the body before passing the value to setWorldTransform.

If you want the non-interpolated position of a body [which will be the position as it was calculated at the end of the last physics tick], use btRigidBody::getWorldTransform() and query the body directly.

To get the interpolated values for rendering it is necessary to call StepSimulation(deltaTime) in your rendering loop. Only include a deltaTime parameter, no other arguments.

Furthermore, browsing the code of Bullet, stemming from int btDiscreteDynamicsWorld::stepSimulation( btScalar timeStep,int maxSubSteps, btScalar fixedTimeStep)s part:

for (int i=0;i<clampedSimulationSteps;i++)
{
  internalSingleStepSimulation(fixedTimeStep);
  synchronizeMotionStates();
}

we find this function:

void btRigidBody::predictIntegratedTransform(btScalar timeStep,btTransform& predictedTransform) 
{
  btTransformUtil::integrateTransform(
    m_worldTransform,
    m_linearVelocity,
    m_angularVelocity,
    timeStep,
    predictedTransform );
}

that is called at some point to do a simulation step to update the body world transform (predictedTransform here is called with body->getInterpolationWorldTransform()); and this other method that is called to update the MotionState:

void btDiscreteDynamicsWorld::synchronizeSingleMotionState(btRigidBody* body)
{
  btAssert(body);

  if (body->getMotionState() && !body->isStaticOrKinematicObject())
  {
    btTransform interpolatedTransform;
    btTransformUtil::integrateTransform(
      body->getInterpolationWorldTransform(),
      body->getInterpolationLinearVelocity(),
      body->getInterpolationAngularVelocity(),
      (m_latencyMotionStateInterpolation && m_fixedTimeStep) ? 
        m_localTime - m_fixedTimeStep : 
        m_localTime*body->getHitFraction(),
      interpolatedTransform);
    body->getMotionState()->setWorldTransform(interpolatedTransform);
  }
}

We see that there is an extra step done to synchronizeMotionStates, which seems to base it's calculations on the calculated body information and potentially on a different time step for the integration.

The key element here is m_latencyMotionStateInterpolation which is true by default. Looking at the documentation for this variable (emphasis mine):

Interpolate motion state between previous and current transform, instead of current and next transform. This can relieve discontinuities in the rendering, due to penetrations

This seems to be why you get lag when using the motion state's value instead of the body's value.


In your situation, if you are able to update your graphics 60 times per second, and you're able to update your physics simulation 60 times per second, and you do it on a 1:1 basis, and don't care about movement prediction, it seems to be recommended to call:

m_DynamicsWorld->stepSimulation(1 / 60.0f, 1, 1 / 60.0f);

and to get your transform directly from the body, as you have discovered.

I hope it helps :)

\$\endgroup\$
  • \$\begingroup\$ Seems like you are right. The extra step to synchronizeMotionStates is causing the lag. So this is not a BUG in BulletPhysics. I'll stick to getting worldTransforms from rigidBodies directly instead of MotionStates. \$\endgroup\$ – Manmohan Bishnoi May 10 '17 at 7:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.