I'm looking for information on how to save the runtime state of rigid bodies with Bullet Physics. Most of my world consists of static objects, but I have a few dynamic and kinematic objects as well. I need to take a snapshot of the game state and later restore the exact same state so that it produces the same simulation as if there wasn't any pause. I can easily (and prefer to) recreate the whole world including the rigid bodies, their configuration, collision shapes and constraints.
In addition I need to reset the objects to their initial state, but I think solving the save/restore problem also solves resetting.
I'm using JBullet, which is based on Bullet version 2.72. This means that the built-in serialization is not available for me, as it was added in version 2.76. However answers utilizing the serialization are also welcome, as Java has built-in serialization and others might find it useful. However the description on the wiki page sounds like it's meant for storing whole worlds instead of just the runtime state.
Checking the source code of RigidBody and CollisionObject reveals lots of internal non-final fields of which many are pointers instead primitives. I don't know which of the fields I should save and how to handle the non-primitive fields.
I am surprised to not having found any information on the Internet about this, as I think this is necessary for any game using Bullet physics and requiring exact save and restore functionality. I would prefer a solution that requires only the public API, but I'm open to other solutions as well including modifying the source code as a last resort. I'm also aware of the differences on floating point operations between platforms, but that is not a concern for me.
I implemented the solution suggested by Byte56. I'm now saving and restoring worldTransform, linearVelocity and angularVelocity. I also tried motionState, but that did not have any effect. After restoring the state my object seems to continue the correct trajectory until first collision with a (static) wall. After the collision the object doesn't follow the same path anymore. Interestingly there seems to be only 5-7 slightly different paths that the object randomly chooses.
Without the save and restore my simulation is completely deterministic and always proceeds exactly the same results when running multiple times with the same starting values.
I was thinking that the randomness could have been because of uneven number of simulation steps. I'm using frame skipping and passing 1.0 / 60 as the delta time for stepSimulation:
dynamicsWorld.stepSimulation(deltaTime, 100, 1.0f / 200);. I tried changing 200 to 180, but that didn't help. I wonder if there is something in the DiscreteDynamicsWorld that I should also save. I also tried to save
DiscreteDynamicsWorld.localTime through reflection, but no luck.
After closer investigation even the initial trajectory before any collisions is slightly off. However there seems to be only a constant offset in the coordinates and after the first collision the path changes direction compared to the original.
I implemented a custom serializer using Java Reflection API, which recursively stores all primitive fields from
DiscreteDynamicsWorld. That didn't help. I also tried changing physics updating to just
dynamicsWorld.stepSimulation(1.0f / 60.0f);, but no luck there either. Now I'm out of ideas how to proceed.
setRandSeedfunction that takes a
longas an argument. Perhaps saving and resetting a seed will help? I haven't tried it out yet, just thought I'd let you know for something to look into. I'm not sure what the solver uses random values for... \$\endgroup\$