Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more..
    Dismiss Notice
  3. Dismiss Notice

Question Is there a way to isolate Physics.Processing areas and interactions for performance?

Discussion in 'Physics' started by BagoDev, Sep 17, 2022.

  1. BagoDev

    BagoDev

    Joined:
    Jan 2, 2017
    Posts:
    21
    Is there some way to isolate or offload a particular physics processing for a particular set of game objects? I'm not talking about just putting collision layer masks on interaction methods, but prevent anything from processing on a set of collider objects that are not X type game object or Y type physics interaction.

    Some context: We are currently utilizing a headless unity instance (2020.3.17f1) for our authoritative game server, and as we have progressed further in development of our larger scenes, just having the static ground colliders active in the scene, without desired interactions being run on them, is causing huge performance problems.

    We minimized mesh colliders faces and tried to do primitive approximations as best we could without sacrificing too much accuracy. Almost all of these colliders though are only used for a single purpose -> to check if/when a player is grounded. Nothing else needs to interact with these colliders except the box raycasts being projected down from our players. See one of the spikes below with only the terrain collider active, and 0 players on server:



    No players, 0 ray/box casts, but still huge performance issues. Not sure if the main culprit is these overlaps and contact counts as turning off the terrain does nothing to these values, but maybe its just counting and not processing? Ideally these ground colliders would NEVER interact or process with anything that is not a box raycast from a player, but I'm not sure if its possible to configure the physics system in a way to isolate to only those interactions when dealing with these specific static colliders.

    Might be reaching for a magic pill solution here, maybe its just simply a matter of making more primitive collider approximations and just removing all our mesh collider scene geometry from our server box, or if there is some practice and configuration we are missing to make this a non-issue. Still tinkering with changing broadphase types and adjusting physics system parameters, but I don't really fully understand the extent of adjusting these settings beyond what the documentation outlines.

    I'm definitely not an expert on Unity physics. Any resources, assets, advice, or points in the right direction would be greatly appreciated.

    So far I've reviewed and tried different optimizations from these sources with no luck:
    https://www.youtube.com/watch?v=pTz3LMQpvfA
    https://docs.unity3d.com/Manual/iphone-Optimizing-Physics.html

    ... and more blog posts than I care to admit that just have regurgitation of similar solutions

    **Findings:
    > Looks like the actual culprit was not the mesh collider volumes or static terrain volumes, but was actually these kinematic rigidbodies that were left over from a test phase on area of influence sphere colliders. Didn't realize as the the rigidbody count was showing 0 on the profiler, must be labled under kinematics?
    > Utilizing the Layer Collision Matrix to ignore layers of collision not needed also had large performance gains.
     
    Last edited: Sep 18, 2022
  2. BagoDev

    BagoDev

    Joined:
    Jan 2, 2017
    Posts:
    21
    Didn't even see the Layer Collision Matrix, in the Physics settings, think this is what I was looking for as I can turn off interactions with everything from my Ground layer, though there is still a large performance overhead just having the colliders active in scene.
     
    Last edited: Sep 17, 2022
  3. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    446
    Where do those 12 kB of garbage come from?
     
  4. BagoDev

    BagoDev

    Joined:
    Jan 2, 2017
    Posts:
    21
    It's from a script, nothing related to physics. I appreciate you pointing it out though, I've only recently started in with the Heap Allocations Viewer to clean up unnecessary allocations in our code. I wish I originally had this plugin before we started in on development, its so useful in fixing these alloc issues.
     
    Last edited: Sep 18, 2022
  5. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    446
    Indeed, although a low framerate could force the physics update (FixedUpdate, OnAnimatorMove, simulation, OnCollision/TriggerXXX, etc) to run multiple times just to keep up. Are you familiar with Maximum Allowed Timestep?

    I'm not saying this is what's causing you trouble, probably not.

    It is weird because you said there weren't players in the scene when that big pink spike happened. In any case, How many rays are you using per character? Performance-wise, raycasts are not the best.
     
    Last edited: Sep 18, 2022
  6. BagoDev

    BagoDev

    Joined:
    Jan 2, 2017
    Posts:
    21
    I've seen the setting for max allowed timestep, but I'm not really sure how to tune it. I would imagine since I'm using it for ground detection, and these updates are constant, that a dropped calculation here or there wouldn't be an issue... so I wouldn't increase it? but maybe lowering it could alleviate issues in a high frame rate situation? At least that's my take away from what the docs say.

    The spike I think was the low-frame rate situation you described before from all the interacting kinematic rigidbodies. (We were using them originally because OnTrigger methods were not firing on certain volumes unless we had a rigidbody component on interacting objects.)

    As for the player rays, we only use a single ray, and it only extends 1.5f below the player checking for ground collision layer.
     
  7. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    446
    Don't worry, i don't think this is affecting performance. I just mentioned that as a way for the physics to do extra work in case the framerate drops. In this case, with 30 fps (32ms) and a fixed timestep = 20ms (i guess) you will get one extra call here and there. Also, the framerate goes to 60 right after the spike.
     
  8. tjmaul

    tjmaul

    Joined:
    Aug 29, 2018
    Posts:
    464
    Sorry, I’m late to the party. I also looked at the profiler screenshot and I’m confused because you mentioned there is no player interaction, but there are thousands of trigger overlaps, kinematic and dynamic rigidbodies and active contacts. From your post I would assume we’d only see static colliders and nothing else. Can you elaborate on this?

    I’d also like to point out that the processing times come in a very repetitive pattern. Any ideas on why this is?

    sorry that I don’t have answers but maybe answering those questions might lead you somewhere.
     
  9. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,533
    This is physics 101 so you've likely still got things interacting that shouldn't as you designed your levels/scripts without layers in mind. A common culprit is creating large area triggers to know when you go out of a level or for triggering animation/audio. This can have a huge cost because you're only considering it for one thing but it's potentially overlapping hundreds of things. I've even seen these attached to camera that are moving. These still overlap in the broadphase. Certainly, they should be set to not interact over just not looking at the callbacks. Just a guess.
     
  10. BagoDev

    BagoDev

    Joined:
    Jan 2, 2017
    Posts:
    21
    Was an issue with area colliders not marked with a specific layer and everything interacting within the layer collision matrix. As for the repetitive pattern, I think you might be seeing our tick systems, we have event notifications going out at different tick (frame count) intervals to the server managers and systems.

    I'm a 'mostly' solo dev studio on my first commercial game project, even with near a decade in software development, the amount of 101 gotchas I've been going through these past couple years is vast. This particular issue is for the server build, and as for your assessment, you are right on the money. We use large simple trigger volumes for a myriad of purposes. Most are static like water/ocean volume, environment hazard areas, hostile areas, etc, but some are attached to moving NPCs and Players for things like area of influence trackers to track who gets culling notifications and positional updates. But based just on the matrix update and removing the un-necessary rigidbodies, here is one player on server moving around in a small town.



    Much better CPU performance. With the only rigidbody kinematics being on players, I'm hoping this will still be fine at scale. I'm honestly more scared of the GC alloc issues now, so much pooling and allocation needed -_-

    I appreciate everyone's feedback and responses.
     
    Last edited: Sep 19, 2022
    tjmaul and MelvMay like this.
  11. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,533
    Only single contact and single trigger overlap which is good but wow, 38.59k static colliders! That's a big scene. Probably stating the obvious but the time above (1.97ms) is being spent in your scripts as is the 5.3kb alloc. Not sure if you're running queries or not but, assuming you're not already, worth checking that you use the 3D "non alloc" queries.
     
  12. BagoDev

    BagoDev

    Joined:
    Jan 2, 2017
    Posts:
    21
    So something like:

    Code (CSharp):
    1. private int _mHitCount;
    2. private RaycastHit[] mHits = new RaycastHit[1];
    3.  
    4. private bool OnGroundBoxCast()
    5. {
    6.     var t = transform;
    7.     _mHitCount = Physics.BoxCastNonAlloc(_mainCollider.bounds.center, boxcastSize, -t.up, mHits,
    8.         Quaternion.identity, distBoxcastGround, groundDetectionLayerMask);
    9.     if (_mHitCount > 0)
    10.     {
    11.         //do stuff
    12.         return true;
    13.     }
    14.  
    15.     return false;
    16. }
    ... would be performant? Not sure how big my buffer needs to be with the layer mask?

    And yes, big scene! Lots of dynamic culling for clients both rendering and net traffic wise. Currently my GC alloc battle is focused on player serializations for saving to DB. They generate upwards of 336kb~ of allocations PER player every X seconds. Trying to fix naive implementations of .ToArray() off of memory streams with stuff like Microsoft.IO.RecyclableMemoryStream. Welcome to my nightmare :)
     
    MelvMay likes this.
  13. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,533
    It's not necessarily faster to run it, just that reusing the array (as you have done there) means it won't get left to the GC which sounds like a battle you're in right now so will help, especially because this stuff is higher frequency stuff you'll be doing so a lot of potential waste. Unlike 2D, in 3D there's no "List<RaycastHit>" option which will be automatically resized so unfortunately you'll need to provide an array that's big enough for the maximum number of hits you expect to receive.

    While you're in the GC trenches, make sure you always have this/these options on when using 2D/3D physics: https://docs.unity3d.com/2023.1/Documentation/ScriptReference/30_search.html?q=reusecol

    I implemented this a while back for both and it ensures it reuses the class of Collision/Collision2D for each callback therefore not throwing it at the GC afterwards. You need to ensure you don't store it because it's reused i.e. written over for each callback. Maybe you're already using it though, it should be on by default.
     
    BagoDev likes this.
  14. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,533
    BTW: I think the "ScriptRunDelayedFixedUpdate" in the profiler above is when coroutines run (hence the "delayed" part); ones that are yielding on FixedUpdate if I remember correctly and not just standard FixedUpdate.
     
    BagoDev likes this.