Search Unity

Question Help with Physics.Simulate() on local physics scene.

Discussion in 'Physics' started by Toack, Jan 18, 2022.

  1. Toack

    Toack

    Joined:
    Dec 18, 2006
    Posts:
    109
    I'm having a weird issue in which simulated physics doesn't match the real one.

    I go through my scene an duplicate all colliders and put them on a new scene for physics simulation. Most of the time it matches, but sometimes it diverges giving a different output, it could be 2 balls a little to the side, or a whole new output depending on at which time in the simulation the error is introduced.

    It usually happens on slow velocities, like it is not responding to the bounce threshold in the physics settings.

    In this example you can see they both, the simulated and the real, start the same and stay the same for a while, but near the end, in the final bounce, the reals separate while the simulated stay close to each other (like no bounce).



    Things I have checked.
    • All colliders are created with the same settings.
    • All rigidbodies are created with the same settings and share the same material.
    • The initial force is the same for both.
    I don't know if the simulated scene share the same global physics settings but as I said, it seems like the bounce threshold in the global physics settings is not applied to the simulated scene.

    Please help, I don't know what else to look for.

    PD: What happens in the real scene is the intended behavior.
     
  2. Toack

    Toack

    Joined:
    Dec 18, 2006
    Posts:
    109
    Seems like a bug from Unity.

    Things I tried:
    • Upgrading to unity 2019.4 LTS.
    • Upgrading to unity 2020.3 LTS.
    However, another thing I tried was to move the simulated units into the real scene, and I could observe that the behavior of them is correct, while not being correct on the simulated scene.
     
  3. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    I'm not a 3D physics dev but all Local Physics Scenes of which the default is one (just the default one) all use the global settings. Also, when you set the bounce threshold, it iterates all physics scenes and sets them individually. A test would be to have the bounce threshold set to something obvious you can check and see if it's applied to the default physics scene and not one you create. Or create two physics scenes and compare them.

    Also, the Physics.Simulate() call and Unity automatically calling simulate are the exact same code-path.

    If you think there's a bug then you're best to submit a bug report so it can be looked at.
     
  4. Toack

    Toack

    Joined:
    Dec 18, 2006
    Posts:
    109
    I could imagine both, same code path for Simulate() and global settings for all scenes, but thanks for confirming.

    I will try your suggestion about something obvious tonight, it makes sense to discover this.

    Thank you for your post.
     
    MelvMay likes this.
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    Feel free to ask though if something isn't making sense.
     
  6. Toack

    Toack

    Joined:
    Dec 18, 2006
    Posts:
    109
    I created a project with just this logic, here are some tests

    Test 1: The problem that I have, simulated physics have a different behaviour.



    Test 2: The same but before the bounce, I grab the simulated ball and move it into the original scene, the ball behaves as intended.



    Test 3: For the bounce to work, I changed the bounce threshold in the physics settings to 0.001, reverting it back to the default value makes the simulations match, and also, the simulated scene behaves exactly the same as in the test 1.



    A final test I did, was to disable automaticSimulation and simulate both using Physics.Simulate(Time.fixedDeltaTime) and physicsScene.Simulate(Time.fixedDeltaTime) and it behaves as in Test 1. So apparently, those calls do not go through the same code path.
     
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    Test 1 makes it very clear that something to do with the bounce-threshold is wrong. This would suggest that, for some reason, when the local physics scene is created, it's not having this set. But this cannot be true (on the face of it, looking at the code) because the "default" one is created in the same way in the same bit of code, there's a "CreateScene()" call. So that is strange.

    Test 1, it's not clear how dragging is moving to another scene. I can only presume you do that as part of the dragging but yes, seems to confirm bounce-threshold not correct for sure.

    Test 3, if I follow correctly, would seem to confirm that the initial bounce-threshold then isn't being applied and being that I can see it is applied (in the PhysX Scene Description) then that is very confusing.

    They do go through the same code path. There's a single entry point in common which does all the simulation work. There's no special preparation before that whether it comes from Unity or from the scripts. The only thing that differs is where the time-step value comes from and the scene settings.

    Although I'm confused on the comparison between the above two things. Physics.Simulate just automatically grabs the default scene because it doesn't have a scene argument. It then calls that scene via physicsScene.Simulate. It is the same. They both call Simulate_Internal which calls the C++ method "Simulate"

    Don't take my word for it though, the code for this is public here.

    Here's the start of the C++ side. PhysicsManager::Simulate is what "Simulate_Internal" calls:
    Code (CSharp):
    1. void PhysicsManager::FixedUpdate()
    2. {
    3.     if (!m_AutoSimulation)
    4.         return; // in this mode the users are expected to call Simulate themselves
    5.  
    6.     float dt = GetTimeManager().GetFixedDeltaTime();
    7.  
    8.     Simulate(GetDefaultPhysicsSceneHandle(), dt);
    9. }
    10.  
    11. void PhysicsManager::Simulate(PhysicsSceneHandle sceneHandle, float dt)
    12. {
    13.     // Fetch the physics scene.
    14.     PhysicsScene* physicsScene = GetPhysicsScene(sceneHandle);
    15.     if (physicsScene == NULL)
    16.     {
    17.         WarningString("Physics.Simulate(...) was called with an invalid scene handle therefore the simulation was not run.");
    18.         return;
    19.     }
    20.  
    21.  
    22. ...
    I added the FixedUpdate portion too. This is internal to Unity and you can see that all it does is call the exact same code-path above.

    The only differences possible are the physics scene i.e. the physics world and its settings.

    Conclusion

    Whilst I'm not a 3D physics dev and this isn't my responsibility, I do know enough about this to continue helping you. If you don't mind, could you host your Test 1 set-up somewhere so I can take a look at it? If you want me to host it for you, DM me with your email and I'll set-up a private workspace only you and I can use for you to upload. Better still, you could submit this as a bug because this really does look wrong and I can take a look. I won't be the person fixing it but I can try to fast-track the confirmation of the bug and possibly submit a potential fix to the 3D team to verify.

    Hope this helps and thanks for taking the time to clearly demonstrate the issue.
     
  8. Toack

    Toack

    Joined:
    Dec 18, 2006
    Posts:
    109
    Cool cool, same code path but the bug then is probably around the global settings being different on both scenes (I still don't discard I'm missing something obvious or doing something I shouldn't in the setup).

    I did submit as a bug yesterday and attached the whole project for these tests. I also linked to this post.

    (The report tool did everything for me :D)
     
  9. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    Maybe, sort of looks like way but potentially it's something related to PhysicsMaterial bounce (restitution) although that would be easy to test if the collision were at a low angle and the friction were high.

    Do you have the case number?
     
  10. Toack

    Toack

    Joined:
    Dec 18, 2006
    Posts:
    109
    Good news, they answered that 2018 LTS is no longer supported, so I upgraded to 2019 LTS and the same issue, but 2020 LTS doesn't have it on the test project.

    I remember upgrading my main project into 2020 LTS (that is why I have it installed) and the issue was still threre. I'm going to do that test again.

    2019 LTS has the issue but I can live upgrading to 2020 LTS if the main project has no other issues related to that upgrade.

    I will let you know.

    PD: Case number 1397195 (in case you want to take a look at the setup).
     
  11. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    Sounds like something was fixed. Note that I was looking specifically at our trunk code which is 2022.2.

    I'll take a look though at it, thanks.
     
  12. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    So yes, I found a change in 2020 onwards. It was fixed via this report: https://issuetracker.unity3d.com/is...t-bouncethreshold-that-predate-their-creation

    The change was indeed related to when the local physics world (scene) was created where it copies all the global settings; it was missing the bounce threshold. It seems the update of that setting was already being applied to all scenes so that part works.
     
  13. Toack

    Toack

    Joined:
    Dec 18, 2006
    Posts:
    109
    So I could workaround the issue on 2018 LTS by re-setting that value when I create the local physics scene?
     
  14. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    It would seem that way yes.
     
  15. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    So I just took a look at the C++ source but it checks to see if the threshold has changed so as to avoid unnecessary work so you'd need to alter first to something different than what it is and then back to whatever value it was unfortunately i.e. something like:

    Code (CSharp):
    1. var threshold = Physics.bounceThreshold;
    2. Physics.bounceThreshold = threshold + 0.1f
    3. Physics.bounceThreshold = threshold;
    Awful workaround but in theory it will work.
     
  16. Toack

    Toack

    Joined:
    Dec 18, 2006
    Posts:
    109
    Yeah, I will test that if 2020 LTS upgrade is not an option.

    But good info because I remember doing something like
    Physics.bounceThreshold = Physics.bounceThreshold
    and same issue, I should have guessed same value may not trigger the change.
     
    MelvMay likes this.
  17. Toack

    Toack

    Joined:
    Dec 18, 2006
    Posts:
    109
    I have perfect simulation on 2020 LTS! I didn't test that much and I will be on the lookout, but everything seems to be working correctly!

    Thank you so much for all your time, insights, and tips.

    I will properly upgrade to 2020 LTS now.

    Cheers!
     
    MelvMay likes this.
  18. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    Good to hear, good luck!