Search Unity

Need advice from someone more experienced with Physics regarding performance

Discussion in 'Physics' started by Belleal, Sep 28, 2018.

  1. Belleal

    Belleal

    Joined:
    Jan 11, 2016
    Posts:
    17
    Hello guys, I've been working for a while on my game Masters of Puzzle. For some time now I am fighting with a nasty performance problem in the Physics department especially with the larger puzzle tile sets (i.e. 1000 tiles and above). The issue is easiest to observe when the tiles are first packed into the box together. Check this out:

    Packed Tiles.PNG Profiler 1.PNG Profiler 2.PNG

    As you can see most of the calculating power is going into physics, but I am not experienced enough with this area to pick an angle to start optimizing.

    The structure of each puzzle tile is essentially a single mesh with a compound collider:
    Tile Colliders 1.PNG Tile Colliders 2.PNG
    There are no triggers or any other event handlers related to physics. Therefore I assume the overhead here comes strictly from Unity native processes handling my configuration of objects.

    I know this is a terribly specific situation to my game, but I will appreciate any suggestion on where to start looking for optimization on solving this. I am not afraid to read or dig in deeply, I just don't have an idea what to look for.

    Thanks in advance for any help!
     
  2. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,510
    First things that come to my mind:
    • Try Unity 2018.3 (currently in beta). Physics engine has been upgraded and reported to be more efficient in some situations.
    • Play with the Physics options (Edit > Projects Settings > Physics), specially: Sleep Threshold, Enable Adaptative Force, Contacts Generation, Broadphase Type.
    • Use a single box collider per tile, at least while they're packed into the box. You may keep the compound collider disabled in this situation, then switch to it if the situation requires such precise collisions (i.e. if taken out of the box).
    Hope this helps!
     
  3. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    • If you are enabling and disabling colliders, it causes Physx to create and destroy them, so that's not a great idea.
    • In addition you may find really great improvements from using collision layers properly, so that anything that won't collide with something else can be ignored.
    • Post more information about the rigidbody, object setup etc
     
  4. PolyMad

    PolyMad

    Joined:
    Mar 19, 2009
    Posts:
    2,350
    First of all, the way you have sliced your object is not optimal: you have 6 boxes, but you can cover all the piece with 4.
    Second: if you don't need perfect collisions, use SPHERES. They are by far the fastest collision object.
    In your case, you can have 3 boxes and 1 sphere to cover that piece in the image.

    Now for the best: you don't need to have all those colliders when the pieces are stacked all together, you can simplify it and use a single box, and only switch to the complex collision structure when the piece is layed down on the floor.
     
  5. Belleal

    Belleal

    Joined:
    Jan 11, 2016
    Posts:
    17
    Hi guys, thanks for the good feedback! It certainly gives me some ideas to try out and monitor if there is any change in the performance. Moving to Unity 2018, however, might be something of a last resort because it will require effort migrating the TextMesh Pro and some other libraries I use...

    In any case, I'll post an update with the results.

    Oh, and as requested, here are the component settings for the tiles and the colliders:

    PuzzleTileComponents.PNG TileColliderSettings.PNG

    And the Physics settings:
    PhysicsSettings.PNG
     
    Last edited: Sep 29, 2018
  6. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Changing from Continuous to Speculative for rigidbody in 2018.3 is a help for sure. Also that version of Unity is around 2x faster for physics. Can you give me an idea what code you're doing? any on collision stuff? Also your iterations etc are all set quite high. You also don't allow them to sleep easily.

    If you are throwing a lot of puzzle pieces into a jumble at startup, this will cost the most time because physx is creating an internal "island" (a lot of interactions) that's pretty big and it has to solve all that island instead of lots of islands that are smaller.

    More info about what you do is helpful, or even a video. Just, at this point there is no bullet for us to offer you, it's about looking at the problem to solve in another way (assuming you moved to 2018.3 for the biggest magic bullet).
     
  7. Belleal

    Belleal

    Joined:
    Jan 11, 2016
    Posts:
    17
    Hi hippocoder, I will check 2018.3 as well. Hopefully, the migration won't be that painful.

    As for the other things, what I do at the beginning is to generate all the tiles inside the bounds of the box. During that generation, the algorithm makes sure to not spawn tiles that overlap in any way (including their colliders) in the 3D space and to also that no tile intersects the box itself. After that, the tiles are essentially floating objects that will drop a very little distance until they settle inside the box. I suspect from my observations that this is the moment where all these collisions take the better of the physics engine. There are no event handlers or any other custom logic linked to collisions. The only thing I have is OnTriggerEnter for the trigger collider of the parent tile object, but that trigger is disabled during this phase, so it should not be firing.
     
  8. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Still not getting a clear picture of when or what is happening. Is your problem due to the startup when you create the puzzle ? when the user interacts? Is it VR? and so on. Too little information to help.

    I will say that having a low contact offset and sleep threshold is preventing Physx from doing any real meaningful optimisation with large collections like this. It's basically constantly simulating them and making them simulating others. Just something to think about. Adding yet more fuel to the fire is using continuous collision. Should only set it if you need to, then put it back to discrete. Same for interpolation.

    You might gain significantly more CPU optimising draw calls as well.

    2018.3 allows much more forgiving settings, including Speculative contacts. It also handles fast-rotating objects well.
     
  9. Belleal

    Belleal

    Joined:
    Jan 11, 2016
    Posts:
    17
    Alright, just recorded a 3-minute video showing the issue. It's a standard desktop game btw, no VR involved. I hope this makes things a bit more clear. As you will see, the problem is at the start of the game but it will continue for a while still and not go away completely even after the tiles have settled completely in the box.



    In any case, I will first try adjusting the settings you mentioned. Maybe I am just overkilling it with the values I've set.
     
  10. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Is there any code on your part affecting them? OnCollision calls? in any case does seem like 1,000 rigidbodies with compound colliders all colliding at the same time with potential callback with aggressive settings that ramp up processing time isn't helping :)

    Try a sleep of 3 to start, not 0.01.
    Have iterations at 1.

    Stuff like that. All your settings are overkill for this job.
     
    Belleal likes this.
  11. davidfrk

    davidfrk

    Joined:
    Feb 13, 2017
    Posts:
    43
    Why it says 17 calls to FixedUpdate? Usually I just see one.

    Have you tried changing the Fixed Timestep?
     
  12. davidfrk

    davidfrk

    Joined:
    Feb 13, 2017
    Posts:
    43
    Thinking again profiler shows scripts.Update (blue color) taking a lot of time.

    Could be 1 update for every 17 rounds of physics, which would explain the performance. 270ms / 17 = 16ms for each FixedUpdate.

    Is there anything else in other scripts that could disrupt performance?
     
  13. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    This happens when the main update takes too long. When this occurs, fixed needs to run more times. You will find this happens to all Unity projects where the frame took too long.

    Once he resolves the main bottlenecks he can as a last resort, tweak maximum allowed timestep in time manager. When a frame takes longer than this, Unity disables physics processing. This is an actual last resort though obviously. It's there for those cases where the OS will stall or something stupid happens. It's required because without it, you wouldn't see 17, you'd see 999+ and a crashed Unity in the OP's scenario.
     
  14. Belleal

    Belleal

    Joined:
    Jan 11, 2016
    Posts:
    17
    Yes, increasing the settings you mentioned improves the performance - the better the higher I set them. But ain't I losing precision of the physics simulation with settings so high? I haven't been able to find a good guide on what settings should be used in a scenario like mine...

    As for the scripts part, what I am seeing is that 99% of what is shown in the blue chart is the FixedUpdate call of the puzzle tile objects. I don't understand why it takes such a big chunk of the time, though, because at that point the function does nothing (i.e. no tile is being taken or held at this point):

    Code (CSharp):
    1. private void FixedUpdate() {
    2.    if ( gameObject.GetComponent<Rigidbody>() != null ) {
    3.       if ( IsTaken && !IsHeld ) {
    4.          ...
    5.       } else if ( IsTaken && IsHeld ) {
    6.          ...
    7.       }
    8.    }
    9. }
    Edit: Actually, after playing around some more, the only significant performance gain from the general Physics settings comes from the Default Contact Offset. The rest of the settings do add some additional boost, but not really that much compared to the offset. Oddly enough, this also decreases the script overhead from the FixedUpdate function. What's the relation here I wonder?

     
    Last edited: Sep 30, 2018
  15. PolyMad

    PolyMad

    Joined:
    Mar 19, 2009
    Posts:
    2,350
    You should only activate the collisions between the layers that you need. That could save you a lot.
     
    Belleal likes this.
  16. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    No. With game Physics, the lower the precision you can do, the faster it runs. It's the law of game physics. If you want anything fast, lose the precision, everywhere.

    Do less = runs faster.
    It works = good.

    Keep searching etc because it even explains in the unity manual that default contact offset being set higher is slower, because it will generate (in your case) thousands more contacts that it didn't need to.

    The reason insane precision is allowed is because it's relative.Say the simulation was inside a matchbox? it wouldn't be slow if that's all there was.

    Do matchbox sized simulation for a planet and you will still be processing when entropy claims us all at the end of time. But don't ignore the other settings. Life is not all about contact offset.
     
    Belleal likes this.
  17. davidfrk

    davidfrk

    Joined:
    Feb 13, 2017
    Posts:
    43
    Cache your GetComponent(), this will cut some time and GC alloc in editor too.
     
    DeathByCh0c0 and Belleal like this.
  18. davidfrk

    davidfrk

    Joined:
    Feb 13, 2017
    Posts:
    43
    Could you do a little test?

    Disable the AutoSimulation and use this yant code.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class BasicSimulation : MonoBehaviour {
    4.  
    5.     private float timer;
    6.  
    7.     void Update () {
    8.         if (Physics.autoSimulation)
    9.             return;
    10.  
    11.         timer += Time.deltaTime;
    12.  
    13.         if (timer >= Time.fixedDeltaTime)
    14.         {
    15.             timer -= Time.fixedDeltaTime;
    16.             Physics.SimulateStep(Time.fixedDeltaTime);
    17.         }
    18.     }
    19. }
    This is limited to only one FixedUpdate per Update
     
    Belleal and hippocoder like this.
  19. Belleal

    Belleal

    Joined:
    Jan 11, 2016
    Posts:
    17
    Just to make sure we are on the same page, you mean adding this to the puzzle tile GOs, right? Or to a single object (like the game manager)?
     
  20. davidfrk

    davidfrk

    Joined:
    Feb 13, 2017
    Posts:
    43
    Single object
     
    Belleal likes this.
  21. Belleal

    Belleal

    Joined:
    Jan 11, 2016
    Posts:
    17
    Alright, this is the result:


    From what I observed, it didn't get better than it is with the current Physics settings and auto simulation on. The only change was that the simulation itself was jittery.
     
  22. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Try in https://docs.unity3d.com/Manual/class-TimeManager.html

    Maximum Allowed Timestep = 0.1
    Fixed Timestep = 0.05

    Then for https://docs.unity3d.com/Manual/class-PhysicsManager.html

    Sleep Threshold = 5
    Default Contact Offset = 0.05
    Default Solver Iterations = 1
    Default Solver Velocity Iterations = 1
    Enable Adaptive Force = true
    Contacts Generation = Persistent Contact Manifold
    Contact Pairs Mode = Default Contact Pairs
    Broadphase Type = Sweep And Prune Broadphase
    Friction Type = Patch Friction Type
    Enable Enhanced Determinism = false
    Enable Unified Heightmaps = true

    And yes, 2018.3 beta 3 (or later) is actually required to help this problem.

    Personally I would simulate it once then store the rotations and positions of each piece, and set all the pieces to that. Probably would still use above settings even with.
     
    Belleal likes this.
  23. davidfrk

    davidfrk

    Joined:
    Feb 13, 2017
    Posts:
    43
    I don't know, the profiler keeps pointing several calls FixedUpdate.ScriptRunBehaviourFixedUpdate.

    Should be just one, any idea why hippocoder?
     
    Last edited: Oct 1, 2018
  24. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Only for auto. For auto it will keep calling fixed update repeatedly so x number of steps occur in y time, which is something my above suggested settings try to avoid.
     
  25. davidfrk

    davidfrk

    Joined:
    Feb 13, 2017
    Posts:
    43
    AutoSimulation is off, could it be a bug? Unity keeps calling it.
     
  26. davidfrk

    davidfrk

    Joined:
    Feb 13, 2017
    Posts:
    43
    Ow, I found it in another post:

    FixedUpdate is just a callback, it isn't directly related to physics; it just gives you a callback with a fixed timestep. It'll still get called more than once if it needs to catch up. FixedUpdate will still happen even if you turn off the auto-simulation. It's just that physics won't be called during the fixed update and you are left to call it yourself either in the fixed update or per-frame as you're doing here.

    Good to know
     
    WaqasGameDev, Edy and Belleal like this.
  27. PolyMad

    PolyMad

    Joined:
    Mar 19, 2009
    Posts:
    2,350
    Honestly, I don't think that you can have thousands of objects all colliding together smoothly, unless you run on a very high end PC.
     
  28. Belleal

    Belleal

    Joined:
    Jan 11, 2016
    Posts:
    17
    Hi hippocoder, just did a test run with the settings you suggested but the performance is very bad. Also, there are some simulation artefacts (i.e. tiles hanging in the air). Check this out:


    It's more or less the same with auto simulation on and off (in which case I use the Physics.Simulate as suggested above). The puzzle tiles have the CCD set to ContinuousSpeculative in this scenario.

    Another test I did was with slightly more precise settings in the Physics and CCD set to Discrete. This was way more efficient in terms of performance, but I can't help and wonder what is the tradeoff in picking only discrete CCD, and would it make a difference in my type of game?
     
  29. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Discrete is best performance. You get a speculative version in 2018.3 as well. There is no magic bullet left really, so I'm going to bow out. You need to look at precalculating things as well.
     
  30. Belleal

    Belleal

    Joined:
    Jan 11, 2016
    Posts:
    17
    Very well, thank you for all your help. :)
     
  31. DeathByCh0c0

    DeathByCh0c0

    Joined:
    Dec 26, 2013
    Posts:
    1