Search Unity

Question Can't get same result from auto and manual simulation of Physics Scene

Discussion in 'Physics' started by RedGirafeGames, Aug 26, 2020.

  1. RedGirafeGames

    RedGirafeGames

    Joined:
    Sep 30, 2016
    Posts:
    32
    Hi,

    I've posted the question on answers.unity.com but didn't get any response, so I try here :
    https://answers.unity.com/questions/1759033/physicsscenesimulate-has-different-result-than-aut.html

    I am developing a tool allowing to control physics simulation.
    I am duplicating the active scene and simulate the PhysicsScene manually but I can't manage to get the same result when I simulate the same PhysicsScene automatically using Physics.autoSimulation = true.

    The difference is not big, it needs many assets and collisions to get something different, so it will work with very simple samples.

    I have uploaded a sample project on Git.
    https://bitbucket.org/redgirafegames/physicssceneerrorsample/src/master/

    Here is most of the code simulating the scene :

    Code (CSharp):
    1. void Start()
    2.      {
    3.          var csp = new CreateSceneParameters(LocalPhysicsMode.Physics3D);
    4.          var newScene = SceneManager.CreateScene("physics", csp);
    5.          physicsScene = newScene.GetPhysicsScene();
    6.          var clone = Instantiate(toClone, toClone.transform.position,
    7.              toClone.transform.rotation);
    8.          for (int i = 0; i < toClone.transform.childCount; i++)
    9.          {
    10.              var child = clone.transform.GetChild(i);
    11.              var rend = child.GetComponent<Renderer>();
    12.              if (rend != null)
    13.              {
    14.                  Debug.Log("set color");
    15.                  //Call SetColor using the shader property name "_Color" and setting the color to red
    16.                  rend.material.SetColor("_Color", Color.red);
    17.              }
    18.          }
    19.          SceneManager.MoveGameObjectToScene(clone, newScene);
    20.          SimulatePhysicsScene(testDuration);
    21.      }
    22.      private void SimulatePhysicsScene(float duration)
    23.      {
    24.          var t = 0.0f;
    25.          while (t < duration)
    26.          {
    27.              physicsScene.Simulate(Time.fixedDeltaTime);
    28.              t += Time.fixedDeltaTime;
    29.          }
    30.          Debug.Log("Physics scene simulation ended");
    31.      }
    Looks like a bug to me, but that's just too big I must be missing something obvious and I really don't know what...

    Thanks,
    Thomas
     
  2. RedGirafeGames

    RedGirafeGames

    Joined:
    Sep 30, 2016
    Posts:
    32
    Some advancement :
    In fact if I simulate manually the default scene, I get the same result as the Automatic simulation.

    So the problem must be that the default scene and the new scene created for the physics simulation are different... but I don't see where... The scenes objects are strictly the same and I don't see any parameter or configuration when creating a new scene.
     
  3. RedGirafeGames

    RedGirafeGames

    Joined:
    Sep 30, 2016
    Posts:
    32
    It's driving me nuts, Physics are just bugged...
    After hours of test, I can get a different simulation results from the exact same scene before and after a Unity reboot... and it's a very simple scene with 2 spheres... Is there some random seed for Physics somewhere???

    I understand that it can't be deterministic between different computers... but an extra simple scene on the same computer??
     
  4. RedGirafeGames

    RedGirafeGames

    Joined:
    Sep 30, 2016
    Posts:
    32
    I have modified the sample to make it the most simple possible.
    Now it is just :
    - a plane
    - 2 spheres
    - I clone this 3 elements in a new scene by code, and set their color to red
    - I manually simulate both scenes in FixedUpdate
    => I Get a different simulation result as soon as there is a collision : Please why?

    Simulation start
    scene_init.png

    Simulation after collision (red and black should overlap)
    scene_result.png

    Here is all the code of the project :

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.SceneManagement;
    3.  
    4. public class GameLogic : MonoBehaviour
    5. {
    6.     public GameObject toClone;
    7.  
    8.     public Scene newScene;
    9.     private PhysicsScene _physicsScene;
    10.  
    11.     private void Awake()
    12.     {
    13.         Physics.autoSimulation = false;
    14.     }
    15.  
    16.     void Start()
    17.     {
    18.         var csp = new CreateSceneParameters(LocalPhysicsMode.Physics3D);
    19.         newScene = SceneManager.CreateScene("physics", csp);
    20.         newScene = SceneManager.GetSceneAt(1);
    21.         _physicsScene = newScene.GetPhysicsScene();
    22.  
    23.         var clone = Instantiate(toClone);
    24.         // Cloned color to differentiate
    25.         for (int i = 0; i < toClone.transform.childCount; i++)
    26.         {
    27.             clone.transform.GetChild(i).GetComponent<Renderer>().material.SetColor("_Color", Color.red);
    28.         }
    29.  
    30.         SceneManager.MoveGameObjectToScene(clone, newScene);
    31.     }
    32.  
    33.     private void FixedUpdate()
    34.     {
    35.         _physicsScene.Simulate(Time.fixedDeltaTime);
    36.         Physics.Simulate(Time.fixedDeltaTime);
    37.     }
    38. }
    The project is still available on git to test : https://bitbucket.org/redgirafegames/physicssceneerrorsample/src/master/

    Thanks
     
  5. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    Is this DOTS physics? If not, standard unity physics isn’t deterministic so it will not always be the same.
     
  6. RedGirafeGames

    RedGirafeGames

    Joined:
    Sep 30, 2016
    Posts:
    32
    Thanks for your reply, it's standard Unity 2019 Physics, so I don't think (I didn't know DOTS physics before your message) it's DOTS physics.

    I know it's not deterministic, but I get the exact same "wrong" result if I run 10 times in a row in my editor. So I don't think that's the source of the problem, it's clearly enough deterministic (and with the simplicity of the scene... I really hope so...) to get the same result every time, but the clone scene just gives a different output.
     
  7. RedGirafeGames

    RedGirafeGames

    Joined:
    Sep 30, 2016
    Posts:
    32
    Just to clarify what I say :
    From what I test, the example from the documentation (simulating pool balls trajectories) is completly wrong and is absolutly not working
    https://docs.unity3d.com/Manual/physics-multi-scene.html

    I can't simulate the balls trajectories as I don't have the same result in 2 different scenes with the same objects and configuration.
     
  8. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    Yeah because like I said, it’s not deterministic

    the new Unity physics (Dots physics) is meant to be deterministic. Maybe you should investigate using that or try implementing your own physics solution that is deterministic.
     
  9. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    Obviously deterministic can mean several things. Until you control the mismatched implementations of floating-point across CPU then it's not going to be fully determinstic and classic or DOTS physics are the similar in this regard but also not limited to physics. Statements about determinism often refer to not introducing differences on the same platform given the same starting conditions and that's a guiding principle of DOTS but it's also supposed to be the same for classic physics. None of these are fully deterministic across CPU though ... yet!

    Given the basic simulation configuration here I'd be very surprised if the minor deterministic changes of floating-point would make such a huge change and that it was likely related to contact processing order etc so a problem of non-determinism given the same starting conditions.

    I took a quick look at your project and didn't see anything you're doing to cause this but thought it might be that by adding in the cloned physics objects into the default scene initially while existing stuff is active then moving them to another physics scene causes the broadphase order of contacts to change for the original (default scene objects) or at least something related to that. I am not a 3D physics dev so I'm not sure what the crossover here is in relation to things like broadphase etc.

    To verify that though I set the "toClone" GameObject inactive in the scene first then after cloning I set them to both active so no physics is co-resident in the physics scene at any time. Again, this is to ensure that both scenes when activated are identical in terms of how they are stored internally so in theory should be as close as you can get.

    This is the changed script:
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.SceneManagement;
    4.  
    5. public class GameLogic : MonoBehaviour
    6. {
    7.     public GameObject toClone;
    8.  
    9.     public Scene newScene;
    10.     private PhysicsScene _physicsScene;
    11.  
    12.     private void Awake()
    13.     {
    14.         Physics.autoSimulation = false;
    15.     }
    16.    
    17.     void Start()
    18.     {
    19.         var csp = new CreateSceneParameters(LocalPhysicsMode.Physics3D);
    20.         newScene = SceneManager.CreateScene("physics", csp);
    21.         newScene = SceneManager.GetSceneAt(1);
    22.         _physicsScene = newScene.GetPhysicsScene();
    23.  
    24.         // Take this out of the simulation.
    25.         toClone.SetActive(false);
    26.        
    27.         var clone = Instantiate(toClone);
    28.         // Cloned color to differentiate
    29.         for (int i = 0; i < toClone.transform.childCount; i++)
    30.         {
    31.             clone.transform.GetChild(i).GetComponent<Renderer>().material.SetColor("_Color", Color.red);
    32.         }
    33.  
    34.         SceneManager.MoveGameObjectToScene(clone, newScene);
    35.        
    36.         // Add both to the simulation now they're in different physics scenes so should not
    37.         // affect each other internally.
    38.         toClone.SetActive(true);
    39.         clone.SetActive(true);
    40.     }
    41.  
    42.     private void FixedUpdate()
    43.     {
    44.         _physicsScene.Simulate(Time.fixedDeltaTime);
    45.         Physics.Simulate(Time.fixedDeltaTime);
    46.     }
    47. }
    48.  
    This WorksOnMyMachine(tm) but it would be interesting to see if it's the same on yours.

    https://gyazo.com/db9b63abfa63057d040de3c4fce61fc0

    Anyway, hope it helps.
     
    Last edited: Sep 14, 2020
  10. RedGirafeGames

    RedGirafeGames

    Joined:
    Sep 30, 2016
    Posts:
    32
    @MelvMay Thanks ! It works for me too, that's a great starting point to investigate my bigger case!
    I would have never expected that changing a game object's property during the execution of a method (inactive / active in Start execution) would have an impact... that's... disapointing...

    @Antony-Blackett Thanks for your time and replies, I think @MelvMay explained way better than me what I tried to say in my previous posts.
     
  11. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    Well know that what you were doing was deterministic i.e. those two scenes did the same exact thing each time! You wanted both scenes to do the same thing with respect to each other but certain modifications have side-effects, some subtle.

    This is no different than you modifying something in the original scene yourself and getting a slightly different result. For instance, adding in a trigger collider that won't produce a collision response but may change the order of contacts calculated. You can run that multiple times and it'll produce the same result but if you take out the trigger you might get a slightly different result. Note I've not tried the trigger thing.

    In short, your starting conditions were changed from two objects running a simulation into four objects then two removed and placed in another scene then running a simulation which is different. This is not to excuse these kinds of side-effects which can be a real PITA but only to explain them.

    Anyway, glad I could help a lilttle.
     
    RedGirafeGames likes this.
  12. RedGirafeGames

    RedGirafeGames

    Joined:
    Sep 30, 2016
    Posts:
    32
    That makes things way harder than I thought but I get the point, thanks for your detailed explanations.
     
  13. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    I guess it depends fully on what you want to do but it shouldn't get in your way as you should always consider changes to be inputs so you're breaking determinism.

    The crux of the fix is to NOT modify the scene you're predicting at all. An easy way to do this is to NOT start creating cloned objects in it then move them; simply set the active scene to the prediction scene and clone in there then restore the active scene and carry on like this:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.SceneManagement;
    3.  
    4. public class GameLogic : MonoBehaviour
    5. {
    6.     public GameObject toClone;
    7.  
    8.     public Scene newScene;
    9.     private PhysicsScene _physicsScene;
    10.  
    11.     private void Awake()
    12.     {
    13.         Physics.autoSimulation = false;
    14.     }
    15.  
    16.     void Start()
    17.     {
    18.         var csp = new CreateSceneParameters(LocalPhysicsMode.Physics3D);
    19.         newScene = SceneManager.CreateScene("physics", csp);
    20.         newScene = SceneManager.GetSceneAt(1);
    21.         _physicsScene = newScene.GetPhysicsScene();
    22.  
    23.         // Switch to the new scene so cloned objects appear directly in it.
    24.         var oldActiveScene = SceneManager.GetActiveScene();
    25.         SceneManager.SetActiveScene(newScene);
    26.  
    27.         var clone = Instantiate(toClone);
    28.      
    29.         // Cloned color to differentiate
    30.         for (int i = 0; i < toClone.transform.childCount; i++)
    31.         {
    32.             clone.transform.GetChild(i).GetComponent<Renderer>().material.SetColor("_Color", Color.red);
    33.         }
    34.  
    35.         // Restore the old active scene.
    36.         SceneManager.SetActiveScene(oldActiveScene);
    37.  
    38.     }
    39.  
    40.     private void FixedUpdate()
    41.     {
    42.         _physicsScene.Simulate(Time.fixedDeltaTime);
    43.         Physics.Simulate(Time.fixedDeltaTime);
    44.     }
    45. }
    This completely removes any activate/deactivate or scene-moving code and is a lot faster.
     
    RedGirafeGames likes this.
  14. RedGirafeGames

    RedGirafeGames

    Joined:
    Sep 30, 2016
    Posts:
    32
    Amazing !!
    With the activeScene switch I really get exactly the same result even with complex scene now.
    And as you say, it's really cleaner than the activate/deactivate wich was looking more like a hack.

    Thank you so much! I was stuck for weeks with that.

    Concerning what I want do, as I said in my first post, I'm building a tool for the asset store, that will allow to control physics simulation, so even if getting exactly the same result is not always possible, depending on very subtle things, I won't have the hand on the scene and I just want to be able to explain to my tool's users how they can get determinism or why it could fail.

    Now I can, thanks again !
     
    MelvMay likes this.
  15. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    Cool, glad I could help. Good luck with your project.
     
  16. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778

    So Unity Physics (DOTS) is not deterministic across platforms? You say 'yet' so that is planned? Is that planned for only Unity Physics or classic physics as well?
     
  17. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    Not AFAIK.

    Remember that it's not about physics but about how floating-point is handled. The change to how floating-point is handled will simultanesously affect everything DOTS that uses it including physics so it won't be physics changes. All physics can do is be deterministic on the same platform/architecture and that does (or should) apply to classic and DOTS physics engines right now.

    I believe that is planned to be a feature of the Burst compiler in the future. Unity have discussed this under "Cross platform & architecture floating point determinism" in past showing the specificity of the problem.
     
    Antony-Blackett likes this.