Phong13 / BulletSharpUnity3d

A fork of the BulletSharp project to make the Bullet Physics Engine usable from C# code in Unity3d

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Ahead-of-time simulation via StepSimulation call does not match realtime simulation

VoxelBoy opened this issue · comments

Repro scene package (Unity 5.3.5):
https://dl.dropboxusercontent.com/u/561110/bulletAheadOfTimeSimulation.unitypackage

Hit play and click the left mouse button. A launch force is added to a clone ball and its trajectory is calculated in a single frame using DynamicsWorld.StepSimulation method. Right afterwards, the same force is added to the original ball. The two simulations don't match, as can be seen by the ghost objects left behind by the ahead-of-time simulation.

Also, sometimes the original ball fails to be affected by the force applied to it and simply falls straight down. Play the scene several times to notice that the ball sometimes launches forward with the applied force and sometimes falls straight down.

Thanks for preparing these. I am tied up all day Thursday but will take a look on Friday.

I had a look, I think it is working correctly. Here are a couple of thoughts on what is going on.

Bullet StepSimulation steps the simulation by exactly fixedTimeStep (third argument). If timeStep is less than fixedTimeStep, then bullet interpolates between the last two time steps (it generates a new simulation step if necessary). It continues interpolating as StepSimulation is called until a new simulation step is needed and it then simulates the a new one exactly fixedTimeSteps from the last one and interpolates between it and the previous time step. In your example, the realtime simulation is being sampled in Update which will result in interpolated values between the fixedTimeSteps. In your offline simulation, the sampling timesteps are exactly .02. This will result in different positions because the sampling is happening at different times. More info here: http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World

Aside: If you want to do an offline simulation, I would strongly recommend that you don't use the BPhysicsWorld component (which is hooked into Unity events (Update, FixedUpdate) etc.... Instead use the lower level BulletSharp API directly. See the BulletSharpDemos/BasicDemo for an example of how to create a BulletWorld add some objects and step it.

So what is your recommendation for doing an offline simulation that can later be matched perfectly with a realtime simulation?

Also, did you notice that the ball sometimes falls straight down? (If not I'd recommend you run the scene about 10 times and see if the ball will launch or not each time) Any idea what might be causing that?

I would create a second DynamicsWorld with the same configuration as the one in BPhysicsWorld. See method _InitializePhysicsWorld. Then I would add the rigidbodies with the same settings as the ones in the BPhysicsWorld and step the simulation as you did collecting the positions at the end of each FixedTimeStep. These positions will match those generated with the BPhysicsWorld simulation at the end of the FixedTimeStep times. The actual positions of the objects when rendered will be interpolations between these fixed points because the rendering loop is not in synch with the perfect 60 Hz physics loop.

Thanks for mentioning the AddForce problem. That seems to be related. It seems that if the force is added during an Update loop and the StepSimulation is merely an interpolation step (does not trigger simulation of the next timestep), then the force accumulator is cleared before the forces are used in a simulation step. This is a fairly serious problem. Will need to give this some thought about how best to deal with it.

I did some reading about the AddForce problem and looked at the bullet source. It appears that for sudden impulses we should be using AddImpulse. This works as you would expect. AddForce is designed to be used for forces that are applied over many timesteps. For some of those timesteps nothing will happen however the force will be applied for exactly one timestep in each fixedTime interval.

Thanks for the explanations!

I've pulled the latest commit and without doing anything else the offline and realtime simulations match almost exactly now! I'll still look into the lower-level API and creating a second DynamicsWorld but this is very encouraging.

I've tried your suggestion of creating a separate physics world from the lower-level API, building on top of the SimpleOfflineSimulation example you added in your latest commit. However, the result of the offline simulation using the separate physics world is worse than my previous attempt at stepping the existing realtime world.

I've uploaded the repro scene here:
https://dl.dropboxusercontent.com/u/561110/bulletOfflineSimulation_LowLevelAPI.unitypackage

You can switch between the two methods (using separate physics world vs same world) by toggling the "useSecondBulletWorldForSimulation" bool on the Test gameObject's BallThrowTest component.

Could you take a look to see if I'm missing something?
Also, I'm not quite sure how doing it this way is any different than what I was doing before. It's still about stepping a world many time in one frame with fixed timesteps vs letting it play out in realtime, except this time it's a seperate world. I can't see what's different; maybe you can help me understand.

Thank you for helping me figure this out.

I will try to take a look later today. It will be deterministic as long as
the worlds and rigid bodies are created with the same settings and the
world is stepped the same number of times. The advantage of using a
separate world is a big increase in flexibility and maintainability. If you
use the same world then you need to roll back the time to get the world
back to its initial configuration. If you have triggers and/or collision
callbacks then these probably need to be disabled. Also with a separate
world you can spread the load of the simulation across several frames which
can be necessary if the simulation is big.

On Sun, Jun 19, 2016 at 6:34 PM, Yilmaz Kiymaz notifications@github.com
wrote:

I've tried your suggestion of creating a separate physics world from the
lower-level API, building on top of the SimpleOfflineSimulation example you
added in your latest commit. However, the result of the offline simulation
using the separate physics world is worse than my previous attempt at
stepping the existing realtime world.

I've uploaded the repro scene here:

https://dl.dropboxusercontent.com/u/561110/bulletOfflineSimulation_LowLevelAPI.unitypackage

You can switch between the two methods (using separate physics world vs
same world) by toggling the "useSecondBulletWorldForSimulation" bool on the
Test gameObject's BallThrowTest component.

Could you take a look to see if I'm missing something?
Also, I'm not quite sure how doing it this way is any different than what
I was doing before. It's still about stepping a world many time in one
frame with fixed timesteps vs letting it play out in realtime, except this
time it's a seperate world. I can't see what's different; maybe you can
help me understand.

Thank you for helping me figure this out.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#31 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AK1VEYCBlEVUNMUGApfgyneNjHmt7h7Jks5qNe4IgaJpZM4I26is
.

Ian Deane
DigitalOpus http://digitalopus.ca
Twitter: @digitalopus https://twitter.com/DigitalOpus
Vote for my new game EVA Infinity on Steam Greenlight
http://steamcommunity.com/sharedfiles/filedetails/?id=535754554!

Sorry this took a while to take a look. I had a look and was able to improve the situation by making a few tweeks to the offline simulation. I copied most of the rigidbody parameters from the Unity components:

    rbInfo.AngularDamping = rb.angularDamping;
        rbInfo.Friction = rb.friction;
        rbInfo.LinearDamping = rb.linearDamping;
        rbInfo.RollingFriction = rb.rollingFriction;
        etc...

Also the physics timestep was different: World.StepSimulation(1f / 60f, 10, 1f / 60f);

With these parameters both predictions appear identical and closely match the realtime simulation up to the final bounce. I am not sure why they diverge after the final bounce. If I get time I will look into this further.

It appears that for bullet 2.X to be deterministic the rigid bodies in need to be added to the offline world in the same order as the source world. This ensures that collisions are resolved in the same order. With this change the offline sim is deterministic. Also check that the Unity fixedTimeStep matches the bullet timestep.