From 3473e4e4511b2d4e6d54de73c73efcda1153ed5d Mon Sep 17 00:00:00 2001 From: Sam Haves Date: Fri, 11 Jul 2025 05:36:35 -0700 Subject: [PATCH] Add group support to mjcPhysics equivalents for sites, geoms, actuators, and joints. PiperOrigin-RevId: 781945497 Change-Id: I5c409f05e6bae33c181a51c273f260daea6004fc --- .../usd/mjcPhysics/collisionAPI.h | 26 ++++++++++- .../experimental/usd/mjcPhysics/jointAPI.h | 26 ++++++++++- .../experimental/usd/mjcPhysics/sceneAPI.h | 2 +- .../experimental/usd/mjcPhysics/siteAPI.h | 27 +++++++++++- .../experimental/usd/mjcPhysics/tokens.h | 7 ++- .../usd/mjcPhysics/collisionAPI.cpp | 12 ++++++ .../usd/mjcPhysics/generatedSchema.usda | 26 ++++++++--- src/experimental/usd/mjcPhysics/jointAPI.cpp | 12 ++++++ src/experimental/usd/mjcPhysics/schema.usda | 43 ++++++++++++++++--- src/experimental/usd/mjcPhysics/siteAPI.cpp | 30 +++++++++++-- src/experimental/usd/mjcPhysics/tokens.cpp | 4 ++ .../usd/plugins/mjcf/mujoco_to_usd.cc | 9 ++++ src/experimental/usd/usd_to_mjspec.cc | 15 +++++++ .../usd/plugins/mjcf/mjcf_file_format_test.cc | 19 +++++--- 14 files changed, 234 insertions(+), 24 deletions(-) diff --git a/include/mujoco/experimental/usd/mjcPhysics/collisionAPI.h b/include/mujoco/experimental/usd/mjcPhysics/collisionAPI.h index 73ea291a..8c4de794 100644 --- a/include/mujoco/experimental/usd/mjcPhysics/collisionAPI.h +++ b/include/mujoco/experimental/usd/mjcPhysics/collisionAPI.h @@ -40,7 +40,7 @@ class SdfAssetPath; /// \class MjcPhysicsCollisionAPI /// -/// API describing a Mujoco collider. +/// API describing a MuJoCo collider. /// class MjcPhysicsCollisionAPI : public UsdAPISchemaBase { public: @@ -142,6 +142,30 @@ class MjcPhysicsCollisionAPI : public UsdAPISchemaBase { MJCPHYSICS_API const TfType &_GetTfType() const override; + public: + // --------------------------------------------------------------------- // + // GROUP + // --------------------------------------------------------------------- // + /// Integer MuJoCo group to which the collider belongs. + /// + /// | || + /// | -- | -- | + /// | Declaration | `uniform int mjc:group = 0` | + /// | C++ Type | int | + /// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Int | + /// | \ref SdfVariability "Variability" | SdfVariabilityUniform | + MJCPHYSICS_API + UsdAttribute GetGroupAttr() const; + + /// See GetGroupAttr(), 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 CreateGroupAttr(VtValue const &defaultValue = VtValue(), + bool writeSparsely = false) const; + public: // --------------------------------------------------------------------- // // SHELLINERTIA diff --git a/include/mujoco/experimental/usd/mjcPhysics/jointAPI.h b/include/mujoco/experimental/usd/mjcPhysics/jointAPI.h index 9d75b696..d3b25f2f 100644 --- a/include/mujoco/experimental/usd/mjcPhysics/jointAPI.h +++ b/include/mujoco/experimental/usd/mjcPhysics/jointAPI.h @@ -40,7 +40,7 @@ class SdfAssetPath; /// \class MjcPhysicsJointAPI /// -/// API describing a Mujoco joint. +/// API describing a MuJoCo joint. /// /// For any described attribute \em Fallback \em Value or \em Allowed \em Values /// below that are text/tokens, the actual token is published and defined in @@ -146,6 +146,30 @@ class MjcPhysicsJointAPI : public UsdAPISchemaBase { MJCPHYSICS_API const TfType &_GetTfType() const override; + public: + // --------------------------------------------------------------------- // + // GROUP + // --------------------------------------------------------------------- // + /// Integer MuJoCo group to which the joint belongs. + /// + /// | || + /// | -- | -- | + /// | Declaration | `uniform int mjc:group = 0` | + /// | C++ Type | int | + /// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Int | + /// | \ref SdfVariability "Variability" | SdfVariabilityUniform | + MJCPHYSICS_API + UsdAttribute GetGroupAttr() const; + + /// See GetGroupAttr(), 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 CreateGroupAttr(VtValue const &defaultValue = VtValue(), + bool writeSparsely = false) const; + public: // --------------------------------------------------------------------- // // MJCSPRINGDAMPER diff --git a/include/mujoco/experimental/usd/mjcPhysics/sceneAPI.h b/include/mujoco/experimental/usd/mjcPhysics/sceneAPI.h index 0fc13cd8..86386f95 100644 --- a/include/mujoco/experimental/usd/mjcPhysics/sceneAPI.h +++ b/include/mujoco/experimental/usd/mjcPhysics/sceneAPI.h @@ -40,7 +40,7 @@ class SdfAssetPath; /// \class MjcPhysicsSceneAPI /// -/// API providing global simulation options for Mujoco. +/// API providing global simulation options for MuJoCo. /// /// For any described attribute \em Fallback \em Value or \em Allowed \em Values /// below that are text/tokens, the actual token is published and defined in diff --git a/include/mujoco/experimental/usd/mjcPhysics/siteAPI.h b/include/mujoco/experimental/usd/mjcPhysics/siteAPI.h index b13099c4..22b650bf 100644 --- a/include/mujoco/experimental/usd/mjcPhysics/siteAPI.h +++ b/include/mujoco/experimental/usd/mjcPhysics/siteAPI.h @@ -18,6 +18,7 @@ /// \file mjcPhysics/siteAPI.h #include +#include #include #include #include @@ -39,7 +40,7 @@ class SdfAssetPath; /// \class MjcPhysicsSiteAPI /// -/// API describing a Mujoco site. +/// API describing a MuJoCo site. /// class MjcPhysicsSiteAPI : public UsdAPISchemaBase { public: @@ -140,6 +141,30 @@ class MjcPhysicsSiteAPI : public UsdAPISchemaBase { MJCPHYSICS_API const TfType &_GetTfType() const override; + public: + // --------------------------------------------------------------------- // + // GROUP + // --------------------------------------------------------------------- // + /// Integer MuJoCo group to which the collider belongs. + /// + /// | || + /// | -- | -- | + /// | Declaration | `uniform int mjc:group = 0` | + /// | C++ Type | int | + /// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Int | + /// | \ref SdfVariability "Variability" | SdfVariabilityUniform | + MJCPHYSICS_API + UsdAttribute GetGroupAttr() const; + + /// See GetGroupAttr(), 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 CreateGroupAttr(VtValue const &defaultValue = VtValue(), + bool writeSparsely = false) const; + public: // ===================================================================== // // Feel free to add custom code below this line, it will be preserved by diff --git a/include/mujoco/experimental/usd/mjcPhysics/tokens.h b/include/mujoco/experimental/usd/mjcPhysics/tokens.h index 202a1e3c..b1db8e82 100644 --- a/include/mujoco/experimental/usd/mjcPhysics/tokens.h +++ b/include/mujoco/experimental/usd/mjcPhysics/tokens.h @@ -338,7 +338,8 @@ struct MjcPhysicsTokensType { const TfToken mjcGear; /// \brief "mjc:group" /// - /// MjcPhysicsTransmission + /// MjcPhysicsSiteAPI, MjcPhysicsImageableAPI, MjcPhysicsCollisionAPI, + /// MjcPhysicsTransmission, MjcPhysicsJointAPI const TfToken mjcGroup; /// \brief "mjc:inertia" /// @@ -589,6 +590,10 @@ struct MjcPhysicsTokensType { /// /// Schema identifier and family for MjcPhysicsCollisionAPI const TfToken MjcCollisionAPI; + /// \brief "MjcImageableAPI" + /// + /// Schema identifier and family for MjcPhysicsImageableAPI + const TfToken MjcImageableAPI; /// \brief "MjcJointAPI" /// /// Schema identifier and family for MjcPhysicsJointAPI diff --git a/src/experimental/usd/mjcPhysics/collisionAPI.cpp b/src/experimental/usd/mjcPhysics/collisionAPI.cpp index 0ff817fb..7499cdb9 100644 --- a/src/experimental/usd/mjcPhysics/collisionAPI.cpp +++ b/src/experimental/usd/mjcPhysics/collisionAPI.cpp @@ -75,6 +75,17 @@ const TfType &MjcPhysicsCollisionAPI::_GetTfType() const { return _GetStaticTfType(); } +UsdAttribute MjcPhysicsCollisionAPI::GetGroupAttr() const { + return GetPrim().GetAttribute(MjcPhysicsTokens->mjcGroup); +} + +UsdAttribute MjcPhysicsCollisionAPI::CreateGroupAttr( + VtValue const &defaultValue, bool writeSparsely) const { + return UsdSchemaBase::_CreateAttr( + MjcPhysicsTokens->mjcGroup, SdfValueTypeNames->Int, + /* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely); +} + UsdAttribute MjcPhysicsCollisionAPI::GetShellInertiaAttr() const { return GetPrim().GetAttribute(MjcPhysicsTokens->mjcShellinertia); } @@ -101,6 +112,7 @@ static inline TfTokenVector _ConcatenateAttributeNames( const TfTokenVector &MjcPhysicsCollisionAPI::GetSchemaAttributeNames( bool includeInherited) { static TfTokenVector localNames = { + MjcPhysicsTokens->mjcGroup, MjcPhysicsTokens->mjcShellinertia, }; static TfTokenVector allNames = _ConcatenateAttributeNames( diff --git a/src/experimental/usd/mjcPhysics/generatedSchema.usda b/src/experimental/usd/mjcPhysics/generatedSchema.usda index 0fafcead..517e5100 100644 --- a/src/experimental/usd/mjcPhysics/generatedSchema.usda +++ b/src/experimental/usd/mjcPhysics/generatedSchema.usda @@ -4,7 +4,7 @@ ) class "MjcSceneAPI" ( - doc = "API providing global simulation options for Mujoco." + doc = "API providing global simulation options for MuJoCo." ) { uniform bool mjc:flag:actuation = 1 ( @@ -221,15 +221,23 @@ class "MjcSceneAPI" ( } class "MjcSiteAPI" ( - doc = "API describing a Mujoco site." + doc = "API describing a MuJoCo site." ) { + uniform int mjc:group = 0 ( + displayName = "Group" + doc = "Integer MuJoCo group to which the collider belongs." + ) } class "MjcCollisionAPI" ( - doc = "API describing a Mujoco collider." + doc = "API describing a MuJoCo collider." ) { + uniform int mjc:group = 0 ( + displayName = "Group" + doc = "Integer MuJoCo group to which the collider belongs." + ) uniform bool mjc:shellinertia = 0 ( displayName = "Shell Inertia" doc = "Enables handling of the inertia assuming mass is concentrated on the surface." @@ -237,7 +245,7 @@ class "MjcCollisionAPI" ( } class "MjcMeshCollisionAPI" ( - doc = "API describing a Mujoco mesh collider." + doc = "API describing a MuJoCo mesh collider." ) { uniform token mjc:inertia = "legacy" ( @@ -318,6 +326,10 @@ class MjcTransmission "MjcTransmission" ( uniform double[] mjc:gear = [1, 0, 0, 0, 0, 0] ( doc = "This attribute scales the length (and consequently moment arms, velocity and force) of the actuator, for all transmission types. It is different from the gain in the force generation mechanism, because the gain only scales the force output and does not affect the length, moment arms and velocity. For actuators with scalar transmission, only the first element of this vector is used. The remaining elements are needed for joint, jointinparent and site transmissions where this attribute is used to specify 3D force and torque axes." ) + uniform int mjc:group = 0 ( + displayName = "Group" + doc = "Integer MuJoCo group to which the transmission belongs." + ) uniform bool mjc:jointInParent = 0 ( doc = "If true and applied to ball and free joints, the 3d rotation axis given by gear is defined in the parent frame (which is the world frame for free joints) rather than the child frame." ) @@ -363,7 +375,7 @@ class MjcKeyframe "MjcKeyframe" ( } class "MjcJointAPI" ( - doc = "API describing a Mujoco joint." + doc = "API describing a MuJoCo joint." ) { uniform token mjc:actuatorfrclimited = "auto" ( @@ -388,6 +400,10 @@ class "MjcJointAPI" ( uniform double mjc:frictionloss = 0 ( doc = "Friction loss due to dry friction. This value is the same for all degrees of freedom created by this joint. Semantically friction loss does not make sense for free joints, but the compiler allows it. To enable friction loss, set this attribute to a positive value." ) + uniform int mjc:group = 0 ( + displayName = "Group" + doc = "Integer MuJoCo group to which the joint belongs." + ) uniform double mjc:margin = 0 ( doc = "The distance threshold below which limits become active. Recall that the Constraint solver normally generates forces as soon as a constraint becomes active, even if the margin parameter makes that happen at a distance. This attribute together with solreflimit and solimplimit can be used to model a soft joint limit." ) diff --git a/src/experimental/usd/mjcPhysics/jointAPI.cpp b/src/experimental/usd/mjcPhysics/jointAPI.cpp index 0adaf2ed..fac959a1 100644 --- a/src/experimental/usd/mjcPhysics/jointAPI.cpp +++ b/src/experimental/usd/mjcPhysics/jointAPI.cpp @@ -74,6 +74,17 @@ const TfType &MjcPhysicsJointAPI::_GetTfType() const { return _GetStaticTfType(); } +UsdAttribute MjcPhysicsJointAPI::GetGroupAttr() const { + return GetPrim().GetAttribute(MjcPhysicsTokens->mjcGroup); +} + +UsdAttribute MjcPhysicsJointAPI::CreateGroupAttr(VtValue const &defaultValue, + bool writeSparsely) const { + return UsdSchemaBase::_CreateAttr( + MjcPhysicsTokens->mjcGroup, SdfValueTypeNames->Int, + /* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely); +} + UsdAttribute MjcPhysicsJointAPI::GetMjcSpringdamperAttr() const { return GetPrim().GetAttribute(MjcPhysicsTokens->mjcSpringdamper); } @@ -265,6 +276,7 @@ static inline TfTokenVector _ConcatenateAttributeNames( const TfTokenVector &MjcPhysicsJointAPI::GetSchemaAttributeNames( bool includeInherited) { static TfTokenVector localNames = { + MjcPhysicsTokens->mjcGroup, MjcPhysicsTokens->mjcSpringdamper, MjcPhysicsTokens->mjcSolreflimit, MjcPhysicsTokens->mjcSolimplimit, diff --git a/src/experimental/usd/mjcPhysics/schema.usda b/src/experimental/usd/mjcPhysics/schema.usda index 7fe2874e..f60acdf4 100644 --- a/src/experimental/usd/mjcPhysics/schema.usda +++ b/src/experimental/usd/mjcPhysics/schema.usda @@ -98,7 +98,7 @@ class "MjcSceneAPI" customData = { string className = "SceneAPI" } - doc = """API providing global simulation options for Mujoco.""" + doc = """API providing global simulation options for MuJoCo.""" inherits = ) @@ -516,22 +516,37 @@ class "MjcSiteAPI" customData = { string className = "SiteAPI" } - doc = """API describing a Mujoco site.""" + doc = """API describing a MuJoCo site.""" inherits = ) -{} +{ + uniform int mjc:group = 0 ( + customData = { + string apiName = "Group" + } + displayName = "Group" + doc = """Integer MuJoCo group to which the collider belongs.""" + ) +} class "MjcCollisionAPI" ( customData = { string className = "CollisionAPI" } - doc = """API describing a Mujoco collider.""" + doc = """API describing a MuJoCo collider.""" inherits = ) { + uniform int mjc:group = 0 ( + customData = { + string apiName = "Group" + } + displayName = "Group" + doc = """Integer MuJoCo group to which the collider belongs.""" + ) uniform bool mjc:shellinertia = False ( customData = { string apiName = "ShellInertia" @@ -546,7 +561,7 @@ class "MjcMeshCollisionAPI" customData = { string className = "MeshCollisionAPI" } - doc = """API describing a Mujoco mesh collider.""" + doc = """API describing a MuJoCo mesh collider.""" inherits = ) @@ -579,6 +594,14 @@ class MjcTransmission "MjcTransmission" inherits = ) { + uniform int mjc:group = 0 ( + customData = { + string apiName = "Group" + } + displayName = "Group" + doc = """Integer MuJoCo group to which the transmission belongs.""" + ) + rel mjc:target ( doc = "Actuator transmission target." ) @@ -728,11 +751,19 @@ class "MjcJointAPI" customData = { string className = "JointAPI" } - doc = """API describing a Mujoco joint.""" + doc = """API describing a MuJoCo joint.""" inherits = ) { + uniform int mjc:group = 0 ( + customData = { + string apiName = "Group" + } + displayName = "Group" + doc = """Integer MuJoCo group to which the joint belongs.""" + ) + uniform double[] mjc:springdamper = [0, 0] ( doc = "When both numbers are positive, the compiler will override any stiffness and damping values specified with the attributes below, and will instead set them automatically so that the resulting mass-spring-damper for this joint has the desired time constant (first value) and damping ratio (second value). This is done by taking into account the joint inertia in the model reference configuration. Note that the format is the same as the solref parameter of the constraint solver." ) diff --git a/src/experimental/usd/mjcPhysics/siteAPI.cpp b/src/experimental/usd/mjcPhysics/siteAPI.cpp index d9269b41..87bf0025 100644 --- a/src/experimental/usd/mjcPhysics/siteAPI.cpp +++ b/src/experimental/usd/mjcPhysics/siteAPI.cpp @@ -74,12 +74,36 @@ const TfType &MjcPhysicsSiteAPI::_GetTfType() const { return _GetStaticTfType(); } +UsdAttribute MjcPhysicsSiteAPI::GetGroupAttr() const { + return GetPrim().GetAttribute(MjcPhysicsTokens->mjcGroup); +} + +UsdAttribute MjcPhysicsSiteAPI::CreateGroupAttr(VtValue const &defaultValue, + bool writeSparsely) const { + return UsdSchemaBase::_CreateAttr( + MjcPhysicsTokens->mjcGroup, SdfValueTypeNames->Int, + /* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely); +} + +namespace { +static inline TfTokenVector _ConcatenateAttributeNames( + const TfTokenVector &left, const TfTokenVector &right) { + TfTokenVector result; + result.reserve(left.size() + right.size()); + result.insert(result.end(), left.begin(), left.end()); + result.insert(result.end(), right.begin(), right.end()); + return result; +} +} // namespace + /*static*/ const TfTokenVector &MjcPhysicsSiteAPI::GetSchemaAttributeNames( bool includeInherited) { - static TfTokenVector localNames; - static TfTokenVector allNames = - UsdAPISchemaBase::GetSchemaAttributeNames(true); + static TfTokenVector localNames = { + MjcPhysicsTokens->mjcGroup, + }; + static TfTokenVector allNames = _ConcatenateAttributeNames( + UsdAPISchemaBase::GetSchemaAttributeNames(true), localNames); if (includeInherited) return allNames; diff --git a/src/experimental/usd/mjcPhysics/tokens.cpp b/src/experimental/usd/mjcPhysics/tokens.cpp index 388c4628..96f0e67b 100644 --- a/src/experimental/usd/mjcPhysics/tokens.cpp +++ b/src/experimental/usd/mjcPhysics/tokens.cpp @@ -84,6 +84,7 @@ MjcPhysicsTokensType::MjcPhysicsTokensType() mjcGainPrm("mjc:gainPrm", TfToken::Immortal), mjcGainType("mjc:gainType", TfToken::Immortal), mjcGear("mjc:gear", TfToken::Immortal), + mjcGroup("mjc:group", TfToken::Immortal), mjcInertia("mjc:inertia", TfToken::Immortal), mjcJointInParent("mjc:jointInParent", TfToken::Immortal), mjcLengthRangeMax("mjc:lengthRange:max", TfToken::Immortal), @@ -146,6 +147,7 @@ MjcPhysicsTokensType::MjcPhysicsTokensType() true_("true", TfToken::Immortal), user("user", TfToken::Immortal), MjcCollisionAPI("MjcCollisionAPI", TfToken::Immortal), + MjcImageableAPI("MjcImageableAPI", TfToken::Immortal), MjcJointAPI("MjcJointAPI", TfToken::Immortal), MjcKeyframe("MjcKeyframe", TfToken::Immortal), MjcMeshCollisionAPI("MjcMeshCollisionAPI", TfToken::Immortal), @@ -219,6 +221,7 @@ MjcPhysicsTokensType::MjcPhysicsTokensType() mjcGainPrm, mjcGainType, mjcGear, + mjcGroup, mjcInertia, mjcJointInParent, mjcLengthRangeMax, @@ -278,6 +281,7 @@ MjcPhysicsTokensType::MjcPhysicsTokensType() true_, user, MjcCollisionAPI, + MjcImageableAPI, MjcJointAPI, MjcKeyframe, MjcMeshCollisionAPI, diff --git a/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc b/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc index 1b71d00f..f2dbbded 100644 --- a/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc +++ b/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc @@ -1463,6 +1463,9 @@ class ModelWriter { ApplyApiSchema(data_, site_path, MjcPhysicsTokens->MjcSiteAPI); + WriteUniformAttribute(site_path, pxr::SdfValueTypeNames->Int, + MjcPhysicsTokens->mjcGroup, site->group); + int site_id = mjs_getId(site->element); auto transform = MujocoPosQuatToTransform(&model_->site_pos[3 * site_id], &model_->site_quat[4 * site_id]); @@ -1508,6 +1511,9 @@ class ModelWriter { return; } + WriteUniformAttribute(geom_path, pxr::SdfValueTypeNames->Int, + MjcPhysicsTokens->mjcGroup, geom->group); + // Apply the physics schemas if we are writing physics and the // geom participates in collisions. if (write_physics_ && (model_->geom_contype[geom_id] != 0 || @@ -1855,6 +1861,9 @@ class ModelWriter { // Finally write the mjcPhysicsJointAPI attributes. ApplyApiSchema(data_, joint_path, MjcPhysicsTokens->MjcJointAPI); + WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Int, + MjcPhysicsTokens->mjcGroup, joint->group); + WriteUniformAttribute( joint_path, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcSpringdamper, diff --git a/src/experimental/usd/usd_to_mjspec.cc b/src/experimental/usd/usd_to_mjspec.cc index b0b177ee..ac152a7d 100644 --- a/src/experimental/usd/usd_to_mjspec.cc +++ b/src/experimental/usd/usd_to_mjspec.cc @@ -570,6 +570,11 @@ void ParseMjcPhysicsCollisionAPI( geom->typeinertia = shell_inertia ? mjtGeomInertia::mjINERTIA_SHELL : mjtGeomInertia::mjINERTIA_VOLUME; } + + auto group_attr = collision_api.GetGroupAttr(); + if (group_attr.HasAuthoredValue()) { + group_attr.Get(&geom->group); + } } void ParseMjcPhysicsMeshCollisionAPI( @@ -793,6 +798,11 @@ void ParseMjcPhysicsTransmission(mjSpec* spec, void ParseMjcPhysicsJointAPI(mjsJoint* mj_joint, const pxr::MjcPhysicsJointAPI& joint_api) { + auto group_attr = joint_api.GetGroupAttr(); + if (group_attr.HasAuthoredValue()) { + group_attr.Get(&mj_joint->group); + } + auto springdamper_attr = joint_api.GetMjcSpringdamperAttr(); if (springdamper_attr.HasAuthoredValue()) { pxr::VtDoubleArray springdamper; @@ -1178,6 +1188,11 @@ void ParseMjcPhysicsSite(mjSpec* spec, const pxr::MjcPhysicsSiteAPI& site_api, site_api.GetPrim().GetPath().GetAsString().c_str()); SetLocalPoseFromPrim(site_api.GetPrim(), parent_prim, site, xform_cache); + auto group_attr = site_api.GetGroupAttr(); + if (group_attr.HasAuthoredValue()) { + group_attr.Get(&site->group); + } + // Convert USD type to MuJoCo type. if (!MaybeParseGeomPrimitive(prim, site, xform_cache)) { mju_error("Prim with SiteAPI has unsupported typej %s", diff --git a/test/experimental/usd/plugins/mjcf/mjcf_file_format_test.cc b/test/experimental/usd/plugins/mjcf/mjcf_file_format_test.cc index a9070179..a09cf111 100644 --- a/test/experimental/usd/plugins/mjcf/mjcf_file_format_test.cc +++ b/test/experimental/usd/plugins/mjcf/mjcf_file_format_test.cc @@ -1097,10 +1097,10 @@ static constexpr char kSiteXml[] = R"( - - - - + + + + @@ -1130,6 +1130,12 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestSitePrimsAuthored) { EXPECT_PRIM_IS_A(stage, "/test/ball/ellipsoid_site", pxr::UsdGeomSphere); EXPECT_PRIM_API_APPLIED(stage, "/test/ball/ellipsoid_site", pxr::MjcPhysicsSiteAPI); + + ExpectAttributeEqual(stage, "/test/box_site.mjc:group", 0); + ExpectAttributeEqual(stage, "/test/ball/sphere_site.mjc:group", 1); + ExpectAttributeEqual(stage, "/test/ball/capsule_site.mjc:group", 2); + ExpectAttributeEqual(stage, "/test/ball/cylinder_site.mjc:group", 3); + ExpectAttributeEqual(stage, "/test/ball/ellipsoid_site.mjc:group", 4); } TEST_F(MjcfSdfFileFormatPluginTest, TestSitePrimsPurpose) { @@ -1538,6 +1544,7 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestMjcPhysicsTransmission) { true_); ExpectAttributeEqual(stage, "/test/Transmissions/general.mjc:ctrlRange:min", @@ -1702,6 +1710,7 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestMjcPhysicsJointAPI) { ({1, 2})); ExpectAttributeEqual(stage, "/test/parent/child/my_joint.mjc:solreflimit", @@ -2129,7 +2139,6 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestMjcPhysicsKeyframe) { ExpectAttributeEqual(stage, "/test/Keyframes/Keyframe.mjc:qpos", pxr::VtDoubleArray({3}), pxr::UsdTimeCode(2.0)); } - } // namespace } // namespace usd } // namespace mujoco