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
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?
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…
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.
Is there some kind of performance downside to moving/spawning/despawning a static body compared to kinematic body? (UnityPhysics and Havok)
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?
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
If I do end up having to make my body kinematic, can I solve this problem here?
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.
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.
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.
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.
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%
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)
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:
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?
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.
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(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
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.