Skip to content

Commit 792f53c

Browse files
committed
USD : Adopt newton-usd-schemas & deprecate MjcPhysics equivalents
1 parent facebe5 commit 792f53c

5 files changed

Lines changed: 459 additions & 107 deletions

File tree

plugin/usd_decoder/usd_decoder.cc

Lines changed: 228 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
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>
@@ -82,6 +83,27 @@
8283

8384
using pxr::MjcPhysicsTokens;
8485
using 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

86108
struct 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(&timestep);
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(&timestep);
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

16701778
void 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

18782017
void 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

Comments
 (0)