diff --git a/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc b/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc index a3a21d17..bac02a5e 100644 --- a/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc +++ b/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc @@ -1821,6 +1821,17 @@ class ModelWriter { : pxr::KindTokens->subcomponent; SetPrimKind(data_, body_path, kind); + // If the parent is not the world body, but is child of the world body + // then we need to apply the articulation root API. + if (parent_id != kWorldIndex) { + int parent_parent_id = + mjs_getId(mjs_getParent(parent->element)->element); + if (parent_parent_id == kWorldIndex) { + ApplyApiSchema(data_, parent_path, + pxr::UsdPhysicsTokens->PhysicsArticulationRootAPI); + } + } + // Apply the PhysicsRigidBodyAPI schema if we are writing physics. if (write_physics_) { // If the body had a mass specified then it must have either inertia or @@ -1926,13 +1937,6 @@ class ModelWriter { pxr::UsdGeomTokens->Xform); SetPrimKind(data_, world_group_path, pxr::KindTokens->group); - if (write_physics_) { - // Apply the PhysicsArticulationRootAPI to the world body so that - // everything under it is automatically considered an articulation. - ApplyApiSchema(data_, world_group_path, - pxr::UsdPhysicsTokens->PhysicsArticulationRootAPI); - } - return world_group_path; } }; 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 a0698ef4..5faec4f7 100644 --- a/test/experimental/usd/plugins/mjcf/mjcf_file_format_test.cc +++ b/test/experimental/usd/plugins/mjcf/mjcf_file_format_test.cc @@ -1139,6 +1139,9 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsRigidBody) { + + + )"; @@ -1153,18 +1156,26 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsRigidBody) { EXPECT_PRIM_VALID(stage, "/physics_test/test_body"); EXPECT_PRIM_VALID(stage, "/physics_test/test_body/test_body_2"); - // Articulation root is applied to the root of the physics scene (worldbody). - EXPECT_PRIM_API_APPLIED(stage, "/physics_test", - pxr::UsdPhysicsArticulationRootAPI); - EXPECT_PRIM_API_APPLIED(stage, "/physics_test/test_body", pxr::UsdPhysicsRigidBodyAPI); - EXPECT_PRIM_API_NOT_APPLIED(stage, "/physics_test/test_body", - pxr::UsdPhysicsArticulationRootAPI); EXPECT_PRIM_API_APPLIED(stage, "/physics_test/test_body/test_body_2", pxr::UsdPhysicsRigidBodyAPI); + EXPECT_PRIM_API_APPLIED(stage, "/physics_test/test_body_3", + pxr::UsdPhysicsRigidBodyAPI); + + // Articulation root is applied to the children of the world body. + EXPECT_PRIM_API_APPLIED(stage, "/physics_test/test_body", + pxr::UsdPhysicsArticulationRootAPI); + // test_body_3 is a child of the world but has no children so should not be + // an articulation root. + EXPECT_PRIM_API_NOT_APPLIED(stage, "/physics_test/test_body_3", + pxr::UsdPhysicsArticulationRootAPI); + + // Articulation root is not applied to other bodies or world body. + EXPECT_PRIM_API_NOT_APPLIED(stage, "/physics_test", + pxr::UsdPhysicsArticulationRootAPI); EXPECT_PRIM_API_NOT_APPLIED(stage, "/physics_test/test_body/test_body_2", - pxr::UsdPhysicsArticulationRootAPI); + pxr::UsdPhysicsArticulationRootAPI); // Geoms should not have RigidBodyAPI applied either. EXPECT_PRIM_API_NOT_APPLIED(stage, "/physics_test/test_body/test_geom",