Over the past few weeks I have been working on resolving the physics issues that are preventing me from upgrading to Unity 5. For those that don’t know, Unity 4 uses PhysX 2.8, whereas Unity 5 uses PhysX 3.3, the new version being a major re-architecture of the PhysX implementation as I understand it. The resulting differences in physics behaviour have caused me a fair few problems.
A while back I outlined these problems, but I’ll run through the remaining ones again here, along with the current state of play for each of them.
Collision contact tolerance
The collision contact tolerance is important to set up so that adjacent parts in a construction have enough leeway to slide past each other without jamming up, while also not allowing parts to sink too far into each other. In order to replicate the same contact behaviour in Unity 5 as in Unity 4, it turns out you have to set the collider’s contactOffset to the same value you had Physics.minPenetrationForPenalty set to in Unity 4, and then also shrink the colliders by this same amount in all directions. This shrinking was a bit annoying to have to do, as I use the collider dimensions for other stuff, but at least it seems to have done the trick.
Instability at high angular velocities
Physics engines, given that they integrate at discrete time intervals (rather than being continuous like IRL physics), often struggle with objects with high velocities, the only way around this really is to update the simulation more often with a smaller time step. So in order to allow for rapidly spinning parts like gears, axles, etc. in GearBlocks I have to use a small time step (Time.fixedDeltaTime), otherwise things would become unstable and start wobbling all over the place. However in Unity 5, I had to set it to be even smaller in order to get the same level of stability, unfortunately offsetting much of the physics performance gains over Unity 4!
Each joint connects two rigidbodies, one being the owner of the joint, the other the connected rigidbody. One thing I discovered that helps with stability is to set up the owner / connected relationship in a particular order. The PhysX documentation recommends having the rigidbody with the higher mass of the pair be the owner. I found that it was even more effective to have low velocity parts (e.g. blocks, motors, etc.) be the owner, and those with high angular velocities (e.g. axles) be the connected. Setting joints up in this way meant I could get stable behaviour in Unity 5 without having to reduce Time.fixedDeltaTime by quite so much. Unity 5 / PhysX 3.3 seems super sensitive to this ordering, whereas Unity 4 / PhysX 2.8 doesn’t seem to care. It’s tricky to set up though because I don’t know ahead of time which parts of a construction are going to be the fast spinning ones (and I can’t change the ordering once the construction is unfrozen and moving without causing other problems which I won’t get into here). So right now I’m working on something that’ll use an educated guess and hopefully get it right in most cases.
Unstable collision behaviour
In Unity 5, for some constructions when contacting flat ground, their collision response with the ground isn’t very stable and they can keep bouncing around for ages after the initial collision. What’s more, this gets worse the smaller the simulation time step. Setting up the joint rigidbody ordering as I discussed above seems to reduce this instability though. Also setting the rigidbody’s maxDepenetrationVelocity to a smallish value helps too.
Joint drives (used for motors)
I was finding that the same force numbers for joint drives were giving different results between Unity 4 and 5. I discovered that in Unity 4 the JointDrive’s maximumForce value should be multiplied by Time.fixedDeltaTime (which is what I was doing), whereas in Unity 5 it should not. In other words, Unity 4 expects an impulse value, but Unity 5 wants a force value!
Configurable joint velocity drives
Once I grasped the differences in the way the settings behave, I was able to get these working, sort of. I found that they still don’t work if the rigidbody’s mass is below some threshold, and there also seems to be a dependency on Time.fixedDeltaTime. Not really sure what’s going on here, I need to do some more investigation on this one.
Getting there, but more to do
Well, if anyone out there is still in the process of upgrading to Unity 5, I hope my findings might be useful to you! I’m hopeful I can resolve all this stuff soon, after which I still have to migrate away from some deprecated APIs, and work around a bunch of other bugs and issues I’m having in Unity 5. Anyway, I can’t wait to put this upgrade to bed so I can get back to actually making the game!