Search Unity

Optimizing performance of many rigidbodies

Discussion in 'Physics' started by DustySkunk, Aug 23, 2015.

Thread Status:
Not open for further replies.
  1. DustySkunk

    DustySkunk

    Joined:
    Sep 12, 2013
    Posts:
    13
    Hi all,

    I have a project I'm working on at the moment that requires a large amount of rigidbodies in the scene and I have a few ideas to decrease the performance hit as much as possible that I'd like to run by the community here for feedback.

    First a little background: I have 100+ objects in the scene that require rigidbodies. However, the simulation only requires that one or two of them in close proximity to the player character be active. I'd like to use that fact to try and optimize for performance as much as possible. Here are some of my ideas.

    1) Is there a significant performance difference for a rigidbody with collisions disabled rather than just sleeping? Additionally, is there a performance overhead for re-enabling collision detection? My thought is to start the scene with all rigidbody collision detection disabled for the objects, have a trigger collider on my player character that enables collisions on the objects that are in close proximity. Is that a crazy idea?

    2) What about adding a rigidbody component as required? In this case I would use the trigger collider idea from the previous scenario, but rather than enabling collisions I would add the rigidbody component to each object on the fly. My concern is that as the player character moves through the scene, the number of active rigibodies would increase as it isn't possible (to my knowledge) to remove a rigidbody component without destroying the object it's attached to.

    3) I know that instantiating at runtime is resource intensive.. but what about instantiating all of the required rigidbody game objects during load, hold them in "stasis" off scene somewhere while placeholder static meshes are placed in scene and then "hot swapping" them when required?

    These are all just ideas but I'd love some feedback. Thanks in advance for your replies

    ~Dusty
     
  2. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    You haven't specified target platform nor Unity version.

    But by large, you will not be seeing any performance hit from 100+ rigidbodies. Have you even tested it? In any case:

    1) a rigidbody without a collider (same as disabled) would be quicker. I doubt it would make any difference with a small data set like 100

    2) adding rigidbody as required is pointless. Just use kinematic to turn off physics calculations if you must. But Physx generally will optimise this itself if it is not moving, which leads me to believe you haven't tested this. It will sleep.

    3) bad idea and slower.

    Let us know how you get on with actual testing of it. Because Physx 3.x is really good at keeping itself optimised.
     
    DustySkunk likes this.
  3. DustySkunk

    DustySkunk

    Joined:
    Sep 12, 2013
    Posts:
    13
    Thanks for your quick reply, hippocoder. I apologize for not specifying which platform nor Unity version. I'm using Unity 5.1.1f1 and am targeting PC (64 bit).

    You're right, I haven't tested this yet. I was trying to discern the best approach to use before tackling the problem. Performance is a large concern for me, and I'm paying particular attention to anything that might bottleneck the frame-rate.

    I will absolutely reply here with my preliminary results.
     
  4. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Then you will not be concerned with 100. Come back when it's a thousand :) At smaller numbers like this you tend to do more harm than good trying to optimise (the optimisation is slower than leaving it alone).

    One important thing is to use rigidbody.MovePosition and such when moving them around rather than using the transform if you do it a lot.
     
    AlanMattano likes this.
  5. Martin_H

    Martin_H

    Joined:
    Jul 11, 2015
    Posts:
    4,436

    I hope it's ok if I highjack this thread. I've written a simple test where towers of cubes are created and after 3 seconds they crumble into smaller cubes. Later that's going to be triggered by shooting at the cubes. I quickly got into thousand-cube-territory and the physics calculation went above 60ms on my i7. Especially at the point where I switched out the static big cubes with the small rigid body cubes there was a big spike in the profiler. How do I figure out if there is enough potential for optimization to have "crumbling buildings" at all as a game mechanic while maintaining 1080p60fps on desktops (and Unity 5, since you asked the OP)?
     
  6. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Enabling, disabling, pooling, etc will all cause a high physics spike if done the same physics frame. This is because it doesn't have (AFAIK) an on/off switch for rigidbodies. They're either created or not, and this costs cpu time to do...

    So if you're after crumbling buildings, I would suggest that you offload a "heck of a lot" of the crumble effect to particle system which can to a degree collide very well, and create a premade shattered object you could just switch in I guess!

    There is no real decent optimisation for this scenario other than to create bodies over time or to take the initial hit of swapping solid object for a pre prepared broken one to crumble.

    Now you're in this territory, you need to give Physx room to breathe and room to sleep. Your test has them all moving and all colliding at the same time. This isn't actually what would happen in a game scenario, some of them would be sleeping - not moving - and these don't get calculated.

    So it's your job to:

    - figure what can be pooled - ie is instantiation costing you?
    - figure what part of the crumbling can be baked to animation instead
    - particles?
    - do all parts of the building need to crumble at the same time?
    - low timestep for physics
    - low iterations

    Got to divide the job up as best as you can. Basically Physx 3.x costs when things are moving or changing.
     
    jethrogillgren and Martin_H like this.
  7. Martin_H

    Martin_H

    Joined:
    Jul 11, 2015
    Posts:
    4,436

    Awesome! Thanks a lot for all the information, this was very helpful!

    The way I did the crumbling cubes was like this: I had a big cube for each segment that had the script component on it and an empty child object called "fragments" that had all the small cubes in place already, but deactivated. When the big cube crumbles the script takes the "fragments" object, activates it and changes its parent to the parent of the big cube and deactivates the big cube. That way I tried to offload all instantiation into the start of the level and nothing was really pooled, just premade and deactivated for later use.
    I had hoped to not get spikes on activating the fragments, but apparently that is not how physx works.


    No, and it actually might even look better if it starts to crumble at the place where it is hit first and then frame by frame breaks down the adjacent blocks of the building into fragments.



    Does the physx calculation take into account where in the object hierarchy an object is? Does it make a difference whether I have a deep hierarchy or a very flat one?
     
  8. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Yes. Deep hierarchies cost in Unity. At runtime It's generally always best to flood the main hierarchy root with dynamic objects, since the way Unity transforms work is if a child is moved, it is evaluated from the root to where it is over again. I'm not sure if this has been optimised in 5 or not. I would guess not since it can be worked around.

    As for Physx, I just don't know what overhead is with it. But we know that moving any rigidbody manually or rotating it is quite expensive so we use .MovePosition and .MoveRotation commands if we have to.

    In general be careful about using Unity Instantiate in this scenario as well as that will cause 2x hit from allocation and also Physx internally creating colliders.

    You can do things like create them or activate them over time but I'm not sure if this will happen immediately or in the next fixedupdate. I suspect it would be immediate or raycasts would fail. In any case doing batches of them at a time can't hurt (time slicing).

    The possibility of testing a pool of premade rigidbodies and colliders far away, which are MovePositioned etc into place instead of activating them, may be fruitful but I really can't say as I haven't got this far. I am interested in your findings.
     
    Martin_H likes this.
  9. Martin_H

    Martin_H

    Joined:
    Jul 11, 2015
    Posts:
    4,436

    Thanks again for your input. Your posts go a long way in helping me understand the physics engine and getting a grip on it. However there are still things I don't understand.


    Here is a screenshot of 2 testcases.


    The giant block has my spawner scripts on empty objects as children, which spawn the cube stacks. I have duplicated the whole section twice and for the top test I deactivated the duplicates. As you can see the performance hit seems to grow exponential with the number of rigidbodies (not a surprise).
    What does surprise me is that the stacks don't all behave the same even though they all are created from the same prefabs which are instantiated by the scripts. So there should not be any variance in how they are stacked. Am I entering the wonderful land of numeric instability here or is this a "bug" or limitation of physx?

    I'll gladly share my findings and further tests with you. I tried to verify the hierarchy depth thing by nesting 20 empties into each other and putting my test setup in there. I didn't measure the results with the profiler but I kept an eye on the cpu main time in the stats window and there may be a slight increase at the end of the deep hierarchy tree, but that would be like 10% or so. I have put a script that slowly rotates an object on the root of the deep hierarchy and that had heavy impact on performance. But it seems that is due to it moving and waking up all the rigid bodies at once. There is little to no difference when I put the same rotator script on the test setup that was not deep in the hierarchy (again, maybe 10% or so slower with deep nesting but overall that seems not to be worth much optimization effort, if it makes the hierarchy convoluted and harder to use).

    Limiting the number of rigidbodies that are moving at the same time seems to be top priority if I want to have dynamic destruction effects. I'll see how much I can fake with particles etc. and try to get the most bang out of the rigid bodies that I can afford performance-wise.
     
  10. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Interesting!

    As for the different behaviour, if this is done at editor time then you press play, I can see this being very odd. If it's done at runtime there maybe velocity present due to settling after a move. I am assuming you did it at editor time.

    I do know Physx uses a broadphase to see if something can be rejected early. So a lot of things sharing the same axis aligned space would be a bigger hit on queries, but you would need an awful lot of them. If stacking stability is your goal, there is an option in Physics manager for stacking which you might want to try.

    Other than this I guess it depends on the scales. does it still happen if the original is moved to where the duplicates are, and there aren't any duplicates? this would rule out float imprecision.

    In my tests I found Physx to be stable within -10k to 10k units. I didn't go further than that for my tests. But this is assuming that one typical cube of yours would be 1 unit in size.

    The only thing I could suggest is running a script that sets velocities to zero and also having a higher sleep threshold.

    There is actually a bug in Unity right now where if your parent object doesn't have 1,1,1 scales, children can behave a little funny. Try to ensure that all parents have a scale of 1,1,1.
     
    Martin_H likes this.
  11. Martin_H

    Martin_H

    Joined:
    Jul 11, 2015
    Posts:
    4,436
    I'm doing all my tests by setting things up in the editor and then pressing play to see how things turn out. So there shouldn't be any velocity from me moving things into place manually.

    I've done some more testing:


    Numbers 1, 3, 5, 6 are all the same hierarchy block, just moved to a different position. The big cube is the parent and is scaled 10/10/10. Number 4 is the same block but scaled to 10/0.1/10. It does affect the way the towers collapse a little, but that could also be due to the position of the towers having changed a little.
    For number 2 I made an empty object with scale 1/1/1 and this is the parent to the big cube (which has no children) and the spawners (also 1/1/1).
    To verify that the scaled parent thing was an issue I changed the setup by moving number 2 at the position where 5 was. Still didn't collapse. I then deleted all the others and only duplicated the setup with the correct parent scale and none of them collapsed either. Seems like you were spot on! Thanks a lot!

    I assume you mean the "enable adaptive force" setting? I've found through experimentation that I have to enable that or otherwise every stack collapses right away every time. So I already had that enabled.

    Actually they are scaled to 0.25. When using scaled cubes for prototyping, would the better way to set things up be to always keep physics objects at 1/1/1 scale and attach the scaled cube mesh renderer as a child? I'd understand if that is the case, but it is a bit counter intuitive for noobs that try to get a prototype going with cubes.

    Maybe the mesh filter component should have a size input so that the transform scale can be left alone and still have everything on the same object?

    Sleep threshold is already higher than default (0.05 instead of 0.005). That seems to be a good way to save physics cpu time since object piles come to rest a lot quicker.

    This is the code I use to break the prefab apart:
    Code (csharp):
    1.  
    2.   void Crumble (){
    3.      gameObject.SetActive(false);
    4.      frags.transform.parent = gameObject.transform.parent;
    5.      frags.SetActive(true);
    6.    }
    7.  
    "frags" is just the object that has the rigid bodies as children, I've set the reference in the inspector. I'd say they should start out with zero velocity or am I wrong?

    I really appreciate you sharing your knowledge! I feel like you have helped me navigate around the biggest pitfalls when dealing with physics and now I finally have some reproducable stable results. Figuring out how to turn this into an optimized destructable environment is still a long road ahead, but I see a chance in doing that now. I'll keep you updated if I make progress there or if I have any new findings for general pitfalls and optimization opportunities. Thanks again!
     
  12. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    The order you're activating them in might matter (if they aren't all activated at the same time), and also it might matter if it's in fixed update or not. I don't know, what you're doing is fairly crazy :)

    In any case as soon as something wakes up either by activating or being collided with, physics will ensure the velocity isn't 0, so basically if you woke them up inside fixedupdate, and zeroed out their velocities inside of there too (including angular velocity), it might well have more chance at stability. Only random thoughts at this point but it's safe to assume forces will be on anything that wakes up or is activated, and fixedupdate is when those forces get applied.
     
    Martin_H likes this.
  13. Martin_H

    Martin_H

    Joined:
    Jul 11, 2015
    Posts:
    4,436
    Interesting. I'll keep that in mind for my level generation code. I want to have a few rigid body objects in the scene that are stacked. Not as crazy as in my stress test here, more like big shipping containers with stacks of 2 to 4 containers high. But I'd want them to start in a resting/sleeping physics state so I'll try and force the velocities to zero and do everything in a fixedupdate step.
    Is there a way to force physics updates at a quicker pace than realtime? E.g. can I spawn rigid bodies, simulate a few hundred physics fixedupdate steps during the loading screen as fast as the cpu can do it, and then resume to normal simulation pace?
     
  14. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    There's talk about that over on google groups but Unity hasn't seen/had much request for that yet. Of course it's possible in Physx.

    How fast your physics run is tied to your fixed update rate so check the time manager. You can run them at any frequency you fancy.
     
    Martin_H likes this.
  15. mitaywalle

    mitaywalle

    Joined:
    Jul 1, 2013
    Posts:
    247
    Hello, old thread.

    - What about 2018.1 and current version of PhysX?
    - What about deep-hierarchy nested rigidbody, set to sleep, or kinematic, moved by animation?
    P.S. It's a Ragdoll on characters.

    at this time, we have pretty big impact (Physics take 8-17, 10 average ms) and ~6 ms on UpdateBodies. Freezes, jumping impact.

    ~100 Characters, ~1000 Rigidbody on them, connected by CharacterJoint
    2300 rigidbody overall.

    After sametime removing rigidbodys at runtime, Impact on Physics Increased by 2-6 ms, stay freezing.

    But if rigidbody is removed at start, impact decreased for 2 ms, and became pretty stable.

    I hope this isn't self-confidence.

    Any comments / ideas?
     
    Last edited: May 11, 2018
  16. StCost

    StCost

    Joined:
    Mar 1, 2017
    Posts:
    30
    I have Tree kinematic rigidbody just standing and sleeping. Yet having 300 of them and 10 children in each of them triggers Physics.UpdateBodies for each of child destroying my framerate

    Simply deleting rigibody from them obviously fixes the issue.

    I wonder why static, not moving sleeping kinematic rigidbody spends time on updating anything inside of it.

    Reducing the number of children - helped a lot. But they shouldn't be updated in first place
     
  17. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,459
    Please don't hijack/necro existing threads with your own questions. It's super easy to create your own posts with your own questions.

    Thanks.
     
    Martin_H likes this.
Thread Status:
Not open for further replies.