Search Unity

Separating Physics Scenes

Discussion in 'Physics' started by malkere, Dec 14, 2018.

  1. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    (edit: updated to a working example)

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.SceneManagement;
    3.  
    4. public class PhysicsTest : MonoBehaviour {
    5.  
    6.     PhysicsScene scene1Physics;
    7.     PhysicsScene scene2Physics;
    8.     float timer1 = 0;
    9.     float timer2 = 0;
    10.  
    11.     void Start() {
    12.         Physics.autoSimulation = false;
    13.      
    14.         //this floor remains in the default PhysicsScene, meaning none of the cubes will interact with it
    15.         GameObject floor = GameObject.CreatePrimitive(PrimitiveType.Cube);
    16.         floor.transform.localScale = new Vector3(10, 1, 10);
    17.         floor.transform.position = new Vector3(0, -0.5f, 1);
    18.  
    19.         //cubes 1 and 2 will be added to scene1Physics
    20.         GameObject cube1 = GameObject.CreatePrimitive(PrimitiveType.Cube);
    21.         GameObject cube2 = GameObject.CreatePrimitive(PrimitiveType.Cube);
    22.         //cubes 3 and 4 will be added to scene2Physics
    23.         GameObject cube3 = GameObject.CreatePrimitive(PrimitiveType.Cube);
    24.         GameObject cube4 = GameObject.CreatePrimitive(PrimitiveType.Cube);
    25.  
    26.         cube1.transform.position = new Vector3(0, 1, 1);
    27.         cube2.transform.position = new Vector3(0, 1, 2);
    28.         //cubes 3 and 4 are directly above cubes 1 and 2
    29.         cube3.transform.position = new Vector3(0, 3, 1);
    30.         cube4.transform.position = new Vector3(0, 3, 2);
    31.  
    32.         cube1.AddComponent<Rigidbody>();
    33.         cube2.AddComponent<Rigidbody>();
    34.         cube3.AddComponent<Rigidbody>();
    35.         cube4.AddComponent<Rigidbody>();
    36.  
    37.         //the LocalPhysicsMode is what create a new PhysicsScene separate from the default
    38.         CreateSceneParameters csp = new CreateSceneParameters(LocalPhysicsMode.Physics3D);
    39.         Scene scene1 = SceneManager.CreateScene("MyScene1", csp);
    40.         scene1Physics = scene1.GetPhysicsScene();
    41.  
    42.         Scene scene2 = SceneManager.CreateScene("MyScene2", csp);
    43.         scene2Physics = scene2.GetPhysicsScene();
    44.  
    45.         SceneManager.MoveGameObjectToScene(cube1, scene1);
    46.         SceneManager.MoveGameObjectToScene(cube2, scene1);
    47.         SceneManager.MoveGameObjectToScene(cube3, scene2);
    48.         SceneManager.MoveGameObjectToScene(cube4, scene2);
    49.     }
    50.  
    51.     void Update() {
    52.         timer1 += Time.deltaTime;
    53.         timer2 += Time.deltaTime;
    54.  
    55.         if (scene1Physics != null && scene1Physics.IsValid()) {
    56.             while (timer1 >= Time.fixedDeltaTime) {
    57.                 timer1 -= Time.fixedDeltaTime;
    58.  
    59.                 //commenting out this line will stop the physics in scene1
    60.                 scene1Physics.Simulate(Time.fixedDeltaTime);
    61.             }
    62.         }
    63.      
    64.         if (scene2Physics != null && scene2Physics.IsValid()) {
    65.             while (timer2 >= Time.fixedDeltaTime) {
    66.                 timer2 -= Time.fixedDeltaTime;
    67.  
    68.                 //commenting out this line will stop the physics in scene2
    69.                 //scene2Physics.Simulate(Time.fixedDeltaTime);
    70.             }
    71.         }
    72.      
    73.     }
    74.  
    75. }
    76.  
     
    Last edited: Dec 14, 2018
    esbenrb, Drayanlia, Clonkex and 10 others like this.
  2. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    I wasn't passing the scene parameters into CreateScene, working now, and YES, separate physics!!!
     
  3. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,508
    Can you edit the source code in the first post? This is a nice "hello world" example of using separate physics scenes :)
     
    Last edited: Jul 15, 2019
    malkere likes this.
  4. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    good idea. I added some basic comments as well.
     
    Edy likes this.
  5. Burst2FlameGames

    Burst2FlameGames

    Joined:
    Dec 12, 2012
    Posts:
    1
    Thanks for the example!

    Do you know if it’s possible to raycast in a separate scene? I think I read you couldn’t use Physics.* on objects in scenes.
     
  6. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    Edy likes this.
  7. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
  8. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    Looking at some other posts on Twitter, I fail to see the reason for Unity's example using Update with the timer approach.
    Is this not sufficient?:
    Code (CSharp):
    1.     private void FixedUpdate()
    2.     {
    3.         physicsScene.Simulate(Time.fixedDeltaTime * speed);
    4.     }
     
  9. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,508
    That's an interesting question. The doc for Physics.Simulate states "MonoBehaviour.FixedUpdate will still be called at the rate defined by Time.fixedDeltaTime whether automatic simulation is on or off, and regardless of when you call Physics.Simulate."

    Using Update may be necessary in the Unity side for implementing other features such as Time.maximumDeltaTime or other internal behaviors. But other than that, I don't really see a reason for the FixedUpdate approach not to work. Maybe @yant could bring some additional clarification on this?
     
  10. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    Like, in my example where you have a MonoBehaviour calling Simulate from the default scene, as long you're fine with the tick rate being the same, calling Simulate from the default scene FixedUpdate() would produce the same result, I'm assuming. Stuck on some other multiplayer probs before I can really get to this.
     
  11. Dubmulik

    Dubmulik

    Joined:
    Sep 30, 2014
    Posts:
    5
    I'm not sure if I understand use-case of this correct. Lets say if I have a game like Angry Birds and I want to simulate the trajectory of the bird: Do I really have to clone my scene with every single object in it and then run simulation of both scenes to be able to calculate the trajectory? Seems a little too complex.
     
  12. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,770
    You are likely need jus empty scene. You should be needing importing only dynamic of a bird. I.e. Velocities and gravities. But if you start include bounciness, then you would need objects, where bounce can occure.
     
    malkere likes this.
  13. Dubmulik

    Dubmulik

    Joined:
    Sep 30, 2014
    Posts:
    5
    I need to simulate bounces and almost any other physics event that can happen, so I think I would have to duplicate all the objects in the scene to the physics scene. Sounds bit silly, but I guess that is the only way to get accurate trajectories.
     
  14. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    Angry bird only calculated trajectory which is as Antypodish points out, just the bird and it's own physics to draw a line. Some mobile games will calculate the bounces against the wall or obstacles as well, but those are primitives and easily managed. Calculating non-static object collision in a visible simulation is not something I imagine would be necessary in any situation, but you could yes.
     
  15. odonnellm

    odonnellm

    Joined:
    Jun 22, 2018
    Posts:
    1
    Has anyone thought of a way to retain collision detection between local physics scenes? IE so the boxes would hit and stay on the floor rather than falling through
     
  16. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    No, that goes against the entire point of different physics scenes. Its entire purpose is to separate physics between scenes. If you want the boxes to hit the floor why do you have them in a different scene? You can of course fake the problem in a number of ways: Add a box to each physics scene with no renderer to mimic the box in the original scene, etc. The question is always why and if, there is always a how.
     
  17. odonnellmj

    odonnellmj

    Joined:
    Oct 15, 2018
    Posts:
    1
    I was making a time sphere where time moves at a different speed within the sphere of influence rather than outside, the only caveat is making sure collisions are still handled as objects transition into and out of the local scene. I ended up coming to the same conclusion you did with using colliders in both scenes, works very well and doesn't require all the usual math needed to fake slow/fast motion, here's a very rough version of it running.
     
    malkere and Edy like this.
  18. justaguygames

    justaguygames

    Joined:
    Mar 4, 2015
    Posts:
    21
    Thanks for this. Very weirdly though, adding a second scene with 1 plane and 1 ball takes fps down 50 - 75%?!!
     
  19. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    Percentage doesn't really tell you anything much. The difference from 1000fps to 500fps is 0.1ms, and there's got to be some overhead for each physics scene.
     
  20. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    596
    Thanks for making this nice example public on forums.
     
    Edy and malkere like this.
  21. sdpgames

    sdpgames

    Joined:
    Sep 2, 2014
    Posts:
    17
    You can also make all objects you don't want to be simulated kinematic, remember which ones you set and restore them after the loop. I haven't tested this approach, don't see why it wouldn't fit the job.
     
  22. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    kinematic won't stop simulation it will only not apply forces. In other words everything will still interact with a kinematic object, but the kinematic object won't move. If you are using different physics scenes then objects will have absolutely no awareness of one another, as far as physical interactions go.
     
  23. MirkoSon

    MirkoSon

    Joined:
    Oct 14, 2015
    Posts:
    24
    I edited a stripped down example to predict the impact point of a ball using the same concept.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class SphereController : MonoBehaviour
    4. {
    5.     public Vector3 forceApplied;
    6.  
    7.     private bool isGrounded;
    8.     private ImpactPrediction ip;
    9.  
    10.     private void Awake()
    11.     {
    12.         ip = FindObjectOfType<ImpactPrediction>();
    13.     }
    14.  
    15.     void Update()
    16.     {
    17.         if(Input.GetKeyDown(KeyCode.Space) && isGrounded)
    18.         {        
    19.             ip.PredictImpactPoint(forceApplied);
    20.         }
    21.     }
    22.  
    23.     private void OnCollisionEnter(Collision collision)
    24.     {
    25.         isGrounded = true;
    26.         ip.aim.enabled = false;
    27.     }
    28.  
    29.     private void OnCollisionExit(Collision collision)
    30.     {
    31.         isGrounded = false;
    32.     }
    33. }
    34.  
    35. //////////////////////////////////////////////////////////////////////////////////////////////
    36.  
    37. using UnityEngine;
    38. using UnityEngine.SceneManagement;
    39.  
    40. public class ImpactPrediction : MonoBehaviour
    41. {
    42.     [Tooltip("Steps to be evaluated for prediction")]
    43.     public Vector2 stepsRange = new Vector2(100, 250);
    44.  
    45.     public GameObject original;
    46.     public GameObject floor;
    47.     public SpriteRenderer aim;
    48.  
    49.     private Rigidbody oRb;
    50.  
    51.     private Scene scenePrediction;
    52.     private PhysicsScene scenePredictionPhysics;
    53.  
    54.     // Makes sure steps are integers
    55.     private Vector2 StepsRange
    56.     {
    57.         get
    58.         {
    59.             return new Vector2((int)stepsRange.x, (int)stepsRange.y);
    60.         }
    61.     }
    62.  
    63.  
    64.     void Awake()
    65.     {
    66.         oRb = original.GetComponent<Rigidbody>();
    67.     }
    68.  
    69.     private void Start()
    70.     {
    71.         // Prediction scene setup
    72.         scenePrediction = SceneManager.CreateScene("physics-scene", new CreateSceneParameters(LocalPhysicsMode.Physics3D));
    73.         scenePredictionPhysics = scenePrediction.GetPhysicsScene();
    74.  
    75.         // Create a copy of the floor into the prediction scene
    76.         GameObject pFloor = Instantiate(floor);
    77.         SceneManager.MoveGameObjectToScene(pFloor, scenePrediction);
    78.     }
    79.  
    80.     internal void PredictImpactPoint(Vector3 applyForce)
    81.     {
    82.         // Create a shadow copy of the original asset
    83.         GameObject predictionBall = Instantiate(original, original.transform.position, original.transform.rotation);
    84.         SceneManager.MoveGameObjectToScene(predictionBall, scenePrediction);
    85.         Rigidbody predRb = predictionBall.GetComponent<Rigidbody>();
    86.  
    87.         // Apply same forces to both rigidbodies
    88.         oRb.AddForce(applyForce, ForceMode.Impulse);
    89.         predRb.AddForce(oRb.velocity, ForceMode.VelocityChange);
    90.         predRb.AddForce(applyForce, ForceMode.Impulse);
    91.  
    92.         // Simulate in steps inside the prediction scene
    93.         Vector3 predictedPoint;
    94.  
    95.         for (int i = 0; i < StepsRange.y; i++)
    96.         {
    97.             scenePredictionPhysics.Simulate(Time.fixedDeltaTime);
    98.  
    99.             predictedPoint = predictionBall.transform.position;
    100.  
    101.             if(ContactAtLocation(predictedPoint) != Vector3.zero && i > StepsRange.x)
    102.             {
    103.                 aim.enabled = true;
    104.                 aim.transform.position = new Vector3(predictedPoint.x, aim.transform.position.y, predictedPoint.z);
    105.                 break;
    106.             }
    107.         }
    108.  
    109.         // Discard the shadow copy
    110.         Destroy(predictionBall);
    111.     }
    112.  
    113.     // Checks the distance from the floor and returns the hit point when close enough.
    114.     private Vector3 ContactAtLocation(Vector3 pos)
    115.     {
    116.         RaycastHit hit;
    117.  
    118.         if(Physics.Raycast(pos, -Vector3.up, out hit, 100))
    119.             if (hit.distance <= 0.5)
    120.                 return hit.point;
    121.  
    122.         return default;
    123.     }
    124. }
    125.  
     
    Edy likes this.