Determinism of Unity’s physics engine has been a reoccurring topic within the community and yet I don’t feel like it’s been explored very much as people often condemn it because it uses floating point math.

Many games need determinism for things like synchronous simulations across the network or small, elegant replays. Common knowledge so far has been that the Unity’s physics is not deterministic because of floating point imprecision. According to this article, floats have accuracy of at least 6 digits which, I think, is more than enough precision for physics.

I never saw why the inputs and ouputs for physics couldn’t just be rounded to the significant digits as this would take out nearly all randomness caused by floating point imprecision. Furthermore, certain games like RTS require simulation at very slow intervals - maybe 10 per second - so not only would there be less room for inaccuracies, but the rounding would also cause a less drastic change on the simulation.

As of far, I can think of no reason why through the use of heavy rounding and a low simulation rate the physics can’t be made deterministic. I don’t think there are any random factors (besides imprecision) in the PhysX or Box2D engines and the floats definitely have enough precision for smooth rounding. At the very least, I think the collision detection can be used and the impulses calculated in a custom manner. This is much better than the alternative of having developers coding everything from scratch. Do you think this will work and if not, why?

Physics across different platforms and architectures, or on a single machine needing reproducible results (play backs), would seem to require either an authoritative server or fixed point calculations.

I made a test to see whether or not Unity PhysX can be made deterministic. Please check it out here if you’re interested in helping to solve this mystery.

It seems unintuitive that 1.1 + 1.1 won’t equal to 2.2 on all computers whereas 1.00000000001 + 1.00000000001 might not equal 2.00000000002 because there’s a lot more needed to be stored in just 4 bytes. That’s basically what rounding everything is doing - scaling down the calculations to more manageable numbers for the computers.

An additional complication with true input-based playback for a full scene/match/whatever is the order of operations for the objects themselves. Lots of gameplay things (i.e. jump pads, boosts, whatever), might need to apply forces to objects in the same order in your replay as in the original version to get the same result.

That kind of stuff requires determinism throughout the engine, which Unity isn’t well suited for, especially for object creation/deletion. If you create 10 pieces of physical shrapnel on an explosion, they’re going to have be created in the same order so they handle collisions in the same order later, etc etc…

No, but many events in Unity are ordered by either when they were loaded or by GUID or other essentially random elements. If you have a bunch of game logic scripts, and they’re all doing some kind of distance check or whatever in Update/FixedUpdate, you need to make sure you control the order in order to provide fully deterministic playback.

But even then, if you have 10 objects with RocketExplosion on them, you still need to make they all execute their Update/FixedUpdate in the same order deterministically in order for full deterministic playback to work…

By the way, I’ve conducted more tests on different platforms - sadly, it’s not possible to make Unity’s physics deterministic. They already round positions to the 2nd decimal place and give you no control over what happens in between the roundings.

I’m getting a little out of my depth with low-level stuff, but the very general answer is that there are lots of unordered data structures in use with engines. Something like HashSet at the C# level is a good example of a fast lookup that can’t provide ordered results. It’s basically just an optimization tradeoff.

Most of these data structures are using an object’s HashCode, which can you can see in Unity via the debug Inspector (top-right menu toggle) or via:

Reload the same scene, and that code changes for each object.

So even with float precision wrangled you’re still going to need to architect an engine so that multiple collisions in each frame are processed in the same order, your Update/FixedUpdate logic is in the same order, and that you aren’t just using any random numbers that aren’t passed through some kind of seeded random number generator. It gets pretty deep.

Even at the physics level, truncating/rounding to a defined range is going to bubble up and degrade your actual physics simulation fidelity pretty badly. That kind of limited precision doesn’t seem so bad if you imagine rounding a position every frame, but to do collisions deterministically you’re going to need to round everything at every step (calculating the angles of surfaces, the forces involved, etc etc)…

Rounding floating point numbers to decimal places is not accurate because floating point numbers are not represented in decimal, they are represented in binary. So when you round a number like 1.0011043425546 to a decimal representation 1.001, that is NOT necessarily precisely represented as that exact decimal number. You get just as much inaccuracy when you round to decimal digits as you do when you don’t round at all.

Also, there are many numbers used by the physics simulation that are very small, like in the range of 0.0000000000111 to 0.0000000000222, which can be represented accurately as 1.11E-10 to 2.22E-10, so rounding them off to the nearest 0.0001 completely throws those values away. Rounding to decimal digits is NOT a valid approach to accurate numerical simulation.

No amount or method of rounding floating point numbers will yield deterministic answers.

Suppose two different machines perform a sequence of floating point operations with a correct mathematical answer of 1.5. Machine A gets the result 1.49999999999999999 while Machine B gets the result 1.500000000000001. Machine A rounds to 1, Machine B rounds to 2.