MuJoCo Asset Requirements and Best Practices
MuJoCo loads almost any MJCF file, but a model that compiles is not a model that simulates correctly. This is the practical checklist for MuJoCo assets: compiler settings, mass and inertia, convex collision, contact parameters, joints, and the defaults that quietly break training.
Rigyd Team · Published 29 September 2026
MuJoCo is the physics engine most robot-learning teams reach for when they need contact-rich simulation that runs fast, from a single laptop to thousands of parallel environments on MJX or MuJoCo Warp. It is also forgiving in a dangerous way: almost any MJCF file compiles. An asset that compiles, renders, and even sits on a table can still carry the wrong mass, collide as the wrong shape, or become unstable the first time a gripper touches it.
This guide is the practical checklist: what MuJoCo expects from an asset, which defaults quietly break it, and how to check an asset before it costs you a training run. Every default cited here comes from the MuJoCo XML reference.
Quick answer: A MuJoCo asset is an MJCF model whose bodies have realistic mass and inertia, whose collision is built from convex geoms (MuJoCo replaces every mesh with its convex hull), whose contact parameters match the materials, and whose joints carry real limits, damping and armature. The defaults to watch are angles in degrees, geom density of water, mesh inertia set to legacy, and joint damping, armature and friction loss of zero.
Format requirements
MuJoCo reads:
- MJCF (
.xml), the native format and the one to target. It describes bodies, joints, geoms, actuators, sensors and simulation options in a single tree rooted atworldbody. - Mesh files as
.stl,.objor.msh, referenced from an<asset>block. The file extension decides the parser. - URDF, which MuJoCo can load directly. The documentation is explicit that URDF represents only a subset of what MuJoCo can model, so treat a URDF import as a starting point and convert to MJCF before you tune anything.
Best practice: keep one MJCF per asset with its meshes beside it, set meshdir in <compiler> so paths resolve, and make the asset a self-contained body that can be attached to any scene.
Compiler settings that change the meaning of the file
The <compiler> element decides how every number in the file is read. Four settings matter for assets:
| Attribute | Default | Why it matters |
|---|---|---|
angle | degree | Joint ranges and Euler angles are read in degrees. Radian values copied from URDF become near-zero limits. |
autolimits | true | A joint is limited as soon as it has a range. Leave it on and always give articulated joints a range. |
inertiafromgeom | auto | Mass and inertia are inferred from geoms only when a body has no <inertial> element. |
balanceinertia | false | An inertia that violates the triangle inequality is a compile error, not a silent fix. Keep it that way and fix the inertia. |
boundmass and boundinertia exist to patch massless bodies. If you need them, the asset has a modeling bug worth fixing instead.
Mass and inertia
Every moving body needs mass and inertia, and MuJoCo gets them one of two ways:
- Explicitly, with an
<inertial>element carryingmass,pos(the centre of mass), anddiaginertiaorfullinertia. This is the right choice when you know the real values. - Inferred from geoms, using each geom's
massordensity. The default density is 1000, the density of water in SI units. A plastic cup, a steel bracket and a foam block left at the default all weigh as if they were water.
Mesh geoms add a second trap. The mesh inertia attribute defaults to legacy, which the documentation says over-counts volume for non-convex meshes and does not recommend. Use convex for solid parts, exact when the mesh is watertight and well-oriented, and shell for hollow objects such as bins, cups and housings, where the mass sits in the walls. For primitive geoms, shellinertia="true" does the same job.
For how to derive these values rather than guess them, see automatically estimating physics properties.
Collision geometry
This is where most MuJoCo assets go wrong, and the rule is simple: MuJoCo only collides convex shapes. Primitives are convex. Meshes can be non-convex and render that way, but for collision each mesh is replaced by its convex hull, computed with qhull. You can see the hulls in MuJoCo's simulate viewer with the H key.
A mug modelled as one mesh collides as a solid lump; nothing goes inside it and a gripper cannot hook the handle. To model a concave object, decompose it into several convex geoms attached to the same body. The decomposition method decides both fidelity and speed; V-HACD vs CoACD vs manual hulls compares the options, and collision mesh best practices covers hull counts per asset class.
Three practices keep collision correct and cheap:
- Separate visual and collision geoms. Give high-detail visual geoms
contype="0"andconaffinity="0"so they never enter collision, and put them in their owngroup. Collide only with the simplified convex geoms. - Cap hull size with
maxhullvert. The default is unlimited. MuJoCo's MJX documentation suggests roughly 200 vertices or fewer per convex mesh for mesh-primitive collisions and fewer than 32 for convex-convex collisions, and recommendsmaxhullvertto get there. - Filter what can touch what.
contypeandconaffinityare 32-bit masks; two geoms collide only if one'scontypeshares a bit with the other'sconaffinity. Parts of the same asset that should never touch each other should not be tested.
Contact parameters
MuJoCo's contact model is richer than a single friction coefficient, and the defaults are rarely right for a specific material:
frictiontakes three values, default1 0.005 0.0001: sliding friction, torsional friction around the contact normal, and rolling friction.condimsets which of those are used, default3:1is frictionless,3is regular sliding friction,4adds torsional friction,6adds rolling friction. Objects that spin in the fingers or roll on a table need4or6.solrefandsolimpset how stiff and how damped the contact is, and how much penetration it tolerates. Soft materials and hard ones should not share values.margininflates the surface for contact detection, default0. A small margin can stabilise resting contact; a large one makes objects float.priorityandsolmixdecide how two geoms' parameters combine when they differ.
Joints and articulated objects
Articulated assets in MuJoCo are nested bodies with joints between them, written as a tree rather than a list of links:
- Joint types are
hinge,slide,ballandfree. A loose object that should fall, slide and be picked up needs afreejoint (<freejoint/>) on its root body; without it the body is welded to its parent. rangesets the limits, read in degrees by default. Withautolimitson, a range is all you need.damping,armatureandfrictionlossall default to zero. Real hinges and slides have all three.armatureadds inertia to the joint's motion, which also stabilises small, light parts such as latches and dials;frictionlossmodels dry friction, so a door stays where it is left.
Actuators are separate elements that act on joints. An object asset usually has none; a robot asset declares them explicitly.
Simulation options
The <option> element belongs to the scene, but an asset should be tested under the options it will run with:
timestepdefaults to0.002s. The documentation calls it the single most important speed-accuracy trade-off. Stiff contacts need a smaller step; solver time constants insolrefshould be at least twice the timestep.integratordefaults toEuler. MuJoCo's modeling guide recommendsimplicitfastas the default choice, especially for models with damping.conedefaults topyramidal.ellipticis the better physical model; pyramidal can be faster and more robust.gravitydefaults to0 0 -9.81: Z is up. Author assets Z-up and in metres to match.
Validation: compiling is not enough
MuJoCo has no equivalent of NVIDIA's SimReady validator. The compiler catches malformed XML, missing files and invalid inertia, and that is where its guarantees end. Before an asset enters training:
- Compile it on its own and read every warning.
- Inspect the hulls in
simulatewithH, and confirm every concave feature the robot needs is represented by its own convex geom. - Drop it and let it settle on a plane with a
freejoint. It should come to rest without jitter, sinking or drift. - Check the numbers: total mass against the real object, centre of mass inside the body, joint limits in the units you meant.
- Exercise the joints to their limits and confirm damping and friction loss hold them where they should stop.
- If you also ship OpenUSD, compare the two exports; mass, limits and joint parameters should match.
Doing this by hand for every asset does not scale. Built-in validation for simulation assets explains how to move these checks into the pipeline that produces the asset.
Common pitfalls
- Radians in a degree file. Joint ranges from URDF or Python land in MJCF as radians while the compiler reads degrees.
- Everything weighs as water. No
<inertial>and no density means default density 1000. - Legacy mesh inertia. Non-convex meshes over-count volume unless
inertiaisconvex,exactorshell. - A single mesh for a concave object. It collides as its convex hull, so containers are solid and handles cannot be hooked.
- Visual meshes in collision. Detailed render meshes left at the default
contypeandconaffinityof1collide as large, expensive hulls. - A welded root. An object without a free joint is fixed to the world and never moves.
- Zero damping and armature on small parts. Light latches and knobs oscillate or explode under contact.
- Unbounded hulls on GPU backends. Large convex hulls slow MJX and Warp far more than they slow CPU MuJoCo.
A pragmatic adoption sequence
- Start from a known-good model. MuJoCo Menagerie is the reference collection of robot models and a good template for structure and defaults.
- Author a few hero assets by hand so the team understands convex decomposition, contact parameters and joint tuning in MuJoCo terms.
- Write the validation steps above as a script and run it on every asset.
- Automate the long tail. Past a few dozen objects, generating assets with decomposition, physics and joints already set is faster than authoring them.
- Override with measured values where you have them, and randomize the rest.
How Rigyd approaches it
Rigyd exports MJCF and OpenUSD for every asset from text, images, or existing 3D files. Collision is built from CoACD convex decomposition, mass and inertia are derived from geometry and material rather than left at defaults, articulated parts carry their limits, damping and armature, and every asset is drop-and-settle tested in headless MuJoCo before it ships. In our parallel-environment benchmark, a Rigyd Rubik's cube with 310 hulls and six hinges ran 8,192 environments on one A100 in MuJoCo Warp. For the OpenUSD side of the same asset, see Isaac Sim asset requirements and best practices.