Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Physics2D.FindNewContacts being called when moving rigidbodies with MovePosition?

Discussion in 'Physics' started by _eternal, Nov 21, 2023.

  1. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    301
    I have a scene in a test project with around 200 objects. Each is set to the same position, and they each have a BoxCollider2D and a Rigidbody2D set to Kinematic. They're all on the Default layer, and I disabled all of the collisions in the collision matrix for regular Physics and Physics 2D.

    In code, I'm moving them all together like this:

    Code (CSharp):
    1. private void FixedUpdate()
    2. {
    3.     Vector2 thisFrameTarget = rBodies[0].position;
    4.  
    5.     if (Input.GetKey(KeyCode.W))
    6.     {
    7.         Vector2 move = Vector2.up * moveSpeed * Time.fixedDeltaTime;
    8.         thisFrameTarget += move;
    9.     }
    10.     if (Input.GetKey(KeyCode.A))
    11.     {
    12.         Vector2 move = Vector2.left * moveSpeed * Time.fixedDeltaTime;
    13.         thisFrameTarget += move;
    14.     }
    15.     if (Input.GetKey(KeyCode.S))
    16.     {
    17.         Vector2 move = Vector2.down * moveSpeed * Time.fixedDeltaTime;
    18.         thisFrameTarget += move;
    19.     }
    20.     if (Input.GetKey(KeyCode.D))
    21.     {
    22.         Vector2 move = Vector2.right * moveSpeed * Time.fixedDeltaTime;
    23.         thisFrameTarget += move;
    24.     }
    25.  
    26.     if (thisFrameTarget != rBodies[0].position)
    27.     {
    28.         foreach (Rigidbody2D rBody in rBodies)
    29.         {
    30.             rBody.MovePosition(thisFrameTarget);
    31.         }
    32.     }
    33. }
    When the objects are moving, I'm getting a 4ms spike from Physics2D.FindNewContacts every 3-4 frames or so.



    Here's a screenshot of the Physics 2D section of the profiler. It looks like the spike is related to something called Broadphase Updates.

    So, we can look at the documentation here: https://docs.unity3d.com/Manual/profiler-2d-physics-profiler-module.html

    It says that "A broadphase update occurs when physics shapes are added, removed or change in size." But, I don't think I'm doing anything to modify the physics shapes? Why would this occur every few frames when the objects are moving (and not even every fixedupdate)?
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,161
    Because the statement is wrong. This is the first part of the simulation step which runs, by default, during the fixed-updates so it runs when the fixed-update runs. "FindNewContacts" isn't directly a broadphase update, it's updating contacts from broadphase pairs discovered when things move.

    199 Kinematic bodies with presumably each with a single collider. There are 19701 broadphase pairs being handled so all of the colliders i.e. approximately 199^2 / 2 so they're all overlapping in the broadphase at least. It cannot know there are no potential contacts without first actually checking these broadphase pairs. It doesn't mean it calculates contacts and spends time there as that what's the broadphase is for, finding trivial pairs and then checking to see if they should even begin to overlap with their masks; if not then nothing else is done but 19701 one of them is a lot.

    When you move something, the object in the broadphase might have to update its position in the broadphase. This can be added to the docs but it's hard to describe that in technical terms as it doesn't mean it updates when it moves as its entry in the broadphase has a margin around it allowing it to move with broadphase update known as "FAT AABBs". This kind of detail tends to not be added to the docs. It's all pure Box2D though.

    5ms for a simulation of 199 bodies sounds like a lot though. Is this a super slow machine or something?

    NOTE: Note that there are two TransformSync calls; at the start of the simulation step one is automaticallyed called in-case you're modifying Transforms but it's only called once and two are showed there so you must also be calling it.
     
  3. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    301
    Hey, thanks for the explanation. So, if I understand this correctly, those Broadphase Pairs are being calculated because we have 199 colliders in close proximity to each other — there's a bit of overhead with handling those colliders, even if their layers are configured such that they don't actually cause a contact. Something like that?

    Nah, it's not a slow computer (3700X and 1080Ti). I just checked in build, and I'm getting similar results (around 3.5 ms instead of 5).

    Hmm, how would I test this? I'm not manually calling it, but maybe it's happening automatically as a result of some other configuration. This is Unity 2022.3.6 btw.
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,161
    Broadphase pairs are just that, AABB in the broadphase that overlap. Those pairs are the only way new contacts can be discovered. This part is super quick though.

    Yes but not 5ms worth of overhead!

    The only other time this is called by Unity is if you've got AutoSyncTransforms on which you should always have off (off by default). I don't think this is the problem though.
     
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,161
    Of course, the Elephant in the room question is why would you have 199 colliders all overlapping each other as that's a lot of overlap pairs in the broadphase i.e very dense. :)
     
  6. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    301
    Hmm, quite puzzling indeed. It's still happening in an empty project (in the scene Overlap Test). AutoSyncTransforms is turned off.

    Yeah, it's a silly situation haha. I was testing an actual problem in my main project, so I set this up in my demo scene to see if moving 200+ rigidbodies would cause any meaningful lag. And I guess it did, but not for the expected reasons (due to the overlaps). Later I'll probably change up the demo scene so I can test the thing that I actually wanted to figure out, which had something to do with DOTweening a bunch of (not overlapping) kinematic bodies.

    I'm still curious about the extra call to AutoSyncTransforms, though. It might be innocuous here, but I'm trying to isolate any misconfigurations that might cause trouble in a real project.
     

    Attached Files:

  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,161
    Yes, it is odd if you're not calling it and no 3rd party package is calling it. The profiler capture you sent showed only a single simulation step that frame so it's not Unity calling it during the simulation.

    Whilst I don't see what else it could be, might be worth quickly disabling the colliders on those Rigidbody2D to ensure it is indeed the reason, just for sanity.
     
  8. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    301
    Yep, looks like that's it. After disabling the colliders, I'm seeing no broadphase pairs, and the entirety of FixedUpdate is only taking 0.19ms (half of which is from 199 calls to Physics2D.SolveDiscreteIsland).

    Interestingly, it looks like those sync calls are unrelated to the spikes.





    Some frames have 1 sync call and a 0 simulation count. Is there any way to debug where this is coming from?

    Strangely, the Physics2D section of the Profiler doesn't seem to work in Development Builds. The Timings row is the only one that gets updated; I can't check the sync calls or other counters, even though the docs say that it should be available in development builds.
     
  9. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,161
    I don't see why it wouldn't work in a Development Build. Those counters are handled just like any other system might used them so odd.

    I honestly wouldn't worry about the Sync Calls, seems like a pointless distraction, they're not going to be taking any time anyway. You can see that nothing is done in them and the CPU area will show you how much time, likely almost 0.

    Your problem here is exclusively that you have 199 things overlapping 199 things and it grows at half the square of that value.

    Of course, you could try to see if turning-on multithreading helps here but there's a good chance this particular calculation won't be being as you're not actually finding any contacts but it's worth a shot.