Understanding Rudimentary Unity Physics

Unity’s physics engine works great, but a lot of the numbers it uses seem to be drawn randomly from a hat and have no real world value (from what I can see). Does anyone know the real world equivalents?

Like for example:

  • Mass - I’m guessing this is in meters (as 1 Unity unit = 1 meter)?

  • Drag - I assume this is ignoring form, induced, wave, interference drags, and skin friction. It’s just a number that is picked out of the air (hah), to represent drag force. However the name is too abstract. Does this actually represent drag force, or the drag coefficient (drag coefficient is a combination of skin friction and form drag, and drag force is the overall force upon the object, subject to current speed, which increases the pressure/force an object is pushing against)?

  • Angular Drag - Ignoring again all forms of drag equations, and is just an abstract number to represent the angular drag on an object.

Is there some way to find out more details on what equations are actually happening? Asides of course using your own custom physics engine?

Unity uses nVidia’s physx for 3D physics and Box2d for 2d physics.

So you suggest I download the Nvidia PhysX source and route through that? Do you know whether Unity makes any custom changes to it? Or is this simply no one but someone with Unity Engine’s source code will know?

No, they are both well documented.

I have no idea what custom changes Unity make but I’d assume the docs for the two implementations would be a good place to start.

For the things you’ve queried I can’t imagine there’d be significant customisation over the default implementation. I could be very wrong, but that’s my guess.

1 Like

Unity physics (PhysX) use the international system of units (SI)

Mass: kilograms

Drag: a damping rate causing a force that opposes the velocity of the rigidbody. If drag is zero then you have pure newtonian cinematics: the object will conserve its momentum (velocity) unless external forces are applied (gravity included). if drag is nonzero then the rigidbody will come to stop even when no other force is acting on it.

Angular Drag: same as drag, but affecting the angular momentum (rotation rate). If angular drag is nonzero, then the object will eventually stop rotating even if no force/torque is acting on it.

The documentation for PhysX is a good place to learn more on Unity physic internals. The drag properties (named damping in PhysX) are described here:

http://docs.nvidia.com/gameworks/content/gameworkslibrary/physx/guide/Manual/RigidDynamics.html#damping

2 Likes

2D physic uses Box2D which uses MKS or Meters-Kilograms-Seconds. For the most part, units are in SI Units.

Distance is in m (Meters)
Mass is in Kg (Kilograms) - Note you thought it was Meters which is a distance.
Time is in s (Seconds)
Drag (Linear Drag) & Angular Drag are cooefficients that damp the linear/angular velocity over time. They don’t have specific units but are applied per fixed-update to a body using the following pseudo-code like so:

linearVelocity *= 1.0f / (1.0f + timeSlice * LinearDrag)
angularVelocty *= 1.0f / (1.0f + timeSlice * AngularDrag)

For completeness, the body linear velocity is updated like so:
linearVelocity += timeSlice * (GravityScale * WorldGravity + (1.0f / Mass) * BodyAppliedForce)

Here’s how the angular velocity is updated
angularVelocity += timeSlice * (1.0f / Inertia) * BodyAppliedTorque

You can find all the above in the Box2D source code here (around line #203).

Box2D is designed to simulate physics enough for a game simulation. It’s not designed to perform accurate simulations of physical reality hence the approximations.

3 Likes

I’ve tried for a whole day to implement two falling cubes, where I do manual drag in a script, and the reference rigidbody2d in the other, but I can’t seem to get them to fall synchronously. Is this a trivial task that I’m just getting wrong, or is there something complicated going on?

If anyone else is able to do this, I would love to analyze your working example.

By the way, what I’ve been doing is to let two identical capsules fall synchronously into a BuoyancyEffector2D with a polygon collider. I don’t know if that’s relevant.

I came across this thread while trying to solve the same problem, and I believe I’ve figured out why none of the formulas mentioned in various forum and Unity Answers posts seem to work.

I think the formula mentioned in this thread (linearVelocity *= 1.0f / (1.0f + timeSlice * LinearDrag)) may be outdated, as a more recent answer claims that Unity calculates drag like this instead: velocity = velocity * (1 - deltaTime * drag);

That also matches up with what I found in the PhysX source code, and yet when I tried this with 2 cubes (each with a rigidbody), one using the built in drag and the other using the code below, they fell to the ground at different speeds.

private void FixedUpdate()
{
    body.velocity *= Mathf.Max(1f - drag * Time.fixedDeltaTime, 0f);
}

This is simply due to the order in which things happen. When PhysX applies drag internally, it does so after applying gravity (and I think after integrating all accumulated forces from AddForce calls since the last physics step). Meanwhile, when we modify the velocity directly in FixedUpdate, gravity and any forces that were applied since the last physics step have not yet been integrated into said velocity. This essentially results in forces having a whole physics step to move the object before they’re actually affected by drag.

To test this, I disabled gravity and applied a 50m/s VelocityChange force upwards to both objects. Regardless of what I set the drag to, the object using the custom drag always ends up 1 unit higher than the one using the built in drag. This is because the default fixed timestep is 0.02, and the object with the custom drag gets one “free” physics step with no drag applied. 50m/s * 0.02 = 1, which is how far the object travels during that first step, and that’s where it gets the extra 1 unit compared to the object using the built in drag.

The only way I could think of solving this problem was by applying the drag multiplier to forces as you add them via AddForce and to the velocity every physics step (as shown above). For example:

float dragMultiplier = Mathf.Max(1f - drag * Time.fixedDeltaTime, 0f);
Vector3 initialForce = Vector3.up * 50;
body.AddForce(initialForce * dragMultiplier, ForceMode.VelocityChange);
compareTo.AddForce(initialForce, ForceMode.VelocityChange);

body is the object using the custom drag and compareTo is the object using built in drag. Both will come to rest at the same y position, provided they started at the same height and didn’t bump into anything.

As far as I can tell this works for all force modes :slight_smile:

1 Like

As I stated above, the one I mentioned is Box2D only and it’s the one it still uses today so isn’t “outdated”. :slight_smile: Nothing to do with PhysX though.

1 Like

Ah right, that makes sense. My bad for missing the part about it being for 2D :sweat_smile:

1 Like

it’s okay, sometimes both are discussed as the same thing and there’s a lot of cross-over but obviously not everything.

I was really only replying to ensure future readers don’t take that as fact because many do. :slight_smile:

1 Like