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?
Answer
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 MotionState
s 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 {
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 :)
No comments:
Post a Comment