saveKinematicState issue

bbangerter
Posts: 6
Joined: Thu Apr 03, 2008 4:45 pm

saveKinematicState issue

Post by bbangerter »

For kinematic objects, btRigidBody::saveKinematicState computes linear and angular velocities based off the the current state of these and the previous state and the timeStep.

saveKinematicState makes a call to calculate velocity

Code: Select all

btTransformUtil::calculateVelocity(m_interpolationWorldTransform,m_worldTransform,timeStep,m_linearVelocity,m_angularVelocity);
which looks like

Code: Select all

static void	calculateVelocity(const btTransform& transform0,const btTransform& transform1,btScalar timeStep,btVector3& linVel,btVector3& angVel)
{
	linVel = (transform1.getOrigin() - transform0.getOrigin()) / timeStep;
	btVector3 axis;
	btScalar  angle;
	calculateDiffAxisAngle(transform0,transform1,axis,angle);
	angVel = axis * angle / timeStep;
}
The problem lies in that timeStep (passed up from btDiscreteDynamicsWorld::stepSimulation) is the timeStep of a single simulation step. While the current position and orientation of the rigid body may have passed through more than a single simulation step if maxSubSteps passed to stepSimulation is greater than 1. This is effectively resulting in a multiplier to the true velocity/angular velocity of the kinematic object. i.e., in our case for our debug builds we pass in a maxSteps of 4, so we have been getting velocities on our kinematic objects 4 times greater than what they should be.

I believe the following fixes the issue (it fixes it for our project, but I don't feel confident enough with all the inner workings of bullet to say it won't cause other issues).

The original function btDiscreteDynamicsWorld::stepSimulation (from v2.67) looks like this

Code: Select all

int	btDiscreteDynamicsWorld::stepSimulation( btScalar timeStep,int maxSubSteps, btScalar fixedTimeStep)
{
	startProfiling(timeStep);

	BT_PROFILE("stepSimulation");

	int numSimulationSubSteps = 0;

	if (maxSubSteps)
	{
		//fixed timestep with interpolation
		m_localTime += timeStep;
		if (m_localTime >= fixedTimeStep)
		{
			numSimulationSubSteps = int( m_localTime / fixedTimeStep);
			m_localTime -= numSimulationSubSteps * fixedTimeStep;
		}
	} else
	{
		//variable timestep
		fixedTimeStep = timeStep;
		m_localTime = timeStep;
		if (btFuzzyZero(timeStep))
		{
			numSimulationSubSteps = 0;
			maxSubSteps = 0;
		} else
		{
			numSimulationSubSteps = 1;
			maxSubSteps = 1;
		}
	}

	//process some debugging flags
	if (getDebugDrawer())
	{
		gDisableDeactivation = (getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_NoDeactivation) != 0;
	}
	if (numSimulationSubSteps)
	{

		saveKinematicState(fixedTimeStep);

		applyGravity();

		//clamp the number of substeps, to prevent simulation grinding spiralling down to a halt
		int clampedSimulationSteps = (numSimulationSubSteps > maxSubSteps)? maxSubSteps : numSimulationSubSteps;

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

	} 

	synchronizeMotionStates();

	clearForces();

#ifndef BT_NO_PROFILE
	CProfileManager::Increment_Frame_Counter();
#endif //BT_NO_PROFILE
	
	return numSimulationSubSteps;
}
I modified the section of code around the call to saveKinematicState as follows

Code: Select all

	if (numSimulationSubSteps)
	{
		//clamp the number of substeps, to prevent simulation grinding spiralling down to a halt
		int clampedSimulationSteps = (numSimulationSubSteps > maxSubSteps)? maxSubSteps : numSimulationSubSteps;

		saveKinematicState(fixedTimeStep * clampedSimulationSteps);

		applyGravity();

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

	}
Notably I compute the clampedSimulationSteps prior to calling saveKinematicState and multiple fixedTimeStep passed into the function by the clampedSimulationSteps.
ole.k
Posts: 17
Joined: Thu Jun 12, 2008 1:32 pm

Re: saveKinematicState issue

Post by ole.k »

I have just detected this issue, too, and found the previous unanswered post in the forum. I think this is a bug. But I would suggest a solution which differs from the solution of bbangerter in that not the time step of the current step (fixedTimeStep * clampedSimulationSteps) is used, but the time step of the previous step (which then has to be remembered), as this is the time elapsed between the last and current transforms of kinematic objects.