Separating Physics Scenes

(edit: updated to a working example)

using UnityEngine;
using UnityEngine.SceneManagement;

public class PhysicsTest : MonoBehaviour {

    PhysicsScene scene1Physics;
    PhysicsScene scene2Physics;
    float timer1 = 0;
    float timer2 = 0;

    void Start() {
        Physics.autoSimulation = false;

        //this floor remains in the default PhysicsScene, meaning none of the cubes will interact with it
        GameObject floor = GameObject.CreatePrimitive(PrimitiveType.Cube);
        floor.transform.localScale = new Vector3(10, 1, 10);
        floor.transform.position = new Vector3(0, -0.5f, 1);

        //cubes 1 and 2 will be added to scene1Physics
        GameObject cube1 = GameObject.CreatePrimitive(PrimitiveType.Cube);
        GameObject cube2 = GameObject.CreatePrimitive(PrimitiveType.Cube);
        //cubes 3 and 4 will be added to scene2Physics
        GameObject cube3 = GameObject.CreatePrimitive(PrimitiveType.Cube);
        GameObject cube4 = GameObject.CreatePrimitive(PrimitiveType.Cube);

        cube1.transform.position = new Vector3(0, 1, 1);
        cube2.transform.position = new Vector3(0, 1, 2);
        //cubes 3 and 4 are directly above cubes 1 and 2
        cube3.transform.position = new Vector3(0, 3, 1);
        cube4.transform.position = new Vector3(0, 3, 2);

        cube1.AddComponent<Rigidbody>();
        cube2.AddComponent<Rigidbody>();
        cube3.AddComponent<Rigidbody>();
        cube4.AddComponent<Rigidbody>();

        //the LocalPhysicsMode is what create a new PhysicsScene separate from the default
        CreateSceneParameters csp = new CreateSceneParameters(LocalPhysicsMode.Physics3D);
        Scene scene1 = SceneManager.CreateScene("MyScene1", csp);
        scene1Physics = scene1.GetPhysicsScene();

        Scene scene2 = SceneManager.CreateScene("MyScene2", csp);
        scene2Physics = scene2.GetPhysicsScene();

        SceneManager.MoveGameObjectToScene(cube1, scene1);
        SceneManager.MoveGameObjectToScene(cube2, scene1);
        SceneManager.MoveGameObjectToScene(cube3, scene2);
        SceneManager.MoveGameObjectToScene(cube4, scene2);
    }

    void Update() {
        timer1 += Time.deltaTime;
        timer2 += Time.deltaTime;

        if (scene1Physics != null && scene1Physics.IsValid()) {
            while (timer1 >= Time.fixedDeltaTime) {
                timer1 -= Time.fixedDeltaTime;

                //commenting out this line will stop the physics in scene1
                scene1Physics.Simulate(Time.fixedDeltaTime);
            }
        }

        if (scene2Physics != null && scene2Physics.IsValid()) {
            while (timer2 >= Time.fixedDeltaTime) {
                timer2 -= Time.fixedDeltaTime;

                //commenting out this line will stop the physics in scene2
                //scene2Physics.Simulate(Time.fixedDeltaTime);
            }
        }

    }

}
14 Likes

I wasn't passing the scene parameters into CreateScene, working now, and YES, separate physics!!!

Can you edit the source code in the first post? This is a nice "hello world" example of using separate physics scenes :)

1 Like

good idea. I added some basic comments as well.

1 Like

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.

There is PhysicsScene.Raycast just for that!
https://docs.unity3d.com/2018.3/Documentation/ScriptReference/PhysicsScene.html
not sure how the rest of physics interactions work yet

1 Like

The 2019.1 documentation has many more functions... I'm not sure if this is just a discrepancy between the documentation versions or not. I assume these are available in 2018.3, haven't tried yet though.
https://docs.unity3d.com/2019.1/Documentation/ScriptReference/PhysicsScene.html

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?:

    private void FixedUpdate()
    {
        physicsScene.Simulate(Time.fixedDeltaTime * speed);
    }

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?

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.

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.

[quote=“Dubmulik”, post:11, topic: 724945]
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.
[/quote]

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.

1 Like

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.

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.

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

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.

[quote=“malkere”, post:16, topic: 724945]
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.
[/quote]
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.

2 Likes

Thanks for this. Very weirdly though, adding a second scene with 1 plane and 1 ball takes fps down 50 - 75%?!!

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.

Thanks for making this nice example public on forums.

2 Likes