#Character Controller Overlap Unexpectedly Slow

1 messages · Page 1 of 1 (latest)

tawny laurel
#

Hi, I’m using the DOTS (Rival) Platformer sample character controller as a starting point for my project.

I use around 1000 individual character controller entities active simultaneously. I set the CollisionFilter in the Physics Shape component of my Character Prefab to not collide with other copies of itself. The Rival character controller is such a marvel of ingenuity that I can pull off over 1000 of these entities running at the same time with well over 60 fps on a modern gaming laptop.

However, I notice a drop to less than 10 fps when the entities overlap at the same position. This is unexpected to me because it runs fine when they don’t overlap, and this tells me it has something to do with the collision system even though the CollisionFilter was set to ignore copies of itself. I know the CollisionFilter I set up (referenced above) is working on some level though, because the entities can pass right through each other otherwise and don’t collide.

The profiler shows that the item taking up the most CPU usage during the entity overlap is the Burst-compiled PlatformerCharacterPhysicsUpdateSystem with the PlatformerCharacterPhysicUpdateJob. I’ve been digging into the function over the past couple days trying to troubleshoot why the Job takes so long when these entities are overlapping, but my troubleshooting takes me into the base Rival Character Controller code which I’m hesitant to modify.

I noticed that disabling Detect Movement Collisions and Decollide From Overlap in the Platform Character Authoring component help improve performance slightly (up to +5 fps), but still less than expected, and then also the entities go through walls which is undesired so this probably isn't the solution.

Is this a bug, or is there a setting in the Platform Character Authoring I can change to prevent the slowdown?

I can provide steps to recreate the issue from the if needed.

Tagging @fresh portal because he's the beast who created Rival.

fresh portal
#

I managed to repro this in the stress test sample, by spawning all characters at the same point. I'll investigate and get back to you!

tawny laurel
#

Thanks Phil! I found one other small bug while I was learning Rival, although I doubt this is related to my original post. In the Platformer sample within the GroundMoveState.cs file, the OnStateVariableUpdate function uses AirRotationSharpness instead of GroundedRotationSharpness.

fresh portal
#

nice catch, will fix!

fresh portal
#

So I made a little test where I take the character controller out of the equation and focus only on physics queries:

  • I create a kinematic capsule physics body
  • I give this capsule body a CollisionFilter that doesn't collide with itself
  • I spawn 5000 of these capsules at world origin
  • I do 5000 physicsWorld.CastCollider that go through the world origin where the 5000 capsules are, using the capsule colliders as input to the query (so the proper collision filters are used)

This is more or less a simple version of what the character does. None of the queries detect any hits (which is what we want, because of our collision filters), but they do take a huge amount of time just like in your use case.

So my conclusion at the moment is that this performance cost comes from the way physics queries work in general. I'll ask the physics team to see if this is expected, then see if I can think of solutions for this use case

tawny laurel
#

Awesome, thanks for the update!

paper quiver
#

Unity physics falls apart a bit if you have 1000s of colliders in a really small space

#

It might be unreasonable to consider this falling apart consider the number of pairs needed to be calculated

#

Physics does scale pretty well to 1000s of colliders when they're spread over a reasonable and realistic area, but yeah throw 10,000 balls in a pool and you'll have issues

fresh portal
#

5000 dynamic bodies all spawning at the same point and ignoring their own group at least performs significantly better than the queries version, but I suspect this should be expected due to the fact that the rigidbody solver does something smarter than just one query at a time

fresh portal
#

@tawny laurel
A possible solution would be to put characters in a different physics world, using this for example:
state.EntityManager.SetSharedComponent(charactersQuery, new PhysicsWorldIndex { Value = 1 });

The characters would do their queries against the regular physics world that contains everything except characters, so character colliders would have no performance impact on character queries. However you'd have to remember this when doing raycasts and expecting to hit characters. It may or may not be a viable solution depending on your use cases

tawny laurel
#

I added that to my scene initialization script, and the characters all float in the AirMove state without interacting with my gravity zone

fresh portal
#

oh yes I see, that would be a good example of "you'd have to remember this when doing raycasts and expecting to hit characters" I suppose 😁

So in this case, the gravity zone system would have to be modified to use the PhysicsWorld of characters instead of the default PhysicsWorld. Or maybe even do its logic for both physics worlds

fresh portal
tawny laurel
#

Ah man. I was hoping it would be as simple as switching the gravity zone's physics world index to 1 as well, but that didn't pan out. 😅

tawny laurel
#

I put all of my characters into a 2nd physics world and I got an incredible performance boost overall. The build of my project went up from 100fps to 180fps when not overlapping, and from <10fps to 150fps when overlapping. Thanks for the suggestion!

dense night
#

This approach just means there’s no character to character collision right?

fresh portal
#

Correct. And if the characters are all colliding with each other, then the situation leading to the performance problem from the first post won't happen in the first place

dense night
#

is it better to place them in another physics world, or is putting them in another physics layer sufficient? I'm guessing physics layer won't work because it'll still have to query the other entities which is what's causing the performance issue to begin with

fresh portal
#

If you think there's a chance they'll all be in the same spot overlapping with each other, then it's better to place them in a separate physics world. The original performance problem happens even if the characters ignore the characters layer

Basically, the performance problem happens because of this:

  • you have 1000 characters spawned in the exact same spot
  • each character does multiple queries per frame, and each query must do checks with every hit in order to see if they should be ignored due to physics filters/layers
  • at 3 queries per character and all characters overlapping, that gives us 1000 x 3 x 1000 = 3,000,000 collision filter checks to do per frame

By putting characters in a separate world, the character colliders don't have to be checked by queries anymore. And if the characters collide with each other, each character will be colliding with at most 4 other characters instead of 1000, which would give us 1000 x 3 x 4 = 12,000 checks to do in a worst case scenario instead of 3 million

steady abyss
fresh portal
#

the PhysicsVelocity.Linear of characters is always zero, and they are instead moved by character systems after the physics update (so they're never moved inside the PhysicsWorld or inside the physics simulation)

#

basically their only reason for being kinematic is because kinematic bodies are optimized for being moved, as opposed to static bodies

steady abyss
somber lark
#

If they are near each other but not inside is it fine?