Both Unity and NVIDIA Omniverse use NVIDIA PhysX under the hood for rigid body simulation. But identical physics engines don’t guarantee identical results — solver settings, default substep counts, collision approximation methods, and scene unit scale can all produce visibly different behavior from the same inputs.
To put this to the test, I built the same experiment in both engines: a 10-row cube pyramid (55 cubes) struck by a rigid sphere, and ran three controlled conditions, changing exactly one variable at a time.
This post walks through the setup, the methodology, and what the comparison revealed.
Why Compare Unity and Omniverse?
- Unity is the industry-standard real-time engine for games, apps, and interactive simulations — mature, widely adopted, built for iteration speed.
- NVIDIA Omniverse is built around USD (Universal Scene Description), targeting simulation, digital twins, and RTX-accelerated rendering/visualization pipelines — increasingly relevant for robotics, synthetic data, and industrial simulation.
Both lean on PhysX for rigid body dynamics, which makes them a fair apples-to-apples testbed for a physics behavior comparison — while also surfacing real workflow differences (USD’s non-destructive layer system vs Unity’s scene-based approach, MDL materials vs Unity shaders, and Python scripting vs C#).
Experiment Setup
Scene geometry (identical in both engines):
- Cube pyramid: 10 rows, base of 10 cubes tapering to 1 — 55 cubes total
- Sphere (projectile): 1.5 m diameter
- Sphere launch height: 2.5 m above ground
- Sphere launch distance: 10 m from the pyramid
- Sphere initial velocity: 20 m/s, set directly (not via impulse/force) for a controlled, reproducible starting condition
Why velocity instead of force: Force depends on mass, timestep, and force mode (Impulse vs continuous Force in Unity), which makes it easy to unintentionally desync two engines’ physics settings. Setting linear velocity directly removes that ambiguity — “the ball starts moving at exactly 20 m/s” means the same thing in any physics engine.
Test Conditions
| Condition | Ball Mass | Ball Velocity | Cube Mass | What It Isolates |
|---|---|---|---|---|
| 1 — Baseline | 20 kg | 20 m/s | 1 kg | Reference collision response |
| 2 — Heavy Ball | 200 kg | 20 m/s | 1 kg | Momentum scaling at constant velocity |
| 3 — Heavy Cubes | 20 kg | 20 m/s | 5 kg | Structural resistance to collapse |
Each condition changes exactly one variable from the baseline, so any visible difference in collapse behavior can be attributed to that single change rather than a compounding effect.
Condition 1 — Baseline (20 kg ball, 1 kg cubes)
This is the control case: a 20 kg, 1.5 m sphere at 20 m/s striking a pyramid of 1 kg cubes. Timestamp in the video above: [add timestamp].
Observations: [Fill in: symmetry of collapse, how many rows toppled, whether cubes scattered or slid, any visible difference between engines’ solvers]
Condition 2 — Heavy Ball (200 kg, same velocity)
Same 20 m/s velocity, same 1.5 m sphere size, but mass increased 10x. Since kinetic energy scales linearly with mass (KE = ½mv²) at constant velocity, this condition tests whether a visually identical-looking ball produces proportionally more destructive impact. Timestamp in the video above: [add timestamp].
Observations: [Fill in: did the pyramid fully collapse vs. partial in baseline, did the ball plow through vs. deflect, did either engine show more visible energy transfer]
Condition 3 — Heavy Cubes (5 kg each)
Ball reverts to baseline (20 kg, 20 m/s), but cube mass increases 5x. This tests the inverse relationship — how much a heavier stack resists the same impact. Timestamp in the video above: [add timestamp].
Observations: [Fill in: was the collapse more localized, did the ball bounce back rather than push through, how many rows actually moved]
Engine-Level Observations
Beyond the physics results themselves, a few workflow differences stood out while building this:
| Aspect | Unity | Omniverse (USD Composer) |
|---|---|---|
| Scene format | Proprietary .unity scene | USD (.usd/.usda/.usdc) — open, layerable |
| Physics setup | Rigidbody + Collider components | Rigid Body + Collider schemas (PhysX-based) |
| Scripting | C# MonoBehaviour | Python (Script Component) or OmniGraph |
| Rendering | Rasterized (URP/HDRP), baked lighting common | RTX real-time/path-traced, live in viewport |
| Units | Meters by default | Stage-dependent (often centimeters) — worth verifying metersPerUnit before tuning velocity/mass |
One practical gotcha worth flagging for anyone trying this themselves: Omniverse stage units aren’t always meters. A velocity value that looks reasonable can behave very differently depending on whether the stage is scaled in centimeters — always check metersPerUnit on the stage before comparing numbers directly against Unity.
Conclusion
Running the same physics experiment across two different engines is a useful exercise for understanding what “the same physics engine” really means in practice — the underlying solver is shared, but scene scale, defaults, and tooling still shape the final result.