4646#include < pxr/base/gf/matrix4f.h>
4747#include < pxr/base/gf/rotation.h>
4848#include < pxr/base/gf/vec3d.h>
49+ #include < pxr/base/tf/staticTokens.h>
4950#include < pxr/base/tf/token.h>
5051#include < pxr/base/vt/types.h>
5152#include < pxr/usd/sdf/path.h>
8283
8384using pxr::MjcPhysicsTokens;
8485using pxr::TfToken;
86+ template <typename T>
87+ using TfStaticData = pxr::TfStaticData<T>;
88+
89+ // clang-format off
90+ TF_DEFINE_PRIVATE_TOKENS (kNewtonTokens ,
91+ ((NewtonMaterialAPI, " NewtonMaterialAPI" ))
92+ ((NewtonMeshCollisionAPI, " NewtonMeshCollisionAPI" ))
93+ ((newtonMaxSolverIterations, " newton:maxSolverIterations" ))
94+ ((newtonTimeStepsPerSecond, " newton:timeStepsPerSecond" ))
95+ ((newtonGravityEnabled, " newton:gravityEnabled" ))
96+ ((newtonContactMargin, " newton:contactMargin" ))
97+ ((newtonContactGap, " newton:contactGap" ))
98+ ((newtonMaxHullVertices, " newton:maxHullVertices" ))
99+ ((newtonTorsionalFriction, " newton:torsionalFriction" ))
100+ ((newtonRollingFriction, " newton:rollingFriction" ))
101+ ((newtonMimicJoint, " newton:mimicJoint" ))
102+ ((newtonMimicCoef0, " newton:mimicCoef0" ))
103+ ((newtonMimicCoef1, " newton:mimicCoef1" ))
104+ ((NewtonMimicAPI, " NewtonMimicAPI" ))
105+ );
106+ // clang-format on
85107
86108struct UsdCaches {
87109 pxr::UsdGeomXformCache xform_cache;
@@ -463,15 +485,48 @@ void ParseUsdPhysicsScene(mjSpec* spec,
463485
464486 SetGravityAttributes (spec, stage, gravity_direction, gravity_magnitude);
465487
466- // Early exit if theres no MjcPhysicsSceneAPI applied.
467- if (!physics_scene.GetPrim ().HasAPI <pxr::MjcPhysicsSceneAPI>()) {
488+ // Parse Newton scene attributes if present (works for Newton-only files)
489+ pxr::UsdPrim scene_prim = physics_scene.GetPrim ();
490+ auto newton_iterations = scene_prim.GetAttribute (
491+ kNewtonTokens ->newtonMaxSolverIterations );
492+ if (newton_iterations && newton_iterations.HasAuthoredValue ()) {
493+ int val;
494+ newton_iterations.Get (&val);
495+ if (val >= 0 ) spec->option .iterations = val;
496+ }
497+ auto newton_timesteps = scene_prim.GetAttribute (
498+ kNewtonTokens ->newtonTimeStepsPerSecond );
499+ if (newton_timesteps && newton_timesteps.HasAuthoredValue ()) {
500+ int val;
501+ newton_timesteps.Get (&val);
502+ if (val > 0 ) spec->option .timestep = 1.0 / val;
503+ }
504+ auto newton_gravity = scene_prim.GetAttribute (
505+ kNewtonTokens ->newtonGravityEnabled );
506+ if (newton_gravity && newton_gravity.HasAuthoredValue ()) {
507+ bool enabled;
508+ newton_gravity.Get (&enabled);
509+ if (!enabled) {
510+ spec->option .disableflags |= mjDSBL_GRAVITY;
511+ }
512+ }
513+
514+ // Early exit if there's no MjcPhysicsSceneAPI applied.
515+ if (!scene_prim.HasAPI <pxr::MjcPhysicsSceneAPI>()) {
468516 return ;
469517 }
470- auto mjc_physics_scene = pxr::MjcPhysicsSceneAPI (physics_scene. GetPrim () );
518+ auto mjc_physics_scene = pxr::MjcPhysicsSceneAPI (scene_prim );
471519
472- double timestep;
473- mjc_physics_scene.GetTimestepAttr ().Get (×tep);
474- spec->option .timestep = timestep;
520+ // MJC values override Newton values only when explicitly authored.
521+ auto timestep_attr = mjc_physics_scene.GetTimestepAttr ();
522+ if (timestep_attr.HasAuthoredValue ()) {
523+ double timestep;
524+ timestep_attr.Get (×tep);
525+ spec->option .timestep = timestep;
526+ mju_warning (" Scene '%s' uses deprecated mjc:option:timestep. "
527+ " Please migrate to newton:timeStepsPerSecond." ,
528+ scene_prim.GetPath ().GetText ());
529+ }
475530
476531 double impratio;
477532 mjc_physics_scene.GetImpRatioAttr ().Get (&impratio);
@@ -586,9 +641,15 @@ void ParseUsdPhysicsScene(mjSpec* spec,
586641 spec->option .solver = mjSOL_PGS;
587642 }
588643
589- int iterations;
590- mjc_physics_scene.GetIterationsAttr ().Get (&iterations);
591- spec->option .iterations = iterations;
644+ auto iterations_attr = mjc_physics_scene.GetIterationsAttr ();
645+ if (iterations_attr.HasAuthoredValue ()) {
646+ int iterations;
647+ iterations_attr.Get (&iterations);
648+ spec->option .iterations = iterations;
649+ mju_warning (" Scene '%s' uses deprecated mjc:option:iterations. "
650+ " Please migrate to newton:maxSolverIterations." ,
651+ scene_prim.GetPath ().GetText ());
652+ }
592653
593654 int ls_iterations;
594655 mjc_physics_scene.GetLSIterationsAttr ().Get (&ls_iterations);
@@ -638,9 +699,19 @@ void ParseUsdPhysicsScene(mjSpec* spec,
638699 mjc_physics_scene.GetDamperFlagAttr ().Get (&damper_flag);
639700 spec->option .disableflags |= (!damper_flag ? mjDSBL_DAMPER : 0 );
640701
641- bool gravity_flag;
642- mjc_physics_scene.GetGravityFlagAttr ().Get (&gravity_flag);
643- spec->option .disableflags |= (!gravity_flag ? mjDSBL_GRAVITY : 0 );
702+ auto gravity_flag_attr = mjc_physics_scene.GetGravityFlagAttr ();
703+ if (gravity_flag_attr.HasAuthoredValue ()) {
704+ bool gravity_flag;
705+ gravity_flag_attr.Get (&gravity_flag);
706+ if (!gravity_flag) {
707+ spec->option .disableflags |= mjDSBL_GRAVITY;
708+ } else {
709+ spec->option .disableflags &= ~mjDSBL_GRAVITY;
710+ }
711+ mju_warning (" Scene '%s' uses deprecated mjc:flag:gravity. "
712+ " Please migrate to newton:gravityEnabled." ,
713+ scene_prim.GetPath ().GetText ());
714+ }
644715
645716 bool clampctrl_flag;
646717 mjc_physics_scene.GetClampCtrlFlagAttr ().Get (&clampctrl_flag);
@@ -914,13 +985,39 @@ void ParseMjcPhysicsCollisionAPI(
914985 }
915986
916987 auto margin_attr = collision_api.GetMarginAttr ();
917- if (margin_attr.HasAuthoredValue ()) {
988+ auto gap_attr = collision_api.GetGapAttr ();
989+ bool mjc_margin_authored = margin_attr.HasAuthoredValue ();
990+ bool mjc_gap_authored = gap_attr.HasAuthoredValue ();
991+
992+ if (mjc_margin_authored) {
918993 margin_attr.Get (&geom->margin );
994+ mju_warning (" Prim '%s' uses deprecated mjc:margin. "
995+ " Please migrate to newton:contactMargin and newton:contactGap." ,
996+ collision_api.GetPrim ().GetPath ().GetText ());
919997 }
920-
921- auto gap_attr = collision_api.GetGapAttr ();
922- if (gap_attr.HasAuthoredValue ()) {
998+ if (mjc_gap_authored) {
923999 gap_attr.Get (&geom->gap );
1000+ mju_warning (" Prim '%s' uses deprecated mjc:gap. "
1001+ " Please migrate to newton:contactGap." ,
1002+ collision_api.GetPrim ().GetPath ().GetText ());
1003+ }
1004+
1005+ // Newton collision fallback: newton:contactMargin + newton:contactGap -> margin, gap
1006+ if (!mjc_margin_authored || !mjc_gap_authored) {
1007+ pxr::UsdPrim prim = collision_api.GetPrim ();
1008+ auto newton_margin = prim.GetAttribute (kNewtonTokens ->newtonContactMargin );
1009+ auto newton_gap = prim.GetAttribute (kNewtonTokens ->newtonContactGap );
1010+ float n_margin = 0 , n_gap = 0 ;
1011+ bool has_newton_margin = newton_margin && newton_margin.HasAuthoredValue ();
1012+ bool has_newton_gap = newton_gap && newton_gap.HasAuthoredValue ();
1013+ if (has_newton_margin) newton_margin.Get (&n_margin);
1014+ if (has_newton_gap) newton_gap.Get (&n_gap);
1015+ if (!mjc_gap_authored && has_newton_gap) {
1016+ geom->gap = n_gap;
1017+ }
1018+ if (!mjc_margin_authored && has_newton_margin) {
1019+ geom->margin = n_margin + geom->gap ;
1020+ }
9241021 }
9251022}
9261023
@@ -942,8 +1039,19 @@ void ParseMjcPhysicsMeshCollisionAPI(
9421039 }
9431040
9441041 auto maxhullvert_attr = mesh_collision_api.GetMaxHullVertAttr ();
1042+ auto newton_maxhull = mesh_collision_api.GetPrim ().GetAttribute (
1043+ kNewtonTokens ->newtonMaxHullVertices );
9451044 if (maxhullvert_attr.HasAuthoredValue ()) {
9461045 maxhullvert_attr.Get (&mesh->maxhullvert );
1046+ if (!newton_maxhull || !newton_maxhull.HasAuthoredValue ()) {
1047+ mju_warning (" Prim '%s' uses deprecated mjc:maxhullvert. "
1048+ " Please migrate to newton:maxHullVertices." ,
1049+ mesh_collision_api.GetPrim ().GetPath ().GetText ());
1050+ }
1051+ } else if (newton_maxhull && newton_maxhull.HasAuthoredValue ()) {
1052+ int val;
1053+ newton_maxhull.Get (&val);
1054+ mesh->maxhullvert = val;
9471055 }
9481056}
9491057
@@ -1668,15 +1776,42 @@ void ParseUsdPhysicsMaterialAPI(
16681776}
16691777
16701778void ParseMjcPhysicsMaterialAPI (
1671- mjsGeom* geom, const pxr::MjcPhysicsMaterialAPI& material_api) {
1672- auto torsional_friction_attr = material_api.GetTorsionalFrictionAttr ();
1673- if (torsional_friction_attr.HasAuthoredValue ()) {
1674- torsional_friction_attr.Get (&geom->friction [1 ]);
1675- }
1676-
1677- auto rolling_friction_attr = material_api.GetRollingFrictionAttr ();
1678- if (rolling_friction_attr.HasAuthoredValue ()) {
1679- rolling_friction_attr.Get (&geom->friction [2 ]);
1779+ mjsGeom* geom, const pxr::UsdPrim& material_prim,
1780+ const pxr::MjcPhysicsMaterialAPI& material_api) {
1781+ // Torsional friction: prefer newton:torsionalFriction, fall back to
1782+ // mjc:torsionalfriction with deprecation warning. If both are authored,
1783+ // mjc takes precedence for backwards compatibility.
1784+ auto mjc_torsional = material_api.GetTorsionalFrictionAttr ();
1785+ auto newton_torsional = material_prim.GetAttribute (
1786+ kNewtonTokens ->newtonTorsionalFriction );
1787+ if (mjc_torsional.HasAuthoredValue ()) {
1788+ mjc_torsional.Get (&geom->friction [1 ]);
1789+ if (!newton_torsional || !newton_torsional.HasAuthoredValue ()) {
1790+ mju_warning (" Prim '%s' uses deprecated mjc:torsionalfriction. "
1791+ " Please migrate to newton:torsionalFriction." ,
1792+ material_prim.GetPath ().GetText ());
1793+ }
1794+ } else if (newton_torsional && newton_torsional.HasAuthoredValue ()) {
1795+ float val;
1796+ newton_torsional.Get (&val);
1797+ geom->friction [1 ] = val;
1798+ }
1799+
1800+ // Rolling friction: same deprecation/fallback pattern.
1801+ auto mjc_rolling = material_api.GetRollingFrictionAttr ();
1802+ auto newton_rolling = material_prim.GetAttribute (
1803+ kNewtonTokens ->newtonRollingFriction );
1804+ if (mjc_rolling.HasAuthoredValue ()) {
1805+ mjc_rolling.Get (&geom->friction [2 ]);
1806+ if (!newton_rolling || !newton_rolling.HasAuthoredValue ()) {
1807+ mju_warning (" Prim '%s' uses deprecated mjc:rollingfriction. "
1808+ " Please migrate to newton:rollingFriction." ,
1809+ material_prim.GetPath ().GetText ());
1810+ }
1811+ } else if (newton_rolling && newton_rolling.HasAuthoredValue ()) {
1812+ float val;
1813+ newton_rolling.Get (&val);
1814+ geom->friction [2 ] = val;
16801815 }
16811816}
16821817
@@ -1789,11 +1924,13 @@ void ParseUsdPhysicsCollider(mjSpec* spec,
17891924 if (bound_material) {
17901925 pxr::UsdPrim bound_material_prim = bound_material.GetPrim ();
17911926 if (bound_material_prim.HasAPI <pxr::UsdPhysicsMaterialAPI>() ||
1792- bound_material_prim.HasAPI <pxr::MjcPhysicsMaterialAPI>()) {
1927+ bound_material_prim.HasAPI <pxr::MjcPhysicsMaterialAPI>() ||
1928+ bound_material_prim.HasAPI (kNewtonTokens ->NewtonMaterialAPI )) {
17931929 ParseUsdPhysicsMaterialAPI (
17941930 geom, pxr::UsdPhysicsMaterialAPI (bound_material_prim));
17951931 ParseMjcPhysicsMaterialAPI (
1796- geom, pxr::MjcPhysicsMaterialAPI (bound_material_prim));
1932+ geom, bound_material_prim,
1933+ pxr::MjcPhysicsMaterialAPI (bound_material_prim));
17971934 }
17981935 pxr::SdfPath material_path = bound_material_prim.GetPath ();
17991936 mjsMaterial* material = nullptr ;
@@ -1826,7 +1963,9 @@ void ParseUsdPhysicsCollider(mjSpec* spec,
18261963
18271964 if (!MaybeParseGeomPrimitive (prim, geom, caches.xform_cache )) {
18281965 mjsMesh* mesh = ParseUsdMesh (spec, prim, geom, caches.xform_cache );
1829- if (mesh != nullptr && prim.HasAPI <pxr::MjcPhysicsMeshCollisionAPI>()) {
1966+ if (mesh != nullptr &&
1967+ (prim.HasAPI <pxr::MjcPhysicsMeshCollisionAPI>() ||
1968+ prim.HasAPI (kNewtonTokens ->NewtonMeshCollisionAPI ))) {
18301969 ParseMjcPhysicsMeshCollisionAPI (mesh,
18311970 pxr::MjcPhysicsMeshCollisionAPI (prim));
18321971 }
@@ -1877,8 +2016,8 @@ void ParseMjcEqualityAPISolverParams(
18772016
18782017void ParseConstraint (mjSpec* spec, const pxr::UsdPrim& prim, mjsBody* body,
18792018 pxr::UsdGeomXformCache& xform_cache) {
1880- if (prim.HasAPI <pxr::MjcPhysicsEqualityJointAPI>()) {
1881- // Handle MjcPhysicsEqualityJointAPI on revolute/prismatic joints.
2019+ if (prim.HasAPI <pxr::MjcPhysicsEqualityJointAPI>() ||
2020+ prim. HasAPI ( kNewtonTokens -> NewtonMimicAPI )) {
18822021 pxr::MjcPhysicsEqualityJointAPI eq_joint_api (prim);
18832022 mjsEquality* eq = mjs_addEquality (spec, nullptr );
18842023 eq->type = mjEQ_JOINT;
@@ -1889,28 +2028,76 @@ void ParseConstraint(mjSpec* spec, const pxr::UsdPrim& prim, mjsBody* body,
18892028 eq->objtype = mjOBJ_JOINT;
18902029 mjs_setString (eq->name1 , prim.GetPath ().GetAsString ().c_str ());
18912030
1892- // Get the target joint (joint2) from the MjcEqualityAPI target
1893- // relationship.
1894- pxr::MjcPhysicsEqualityAPI equality_api (prim);
1895- pxr::UsdRelationship target_rel = equality_api.GetMjcTargetRel ();
2031+ // Target joint: prefer newton:mimicJoint, fall back to deprecated mjc:target
18962032 pxr::SdfPathVector targets;
1897- target_rel. GetTargets (&targets );
1898- if (!targets.empty ()) {
2033+ auto newton_mimic_rel = prim. GetRelationship ( kNewtonTokens -> newtonMimicJoint );
2034+ if (newton_mimic_rel && newton_mimic_rel. GetTargets (&targets) && !targets.empty ()) {
18992035 mjs_setString (eq->name2 , targets[0 ].GetAsString ().c_str ());
2036+ } else {
2037+ auto mjc_target_rel = prim.GetRelationship (MjcPhysicsTokens->mjcTarget );
2038+ if (mjc_target_rel && mjc_target_rel.GetTargets (&targets) && !targets.empty ()) {
2039+ mjs_setString (eq->name2 , targets[0 ].GetAsString ().c_str ());
2040+ mju_warning (" Prim '%s' uses deprecated mjc:target. "
2041+ " Please migrate to newton:mimicJoint." ,
2042+ prim.GetPath ().GetText ());
2043+ }
19002044 }
1901- // If no target, name2 remains empty, meaning joint1 is fixed to a constant.
19022045
1903- // Parse individual coefficient attributes for the quartic polynomial.
1904- eq_joint_api.GetCoef0Attr ().Get (&eq->data [0 ]);
1905- eq_joint_api.GetCoef1Attr ().Get (&eq->data [1 ]);
2046+ // Coefficients: prefer Newton, fall back to deprecated MJC
2047+ auto newton_coef0 = prim.GetAttribute (kNewtonTokens ->newtonMimicCoef0 );
2048+ auto newton_coef1 = prim.GetAttribute (kNewtonTokens ->newtonMimicCoef1 );
2049+ if (newton_coef0 && newton_coef0.HasAuthoredValue ()) {
2050+ float val;
2051+ newton_coef0.Get (&val);
2052+ eq->data [0 ] = val;
2053+ } else {
2054+ eq_joint_api.GetCoef0Attr ().Get (&eq->data [0 ]);
2055+ if (eq_joint_api.GetCoef0Attr ().HasAuthoredValue ()) {
2056+ mju_warning (" Prim '%s' uses deprecated mjc:coef0. "
2057+ " Please migrate to newton:mimicCoef0." ,
2058+ prim.GetPath ().GetText ());
2059+ }
2060+ }
2061+ if (newton_coef1 && newton_coef1.HasAuthoredValue ()) {
2062+ float val;
2063+ newton_coef1.Get (&val);
2064+ eq->data [1 ] = val;
2065+ } else {
2066+ eq_joint_api.GetCoef1Attr ().Get (&eq->data [1 ]);
2067+ if (eq_joint_api.GetCoef1Attr ().HasAuthoredValue ()) {
2068+ mju_warning (" Prim '%s' uses deprecated mjc:coef1. "
2069+ " Please migrate to newton:mimicCoef1." ,
2070+ prim.GetPath ().GetText ());
2071+ }
2072+ }
19062073 eq_joint_api.GetCoef2Attr ().Get (&eq->data [2 ]);
19072074 eq_joint_api.GetCoef3Attr ().Get (&eq->data [3 ]);
19082075 eq_joint_api.GetCoef4Attr ().Get (&eq->data [4 ]);
19092076
19102077 pxr::UsdPhysicsJoint joint (prim);
19112078 ParseJointEnabled (eq, joint);
19122079
1913- ParseMjcEqualityAPISolverParams (eq, equality_api, prim);
2080+ // Solver params are now inline on MjcEqualityJointAPI
2081+ auto solref_attr = prim.GetAttribute (MjcPhysicsTokens->mjcSolref );
2082+ if (solref_attr.HasAuthoredValue ()) {
2083+ pxr::VtDoubleArray solref;
2084+ solref_attr.Get (&solref);
2085+ if (solref.size () == mjNREF) {
2086+ for (int i = 0 ; i < mjNREF; ++i) {
2087+ eq->solref [i] = solref[i];
2088+ }
2089+ }
2090+ }
2091+ auto solimp_attr = prim.GetAttribute (MjcPhysicsTokens->mjcSolimp );
2092+ if (solimp_attr.HasAuthoredValue ()) {
2093+ pxr::VtDoubleArray solimp;
2094+ solimp_attr.Get (&solimp);
2095+ if (solimp.size () == mjNIMP) {
2096+ for (int i = 0 ; i < mjNIMP; ++i) {
2097+ eq->solimp [i] = solimp[i];
2098+ }
2099+ }
2100+ }
19142101 } else if (prim.IsA <pxr::UsdPhysicsFixedJoint>() ||
19152102 prim.IsA <pxr::UsdPhysicsSphericalJoint>()) {
19162103 // Handle fixed joints as weld constraints, spherical joints as connect constraints
0 commit comments