Search Unity

Moving bodies with translation; better to make them static or kinematic?

Discussion in 'Physics for ECS' started by PhilSA, Oct 17, 2020.

  1. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    I have a scene of 20,000 moving capsule bodies that move only by setting Translation.Value

    I've discovered that making their PhysicsBodies static gives me roughly 2x better performance than setting them to kinematic with a velocity of zero. This surprised me because I would've imagined kinematic bodies would be more optimized for moving (prevent rebuilding all static bodies info in PhysicsWorld when there's a change, etc....) Disclaimer; I haven't yet dug into the source code of BuildPhysicsWorld to verify all this

    Any thoughts on this? I'm mostly wondering if static moving bodies would eventually end up performing worse than kinematic in a scene that has lots of static geometry.

    I wonder if there could be some kind of middle ground between static bodies and kinematic bodies, where the body is optimized for being moved or spawned/destroyed without triggering static collision world rebuilds, but doesn't have any of the cost of physics stepping with a velocity. Would be cool if they could raise collision events too, unlike static bodies

    (tested in UnityPhysics and not Havok for now)
     
    Last edited: Oct 17, 2020
  2. desertGhost_

    desertGhost_

    Joined:
    Apr 12, 2018
    Posts:
    260
    I think it would be fine using static since Unity Physics rebuilds the collision world each frame and is "stateless". Have you checked if there are any collision issues with moving a static body? If you move a static body and have a dynamic rigidbody roll into its path do they collide?
     
  3. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    That does work fine, yeah

    Actually, when moving with translation and not with velocity, Kinematic bodies seem to have an issue that static bodies don't have:
    As you can see, when in kinematic mode, it has much more difficulty with solving the collision. I suppose it's kinda normal because it probably expects to be able to rely on velocity to solve kinematic-vs-dynamic collisions, and in this case, velocity is always 0. So it's more of a misuse than a bug I believe

    But you're right that since UnityPhysics is stateless, static is probably fine. I'd still be curious to hear an opinion on this from one of the physics devs, though. Just in case things would be different in Havok, etc....
     
    Last edited: Oct 18, 2020
  4. desertGhost_

    desertGhost_

    Joined:
    Apr 12, 2018
    Posts:
    260
    I'd also like an official answer on this.

    I would suspect Havok would teleport the static collider when the entity's translation changes (otherwise floating origin solutions would not work with static colliders), but I haven't explicitly tested this with Havok.
     
  5. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    A summary of questions I'd like to ask to @steveeHavok or @petarmHavok for this thread:
    1. Is there some kind of performance downside to moving/spawning/despawning a static body compared to kinematic body? (UnityPhysics and Havok)
    2. If there is a performance downside, is it possible to have a type of body that is just like Static (doesn't have the cost of a physics step with a PhysicsVelocity/Mass/Gravity), but is expected to be moved or created frequently?
    3. Is it possible to configure a static body to be able to raise events, without requiring the other body to be kinematic or dynamic. Possibly this could be a feature of the physics body type of point #2
    4. If I do end up having to make my body kinematic, can I solve this problem here?
     
    Last edited: Oct 19, 2020
  6. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    1. Yes (or at least I would expect there to be a performance downside in moving 'static' bodies!). BuildPhysicsWorld does check for body count & ECS chunk changes and doesn't actually update the Static BVH if there were none. So moving a single 'static' body should trigger a complete rebuild. On the simulation side Havok has a few extra trees and can benefit from incremental update so would be better off here compared to Unity Physics if used directly. However, Havok Physics is only used for the simulation at the minute, so queries will still requiring the Unity Physics BVH to be up to date.
    2. Unity Physics doesn't distinguish between Kinematic and Dynamic bodies. They are all considered dynamic and go into the same dynamic BVH. There is currently only a static BVH and a dynamic BVH. We did debate whether we should add a third tree (or indeed more) however the extra code complexity (and everything that comes from that) didn't seem to justify potential performance gains in specific cases. I'm also surprised by the 2x performance increase you are getting. I'm wondering if moving the 20k bodies into the static BVH is leading to a more cheaply constructed and queried tree compared to mixing them with the rest of the fully dynamic bodies.
    3. Anything is of course possible, but options for static/'static' events would be a last resort. First, I'd like to understand why you get the 2x performance improvement and make improvements based on those results before thinking about adding extra paths in the core code. I am wondering how representative the scene you are testing is to an average use case? I'm thinking that optimizing for one specific scenario may degrade performance for other more general scenarios.
    4. For a character controller you are trying to take back control from the simulation, but to do this you really need to take full control including the impact on dynamic bodies from the character walking up to or into another body. For example, the sample Character Controller is Kinematic but using
      CollisionReponse.None
      . Then it collects all its own hit information and applies impulses appropriately.
      The differences you are seeing between the Static capsule and the Kinematic capsule against the dynamic orange box comes from the interpenetration response being different between a static/dynamic pair and a dynamic/dynamic pair. The former case tries to resolve the interpenetration in a single frame were as the latter resolves the interpenetration over a few frames (I talk about this in the 2019 Unite talk).
      So it sounds like you are trying for a mix of full control for movement of the character, but relying on simulation control for interpenetration recovery?

      I was thinking a
      CollisionResponse.RaiseCollisionEvent
      option would be very nice for a character controller use case. With this option you can have full control over collision response, while relying on the general simulation pipeline to gather the collision information for you.
     
    BobFlame and PhilSA like this.
  7. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Thanks for the detailed answer! I will be coming back later today with a follow up and some stats (can't answer too much during work).

    But right now I can tell you that my initial results of "2x better performance" seem to have been a mistake of some sort. My latest tests show a difference of only about 10%
     
    Last edited: Oct 19, 2020
    steveeHavok and petarmHavok like this.
  8. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Allright, so I've made several tests comparing static characters to kinematic characters in different scenarios:

    Using Unity 2020.2, UnityPhysics 0.5, and an i5-4690k

    1- 5000 characters on a single static box collider floor

    • Static: 5.35ms
    • Kinematic: 6.25ms

    2- 5000 characters on a floor made out of 10k different static spheres (not a compound collider; they are 10k different static bodies)

    • Static: 16.6ms
    • Kinematic: 19.2ms

    3- 5000 characters on a single static box collider floor, but there are also 10k different static spheres elsewhere in the scene (the characters aren't touching the spheres)

    • Static: 10.2ms
    • Kinematic: 8.2ms
    I don't really understand those results. Test #3 shows that kinematic characters perform better than static characters when there are lots of static bodies in the scene that don't need to be rebuilt, but Test #2 shows that when the characters are actually on the spheres, then kinematic characters perform more poorly (?). None of the physics objects here are setup to raise events, so I have no idea why that would be the case. I don't think my CC systems do anything different based on whether we are static or kinematic either

    But, my conclusion is that I'll just go with kinematic (or provide the option to end users). So no need for a 4th physics body type, or a Static body that raises events. And as for pushing Dynamic bodies, I will also just do custom logic to handle it.

    ________________________________________

    EDIT: This is what the profiler window looks like in Test #2:

    Static:


    Kinematic:


    Looks like for Kinematic characters, there's a bunch of time spent on a single thread for "CreateDispatchPairPhasesJob", right before a CreateContactJacobians which static characters also don't have. I'm assuming this is because kinematic & dynamic are treated the same by the engine, despite kinematic-vs-static pairs not really serving a purpose for kinematic bodies?
     
    Last edited: Oct 20, 2020
  9. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Some of the cost of the kinematic bodies come from the solver/integration, allowing you to have collision events for example, which you don't have for static bodies. But yeah, the scheduling part (CreateDispatchPairPhases) is the worst. It's a single threaded bottleneck only there for collisions, trying to order the solving of body pairs, which you don't really have since you are solving all your stuff in the character controller code.

    My advice (as Steve pointed out) - use the kinematic character, but have its collider material's CollisionResponse set to None. That will completely remove it from the physics simulation, but the queries will still be able to hit it. That's what we do for our character and we designed it mostly for the character use case. You'll need to handle collisions vs. dynamic bodies on your own, as well as events.
     
  10. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    Oh right I totally forgot to try this, I'll give it a shot
     
    petarmHavok likes this.
  11. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,926
    I tried kinematic characters with a CollisionResponse of "Collide" vs "None" in Test #2:

    Collide:


    None:


    It looks like I'm getting more or less the exact same results in both cases and the pairs generation jobs are still there.... are you seeing anything I'm missing? I'm doing a Debug.Log() of "UnsafeUtility.AsRef<ConvexColliderHeader>(physicsCollider.ColliderPtr).Material.CollisionResponse" at runtime just to be 100% sure the collisionResponse is truly "None", and I can confirm that it is. I can also confirm that changing the characters to static eliminates the pairs jobs, so it's really my characters that cause them


    ______________________

    EDIT: tried with Havok; and here switching between "None" and "Collide" does make a big difference. It's just in UnityPhysics that it doesn't change anything
     
    Last edited: Oct 20, 2020
    florianhanke likes this.
  12. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Ah, right, I was having Havok in mind with this. Unfortunately in Unity Physics this collision response is filtered a bit later. I'll look into it, there surely is an earlier point where we can filter these. Will get back to you soon.
     
    PhilSA likes this.