- Home /
Poor performance setting Rigidbody.position many times per frame
Hello. I'm experiencing performance issues in my game when moving a number of Rigidbodies around.
The scenario: I have a scene with about 500 rigidbodies, all with colliders (many of these with multiple colliders). There is a similar number of other static, non-rigidbody objects in the scene with colliders.
I'm attempting to replicate this scene across a network. On one computer, the player can interact with a number of those 500 rigidbodies, and it prioritises the most important updates based on criteria (that rigidbody's velocity, how long since its info was last sent, whether it is sleeping, etc). It then sends the position, rotation, velocities and angular velocities of the most important rigidbodies to the other computer, which then applies those updates to the rigidbody directly.
The physics of these rigidbodies is then played out locally until the next update is received from the remote computer, and this keeps their physics reasonably in sync. Once those objects come to rest, no more updates are sent out until a player next interacts with them. I'm happy with the results here, and have no reason to expect the networking is at fault - just giving context to the scenario.
The receiving computer is setting the rigidbody properties like so:
rigidbody.position = position;
rigidbody.rotation = rotation;
rigidbody.velocity = velocity;
rigidbody.angularVelocity = angularVelocity;
(Note that I'm not using Rigidbody.MovePosition() as I want this change to be a teleport to what we received from the other computer - they've already computed the physics, we don't want to do it again.)
I'm testing this locally on one computer using localhost, and also across a LAN, so we're blasting through a bunch of updates every single frame. The end result is we will call those four lines of code above in the region of 3000 times per second. (Approximately: 60 frames per second * 50 objects per frame.)
(Perhaps this is not a replica of how the game would perform under "real internet" conditions, but it should still perform acceptably when running on a local network, and performance shouldn't deteriorate as people have better internet connectivity.)
Profiling this, however, shows the CPU spending a significant amount of time in the setting of rigidbody.position, and a little less but still a large time in the setting of rigidbody.rotation. For every 1 second of real world time, the setting of rigidbody.position and rigidbody.rotation takes up about 200 milliseconds of it. The rendered frames per second drops to low single-digit numbers.
Performance also seems to decrease as we add more rigidbodies to the scene. Our numbers are better than this if we only have, say, 100 rigidbodies in the scene, but with all 500 it is much worse. This is with the same frequency of calls to rigidbody.position and rigidbody.rotation - the only difference being the number of other, sleeping rigidbodies in the scene. So, scene "complexity" seems to be a problem?
I also tried setting properties on the Transform directly, and playing with Physics.autoSyncTransforms. With either option of Physics.autoSyncTransforms, this seems to improve the time spent setting the position and rotation, but consequently causes a much greater CPU spike at the time these properties are synchronised.
I suspect the moving of each rigidbody causes the physics engine to rebuild some internal structures that hold all of the objects in it, though it's a bit of a blackbox. Does anyone have any thoughts or suggestions on how we could improve things here?
I'm kinda wanting to tell the physics system: "I'm about to move 50 rigidbodies in one big batch, can you please stop doing what you're doing, let me move everything in one go, and then sort things out after with one chunk of overhead instead of 50x over." But I don't think such a thing is possible?
I don't understand one thing: moving all of these rigidbodies are properly computed on host? The problem exists only on client or both of machines?
Hi! The problem only exists on the receiving side, when we receive updates. If we process no updates from the remote computer, performance will jump up to 50-60 FPS. If we're only sending updates to the remote computer, performance is also good.
It's specifically when we get updates from the remote computer, and we manually set the rigidbodies' properties, our performance drops dramatically.
I can only guess two things:
There is a problem with serialization, so filling position and rotation with broken data can lead to unexpected behaviour.
Client and host calculations can differ, so maybe rapid change of rigidbody is the problem. Is it possible to assign position and rotation of rigidbody when it is kinematic? Can you force somehow client's object not to calculate physics?
Hmmm. Regarding 1, the data we're putting in is fine. I'd be surprised if there was a performance hit when sending a vector from C# to the physics engine; the data should just be marshalled by copying three floats at most - if not a single block-copy. (That said, we do seem to hit the performance problems when running in the Unity Editor, and seem to be okay in a standalone build. Perhaps something ugly is going on when passing this data to the Editor...)
Regarding 2, the calculations can differ, though that's entirely the point of sending many updates regularly - one computer is the physics authority, the other snaps objects to the values as given by the authority, and does its best to simulate physics in-between those updates so they stay "reasonably" in sync. $$anonymous$$aking the rigidbodies kinematic / disabling the physics for those objects would defeat the ability to simulate the physics in-between those updates... unless I'm misunderstanding something?