Mass and Inertia#
Every dynamic rigid body in Newton needs positive mass and a physically meaningful inertia tensor for stable simulation. Newton provides three ways to assign these properties:
Direct specification on the body via
add_link().Density-based inference from collision shapes added with
ShapeConfig.File import (USD, MJCF, URDF), where mass properties are parsed from the source format and mapped to Newton’s internal representation.
For the distinction between static, kinematic, and dynamic bodies see Articulations.
Best practices#
Tip
Dynamic bodies should have positive mass.
If a body has no shapes with density, set mass and inertia
explicitly on add_link().
Tip
Use is_kinematic=True for prescribed motion — do not rely on
zero mass to make a body immovable. See Articulations for details.
Tip
Prefer density-based inference when possible. Letting Newton compute mass and inertia from shape geometry keeps mass properties consistent with collision geometry and avoids manual bookkeeping.
Tip
Use lock_inertia=True to protect hand-specified mass properties
from subsequent shape additions. This is the mechanism the MJCF importer
uses when an <inertial> element is present.
Tip
Check finalize warnings. Set validate_inertia_detailed=True on
ModelBuilder during development to get per-body warnings
for any mass or inertia values that were corrected.
Specifying mass and inertia#
Direct specification on the body#
add_link() accepts the following inertial
parameters:
mass— body mass [kg]. Defaults to0.0.inertia— 3x3 inertia tensor [kg m2] relative to the center of mass. Defaults to the zero matrix.com— center-of-mass offset [m] from the body origin. Defaults to the origin.armature— artificial scalar inertia [kg m2] added to the diagonal of the inertia tensor. Useful for regularization.
These values serve as the initial mass properties of the body. If shapes with positive density are subsequently added, their contributions are accumulated on top of these initial values (see below).
Automatic inference from shape density#
When a shape is added via one of the add_shape_*() methods with
ShapeConfig.density > 0, Newton
automatically computes mass, center of mass, and inertia tensor from the shape
geometry and accumulates the result onto the parent body.
The accumulation follows three steps:
Mass: the shape’s mass is added to the body’s total mass.
Center of mass: the body COM is recomputed as the mass-weighted average of the existing body COM and the shape’s COM (transformed to body frame).
Inertia: both the existing body inertia and the shape inertia are shifted to the new COM using the parallel-axis theorem (Steiner’s theorem), then summed.
This means multiple shapes on the same body compose additively.
import numpy as np
import warp as wp
import newton
builder = newton.ModelBuilder()
# Body with initial mass 2.0 kg
body = builder.add_link(mass=2.0)
# Shape adds mass from density: a 1m-radius sphere at 1000 kg/m^3
builder.add_shape_sphere(body, radius=1.0, cfg=builder.ShapeConfig(density=1000.0))
sphere_mass = 4.0 / 3.0 * np.pi * 1000.0 # ~4189 kg
assert abs(builder.body_mass[body] - (2.0 + sphere_mass)) < 1.0
Special cases:
Planes and heightfields never contribute mass, regardless of density.
Sites enforce
density=0and never contribute mass.lock_inertia=Trueonadd_link()prevents subsequent shape additions from modifying the body’s mass, COM, or inertia.Hollow shapes (
ShapeConfig.is_solid=False) compute shell inertia by subtracting the inner volume’s contribution from the outer, usingShapeConfig.marginas shell thickness.Cylinder mass properties include the circular side profile selected by
barrel_radius.
Rod and cable mass#
add_rod() builds each segment as a capsule, and
neighboring capsules overlap at their tips. Rods therefore take segment mass
from the cylindrical part only, density * area * rest_length, so refining
the same centerline preserves total mass. area is pi * radius**2, or
for hollow rods (is_solid=False) the tube wall of thickness margin.
total_mass [kg] instead sets the mass of the whole rod, distributed by rest
length, and overrides ShapeConfig.density.
Segment inertia is the solid-cylinder or open-tube tensor at the assigned mass
and rest length. For outer radius r, inner radius a (zero for a solid
rod), and rest length L, the local axial moment is m * (r**2 + a**2) / 2
and both transverse moments are m * ((r**2 + a**2) / 4 + L**2 / 12).
Collision geometry stays capsule-based. USD cable import uses the same solid
cylinder mass and inertia model; default_shape_cfg.is_solid does not apply
to imported cables. Capsules joined manually with rod joints keep ordinary
capsule mass and inertia.
This replaces the previous capsule-based inertia for native rods and USD cables, changing their angular response. Scenes tuned to that approximation may need to retune their solver settings. Hollow mass and inertia use the tube wall; material-derived rod stiffness retains its solid-circle convention. Use explicit section rigidities when modeling a hollow material section.
Mass resolution during file import#
When importing from USD, MJCF, or URDF, each format has its own rules for how mass properties are authored, inferred, or overridden. Regardless of format, shape-derived contributions all flow through the same accumulation logic described above.
The common pattern across formats is:
Explicit inertial data takes precedence when present (
UsdPhysics.MassAPIfor USD,<inertial>for MJCF/URDF).Shape-based inference is the fallback when explicit data is missing — mass and inertia are computed from collision geometry and density.
Both MJCF and URDF importers accept
ignore_inertial_definitions=Trueto skip explicit inertial data and always infer from shapes.
For format-specific details, see:
USD: USD Parsing and Schema Resolver System — covers the
MassAPIprecedence cascade,ComputeMassPropertiescallback, and collider density priority.MJCF:
add_mjcf()— follows MuJoCo semantics where<inertial>fully overrides geom-derived mass (vialock_inertia), and geoms contribute via density when<inertial>is absent. Mesh geoms use theinertiamode of their<mesh>asset: MuJoCo’s defaultlegacysums absolute tetrahedron volumes,exactuses the signed volume,convexthe convex hull (limited bymaxhullvertas in MuJoCo), andshellthe surface area. A mesh without faces uses MuJoCo’s convex hull of all its vertices, not the collision hull, and a primitive geom fitted to a mesh is sized and posed by the equivalent inertia box of the mesh’s mode, as in MuJoCo. A mesh with too little surface area or volume for its mode, which MuJoCo rejects, adds no mass and logs a warning; useinertia="shell"to give flat or open surface meshes mass. Anexactmesh whose faces have inconsistent orientation, which MuJoCo also rejects, logs a warning and keeps its signed volume.URDF:
add_urdf()— uses<inertial>directly when present; falls back to collision geometry with default density otherwise. By default visual shapes do not contribute mass; however,parse_visuals_as_colliders=Truepromotes visual geometry into the collider set, making it mass-contributing atdefault_shape_density.
Validation and correction at finalize#
During finalize(), Newton validates and optionally
corrects mass and inertia properties for all bodies.
Compiler settings#
The following attributes on ModelBuilder control validation
behavior:
Setting |
Default |
Description |
|---|---|---|
|
Fix triangle-inequality violations on principal moments by shifting eigenvalues uniformly. |
|
|
Minimum mass value. If set, clamps small masses up to this value. |
|
|
Minimum inertia eigenvalue. If set, ensures all principal moments are at least this value. |
|
|
When |
|
|
Non-negative relative eigenvalue threshold (dimensionless). |
|
|
Positive absolute floor for eigenvalue and triangle-inequality tolerances [kg·m²]. |
|
|
Non-negative extra diagonal shift applied when repairing inertia [kg·m²]. Zero disables the extra shift, not validation. |
Small-inertia models#
The eigenvalue threshold is
max(inertia_relative_tolerance * largest_moment, inertia_absolute_tolerance).
When the smallest moment is below this threshold, all three moments are
shifted by threshold - smallest_moment + inertia_correction. Thus the
correction is not a minimum imposed on every tensor.
For example, a 0.1 mm diameter capsule with 0.5 mm cylindrical length and density 1,000 kg/m³ has an axial moment of approximately 5.4e-18 kg·m². To preserve this valid tensor while retaining validation, lower the absolute tolerance before finalization:
builder.inertia_absolute_tolerance = 1e-20
model = builder.finalize()
This example value is specific to that scale, not a universal recommended
tolerance. Lowering inertia_correction alone does not prevent a tensor
below the threshold from being adjusted. The numerical settings apply equally
to the detailed CPU and fast Warp paths. They must be finite and within the
float32 range; the absolute tolerance must remain positive in float32.
Changing inertia_correction is a separate repair-policy choice. Setting it
to zero removes the extra padding for tensors that fail validation; for example,
a positive-mass body with zero inertia is repaired to approximately
inertia_absolute_tolerance * identity. Retaining the default correction
avoids that change and does not affect tensors that pass validation. A repair
still includes a representable positive shift if rounding would leave the
tensor singular. Inverse inertia is computed with float64 intermediates and
stored in float32; both the tensor and its inverse must remain representable
in float32.
To skip the entire mass/inertia validation and correction stage:
model = builder.finalize(skip_validation_inertia=True)
This preserves the builder’s mass and inertia, including invalid values.
Finalization always recomputes derived inverses from the final properties,
including after manual edits or imports. Non-positive masses receive zero
inverse mass and zero inverse inertia; singular tensors receive zero inverse
inertia. Validation skipping omits finiteness, symmetry, positive-definiteness,
mass and inertia bounds, and triangle-inequality checks. The caller is
responsible for supplying consistent properties supported by the chosen
solver. finalize(skip_all_validations=True) also skips this stage.
Unlike earlier releases, skip_all_validations=True now also disables mass
and inertia bounds and balancing. To retain those corrections while skipping
other checks, leave skip_all_validations=False and
skip_validation_inertia=False and enable the individual skip flags for
the checks you want to omit.
Neither option undoes earlier importer processing, shape-derived mass computation, or fixed-joint merging. These settings are model-compilation policy, applied after import; they do not introduce new USD-authored fields.
Checks performed#
The detailed (validate_inertia_detailed=True) and fast (default) validation
paths apply the same conceptual checks, but the detailed path emits per-body
warnings. Work is underway to unify the two implementations.
The following checks are applied in order:
Negative mass — set to zero.
Small positive mass below
bound_mass— clamped (ifbound_massis set).Zero mass with non-zero inertia — inertia zeroed.
Inertia symmetry — enforced via \((I + I^T) / 2\).
Positive definiteness — eigenvalues below the configured threshold adjusted.
Eigenvalue bounds — all eigenvalues clamped to at least
bound_inertia(if set).Triangle inequality — principal moments must satisfy \(I_1 + I_2 \geq I_3\). If violated and
balance_inertiaisTrue, eigenvalues are shifted uniformly to satisfy the inequality.
Note
collapse_fixed_joints() merges mass and inertia
across collapsed bodies before validation runs.
Shape inertia reference#
The table below summarizes the mass formula for each shape type when density
is positive. For the full inertia tensor expressions, see
compute_inertia_shape().
Shape |
Mass |
Notes |
|---|---|---|
Sphere |
\(\tfrac{4}{3} \pi r^3 \rho\) |
Hollow: shell inertia (outer minus inner). |
Box |
\(8\, h_x h_y h_z\, \rho\) |
Half-extents. |
Capsule |
hemisphere caps + cylinder |
\((\tfrac{4}{3}\pi r^3 + 2\pi r^2 h)\,\rho\) |
Cylinder |
\(\pi r^2 h\, \rho\) |
|
Cone |
\(\tfrac{1}{3} \pi r^2 h\, \rho\) |
Center of mass offset from base. |
Ellipsoid |
\(\tfrac{4}{3} \pi a\,b\,c\, \rho\) |
Semi-axes. |
Mesh |
Integrated from triangles |
Cached on |
Plane |
Always 0 |
Regardless of density. |
Heightfield |
Always 0 |
Regardless of density. |
Hollow shapes (ShapeConfig.is_solid=False) compute shell inertia by
subtracting the inner volume’s contribution, using
ShapeConfig.margin as shell thickness.