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);
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.
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>.
Code: Select all
m_localTime = timeStep;
Code: Select all
m_localTime = 0;
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.