Consider this case:
- There are a client and a server, both running physics simulation
- If client’s prediction is wrong, resimulation is required
- For example, there is a vehicle which requires synchronization
Ideally, vehicle’s state on a client should be fully restored - it includes all the params used for calculations (including ones that are not exposed via public field/method). The obvious choice is to use binary serialization provided by physx, but it has its caveats:
- If server and client are on different platforms, binary data should be converted
- It serializes all the params, including ones that are not needed in this particular situation. For example, PxVehicleWheels4SimData param is not needed since the vehicle was created with the same params on a server and a client. It drastically increases size of resulting binary data
The questions are:
- Is there a better way to synchronize physx objects over a network other than using full binary serialization? Retargeting it to other platforms might not be a problem since extensions library can do that, but serializing excessive (in this particular case) data is a problem.
- Is there a way to ‘filter’ data which is being serialized and provide it later, similar to serializing incomplete collections? Can it be achieved via extending serialization and creating custom class derived from PxBase?
- Is synchronizing angular/linear velocities and transforms seem to be enough in someone’s experience? Seems to be not enough in mine
Of course, there is always an option to modify headers and make private variables public and then serializing them by myself. It’s not very convenient, obviously.
I think that it’s an interesting topic to discuss and share knowledge. Thanks!
Serializing the whole rigid body is a bit wasteful because most of the data is unchanged from one frame to the next. You should only need to communicate changes. For a rigid body that will typically be velocity, angular velocity and transform. For a vehicle that might include engine speed, gear, wheel rotation speeds as well as the rigid body data.
It’s common to quantize network data to reduce the number of bits required to represent a float. I’d recommend looking at that after you have a basic system working.
Thanks for answering!
In my experience though, for vehicles it’s not enough to sync the params you mentioned (i.e. linear velocity, angular velocity, transform, gear, engine speed, wheel rotation speed). It works but difference on a server and a client is increasing pretty quickly.
It works much better when I also sync these params (in addition to the ones above): analog inputs (i.e. mDriveDynData->getAnalogInputs(i)) and internal jounces values (i.e. PxVehicleWheelsDynData.mWheels4DynData.mJounces, these are private but it’s easy to add a getter and setter for them). It’s a little strange that I have to sync analog inputs, since applied input is the same on a server and a client, but nonetheless these values (mDriveDynData->getAnalogInputs(i)) are different. I assume it’s because of a different number of simulations (client should invoke additional simulations when prediction turned out to be wrong).
Also, I wanted to ask about partial simulation. As far as I know there is no direct way to simulate PxScene partially, but it’s required when we have one actor whose position is different from server, and we want to resimulate only this one. I see multiple ways to achieve that:
- Restore every actor’s state from a server and run full simulation
- Mark every actor we don’t want to resimulate as kinematic, save velocities, invoke resimulation, mark as non-kinematic, restore velocities
- Use second scene and sync transforms after simulation
Is there a recommended way of doing this? It seems like kinematic flag is the way to go. Just curious if there any caveats.
I think the kinematic flag is the way to go.