Bullet is extrapolating, not interpolating + other bug+fix

Post Reply
theagentd
Posts: 1
Joined: Sun Oct 06, 2013 6:46 pm

Bullet is extrapolating, not interpolating + other bug+fix

Post by theagentd »

I'm getting visible snapping whenever the velocity of a body is changed.

I have a simple test program in which I have a sphere falling due to gravity. I'm running at a fixed time step of 1/2f (to exaggerate the problem), and I'm updating at 1/32f intervals, which results in 16 interpolated positions for each real internal step. After every tick there is a huge snap caused by Bullet extrapolating, which is not accurate when velocity changes. Each call to stepSimulation() I print out the difference in Y-position of the interpolated transform. Here's the output: http://pastie.org/8382173

After each tick, the position has to be corrected since the predicted collision was not correct due to gravity. The problem lies in btTransformUtil.h: https://code.google.com/p/bullet/source ... formUtil.h The first line:

Code: Select all

predictedTransform.setOrigin(curTrans.getOrigin() + linvel * timeStep);
This is the complete opposite of interpolation; it's extrapolation. Either the Wiki is completely misguiding, or this code is not doing what it's supposed to.

Related: http://liquidrockgames.blogspot.se/2009 ... ndent.html


EDIT 1:

On top of this, running Bullet without extrapolation (world.stepSimulation(timeStep, 0);) will cause the transform given to MotionState.setWorldTransform() to still be extrapolated.

Here's an example flow of my program:

Code: Select all

Game loop iteration start.

world.stepSimulation(timestep, 0); called.
Tick callback received. In here I also modify the velocity manually, which would screw up the extrapolation. Y is not modified however, so that is not the problem seen here.
Transform updated by Bullet through MotionState.setWorldTransform().
world.stepSimulation() returns.

Starting render procedure.

Position from btRigidBody.getWorldTransform():
[1.0|0.0|0.0|0.9941138]
[0.0|1.0|0.0|6.691561]
[0.0|0.0|1.0|0.97757304]
[0.0|0.0|0.0|1.0]

Position set earlier by Bullet from MotionState.setWorldTransform():
[1.0|0.0|0.0|0.9941138]
[0.0|1.0|0.0|5.476966]
[0.0|0.0|1.0|0.97757304]
[0.0|0.0|0.0|1.0]

Render procedure returns.
End of game loop iteration.
The ground level here is at 7.5. Notice how exaggerated the natural tunneling is in the extrapolated transform from MotionState.setWorldTransform(). The next update/frame however gives identical positions for both methods since now the velocity is 0 after it has hit the ground:

Code: Select all

Position from btRigidBody.getWorldTransform():
[1.0|0.0|0.0|0.9941138]
[0.0|1.0|0.0|7.338312]
[0.0|0.0|1.0|0.97757304]
[0.0|0.0|0.0|1.0]

Position set earlier by Bullet from MotionState.setWorldTransform():
[1.0|0.0|0.0|0.9941138]
[0.0|1.0|0.0|7.338312]
[0.0|0.0|1.0|0.97757304]
[0.0|0.0|0.0|1.0]

Am I missing something here? Bullet seems to be causing unnecessary amounts of tunneling regardless of if extrapolation is supposed to be enabled or not! :( I would be very happy if someone could try to reproduce this!


EDIT 2:
Further testing confirmed that world.stepSimulation(timestep, 0) extrapolates exactly <timestep> seconds ahead into the unknown future when updating MotionStates through setWorldTransform():

Code: Select all

Update time step: 0.12501013
Body velocity: 10.0
btRigidBody getWorldTransform() Y translation: 36.244843
btMotionState setWorldTransform() Y translation: 37.494946
Difference: 1.250103 which is almost exactly <velocity> * <time step>.
This is caused in https://code.google.com/p/bullet/source ... sWorld.cpp on line 416:

Code: Select all

m_localTime = timeStep;
Later, m_localTime is passed into the extrapolation function on line 361 in the same file. m_localTime is only used for extrapolation, so simply replacing the above code with

Code: Select all

m_localTime = 0;
would solve this problem for variable time steps (but not do anything for my original problem).


EDIT 3:
My brain isn't going to let me sleep, so I might as well... After seeing the code, I realized that it may be possible to very easily turn the extrapolation into interpolation for fixed time steps by simply modifying the m_localTime variable. Currently m_localTime ranges from 0 (current frame) to fixedTimeStep (1 step into the unknown future). By simply subtracting fixedTimeStep from m_localTime when passing in that value for integration on line 361 the range would go from -fixedTimeStep (1 step into the past) to 0 instead. This would require a few simple changes to be implemented:
1. fixedTimeStep needs to be saved to a local variable in stepSimulation(), say m_fixedTimeStep.
2. a boolean variable has to be added for switching between interpolation and extrapolation is needed. It also needs a getter and a setter.
3. synchronizeSingleMotionState() should check the mentioned boolean variable, and pass in (m_localTime - m_fixedTime) instead of (m_localTime * body->getHitFraction()) if interpolation is enabled. I'm not 100% sure, but I don't think the hit fraction has to be taken into consideration when interpolating.
Post Reply