Search Unity

(Scripting) Force update of physics scene?

Discussion in 'Physics' started by jwvanderbeck, Jul 2, 2019.

  1. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Hi,

    I am spawning multiple objects in a tight loop. The problem I am running into is that a ray cast from one object doesn't appear to see any of the objects created prior to it in the same loop.

    Is there a way explicitly force the PhysicsScene to be updated during the loop?

    EDIT: Note that the obvious, wait for the next fixedUpdate isn't an option as this is an Editor tool.
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    Could you clarify what you mean by see?

    As soon as you add an object you can perform physics queries on it. Note that if you're adding objects to a specific scene then you need to perform physics queries on that scene and not use the global physics queries on Physics / Physics2D types as they operate on the default physics scene only. but instead use the ones on the PhysicsScene type.

    If you're expecting overlapped colliders to be moved out of the way or have physics callbacks as you add each then I would urge you to not do that as it'd get very expensive.

    Of course, you are free to do what you like and perform a manual simulation using Physics(2D).Simulate or in your case PhysicsScene(2D).Simulate. You'll need to ensure AutoSimulation is off before you can perform a manual simulation.
     
  3. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    I mean in a loop I do this:

    Spawn Object 1
    Spawn Object 2 Above Object 1
    Raycast down from Object 2. Ray does NOT see Object 1 like it should.

    If those two actions take place as separate actions initiated by the user, thus allowing a FixedUpdate between them, then the ray sees the other object. If it happens in code during a loop, thus not allowing FixedUpdate to happen, the ray does NOT see the other object.
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    I was in the middle of editing my reply so take another look. Ensure you're querying the scene in question that you're adding objects to. Queries should work immediately after you've added the physics components.
     
  5. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    We are using the default scene.
     
  6. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    For 2D physics they are available immediately and AFAIK the same goes for 3D physics so I am not sure. Which are you using?
     
  7. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    3D. The raycast is performed using Physics.RaycastAll
     
  8. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    I just asked the 3D physics dev if my assumption about 3D physics above is correct or not. He should reply here.
     
  9. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    I just got it confirmed that 3D physics components added to the scene are available to be queried immediately. Apparently it has been that way since Unity 5.0.

    I am therefore not sure what is going wrong in your case. Maybe a code snippet would help, maybe not. Maybe try a simple case of adding a sphere then instantly seeing if you can query it.
     
  10. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    I'll try to create a simple reproduction case.
     
  11. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Ok this does appear to work as expected in a simple test case, so I'm at a loss as to why it doesn't in the actual code. I will need to dig into it more :(
     
    MelvMay likes this.
  12. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Hah got it. I works in a SIMPLE case, as in spawning the object and casting:
    Code (CSharp):
    1. m_child = (GamObject)PrefabUtility.InstantiatePrefab(childPrefab);
    2. Vector3 direction = m_child.transform.position - transform.position;
    3. RaycastHit[] hitInfos = Physics.RaycastAll(transform.position, direction, 100000f).ToArray();
    4. Debug.Log(hitInfos.Length);  // Outputs 1
    However, spawn the object and then change its parent before casting and it fails:
    Code (CSharp):
    1. m_child = (GamObject)PrefabUtility.InstantiatePrefab(childPrefab);
    2. m_child.transform.SetParent(transform, false);
    3. Vector3 direction = m_child.transform.position - transform.position;
    4. RaycastHit[] hitInfos = Physics.RaycastAll(transform.position, direction, 100000f).ToArray();
    5. Debug.Log(hitInfos.Length);  // Outputs 0
    If I retrigger the spawn & cast, then it will see 1, then 2, etc in the debug log. So each run through it only sees the previous spawns, not the current one.

    NOTE: I am drawing a DebugRay in the scene to visualize the Raycast so I can verify it is indeed pointing properly:

    Code (CSharp):
    1. Debug.DrawRay(transform.position, direction, Color.blue, 5f);
    My guess here is that the collider is not updating immediately when the spawned object moves as a result of the parenting with worldPositionStays false.
     
    peeka likes this.
  13. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    That's because by default on new projects AutoSyncTransforms is off. You should try to avoid having this setting on for performance reasons. You can perform a manual SyncTransforms but this has a performance cost too when you call it but it might not be an issue in your case. Note there's more detail on the above doc links.

    In most cases it's best to set the transform prior to adding physics components if you want to immediately query them. In the case of prefab instantiation, I'd need to check, but maybe Object.Instantiate sets the transform prior to adding in the other components or activating it but I suspect that might not be the case.
     
    peeka likes this.
  14. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    I had tried done some testing with autoSyncTransforms but it was only a quick test as I wasn't sure it was a solution. Let m dig into that a bit more.
     
  15. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Many, Many thanks. Using Object.Instantiate does indeed seem to work.

    EDIT: SyncTransforms also works but the impression I got was it should be more performant to do it with Instantiate
     
    MelvMay likes this.
  16. peeka

    peeka

    Joined:
    Dec 3, 2014
    Posts:
    113
    Don't ever close this thread, I run into this exact problem, and this helped me!
     
    l337codeguy likes this.
  17. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    This fun little dive was while I was making this which was shown at SIGGRAPH last year :)
     
    peeka likes this.
  18. peeka

    peeka

    Joined:
    Dec 3, 2014
    Posts:
    113
    I switched to use Object.Instance it works!
     
  19. JoshValjosh

    JoshValjosh

    Joined:
    Dec 5, 2018
    Posts:
    3
    Could this perhaps be added to the Raycast documentation? This cost me over a dozen hours of development time looking for solutions, workarounds, or known issue reports. Simply state that a ray will not hit an object that has moved until the next physics update, but that transforms can be synced manually with SyncTransforms(). I'm using raycasting to set up a puzzle, and the alternative do raycasting in Start is complex logic through several calls to FixedUpdate.
     
  20. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    This is not specific to Raycast. If you modify a Transform, it ONLY modifies a Transform, it doesn't modify ANY other component. Should this be added to every single method and property on both the 2D or 3D physics systems that perform any reading of any kind? No, of course not.

    The problem is that you're using the Transform system as the authority on the pose when in-fact it's the Rigidbody that WRITES to the transform and acts as a proxy to it for you so it's the other way around. You should use the Rigidbody API to cause movements. The whole point of a Rigidbody is to move around using physical motion and update the Transform system.

    If you are moving stuff in physics by driving the Transform you're doing it incorrectly.

    If you're using SyncTransforms, you're using a method that is only there for bad practices and legacy behaviour.
     
    Noogy likes this.