Merge pull request #3156 from andrewkaufman:newton-schemas

PiperOrigin-RevId: 925328794
Change-Id: If45b8659ea9b88785660331bca5ee837ac172f67
This commit is contained in:
Copybara-Service
2026-06-02 07:06:59 -07:00
13 changed files with 635 additions and 116 deletions
@@ -323,6 +323,8 @@ class MjcPhysicsCollisionAPI : public UsdAPISchemaBase {
// --------------------------------------------------------------------- //
// MARGIN
// --------------------------------------------------------------------- //
/// DEPRECATED: Use newton:contactMargin and newton:contactGap instead.
///
/// Geometric inflation of the geom surface for the purpose of contact force
/// generation.
///
@@ -348,6 +350,8 @@ class MjcPhysicsCollisionAPI : public UsdAPISchemaBase {
// --------------------------------------------------------------------- //
// GAP
// --------------------------------------------------------------------- //
/// DEPRECATED: Use newton:contactGap instead.
///
/// Additional contact detection buffer beyond margin. Contacts are detected
/// at distance margin + gap but forces are only generated at distance margin.
///
@@ -43,12 +43,20 @@ class SdfAssetPath;
/// \class MjcPhysicsEqualityJointAPI
///
/// API providing extension attributes to represent equality/joint constraints.
/// This API is applied to a joint prim which acts as the constrained joint
/// (joint1 in MuJoCo terminology). The target relationship points to another
/// joint prim which is the reference joint (joint2 in MuJoCo terminology). The
/// constrained joint's position or angle is constrained to be a quartic
/// polynomial of the reference joint's position or angle. Only scalar joint
/// types (slide and hinge) can be used.
///
/// This API is applied to a joint prim which acts as the follower (joint0). The
/// leader joint (joint1) is specified via the newton:mimicJoint relationship
/// inherited from NewtonMimicAPI.
///
/// The follower's position or angle is constrained to be a quartic polynomial
/// of the leader's position or angle: joint0 = coef0 + coef1*(joint1) +
/// coef2*(joint1)^2 + coef3*(joint1)^3 + coef4*(joint1)^4
///
/// The constant (coef0) and linear (coef1) coefficients are provided by
/// NewtonMimicAPI as newton:mimicCoef0 and newton:mimicCoef1. The higher-order
/// coefficients (coef2-coef4) are provided by this API.
///
/// Only scalar joint types (slide and hinge) can be used.
///
class MjcPhysicsEqualityJointAPI : public UsdAPISchemaBase {
public:
@@ -150,10 +158,60 @@ class MjcPhysicsEqualityJointAPI : public UsdAPISchemaBase {
MJCPHYSICS_API
const TfType& _GetTfType() const override;
public:
// --------------------------------------------------------------------- //
// SOLIMP
// --------------------------------------------------------------------- //
/// Constraint solver parameter for equality constraint simulation.
///
/// | ||
/// | -- | -- |
/// | Declaration | `uniform double[] mjc:solimp = [0.9, 0.95, 0.001, 0.5, 2]`
/// | | C++ Type | VtArray<double> | | \ref Usd_Datatypes "Usd Type" |
/// SdfValueTypeNames->DoubleArray | | \ref SdfVariability "Variability" |
/// SdfVariabilityUniform |
MJCPHYSICS_API
UsdAttribute GetSolImpAttr() const;
/// See GetSolImpAttr(), and also
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
/// If specified, author \p defaultValue as the attribute's default,
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
/// the default for \p writeSparsely is \c false.
MJCPHYSICS_API
UsdAttribute CreateSolImpAttr(VtValue const& defaultValue = VtValue(),
bool writeSparsely = false) const;
public:
// --------------------------------------------------------------------- //
// SOLREF
// --------------------------------------------------------------------- //
/// Constraint solver parameter for equality constraint simulation.
///
/// | ||
/// | -- | -- |
/// | Declaration | `uniform double[] mjc:solref = [0.02, 1]` |
/// | C++ Type | VtArray<double> |
/// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->DoubleArray |
/// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
MJCPHYSICS_API
UsdAttribute GetSolRefAttr() const;
/// See GetSolRefAttr(), and also
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create.
/// If specified, author \p defaultValue as the attribute's default,
/// sparsely (when it makes sense to do so) if \p writeSparsely is \c true -
/// the default for \p writeSparsely is \c false.
MJCPHYSICS_API
UsdAttribute CreateSolRefAttr(VtValue const& defaultValue = VtValue(),
bool writeSparsely = false) const;
public:
// --------------------------------------------------------------------- //
// COEF0
// --------------------------------------------------------------------- //
/// DEPRECATED: Use newton:mimicCoef0 instead.
///
/// Constant coefficient a0 of the quartic polynomial. The constraint is:
/// y = y0 + a0 + a1*(x-x0) + a2*(x-x0)^2 + a3*(x-x0)^3 + a4*(x-x0)^4.
///
@@ -179,6 +237,8 @@ class MjcPhysicsEqualityJointAPI : public UsdAPISchemaBase {
// --------------------------------------------------------------------- //
// COEF1
// --------------------------------------------------------------------- //
/// DEPRECATED: Use newton:mimicCoef1 instead.
///
/// Linear coefficient a1 of the quartic polynomial.
///
/// | ||
@@ -271,6 +331,22 @@ class MjcPhysicsEqualityJointAPI : public UsdAPISchemaBase {
UsdAttribute CreateCoef4Attr(VtValue const& defaultValue = VtValue(),
bool writeSparsely = false) const;
public:
// --------------------------------------------------------------------- //
// MJCTARGET
// --------------------------------------------------------------------- //
/// DEPRECATED: Use newton:mimicJoint instead.
///
/// Secondary target of the equality constraint (the leader/reference joint).
///
MJCPHYSICS_API
UsdRelationship GetMjcTargetRel() const;
/// See GetMjcTargetRel(), and also
/// \ref Usd_Create_Or_Get_Property for when to use Get vs Create
MJCPHYSICS_API
UsdRelationship CreateMjcTargetRel() const;
public:
// ===================================================================== //
// Feel free to add custom code below this line, it will be preserved by
@@ -42,6 +42,9 @@ class SdfAssetPath;
/// \class MjcPhysicsMaterialAPI
///
/// DEPRECATED: Use NewtonMaterialAPI instead. All attributes on this API have
/// been superseded by Newton equivalents.
///
/// API providing extension attributes to represent physical MuJoCo materials.
///
class MjcPhysicsMaterialAPI : public UsdAPISchemaBase {
@@ -148,6 +151,8 @@ class MjcPhysicsMaterialAPI : public UsdAPISchemaBase {
// --------------------------------------------------------------------- //
// TORSIONALFRICTION
// --------------------------------------------------------------------- //
/// DEPRECATED: Use newton:torsionalFriction instead.
///
/// Friction value acting around contact normal.
///
/// | ||
@@ -173,6 +178,8 @@ class MjcPhysicsMaterialAPI : public UsdAPISchemaBase {
// --------------------------------------------------------------------- //
// ROLLINGFRICTION
// --------------------------------------------------------------------- //
/// DEPRECATED: Use newton:rollingFriction instead.
///
/// Friction value acting around both axes on the contact tangent plane.
///
/// | ||
@@ -179,6 +179,8 @@ class MjcPhysicsMeshCollisionAPI : public UsdAPISchemaBase {
// --------------------------------------------------------------------- //
// MAXHULLVERT
// --------------------------------------------------------------------- //
/// DEPRECATED: Use newton:maxHullVertices instead.
///
/// Sets an upper limit on the number of vertices in the meshes convex hull.
/// The default value of -1 means unlimited.
///
@@ -152,6 +152,8 @@ class MjcPhysicsSceneAPI : public UsdAPISchemaBase {
// --------------------------------------------------------------------- //
// TIMESTEP
// --------------------------------------------------------------------- //
/// DEPRECATED: Use newton:timeStepsPerSecond instead.
///
/// Controls the timestep in seconds used by MuJoCo.
///
/// | ||
@@ -498,6 +500,8 @@ class MjcPhysicsSceneAPI : public UsdAPISchemaBase {
// --------------------------------------------------------------------- //
// ITERATIONS
// --------------------------------------------------------------------- //
/// DEPRECATED: Use newton:maxSolverIterations instead.
///
/// Maximum number of iterations of the constraint solver.
///
/// | ||
@@ -942,6 +946,8 @@ class MjcPhysicsSceneAPI : public UsdAPISchemaBase {
// --------------------------------------------------------------------- //
// GRAVITYFLAG
// --------------------------------------------------------------------- //
/// DEPRECATED: Use newton:gravityEnabled instead.
///
/// Enables the application of gravitational acceleration as defined in
/// mjOption.
///
@@ -656,7 +656,7 @@ struct MjcPhysicsTokensType {
const TfToken mjcSliderSite;
/// \brief "mjc:solimp"
///
/// MjcPhysicsCollisionAPI, MjcPhysicsEqualityAPI
/// MjcPhysicsCollisionAPI, MjcPhysicsEqualityAPI, MjcPhysicsEqualityJointAPI
const TfToken mjcSolimp;
/// \brief "mjc:solimpfriction"
///
@@ -672,7 +672,7 @@ struct MjcPhysicsTokensType {
const TfToken mjcSolmix;
/// \brief "mjc:solref"
///
/// MjcPhysicsCollisionAPI, MjcPhysicsEqualityAPI
/// MjcPhysicsCollisionAPI, MjcPhysicsEqualityAPI, MjcPhysicsEqualityJointAPI
const TfToken mjcSolref;
/// \brief "mjc:solreffriction"
///
@@ -700,7 +700,7 @@ struct MjcPhysicsTokensType {
const TfToken mjcStiffness;
/// \brief "mjc:target"
///
/// MjcPhysicsActuator, MjcPhysicsEqualityAPI
/// MjcPhysicsActuator, MjcPhysicsEqualityAPI, MjcPhysicsEqualityJointAPI
const TfToken mjcTarget;
/// \brief "mjc:torqueScale"
///
+227 -39
View File
@@ -46,6 +46,8 @@
#include <pxr/base/gf/matrix4f.h>
#include <pxr/base/gf/rotation.h>
#include <pxr/base/gf/vec3d.h>
#include <pxr/base/tf/staticData.h>
#include <pxr/base/tf/staticTokens.h>
#include <pxr/base/tf/token.h>
#include <pxr/base/vt/types.h>
#include <pxr/usd/sdf/path.h>
@@ -82,6 +84,27 @@
using pxr::MjcPhysicsTokens;
using pxr::TfToken;
template <typename T>
using TfStaticData = pxr::TfStaticData<T>;
// clang-format off
TF_DEFINE_PRIVATE_TOKENS(kNewtonTokens,
((NewtonMaterialAPI, "NewtonMaterialAPI"))
((NewtonMeshCollisionAPI, "NewtonMeshCollisionAPI"))
((newtonMaxSolverIterations, "newton:maxSolverIterations"))
((newtonTimeStepsPerSecond, "newton:timeStepsPerSecond"))
((newtonGravityEnabled, "newton:gravityEnabled"))
((newtonContactMargin, "newton:contactMargin"))
((newtonContactGap, "newton:contactGap"))
((newtonMaxHullVertices, "newton:maxHullVertices"))
((newtonTorsionalFriction, "newton:torsionalFriction"))
((newtonRollingFriction, "newton:rollingFriction"))
((newtonMimicJoint, "newton:mimicJoint"))
((newtonMimicCoef0, "newton:mimicCoef0"))
((newtonMimicCoef1, "newton:mimicCoef1"))
((NewtonMimicAPI, "NewtonMimicAPI"))
);
// clang-format on
struct UsdCaches {
pxr::UsdGeomXformCache xform_cache;
@@ -463,15 +486,48 @@ void ParseUsdPhysicsScene(mjSpec* spec,
SetGravityAttributes(spec, stage, gravity_direction, gravity_magnitude);
// Early exit if theres no MjcPhysicsSceneAPI applied.
if (!physics_scene.GetPrim().HasAPI<pxr::MjcPhysicsSceneAPI>()) {
// Parse Newton scene attributes if present (works for Newton-only files)
pxr::UsdPrim scene_prim = physics_scene.GetPrim();
auto newton_iterations = scene_prim.GetAttribute(
kNewtonTokens->newtonMaxSolverIterations);
if (newton_iterations && newton_iterations.HasAuthoredValue()) {
int val;
newton_iterations.Get(&val);
if (val >= 0) spec->option.iterations = val;
}
auto newton_timesteps = scene_prim.GetAttribute(
kNewtonTokens->newtonTimeStepsPerSecond);
if (newton_timesteps && newton_timesteps.HasAuthoredValue()) {
int val;
newton_timesteps.Get(&val);
if (val > 0) spec->option.timestep = 1.0 / val;
}
auto newton_gravity = scene_prim.GetAttribute(
kNewtonTokens->newtonGravityEnabled);
if (newton_gravity && newton_gravity.HasAuthoredValue()) {
bool enabled;
newton_gravity.Get(&enabled);
if (!enabled) {
spec->option.disableflags |= mjDSBL_GRAVITY;
}
}
// Early exit if there's no MjcPhysicsSceneAPI applied.
if (!scene_prim.HasAPI<pxr::MjcPhysicsSceneAPI>()) {
return;
}
auto mjc_physics_scene = pxr::MjcPhysicsSceneAPI(physics_scene.GetPrim());
auto mjc_physics_scene = pxr::MjcPhysicsSceneAPI(scene_prim);
double timestep;
mjc_physics_scene.GetTimestepAttr().Get(&timestep);
spec->option.timestep = timestep;
// MJC values override Newton values only when explicitly authored.
auto timestep_attr = mjc_physics_scene.GetTimestepAttr();
if (timestep_attr.HasAuthoredValue()) {
double timestep;
timestep_attr.Get(&timestep);
spec->option.timestep = timestep;
mju_warning("Scene '%s' uses deprecated mjc:option:timestep. "
"Please migrate to newton:timeStepsPerSecond.",
scene_prim.GetPath().GetText());
}
double impratio;
mjc_physics_scene.GetImpRatioAttr().Get(&impratio);
@@ -586,9 +642,15 @@ void ParseUsdPhysicsScene(mjSpec* spec,
spec->option.solver = mjSOL_PGS;
}
int iterations;
mjc_physics_scene.GetIterationsAttr().Get(&iterations);
spec->option.iterations = iterations;
auto iterations_attr = mjc_physics_scene.GetIterationsAttr();
if (iterations_attr.HasAuthoredValue()) {
int iterations;
iterations_attr.Get(&iterations);
spec->option.iterations = iterations;
mju_warning("Scene '%s' uses deprecated mjc:option:iterations. "
"Please migrate to newton:maxSolverIterations.",
scene_prim.GetPath().GetText());
}
int ls_iterations;
mjc_physics_scene.GetLSIterationsAttr().Get(&ls_iterations);
@@ -638,9 +700,19 @@ void ParseUsdPhysicsScene(mjSpec* spec,
mjc_physics_scene.GetDamperFlagAttr().Get(&damper_flag);
spec->option.disableflags |= (!damper_flag ? mjDSBL_DAMPER : 0);
bool gravity_flag;
mjc_physics_scene.GetGravityFlagAttr().Get(&gravity_flag);
spec->option.disableflags |= (!gravity_flag ? mjDSBL_GRAVITY : 0);
auto gravity_flag_attr = mjc_physics_scene.GetGravityFlagAttr();
if (gravity_flag_attr.HasAuthoredValue()) {
bool gravity_flag;
gravity_flag_attr.Get(&gravity_flag);
if (!gravity_flag) {
spec->option.disableflags |= mjDSBL_GRAVITY;
} else {
spec->option.disableflags &= ~mjDSBL_GRAVITY;
}
mju_warning("Scene '%s' uses deprecated mjc:flag:gravity. "
"Please migrate to newton:gravityEnabled.",
scene_prim.GetPath().GetText());
}
bool clampctrl_flag;
mjc_physics_scene.GetClampCtrlFlagAttr().Get(&clampctrl_flag);
@@ -914,13 +986,39 @@ void ParseMjcPhysicsCollisionAPI(
}
auto margin_attr = collision_api.GetMarginAttr();
if (margin_attr.HasAuthoredValue()) {
auto gap_attr = collision_api.GetGapAttr();
bool mjc_margin_authored = margin_attr.HasAuthoredValue();
bool mjc_gap_authored = gap_attr.HasAuthoredValue();
if (mjc_margin_authored) {
margin_attr.Get(&geom->margin);
mju_warning("Prim '%s' uses deprecated mjc:margin. "
"Please migrate to newton:contactMargin and newton:contactGap.",
collision_api.GetPrim().GetPath().GetText());
}
if (mjc_gap_authored) {
gap_attr.Get(&geom->gap);
mju_warning("Prim '%s' uses deprecated mjc:gap. "
"Please migrate to newton:contactGap.",
collision_api.GetPrim().GetPath().GetText());
}
auto gap_attr = collision_api.GetGapAttr();
if (gap_attr.HasAuthoredValue()) {
gap_attr.Get(&geom->gap);
// Newton collision fallback: newton:contactMargin + newton:contactGap -> margin, gap
if (!mjc_margin_authored || !mjc_gap_authored) {
pxr::UsdPrim prim = collision_api.GetPrim();
auto newton_margin = prim.GetAttribute(kNewtonTokens->newtonContactMargin);
auto newton_gap = prim.GetAttribute(kNewtonTokens->newtonContactGap);
float n_margin = 0, n_gap = 0;
bool has_newton_margin = newton_margin && newton_margin.HasAuthoredValue();
bool has_newton_gap = newton_gap && newton_gap.HasAuthoredValue();
if (has_newton_margin) newton_margin.Get(&n_margin);
if (has_newton_gap) newton_gap.Get(&n_gap);
if (!mjc_gap_authored && has_newton_gap) {
geom->gap = n_gap;
}
if (!mjc_margin_authored && has_newton_margin) {
geom->margin = n_margin;
}
}
}
@@ -942,8 +1040,19 @@ void ParseMjcPhysicsMeshCollisionAPI(
}
auto maxhullvert_attr = mesh_collision_api.GetMaxHullVertAttr();
auto newton_maxhull = mesh_collision_api.GetPrim().GetAttribute(
kNewtonTokens->newtonMaxHullVertices);
if (maxhullvert_attr.HasAuthoredValue()) {
maxhullvert_attr.Get(&mesh->maxhullvert);
if (!newton_maxhull || !newton_maxhull.HasAuthoredValue()) {
mju_warning("Prim '%s' uses deprecated mjc:maxhullvert. "
"Please migrate to newton:maxHullVertices.",
mesh_collision_api.GetPrim().GetPath().GetText());
}
} else if (newton_maxhull && newton_maxhull.HasAuthoredValue()) {
int val;
newton_maxhull.Get(&val);
mesh->maxhullvert = val;
}
}
@@ -1668,15 +1777,42 @@ void ParseUsdPhysicsMaterialAPI(
}
void ParseMjcPhysicsMaterialAPI(
mjsGeom* geom, const pxr::MjcPhysicsMaterialAPI& material_api) {
auto torsional_friction_attr = material_api.GetTorsionalFrictionAttr();
if (torsional_friction_attr.HasAuthoredValue()) {
torsional_friction_attr.Get(&geom->friction[1]);
mjsGeom* geom, const pxr::UsdPrim& material_prim,
const pxr::MjcPhysicsMaterialAPI& material_api) {
// Torsional friction: prefer newton:torsionalFriction, fall back to
// mjc:torsionalfriction with deprecation warning. If both are authored,
// mjc takes precedence for backwards compatibility.
auto mjc_torsional = material_api.GetTorsionalFrictionAttr();
auto newton_torsional = material_prim.GetAttribute(
kNewtonTokens->newtonTorsionalFriction);
if (mjc_torsional.HasAuthoredValue()) {
mjc_torsional.Get(&geom->friction[1]);
if (!newton_torsional || !newton_torsional.HasAuthoredValue()) {
mju_warning("Prim '%s' uses deprecated mjc:torsionalfriction. "
"Please migrate to newton:torsionalFriction.",
material_prim.GetPath().GetText());
}
} else if (newton_torsional && newton_torsional.HasAuthoredValue()) {
float val;
newton_torsional.Get(&val);
geom->friction[1] = val;
}
auto rolling_friction_attr = material_api.GetRollingFrictionAttr();
if (rolling_friction_attr.HasAuthoredValue()) {
rolling_friction_attr.Get(&geom->friction[2]);
// Rolling friction: same deprecation/fallback pattern.
auto mjc_rolling = material_api.GetRollingFrictionAttr();
auto newton_rolling = material_prim.GetAttribute(
kNewtonTokens->newtonRollingFriction);
if (mjc_rolling.HasAuthoredValue()) {
mjc_rolling.Get(&geom->friction[2]);
if (!newton_rolling || !newton_rolling.HasAuthoredValue()) {
mju_warning("Prim '%s' uses deprecated mjc:rollingfriction. "
"Please migrate to newton:rollingFriction.",
material_prim.GetPath().GetText());
}
} else if (newton_rolling && newton_rolling.HasAuthoredValue()) {
float val;
newton_rolling.Get(&val);
geom->friction[2] = val;
}
}
@@ -1789,11 +1925,13 @@ void ParseUsdPhysicsCollider(mjSpec* spec,
if (bound_material) {
pxr::UsdPrim bound_material_prim = bound_material.GetPrim();
if (bound_material_prim.HasAPI<pxr::UsdPhysicsMaterialAPI>() ||
bound_material_prim.HasAPI<pxr::MjcPhysicsMaterialAPI>()) {
bound_material_prim.HasAPI<pxr::MjcPhysicsMaterialAPI>() ||
bound_material_prim.HasAPI(kNewtonTokens->NewtonMaterialAPI)) {
ParseUsdPhysicsMaterialAPI(
geom, pxr::UsdPhysicsMaterialAPI(bound_material_prim));
ParseMjcPhysicsMaterialAPI(
geom, pxr::MjcPhysicsMaterialAPI(bound_material_prim));
geom, bound_material_prim,
pxr::MjcPhysicsMaterialAPI(bound_material_prim));
}
pxr::SdfPath material_path = bound_material_prim.GetPath();
mjsMaterial* material = nullptr;
@@ -1826,7 +1964,9 @@ void ParseUsdPhysicsCollider(mjSpec* spec,
if (!MaybeParseGeomPrimitive(prim, geom, caches.xform_cache)) {
mjsMesh* mesh = ParseUsdMesh(spec, prim, geom, caches.xform_cache);
if (mesh != nullptr && prim.HasAPI<pxr::MjcPhysicsMeshCollisionAPI>()) {
if (mesh != nullptr &&
(prim.HasAPI<pxr::MjcPhysicsMeshCollisionAPI>() ||
prim.HasAPI(kNewtonTokens->NewtonMeshCollisionAPI))) {
ParseMjcPhysicsMeshCollisionAPI(mesh,
pxr::MjcPhysicsMeshCollisionAPI(prim));
}
@@ -1877,8 +2017,8 @@ void ParseMjcEqualityAPISolverParams(
void ParseConstraint(mjSpec* spec, const pxr::UsdPrim& prim, mjsBody* body,
pxr::UsdGeomXformCache& xform_cache) {
if (prim.HasAPI<pxr::MjcPhysicsEqualityJointAPI>()) {
// Handle MjcPhysicsEqualityJointAPI on revolute/prismatic joints.
if (prim.HasAPI<pxr::MjcPhysicsEqualityJointAPI>() ||
prim.HasAPI(kNewtonTokens->NewtonMimicAPI)) {
pxr::MjcPhysicsEqualityJointAPI eq_joint_api(prim);
mjsEquality* eq = mjs_addEquality(spec, nullptr);
eq->type = mjEQ_JOINT;
@@ -1889,20 +2029,48 @@ void ParseConstraint(mjSpec* spec, const pxr::UsdPrim& prim, mjsBody* body,
eq->objtype = mjOBJ_JOINT;
mjs_setString(eq->name1, prim.GetPath().GetAsString().c_str());
// Get the target joint (joint2) from the MjcEqualityAPI target
// relationship.
pxr::MjcPhysicsEqualityAPI equality_api(prim);
pxr::UsdRelationship target_rel = equality_api.GetMjcTargetRel();
// Target joint: prefer newton:mimicJoint, fall back to deprecated mjc:target
pxr::SdfPathVector targets;
target_rel.GetTargets(&targets);
if (!targets.empty()) {
auto newton_mimic_rel = prim.GetRelationship(kNewtonTokens->newtonMimicJoint);
if (newton_mimic_rel && newton_mimic_rel.GetTargets(&targets) && !targets.empty()) {
mjs_setString(eq->name2, targets[0].GetAsString().c_str());
} else {
auto mjc_target_rel = prim.GetRelationship(MjcPhysicsTokens->mjcTarget);
if (mjc_target_rel && mjc_target_rel.GetTargets(&targets) && !targets.empty()) {
mjs_setString(eq->name2, targets[0].GetAsString().c_str());
mju_warning("Prim '%s' uses deprecated mjc:target. "
"Please migrate to newton:mimicJoint.",
prim.GetPath().GetText());
}
}
// If no target, name2 remains empty, meaning joint1 is fixed to a constant.
// Parse individual coefficient attributes for the quartic polynomial.
eq_joint_api.GetCoef0Attr().Get(&eq->data[0]);
eq_joint_api.GetCoef1Attr().Get(&eq->data[1]);
// Coefficients: prefer Newton, fall back to deprecated MJC
auto newton_coef0 = prim.GetAttribute(kNewtonTokens->newtonMimicCoef0);
auto newton_coef1 = prim.GetAttribute(kNewtonTokens->newtonMimicCoef1);
if (newton_coef0 && newton_coef0.HasAuthoredValue()) {
float val;
newton_coef0.Get(&val);
eq->data[0] = val;
} else {
eq_joint_api.GetCoef0Attr().Get(&eq->data[0]);
if (eq_joint_api.GetCoef0Attr().HasAuthoredValue()) {
mju_warning("Prim '%s' uses deprecated mjc:coef0. "
"Please migrate to newton:mimicCoef0.",
prim.GetPath().GetText());
}
}
if (newton_coef1 && newton_coef1.HasAuthoredValue()) {
float val;
newton_coef1.Get(&val);
eq->data[1] = val;
} else {
eq_joint_api.GetCoef1Attr().Get(&eq->data[1]);
if (eq_joint_api.GetCoef1Attr().HasAuthoredValue()) {
mju_warning("Prim '%s' uses deprecated mjc:coef1. "
"Please migrate to newton:mimicCoef1.",
prim.GetPath().GetText());
}
}
eq_joint_api.GetCoef2Attr().Get(&eq->data[2]);
eq_joint_api.GetCoef3Attr().Get(&eq->data[3]);
eq_joint_api.GetCoef4Attr().Get(&eq->data[4]);
@@ -1910,7 +2078,27 @@ void ParseConstraint(mjSpec* spec, const pxr::UsdPrim& prim, mjsBody* body,
pxr::UsdPhysicsJoint joint(prim);
ParseJointEnabled(eq, joint);
ParseMjcEqualityAPISolverParams(eq, equality_api, prim);
// Solver params are now inline on MjcEqualityJointAPI
auto solref_attr = prim.GetAttribute(MjcPhysicsTokens->mjcSolref);
if (solref_attr.HasAuthoredValue()) {
pxr::VtDoubleArray solref;
solref_attr.Get(&solref);
if (solref.size() == mjNREF) {
for (int i = 0; i < mjNREF; ++i) {
eq->solref[i] = solref[i];
}
}
}
auto solimp_attr = prim.GetAttribute(MjcPhysicsTokens->mjcSolimp);
if (solimp_attr.HasAuthoredValue()) {
pxr::VtDoubleArray solimp;
solimp_attr.Get(&solimp);
if (solimp.size() == mjNIMP) {
for (int i = 0; i < mjNIMP; ++i) {
eq->solimp[i] = solimp[i];
}
}
}
} else if (prim.IsA<pxr::UsdPhysicsFixedJoint>() ||
prim.IsA<pxr::UsdPhysicsSphericalJoint>()) {
// Handle fixed joints as weld constraints, spherical joints as connect constraints
+40
View File
@@ -199,6 +199,42 @@ target_link_libraries(mujoco PUBLIC
${MJC_PHYSICS_PLUGIN_TARGET_NAME}
)
## ----- Newton USD Schemas (codeless plugin) -----
function(install_newton_usd_plugin install_base_dir)
include(FetchContent)
FetchContent_Declare(
newton-usd-schemas
GIT_REPOSITORY https://github.com/newton-physics/newton-usd-schemas.git
GIT_TAG v0.1.0rc3
GIT_SHALLOW TRUE
UPDATE_DISCONNECTED TRUE
)
FetchContent_GetProperties(newton-usd-schemas)
if(NOT newton-usd-schemas_POPULATED)
FetchContent_Populate(newton-usd-schemas)
endif()
set(NEWTON_USD_DIR "${newton-usd-schemas_SOURCE_DIR}/newton_usd_schemas")
if(NOT EXISTS "${NEWTON_USD_DIR}")
message(FATAL_ERROR "newton_usd_schemas directory not found in fetched repository")
endif()
set(NEWTON_BUILD_DIR "${CMAKE_BINARY_DIR}/${install_base_dir}/newton")
file(MAKE_DIRECTORY "${NEWTON_BUILD_DIR}")
configure_file("${NEWTON_USD_DIR}/plugInfo.json" "${NEWTON_BUILD_DIR}/plugInfo.json" COPYONLY)
configure_file("${NEWTON_USD_DIR}/generatedSchema.usda" "${NEWTON_BUILD_DIR}/generatedSchema.usda" COPYONLY)
install(FILES "${NEWTON_BUILD_DIR}/plugInfo.json"
DESTINATION "${install_base_dir}/newton"
)
install(FILES "${NEWTON_BUILD_DIR}/generatedSchema.usda"
DESTINATION "${install_base_dir}/newton"
)
endfunction()
## Installation
# Generate and install plugInfo.json for each plugin
@@ -219,6 +255,10 @@ install(FILES
DESTINATION ${MJ_USD_INSTALL_DIR_LIB}/mjcPhysics
)
install_newton_usd_plugin(
${MJ_USD_INSTALL_DIR_LIB}
)
# Install shared libraries
install(TARGETS
${MJCF_PLUGIN_TARGET_NAME}
@@ -79,6 +79,28 @@ const TfType& MjcPhysicsEqualityJointAPI::_GetTfType() const {
return _GetStaticTfType();
}
UsdAttribute MjcPhysicsEqualityJointAPI::GetSolImpAttr() const {
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcSolimp);
}
UsdAttribute MjcPhysicsEqualityJointAPI::CreateSolImpAttr(
VtValue const& defaultValue, bool writeSparsely) const {
return UsdSchemaBase::_CreateAttr(
MjcPhysicsTokens->mjcSolimp, SdfValueTypeNames->DoubleArray,
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
}
UsdAttribute MjcPhysicsEqualityJointAPI::GetSolRefAttr() const {
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcSolref);
}
UsdAttribute MjcPhysicsEqualityJointAPI::CreateSolRefAttr(
VtValue const& defaultValue, bool writeSparsely) const {
return UsdSchemaBase::_CreateAttr(
MjcPhysicsTokens->mjcSolref, SdfValueTypeNames->DoubleArray,
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
}
UsdAttribute MjcPhysicsEqualityJointAPI::GetCoef0Attr() const {
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcCoef0);
}
@@ -134,6 +156,15 @@ UsdAttribute MjcPhysicsEqualityJointAPI::CreateCoef4Attr(
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
}
UsdRelationship MjcPhysicsEqualityJointAPI::GetMjcTargetRel() const {
return GetPrim().GetRelationship(MjcPhysicsTokens->mjcTarget);
}
UsdRelationship MjcPhysicsEqualityJointAPI::CreateMjcTargetRel() const {
return GetPrim().CreateRelationship(MjcPhysicsTokens->mjcTarget,
/* custom = */ false);
}
namespace {
static inline TfTokenVector _ConcatenateAttributeNames(
const TfTokenVector& left, const TfTokenVector& right) {
@@ -149,8 +180,9 @@ static inline TfTokenVector _ConcatenateAttributeNames(
const TfTokenVector& MjcPhysicsEqualityJointAPI::GetSchemaAttributeNames(
bool includeInherited) {
static TfTokenVector localNames = {
MjcPhysicsTokens->mjcCoef0, MjcPhysicsTokens->mjcCoef1,
MjcPhysicsTokens->mjcCoef2, MjcPhysicsTokens->mjcCoef3,
MjcPhysicsTokens->mjcSolimp, MjcPhysicsTokens->mjcSolref,
MjcPhysicsTokens->mjcCoef0, MjcPhysicsTokens->mjcCoef1,
MjcPhysicsTokens->mjcCoef2, MjcPhysicsTokens->mjcCoef3,
MjcPhysicsTokens->mjcCoef4,
};
static TfTokenVector allNames = _ConcatenateAttributeNames(
@@ -4,6 +4,7 @@
)
class "MjcSceneAPI" (
apiSchemas = ["NewtonSceneAPI"]
doc = "API providing global simulation options for MuJoCo."
)
{
@@ -120,7 +121,9 @@ class "MjcSceneAPI" (
)
uniform bool mjc:flag:gravity = 1 (
displayName = "Gravity Toggle"
doc = "Enables the application of gravitational acceleration as defined in mjOption."
doc = """DEPRECATED: Use newton:gravityEnabled instead.
Enables the application of gravitational acceleration as defined in mjOption."""
)
uniform bool mjc:flag:invdiscrete = 0 (
displayName = "Discrete-Time Inverse Dynamics Toggle"
@@ -200,7 +203,9 @@ class "MjcSceneAPI" (
)
uniform int mjc:option:iterations = 100 (
displayName = "Solver Iterations"
doc = "Maximum number of iterations of the constraint solver."
doc = """DEPRECATED: Use newton:maxSolverIterations instead.
Maximum number of iterations of the constraint solver."""
)
uniform token mjc:option:jacobian = "auto" (
allowedTokens = ["auto", "dense", "sparse"]
@@ -265,7 +270,9 @@ class "MjcSceneAPI" (
)
uniform double mjc:option:timestep = 0.002 (
displayName = "Timestep"
doc = "Controls the timestep in seconds used by MuJoCo."
doc = """DEPRECATED: Use newton:timeStepsPerSecond instead.
Controls the timestep in seconds used by MuJoCo."""
)
uniform double mjc:option:tolerance = 1e-8 (
displayName = "Solver Tolerance"
@@ -303,6 +310,7 @@ class "MjcImageableAPI" (
}
class "MjcCollisionAPI" (
apiSchemas = ["NewtonCollisionAPI"]
doc = "API describing a MuJoCo collider."
)
{
@@ -312,7 +320,9 @@ class "MjcCollisionAPI" (
)
uniform double mjc:gap = 0 (
displayName = "Gap"
doc = "Additional contact detection buffer beyond margin. Contacts are detected at distance margin + gap but forces are only generated at distance margin."
doc = """DEPRECATED: Use newton:contactGap instead.
Additional contact detection buffer beyond margin. Contacts are detected at distance margin + gap but forces are only generated at distance margin."""
)
uniform int mjc:group = 0 (
displayName = "Group"
@@ -320,7 +330,9 @@ class "MjcCollisionAPI" (
)
uniform double mjc:margin = 0 (
displayName = "Margin"
doc = "Geometric inflation of the geom surface for the purpose of contact force generation."
doc = """DEPRECATED: Use newton:contactMargin and newton:contactGap instead.
Geometric inflation of the geom surface for the purpose of contact force generation."""
)
uniform int mjc:priority = 0 (
displayName = "Priority"
@@ -345,6 +357,7 @@ class "MjcCollisionAPI" (
}
class "MjcMeshCollisionAPI" (
apiSchemas = ["NewtonMeshCollisionAPI"]
doc = "API describing a MuJoCo mesh collider."
)
{
@@ -355,7 +368,9 @@ class "MjcMeshCollisionAPI" (
)
uniform int mjc:maxhullvert = -1 (
displayName = "Maximum Hull Vertices"
doc = "Sets an upper limit on the number of vertices in the meshes convex hull. The default value of -1 means unlimited."
doc = """DEPRECATED: Use newton:maxHullVertices instead.
Sets an upper limit on the number of vertices in the meshes convex hull. The default value of -1 means unlimited."""
)
}
@@ -537,16 +552,23 @@ class "MjcJointAPI" (
}
class "MjcMaterialAPI" (
doc = "API providing extension attributes to represent physical MuJoCo materials."
apiSchemas = ["NewtonMaterialAPI"]
doc = """DEPRECATED: Use NewtonMaterialAPI instead. All attributes on this API have been superseded by Newton equivalents.
API providing extension attributes to represent physical MuJoCo materials."""
)
{
uniform double mjc:rollingfriction = 0.0001 (
displayName = "Rolling Friction"
doc = "Friction value acting around both axes on the contact tangent plane."
doc = """DEPRECATED: Use newton:rollingFriction instead.
Friction value acting around both axes on the contact tangent plane."""
)
uniform double mjc:torsionalfriction = 0.005 (
displayName = "Torsional Friction"
doc = "Friction value acting around contact normal."
doc = """DEPRECATED: Use newton:torsionalFriction instead.
Friction value acting around contact normal."""
)
}
@@ -586,23 +608,36 @@ class "MjcEqualityWeldAPI" (
}
class "MjcEqualityJointAPI" (
apiSchemas = ["MjcEqualityAPI"]
apiSchemas = ["NewtonMimicAPI"]
doc = """API providing extension attributes to represent equality/joint constraints.
This API is applied to a joint prim which acts as the constrained joint (joint1 in
MuJoCo terminology). The target relationship points to another joint prim which is
the reference joint (joint2 in MuJoCo terminology). The constrained joint's position
or angle is constrained to be a quartic polynomial of the reference joint's position
or angle. Only scalar joint types (slide and hinge) can be used."""
This API is applied to a joint prim which acts as the follower (joint0). The leader
joint (joint1) is specified via the newton:mimicJoint relationship inherited from
NewtonMimicAPI.
The follower's position or angle is constrained to be a quartic polynomial of the
leader's position or angle:
joint0 = coef0 + coef1*(joint1) + coef2*(joint1)^2 + coef3*(joint1)^3 + coef4*(joint1)^4
The constant (coef0) and linear (coef1) coefficients are provided by NewtonMimicAPI
as newton:mimicCoef0 and newton:mimicCoef1. The higher-order coefficients (coef2-coef4)
are provided by this API.
Only scalar joint types (slide and hinge) can be used."""
)
{
uniform double mjc:coef0 = 0 (
displayName = "Coefficient 0"
doc = """Constant coefficient a0 of the quartic polynomial. The constraint is:
doc = """DEPRECATED: Use newton:mimicCoef0 instead.
Constant coefficient a0 of the quartic polynomial. The constraint is:
y = y0 + a0 + a1*(x-x0) + a2*(x-x0)^2 + a3*(x-x0)^3 + a4*(x-x0)^4."""
)
uniform double mjc:coef1 = 1 (
displayName = "Coefficient 1"
doc = "Linear coefficient a1 of the quartic polynomial."
doc = """DEPRECATED: Use newton:mimicCoef1 instead.
Linear coefficient a1 of the quartic polynomial."""
)
uniform double mjc:coef2 = 0 (
displayName = "Coefficient 2"
@@ -616,6 +651,19 @@ class "MjcEqualityJointAPI" (
displayName = "Coefficient 4"
doc = "Quartic coefficient a4 of the quartic polynomial."
)
uniform double[] mjc:solimp = [0.9, 0.95, 0.001, 0.5, 2] (
displayName = "SolImp"
doc = "Constraint solver parameter for equality constraint simulation."
)
uniform double[] mjc:solref = [0.02, 1] (
displayName = "SolRef"
doc = "Constraint solver parameter for equality constraint simulation."
)
rel mjc:target (
doc = """DEPRECATED: Use newton:mimicJoint instead.
Secondary target of the equality constraint (the leader/reference joint)."""
)
}
class MjcTendon "MjcTendon" (
+77 -17
View File
@@ -100,6 +100,7 @@ class "MjcSceneAPI"
}
doc = """API providing global simulation options for MuJoCo."""
prepend apiSchemas = ["NewtonSceneAPI"]
inherits = </APISchemaBase>
)
{
@@ -108,7 +109,9 @@ class "MjcSceneAPI"
string apiName = "Timestep"
}
displayName = "Timestep"
doc = """Controls the timestep in seconds used by MuJoCo."""
doc = """DEPRECATED: Use newton:timeStepsPerSecond instead.
Controls the timestep in seconds used by MuJoCo."""
)
uniform double mjc:option:impratio = 1.0 (
@@ -229,7 +232,9 @@ class "MjcSceneAPI"
string apiName = "Iterations"
}
displayName = "Solver Iterations"
doc = """Maximum number of iterations of the constraint solver."""
doc = """DEPRECATED: Use newton:maxSolverIterations instead.
Maximum number of iterations of the constraint solver."""
)
uniform double mjc:option:tolerance = 1e-08 (
@@ -378,7 +383,9 @@ class "MjcSceneAPI"
string apiName = "GravityFlag"
}
displayName = "Gravity Toggle"
doc = """Enables the application of gravitational acceleration as defined in mjOption."""
doc = """DEPRECATED: Use newton:gravityEnabled instead.
Enables the application of gravitational acceleration as defined in mjOption."""
)
uniform bool mjc:flag:clampctrl = True (
@@ -674,6 +681,7 @@ class "MjcCollisionAPI"
}
doc = """API describing a MuJoCo collider."""
prepend apiSchemas = ["NewtonCollisionAPI"]
inherits = </APISchemaBase>
)
{
@@ -738,7 +746,9 @@ class "MjcCollisionAPI"
string apiName = "Margin"
}
displayName = "Margin"
doc = """Geometric inflation of the geom surface for the purpose of contact force generation."""
doc = """DEPRECATED: Use newton:contactMargin and newton:contactGap instead.
Geometric inflation of the geom surface for the purpose of contact force generation."""
)
uniform double mjc:gap = 0.0 (
@@ -746,7 +756,9 @@ class "MjcCollisionAPI"
string apiName = "Gap"
}
displayName = "Gap"
doc = """Additional contact detection buffer beyond margin. Contacts are detected at distance margin + gap but forces are only generated at distance margin."""
doc = """DEPRECATED: Use newton:contactGap instead.
Additional contact detection buffer beyond margin. Contacts are detected at distance margin + gap but forces are only generated at distance margin."""
)
}
@@ -757,6 +769,7 @@ class "MjcMeshCollisionAPI"
}
doc = """API describing a MuJoCo mesh collider."""
prepend apiSchemas = ["NewtonMeshCollisionAPI"]
inherits = </APISchemaBase>
)
{
@@ -774,7 +787,9 @@ class "MjcMeshCollisionAPI"
string apiName = "MaxHullVert"
}
displayName = "Maximum Hull Vertices"
doc = """Sets an upper limit on the number of vertices in the meshes convex hull. The default value of -1 means unlimited."""
doc = """DEPRECATED: Use newton:maxHullVertices instead.
Sets an upper limit on the number of vertices in the meshes convex hull. The default value of -1 means unlimited."""
)
}
@@ -1035,8 +1050,11 @@ class "MjcMaterialAPI"
customData = {
string className = "MaterialAPI"
}
doc = """API providing extension attributes to represent physical MuJoCo materials."""
doc = """DEPRECATED: Use NewtonMaterialAPI instead. All attributes on this API have been superseded by Newton equivalents.
API providing extension attributes to represent physical MuJoCo materials."""
prepend apiSchemas = ["NewtonMaterialAPI"]
inherits = </APISchemaBase>
)
{
@@ -1045,7 +1063,9 @@ class "MjcMaterialAPI"
string apiName = "TorsionalFriction"
}
displayName = "Torsional Friction"
doc = """Friction value acting around contact normal."""
doc = """DEPRECATED: Use newton:torsionalFriction instead.
Friction value acting around contact normal."""
)
uniform double mjc:rollingfriction = 0.0001 (
@@ -1053,7 +1073,9 @@ class "MjcMaterialAPI"
string apiName = "RollingFriction"
}
displayName = "Rolling Friction"
doc = """Friction value acting around both axes on the contact tangent plane."""
doc = """DEPRECATED: Use newton:rollingFriction instead.
Friction value acting around both axes on the contact tangent plane."""
)
}
@@ -1121,22 +1143,58 @@ class "MjcEqualityJointAPI" (
string className = "EqualityJointAPI"
}
doc = """API providing extension attributes to represent equality/joint constraints.
This API is applied to a joint prim which acts as the constrained joint (joint1 in
MuJoCo terminology). The target relationship points to another joint prim which is
the reference joint (joint2 in MuJoCo terminology). The constrained joint's position
or angle is constrained to be a quartic polynomial of the reference joint's position
or angle. Only scalar joint types (slide and hinge) can be used."""
prepend apiSchemas = ["MjcEqualityAPI"]
This API is applied to a joint prim which acts as the follower (joint0). The leader
joint (joint1) is specified via the newton:mimicJoint relationship inherited from
NewtonMimicAPI.
The follower's position or angle is constrained to be a quartic polynomial of the
leader's position or angle:
joint0 = coef0 + coef1*(joint1) + coef2*(joint1)^2 + coef3*(joint1)^3 + coef4*(joint1)^4
The constant (coef0) and linear (coef1) coefficients are provided by NewtonMimicAPI
as newton:mimicCoef0 and newton:mimicCoef1. The higher-order coefficients (coef2-coef4)
are provided by this API.
Only scalar joint types (slide and hinge) can be used."""
prepend apiSchemas = ["NewtonMimicAPI"]
inherits = </APISchemaBase>
)
{
uniform double[] mjc:solimp = [0.9, 0.95, 0.001, 0.5, 2] (
customData = {
string apiName = "SolImp"
}
displayName = "SolImp"
doc = """Constraint solver parameter for equality constraint simulation."""
)
uniform double[] mjc:solref = [0.02, 1] (
customData = {
string apiName = "SolRef"
}
displayName = "SolRef"
doc = """Constraint solver parameter for equality constraint simulation."""
)
rel mjc:target (
customData = {
string apiName = "MjcTarget"
}
doc = """DEPRECATED: Use newton:mimicJoint instead.
Secondary target of the equality constraint (the leader/reference joint)."""
)
uniform double mjc:coef0 = 0 (
customData = {
string apiName = "Coef0"
}
displayName = "Coefficient 0"
doc = """Constant coefficient a0 of the quartic polynomial. The constraint is:
doc = """DEPRECATED: Use newton:mimicCoef0 instead.
Constant coefficient a0 of the quartic polynomial. The constraint is:
y = y0 + a0 + a1*(x-x0) + a2*(x-x0)^2 + a3*(x-x0)^3 + a4*(x-x0)^4."""
)
@@ -1145,7 +1203,9 @@ class "MjcEqualityJointAPI" (
string apiName = "Coef1"
}
displayName = "Coefficient 1"
doc = """Linear coefficient a1 of the quartic polynomial."""
doc = """DEPRECATED: Use newton:mimicCoef1 instead.
Linear coefficient a1 of the quartic polynomial."""
)
uniform double mjc:coef2 = 0 (
@@ -15,6 +15,7 @@
#include "mjcf/mujoco_to_usd.h"
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <numbers>
#include <string>
@@ -119,6 +120,16 @@ TF_DEFINE_PRIVATE_TOKENS(kTokens,
(UsdPrimvarReader_float2)
(UsdUVTexture)
(UsdPreviewSurface)
((NewtonMaterialAPI, "NewtonMaterialAPI"))
((NewtonMeshCollisionAPI, "NewtonMeshCollisionAPI"))
((newtonTorsionalFriction, "newton:torsionalFriction"))
((newtonRollingFriction, "newton:rollingFriction"))
((newtonMaxHullVertices, "newton:maxHullVertices"))
((newtonMaxSolverIterations, "newton:maxSolverIterations"))
((newtonTimeStepsPerSecond, "newton:timeStepsPerSecond"))
((newtonGravityEnabled, "newton:gravityEnabled"))
((newtonContactMargin, "newton:contactMargin"))
((newtonContactGap, "newton:contactGap"))
);
// Using to satisfy TF_REGISTRY_FUNCTION macro below and avoid operating in PXR_NS.
@@ -393,8 +404,11 @@ class ModelWriter {
WriteUniformAttribute(mesh_spec, pxr::SdfValueTypeNames->Token,
MjcPhysicsTokens->mjcInertia, inertia);
WriteUniformAttribute(mesh_spec, pxr::SdfValueTypeNames->Int,
MjcPhysicsTokens->mjcMaxhullvert, mesh->maxhullvert);
// Newton mesh attribute (replaces deprecated mjc:maxhullvert)
if (mesh->maxhullvert != -1) {
WriteUniformAttribute(mesh_spec, pxr::SdfValueTypeNames->Int,
kTokens->newtonMaxHullVertices, mesh->maxhullvert);
}
// NOTE: The geometry data taken from the spec is the post-compilation
// data after it has been mjCMesh::Compile'd. So don't be surprised if
@@ -500,7 +514,7 @@ class ModelWriter {
const std::vector<std::pair<pxr::TfToken, double>>
option_double_attributes = {
{MjcPhysicsTokens->mjcOptionTimestep, spec_->option.timestep},
// mjc:option:timestep deprecated in favor of newton:timeStepsPerSecond
{MjcPhysicsTokens->mjcOptionTolerance, spec_->option.tolerance},
{MjcPhysicsTokens->mjcOptionLs_tolerance,
spec_->option.ls_tolerance},
@@ -519,7 +533,7 @@ class ModelWriter {
}
const std::vector<std::pair<pxr::TfToken, int>> option_int_attributes = {
{MjcPhysicsTokens->mjcOptionIterations, spec_->option.iterations},
// mjc:option:iterations deprecated in favor of newton:maxSolverIterations
{MjcPhysicsTokens->mjcOptionLs_iterations, spec_->option.ls_iterations},
{MjcPhysicsTokens->mjcOptionNoslip_iterations,
spec_->option.noslip_iterations},
@@ -665,7 +679,7 @@ class ModelWriter {
{MjcPhysicsTokens->mjcFlagContact, mjDSBL_CONTACT},
{MjcPhysicsTokens->mjcFlagSpring, mjDSBL_SPRING},
{MjcPhysicsTokens->mjcFlagDamper, mjDSBL_DAMPER},
{MjcPhysicsTokens->mjcFlagGravity, mjDSBL_GRAVITY},
// mjc:flag:gravity deprecated in favor of newton:gravityEnabled
{MjcPhysicsTokens->mjcFlagClampctrl, mjDSBL_CLAMPCTRL},
{MjcPhysicsTokens->mjcFlagWarmstart, mjDSBL_WARMSTART},
{MjcPhysicsTokens->mjcFlagFilterparent, mjDSBL_FILTERPARENT},
@@ -747,6 +761,19 @@ class ModelWriter {
WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Bool,
MjcPhysicsTokens->mjcCompilerSaveInertial,
(bool)spec_->compiler.saveinertial);
// Newton scene attributes (auto-applied via MjcSceneAPI -> NewtonSceneAPI)
WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Int,
kTokens->newtonMaxSolverIterations,
spec_->option.iterations);
if (spec_->option.timestep > 0) {
WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Int,
kTokens->newtonTimeStepsPerSecond,
static_cast<int>(std::round(1.0 / spec_->option.timestep)));
}
bool gravity_disabled = spec_->option.disableflags & mjDSBL_GRAVITY;
WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Bool,
kTokens->newtonGravityEnabled, !gravity_disabled);
}
void WriteMeshes() {
@@ -868,16 +895,13 @@ class ModelWriter {
pxr::UsdPhysicsTokens->physicsDynamicFriction,
(float)geom->friction[0]);
}
if (geom->friction[1] != geom_default->friction[1]) {
WriteUniformAttribute(material_spec, pxr::SdfValueTypeNames->Double,
MjcPhysicsTokens->mjcTorsionalfriction,
geom->friction[1]);
}
if (geom->friction[2] != geom_default->friction[2]) {
WriteUniformAttribute(material_spec, pxr::SdfValueTypeNames->Double,
MjcPhysicsTokens->mjcRollingfriction,
geom->friction[2]);
}
// Newton material attributes (replaces deprecated mjc:torsionalfriction / mjc:rollingfriction)
WriteUniformAttribute(material_spec, pxr::SdfValueTypeNames->Float,
kTokens->newtonTorsionalFriction,
(float)geom->friction[1]);
WriteUniformAttribute(material_spec, pxr::SdfValueTypeNames->Float,
kTokens->newtonRollingFriction,
(float)geom->friction[2]);
return material_spec;
}
@@ -1706,11 +1730,13 @@ class ModelWriter {
MjcPhysicsTokens->mjcSolimp,
pxr::VtArray<double>(geom->solimp, geom->solimp + mjNIMP));
WriteUniformAttribute(geom_spec, pxr::SdfValueTypeNames->Double,
MjcPhysicsTokens->mjcMargin, geom->margin);
WriteUniformAttribute(geom_spec, pxr::SdfValueTypeNames->Double,
MjcPhysicsTokens->mjcGap, geom->gap);
// Newton collision attributes (replaces deprecated mjc:margin / mjc:gap)
WriteUniformAttribute(geom_spec, pxr::SdfValueTypeNames->Float,
kTokens->newtonContactMargin,
static_cast<float>(geom->margin));
WriteUniformAttribute(geom_spec, pxr::SdfValueTypeNames->Float,
kTokens->newtonContactGap,
static_cast<float>(geom->gap));
if (geom->mass >= mjMINVAL || geom->density >= mjMINVAL) {
ApplyApiSchema(layer_, geom_spec, pxr::UsdPhysicsTokens->PhysicsMassAPI);
@@ -78,6 +78,9 @@ PXR_NAMESPACE_OPEN_SCOPE
// clang-format off
TF_DEFINE_PRIVATE_TOKENS(_tokens,
(st)
((newtonTimeStepsPerSecond, "newton:timeStepsPerSecond"))
((newtonMaxSolverIterations, "newton:maxSolverIterations"))
((newtonGravityEnabled, "newton:gravityEnabled"))
);
// clang-format on
PXR_NAMESPACE_CLOSE_SCOPE
@@ -159,12 +162,20 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsMaterials) {
4.0f);
ExpectAttributeEqual(stage,
"/physics_materials_test/PhysicsMaterials/"
"geom_with_friction.mjc:torsionalfriction",
5.0);
"geom_with_friction.newton:torsionalFriction",
5.0f);
ExpectAttributeEqual(stage,
"/physics_materials_test/PhysicsMaterials/"
"geom_with_friction.mjc:rollingfriction",
6.0);
"geom_with_friction.newton:rollingFriction",
6.0f);
EXPECT_ATTRIBUTE_HAS_NO_AUTHORED_VALUE(
stage,
"/physics_materials_test/PhysicsMaterials/"
"geom_with_friction.mjc:torsionalfriction");
EXPECT_ATTRIBUTE_HAS_NO_AUTHORED_VALUE(
stage,
"/physics_materials_test/PhysicsMaterials/"
"geom_with_friction.mjc:rollingfriction");
}
TEST_F(MjcfSdfFileFormatPluginTest, TestMaterials) {
@@ -692,10 +703,15 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimTimestep) {
</mujoco>
)");
// newton:timeStepsPerSecond = round(1/0.005) = 200
ExpectAttributeEqual(
stage,
kPhysicsScenePrimPath.AppendProperty(MjcPhysicsTokens->mjcOptionTimestep),
0.005);
kPhysicsScenePrimPath.AppendProperty(pxr::_tokens->newtonTimeStepsPerSecond),
200);
// deprecated mjc:option:timestep should not be authored
EXPECT_ATTRIBUTE_HAS_NO_AUTHORED_VALUE(
stage,
kPhysicsScenePrimPath.AppendProperty(MjcPhysicsTokens->mjcOptionTimestep));
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimCone) {
@@ -928,8 +944,12 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimIterations) {
ExpectAttributeEqual(stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionIterations),
pxr::_tokens->newtonMaxSolverIterations),
10);
EXPECT_ATTRIBUTE_HAS_NO_AUTHORED_VALUE(
stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionIterations));
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimLSIterations) {
@@ -1066,7 +1086,7 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimDisableFlags) {
MjcPhysicsTokens->mjcFlagContact,
MjcPhysicsTokens->mjcFlagSpring,
MjcPhysicsTokens->mjcFlagDamper,
MjcPhysicsTokens->mjcFlagGravity,
// mjc:flag:gravity is deprecated, now exported as newton:gravityEnabled
MjcPhysicsTokens->mjcFlagClampctrl,
MjcPhysicsTokens->mjcFlagWarmstart,
MjcPhysicsTokens->mjcFlagFilterparent,
@@ -1083,6 +1103,10 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimDisableFlags) {
ExpectAttributeEqual(stage, kPhysicsScenePrimPath.AppendProperty(flag),
false);
}
ExpectAttributeEqual(
stage,
kPhysicsScenePrimPath.AppendProperty(pxr::_tokens->newtonGravityEnabled),
false);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimEnableFlags) {
@@ -1472,8 +1496,11 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestMjcPhysicsCollisionAPI) {
pxr::VtArray<double>({0.1, 0.2}));
ExpectAttributeEqual(stage, "/test/body/box.mjc:solimp",
pxr::VtArray<double>({0.3, 0.4, 0.5, 0.6, 0.7}));
ExpectAttributeEqual(stage, "/test/body/box.mjc:margin", 0.8);
ExpectAttributeEqual(stage, "/test/body/box.mjc:gap", 0.9);
// margin and gap are now exported as Newton attributes
EXPECT_ATTRIBUTE_HAS_NO_AUTHORED_VALUE(stage, "/test/body/box.mjc:margin");
EXPECT_ATTRIBUTE_HAS_NO_AUTHORED_VALUE(stage, "/test/body/box.mjc:gap");
ExpectAttributeEqual(stage, "/test/body/box.newton:contactMargin", 0.8f);
ExpectAttributeEqual(stage, "/test/body/box.newton:contactGap", 0.9f);
ExpectAttributeEqual(stage, "/test/body/box.mjc:shellinertia", true);
}
@@ -1508,8 +1535,11 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestMjcPhysicsMeshCollisionAPI) {
MjcPhysicsTokens->convex);
ExpectAttributeEqual(stage, "/test/body/tet_shell/Mesh.mjc:inertia",
MjcPhysicsTokens->shell);
ExpectAttributeEqual(stage, "/test/body/tet_max_vert/Mesh.mjc:maxhullvert",
12);
// mjc:maxhullvert deprecated, newton:maxHullVertices used instead
EXPECT_ATTRIBUTE_HAS_NO_AUTHORED_VALUE(
stage, "/test/body/tet_max_vert/Mesh.mjc:maxhullvert");
ExpectAttributeEqual(
stage, "/test/body/tet_max_vert/Mesh.newton:maxHullVertices", 12);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestMassAPIApplied) {