Making Bullet Deterministic
Posted: Wed Oct 18, 2017 9:01 pm
I am working on a stochastic optimization project for humanoid locomotion where I need to be able to snapshot the simulation and restore the simulation state many times during sampling. The initial tests on the character showed the roll-backs and roll-forwards are not suggesting a deterministic behavior. Even for a simple test case of tossing a bunch of boxes around and computing the collective center of mass I see it is slightly different each time.
I have read the other posts about making Bullet deterministic. While there were great suggestions, still I can not make it work.
So far I have avoided destroying and recreating the world, due to its high computational cost and the complexity of the code. Instead, I have tried the following and got slightly better deterministic behavior, but not fully there. The following is mostly taken from Bullet own reset function.
In addition to the reset function you see, I have turned off the warm start in the solver, and made sure the btSequentialImpulseConstraintSolver is not randomized. What else? Am I missing anything? I am mostly suspecting the constraint solver and the collision handling stuff are the culprits. Is there any randomness involved in any of them that I am not aware of?
Thanks
Shahin
I have read the other posts about making Bullet deterministic. While there were great suggestions, still I can not make it work.
So far I have avoided destroying and recreating the world, due to its high computational cost and the complexity of the code. Instead, I have tried the following and got slightly better deterministic behavior, but not fully there. The following is mostly taken from Bullet own reset function.
Code: Select all
void PhysicsMediator::reset()
{
if (m_dynamicsWorld)
{
numObjects = m_dynamicsWorld->getNumCollisionObjects();
///create a copy of the array, not a reference!
btCollisionObjectArray copyArray = m_dynamicsWorld->getCollisionObjectArray();
for (i = 0;i < numObjects;i++)
{
btCollisionObject* colObj = copyArray[i];
btRigidBody* body = btRigidBody::upcast(colObj);
if (body)
{
if (body->getMotionState())
{
btDefaultMotionState* myMotionState = (btDefaultMotionState*)body->getMotionState();
myMotionState->m_graphicsWorldTrans = myMotionState->m_startWorldTrans;
body->setCenterOfMassTransform(myMotionState->m_graphicsWorldTrans);
colObj->setInterpolationWorldTransform(myMotionState->m_startWorldTrans);
colObj->forceActivationState(ACTIVE_TAG);
colObj->activate();
colObj->setActivationState(DISABLE_DEACTIVATION);
colObj->setDeactivationTime(btScalar(2e7));
}
//removed cached contact points (this is not necessary if all objects have been removed from the dynamics world)
m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(colObj->getBroadphaseHandle(),m_dynamicsWorld->getDispatcher());
btRigidBody* body = btRigidBody::upcast(colObj);
if (body && !body->isStaticObject())
{
btRigidBody::upcast(colObj)->setLinearVelocity(btVector3(0, 0, 0));
btRigidBody::upcast(colObj)->setAngularVelocity(btVector3(0, 0, 0));
btRigidBody::upcast(colObj)->clearForces();
}
}
}
///reset some internal cached data in the broad phase
m_dynamicsWorld->getBroadphase()->resetPool(m_dynamicsWorld->getDispatcher());
m_dynamicsWorld->getConstraintSolver()->reset();
}
}
Thanks
Shahin