Search Unity

Physics.Simulate for a single object - possible ?

Discussion in 'Physics' started by MustangLM, Jan 17, 2019.

  1. MustangLM

    MustangLM

    Joined:
    Feb 6, 2015
    Posts:
    35
    Hello,

    is there a possible way of applying Physics.Simulate for a single object only ? and leaving all other physics bodies un-simulated ?

    also will enabling kinematic for a certain object be the same as not simulating physics for it ?

    Thanks.
     
    Last edited: Jan 17, 2019
    ModLunar likes this.
  2. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,508
  3. MustangLM

    MustangLM

    Joined:
    Feb 6, 2015
    Posts:
    35
  4. MustangLM

    MustangLM

    Joined:
    Feb 6, 2015
    Posts:
    35
    The problem I am currently facing in multiple scenes is that I still want different game objects in separate scenes to still interact with each other and the main scene which includes, lets say, the terrain while still maintaining the separate physics simulation.
     
  5. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Test it. It does not take more than 10 mins to write such a test, and will be quite insightful.
     
  6. MustangLM

    MustangLM

    Joined:
    Feb 6, 2015
    Posts:
    35
    Indeed I tested it out, I instantiated 100 primitive cubes with a rigidbody attached to it, each one in its separate physics scene, and simulated all 100 cubes at the same time every 0.02 ms, it heavily impacted performance spiking CPU for 4 ms to 120 ms and dropping my frames from 200 to 6-7 frames per second.
     
  7. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,508
    I had missed this one. Physics will be simulated in the way that other objects will be able to collide with the kinematic rigidbody. The difference is that this body won't react to any physics interactions.
     
  8. MustangLM

    MustangLM

    Joined:
    Feb 6, 2015
    Posts:
    35
    Which is in someway what I want it to do, I was wondering if it will be as deterministic as calling Physics.Simulate which plays a big role in my project.
     
  9. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    This doesn't seem right, that it would cost so much for just 100 separate simulations. Even considering physics setup cost, it's just one rigidbody per scene.
     
  10. MustangLM

    MustangLM

    Joined:
    Feb 6, 2015
    Posts:
    35
    I'll test it again and check if I am updating the scenes correctly.
     
  11. MustangLM

    MustangLM

    Joined:
    Feb 6, 2015
    Posts:
    35
    Here's how I am testing it out, it seems like going above 70'ish really affects performance, assuming I am doing it right :

    Code (CSharp):
    1. //Don't forget to include UnityEngine.SceneManagement;
    2.  
    3.     static int scenecount = 0;
    4.  
    5.     delegate void myDelegate(float step);
    6.     static private myDelegate updatePhysics;
    7.  
    8.     List<PhysicsScene> pScenes = new List<PhysicsScene>();
    9.  
    10.     void Start()
    11.     {
    12.         for (int i = 0; i < 100; i++) //number of objects to spawn
    13.         {
    14.             CreateSceneParameters csp = new CreateSceneParameters(LocalPhysicsMode.Physics3D);
    15.      
    16.             scenecount++;
    17.      
    18.             Scene scene = SceneManager.CreateScene("Space" + scenecount, csp);
    19.      
    20.             GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
    21.      
    22.             cube.transform.position = new Vector3(0, scenecount, 0);
    23.      
    24.             cube.AddComponent<Rigidbody>();
    25.      
    26.             pScenes.Add(scene.GetPhysicsScene());
    27.      
    28.             SceneManager.MoveGameObjectToScene(cube, scene);
    29.  
    30.             updatePhysics += scene.GetPhysicsScene().Simulate; //add it to the delegate
    31.         }
    32.      
    33.     }
    34.  
    35.     private void FixedUpdate()
    36.     {
    37.         updatePhysics(Time.fixedDeltaTime);
    38.     }
     
  12. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    Interesting use of delegates. I agree that shouldn't be so performance intensive, so I gave it a test myself.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.SceneManagement;
    3.  
    4. public class PhysicsTest2 : MonoBehaviour {
    5.  
    6.     PhysicsScene[] scenePhysics;
    7.     float timer = 0;
    8.  
    9.     void Start() {
    10.         QualitySettings.vSyncCount = 0;
    11.         Physics.autoSimulation = false;
    12.         Physics.gravity = new Vector3(0, -1f, 0);
    13.  
    14.         GameObject floor = GameObject.CreatePrimitive(PrimitiveType.Cube);
    15.         floor.transform.localScale = new Vector3(100, 1, 100);
    16.         floor.transform.position = new Vector3(0, -0.5f, 1);
    17.  
    18.         scenePhysics = new PhysicsScene[100];
    19.         CreateSceneParameters csp = new CreateSceneParameters(LocalPhysicsMode.Physics3D);
    20.  
    21.         for (int x = 0; x < 10; x++) {
    22.             for (int z = 0; z < 10; z++) {
    23.                 GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
    24.                 cube.transform.position = new Vector3(x * 2f, 1, z * 2f);
    25.                 cube.AddComponent<Rigidbody>();
    26.  
    27.                 int index = (x * 10) + z;
    28.                 Scene scene = SceneManager.CreateScene("MyScene" + index.ToString(), csp);
    29.                 scenePhysics[index] = scene.GetPhysicsScene();
    30.  
    31.                 SceneManager.MoveGameObjectToScene(cube, scene);
    32.             }
    33.         }
    34.     }
    35.  
    36.     void Update() {
    37.         timer += Time.deltaTime;
    38.         while (timer >= Time.fixedDeltaTime) {
    39.             timer -= Time.fixedDeltaTime;
    40.             foreach (PhysicsScene scene in scenePhysics) {
    41.                 if (scene != null && scene.IsValid()) {
    42.                     scene.Simulate(Time.fixedDeltaTime);
    43.                 }
    44.             }
    45.         }
    46.     }
    47.  
    48. }
    I'm getting 120fps for the simulation.

    As for cross scene interactions, no way. That defeats the purpose/idea behind separate scenes. If each scene had to check physics against all other scenes they wouldn't be separate. You could almost certainly fake things if you really needed to by passing data around, ghost copying colliders here and there, but it would be messy.

    I think you will have better luck working with layers. You can set layers to not interact with certain other layers using LayerMasks, and Physics.IgnoreCollisions and things, to make your objects not touch each other, but still touch the terrain. For example my player spells do not interact with the player or with each other, but will hit buildings, monster, and the environment, etc.
     
    NotaNaN, yant and hippocoder like this.
  13. MustangLM

    MustangLM

    Joined:
    Feb 6, 2015
    Posts:
    35
    thanks for checking out my thread, I agree with you about scene interaction and the Idea of separate scenes, but I just need a way to call Physics.Simulate for a single Rigid Body in the same scene, I've been testing some things by switching on/off isKinematic before calling physics.simulate and preserving velocity and angularVelocity for rigid bodies but it will not give the same result in repeated simulation data which is important for my projects.
     
    Last edited: Jan 18, 2019
  14. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    What are you trying to do exactly?
    I feel like you're approaching this problem in a very weird way.
    Like @malkere said, if you don't want stuff interacting with each other you can just modify the collision matrix in the physics settings.
     
  15. MustangLM

    MustangLM

    Joined:
    Feb 6, 2015
    Posts:
    35
    a similar approach to networking physics using deterministic lockstep, at some moments I need to simulate objects while other objects needs to be un-simulated while preserving their previous forces.

    regarding objects interacting with each other, I do need them to interact with each one another and collide even if its frozen/un-simulated
     
    Last edited: Jan 18, 2019
    ModLunar likes this.
  16. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Physx itself is not deterministic, it will diverge over time due to numerical inaccuracy. It's small, but it is there. If it's just simulate some but pause others, you don't need or want separate simulations. Use layers or ignore collision commands.
     
  17. MustangLM

    MustangLM

    Joined:
    Feb 6, 2015
    Posts:
    35
    I can handle small inaccuracies by fixing the client slightly without him noticing and I achieved that, but for now I need to choose a subset of rigidbodies to simulate while keeping others un-simulated until enough input buffer is available then advancing these ones to catch up in the simulation with the other rigidbodies, currently if one client had some packets lost or a connection problem and the available buffer for that client is now empty the whole server will have to wait for that client to feed us with his inputs for the lost frames and then continue the simulation, this is clearly unacceptable and will lead to fix each client, I can get around this by creating one separate scene for local physics and move rigidbodies with not enough buffer there to not include them in the simulation but when the input is received I will not be able to simulate multiple frames at the same moment without affecting other normal running connections and will lead to fix that client and moving him a huge step backwards.
     
  18. MustangLM

    MustangLM

    Joined:
    Feb 6, 2015
    Posts:
    35
    if @yant could check this out
     
  19. hottabych

    hottabych

    Joined:
    Apr 18, 2015
    Posts:
    107
    Just interested if it's possible to parallelize physics simulation on multiple threads via async/await mechanism.
    Seems like a local PhysicsScene is what I was looking for.
    I could put my gameobject groups intro separate PhysicsScenes and run simulation of each one in a separate Task. Those gameobjects can't interact to objects from other groups though, between itselves only.
    Will it work?
     
    Last edited: Apr 12, 2019
  20. TheoPoilmek

    TheoPoilmek

    Joined:
    Mar 22, 2019
    Posts:
    17
    That sounds incorrect. PhysX itself is deterministic and has flags like PxSceneFlag::eENABLE_ENHANCED_DETERMINISM to deal with edge cases that break it. See the manual.
     
  21. TheoPoilmek

    TheoPoilmek

    Joined:
    Mar 22, 2019
    Posts:
    17
    The way to do that in PhysX would be the immediate mode API. I suppose Unity doesn't use it?
     
  22. CosmicGiant

    CosmicGiant

    Joined:
    Jul 22, 2014
    Posts:
    23
    I need to do exactly this. I'm trying to get projectile path prediction. I can fake it with
    Physics2D.CircleCast
    and some trickery in a loop, but it only works when collisions are straight bounces, with no velocity lost to friction. I don't know how Unity calculates friction. And it becomes a hacky solution at best even if I knew how to properly simulate physics reactions.

    On the other hand, a separate physics scene doesn't have the objects that the projectile would bounce against, unless I clone them in. Which is also bad.

    If I could simply simulate the one physics-prediction projectile in the original scene without simulating the rest of the stuff, that would be ideal. Well, I can, if I find all rigidbodies other than the one used for the prediction, and make them kinematic, then do the simulation, then return the objects to their original states. But just from this explanation, it's pretty clear it would not be ideal either, compared to just specifying the one object I was to simulate.
     
  23. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    That's just not how any of that works unfortunately. You gave the 3 "sound" ideas for getting around the limitation yourself already. I don't think friction is applied to a bounce, maybe you've been trying that out though, I certainly haven't. You could make a series of small casts based on the velocity of the object, small meaning each physics step, and add gravity and other forces manually each step. You can also set the object to zero friction if that's causing problems. I think that's probably your best way to go about it. Unless this is a very integral part of your game, then having a second simplified, zero render, physics only scene for bounce support would be easy, but use up some CPU/RAM.
     
  24. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    I'm trying to finish my implementation of Deterministic Lockstep for my multiplayer game, and strongly need this as well.

    aka: I really need to simulate only 1 or certain objects in my 2D physics scene.
    I already separate GameMaps in my game by Scenes created at runtime that use a PhysicsScene2D, and I want things in the same GameMap to react to each other (triggers, collisions, etc.), so I don't want to isolate by every object.
    Also I've confirmed switching PhysicsScene2D on a Rigidbody2D messes up/restarts their simulation behind the scenes, so it does NOT give the same results as simulating continuously in the same scene.

    It'd be nice to be able to call PhysicsScene2D.Simulate(...) giving a layer mask of which objects to simulate, for example.
    (Disclaimer: I know the 2D physics engine used (called "Box2D") is different than PhysX, but I have the same problem).
     
    NotaNaN likes this.
  25. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    For now though, I found a great solution for 2D!
    Disclaimer: It relies on code I've already written though, so this might look like a lot.
    I wrote this for anyone who's desperate to get it working now, even if it takes a lot of code.

    This solution allows me to do the following:

    1. Simulate 1 player's physics with a Rigidbody2D
    2. NOT resort to rigidbody2D.simulated = false on all other Rigidbody2Ds, ALLOWING physics callbacks like OnTriggerXXX2D and OnCollisionXXX2D to still be called during the player's "isolated" simulation.
    3. Restore state back to the objects that were frozen in a way that keeps them moving as they were previously & uninterrupted


    --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

    I created a struct of data containing a little snapshot of a Rigidbody2D's state:
    Code (CSharp):
    1. [Serializable]
    2. private struct PhysicsState2D {
    3.     public Rigidbody2D rigidbody;
    4.     public Vector2 velocity;
    5.     public float angularVelocity;
    6.     public RigidbodyType2D bodyType;
    7.  
    8.     public PhysicsState2D(Rigidbody2D source) {
    9.         rigidbody = source;
    10.         velocity = rigidbody.velocity;
    11.         angularVelocity = rigidbody.angularVelocity;
    12.         bodyType = rigidbody.bodyType;
    13.     }
    14. }
    15.  
    I populate an existing List<Rigidbody2D> containing all my Rigidbody2Ds in the Scene. Re-using lists help performance rather than allocating new arrays every time to search the physics scene.
    Code (CSharp):
    1. SceneUtil.GetAllComponents<Rigidbody2D>(map.Scene, rootGameObjects, allRigidbodies);
    I wrote this method, which is quite boring -- but it searches the whole Scene (starting at all the root/top-level GameObjects, and calls GetComponent<T>() on every object). This assumes you can't have 2 or more Rigidbody2D components on the same object.
    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Assertions;
    5. using UnityEngine.SceneManagement;
    6.  
    7. public static class SceneUtil {
    8.     //Assumes you DO NOT have more than 1 of the component type on the same GameObject
    9.     public static void GetAllComponents<T>(this Scene scene, List<GameObject> rootGameObjects, List<T> components) where T : Component {
    10.         if (rootGameObjects == null)
    11.             throw new ArgumentNullException(nameof(rootGameObjects));
    12.         if (components == null)
    13.             throw new ArgumentNullException(nameof(components));
    14.  
    15.         rootGameObjects.Clear();
    16.         components.Clear();
    17.         if (!scene.IsValid())
    18.             return;
    19.  
    20.         scene.GetRootGameObjects(rootGameObjects);
    21.  
    22.         foreach (GameObject root in rootGameObjects)
    23.             AddComponentsFromObjects<T>(root.transform, components);
    24.     }
    25.  
    26.     private static void AddComponentsFromObjects<T>(Transform root, List<T> components) where T : Component {
    27.         Assert.IsNotNull(root);
    28.  
    29.         if (root.TryGetComponent(out T component))
    30.             components.Add(component);
    31.  
    32.         int childCount = root.childCount;
    33.         for (int i = 0; i < childCount; i++) {
    34.             AddComponentsFromObjects<T>(root.GetChild(i), components);
    35.         }
    36.     }
    37. }
    38.  
    So after the call to
    Code (CSharp):
    1. SceneUtil.GetAllComponents<Rigidbody2D>(map.Scene, rootGameObjects, allRigidbodies);
    ,
    I loop through my List<Rigidbody2D> called "allRigidbodies" in this example, and freeze the states of almost all them (excluding the 1 player) into a List<PhysicsState2D> that stores their velocity, etc. To freeze each one, I do the following:
    Code (CSharp):
    1. previousStates.Add(new PhysicsState2D(r));
    2. r.velocity = Vector2.zero;
    3. r.angularVelocity = 0;
    4. r.bodyType = RigidbodyType2D.Kinematic;
    NOTE that I don't just set the rigidbody (called "r" above) to be Kinematic. According to the docs on RigidbodyType2D.Kinematic, they can still move with velocity and angularVelocity, despite not reacting to new forces. Thus, it's extremely important to zero out the velocity and angularVelocity, after storing what they were previously. Setting velocity & angularVelocity to zero, and changing to Kinematic -- allow the object to be IN the simulation and NOT move at all, and then RESUME simulation next frame (or whenever you want).

    Then, I simulate the physics scene as usual. Only the player will actually move.

    Finally, I loop through the List<PhysicsState2D> containing the old physics info for the frozen objects in the scene, and restore these states back. Added a null-check in case I destroyed any of the Rigidbody2Ds from before.
    Code (CSharp):
    1. foreach (PhysicsState2D state in previousStates) {
    2.     Rigidbody2D r = state.rigidbody;
    3.     if (r == null)
    4.         continue;
    5.     r.velocity = state.velocity;
    6.     r.angularVelocity = state.angularVelocity;
    7.     r.bodyType = state.bodyType;
    8. }
    P.S. - I hope this helps someone who was trying to make a multiplayer game like I've been!
     
    Kobix, NotaNaN and romhaviv like this.