From e69b6cc5f3fa86922abdd6e5bf544f70b7bbaae4 Mon Sep 17 00:00:00 2001 From: Robin Alazard Date: Fri, 4 Jul 2025 10:38:41 -0700 Subject: [PATCH] Fix wrong extent authoring for Cube. PiperOrigin-RevId: 779230125 Change-Id: I96c3d5daa7a760cd87a714a14ea74a15faf3d7db --- .../usd/plugins/mjcf/mujoco_to_usd.cc | 59 ++++++++++--------- .../usd/plugins/mjcf/mjcf_file_format_test.cc | 4 +- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc b/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc index 8a8a0467..aba248dd 100644 --- a/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc +++ b/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc @@ -337,8 +337,8 @@ class ModelWriter { } void WriteMesh(const mjsMesh *mesh, const pxr::SdfPath &parent_path) { - auto name = GetAvailablePrimName(*mjs_getName(mesh->element), pxr::UsdGeomTokens->Mesh, - parent_path); + auto name = GetAvailablePrimName(*mjs_getName(mesh->element), + pxr::UsdGeomTokens->Mesh, parent_path); pxr::SdfPath subcomponent_path = CreatePrimSpec(data_, parent_path, name, pxr::UsdGeomTokens->Xform); pxr::SdfPath mesh_path = @@ -967,44 +967,50 @@ class ModelWriter { pxr::SdfPath qpos_attr_path = CreateAttributeSpec(data_, keyframe_path, MjcPhysicsTokens->mjcQpos, pxr::SdfValueTypeNames->DoubleArray); - set_attribute_data(qpos_attr_path, - pxr::VtDoubleArray(keyframe->qpos->begin(), - keyframe->qpos->end()), keyframe); + set_attribute_data( + qpos_attr_path, + pxr::VtDoubleArray(keyframe->qpos->begin(), keyframe->qpos->end()), + keyframe); pxr::SdfPath qvel_attr_path = CreateAttributeSpec(data_, keyframe_path, MjcPhysicsTokens->mjcQvel, pxr::SdfValueTypeNames->DoubleArray); - set_attribute_data(qvel_attr_path, - pxr::VtDoubleArray(keyframe->qvel->begin(), - keyframe->qvel->end()), keyframe); + set_attribute_data( + qvel_attr_path, + pxr::VtDoubleArray(keyframe->qvel->begin(), keyframe->qvel->end()), + keyframe); pxr::SdfPath act_attr_path = CreateAttributeSpec(data_, keyframe_path, MjcPhysicsTokens->mjcAct, pxr::SdfValueTypeNames->DoubleArray); - set_attribute_data(act_attr_path, - pxr::VtDoubleArray(keyframe->act->begin(), - keyframe->act->end()), keyframe); + set_attribute_data( + act_attr_path, + pxr::VtDoubleArray(keyframe->act->begin(), keyframe->act->end()), + keyframe); pxr::SdfPath ctrl_attr_path = CreateAttributeSpec(data_, keyframe_path, MjcPhysicsTokens->mjcCtrl, pxr::SdfValueTypeNames->DoubleArray); - set_attribute_data(ctrl_attr_path, - pxr::VtDoubleArray(keyframe->ctrl->begin(), - keyframe->ctrl->end()), keyframe); + set_attribute_data( + ctrl_attr_path, + pxr::VtDoubleArray(keyframe->ctrl->begin(), keyframe->ctrl->end()), + keyframe); pxr::SdfPath mpos_attr_path = CreateAttributeSpec(data_, keyframe_path, MjcPhysicsTokens->mjcMpos, pxr::SdfValueTypeNames->DoubleArray); - set_attribute_data(mpos_attr_path, - pxr::VtDoubleArray(keyframe->mpos->begin(), - keyframe->mpos->end()), keyframe); + set_attribute_data( + mpos_attr_path, + pxr::VtDoubleArray(keyframe->mpos->begin(), keyframe->mpos->end()), + keyframe); pxr::SdfPath mquat_attr_path = CreateAttributeSpec(data_, keyframe_path, MjcPhysicsTokens->mjcMquat, pxr::SdfValueTypeNames->DoubleArray); - set_attribute_data(mquat_attr_path, - pxr::VtDoubleArray(keyframe->mquat->begin(), - keyframe->mquat->end()), keyframe); + set_attribute_data( + mquat_attr_path, + pxr::VtDoubleArray(keyframe->mquat->begin(), keyframe->mquat->end()), + keyframe); } } @@ -1235,23 +1241,22 @@ class ModelWriter { const pxr::SdfPath &body_path) { pxr::SdfPath box_path = CreatePrimSpec(data_, body_path, name, pxr::UsdGeomTokens->Cube); - // MuJoCo uses half sizes. + // MuJoCo uses half sizes. Always set size to 2 (and correspondingly extent + // from -1 to 1), and let scale determine the actual size. pxr::SdfPath size_attr_path = CreateAttributeSpec(data_, box_path, pxr::UsdGeomTokens->size, pxr::SdfValueTypeNames->Double); - pxr::GfVec3f scale(static_cast(size[0]), static_cast(size[1]), - static_cast(size[2])); SetAttributeDefault(data_, size_attr_path, 2.0); pxr::SdfPath extent_attr_path = CreateAttributeSpec(data_, box_path, pxr::UsdGeomTokens->extent, pxr::SdfValueTypeNames->Float3Array); SetAttributeDefault(data_, extent_attr_path, - pxr::VtArray({ - pxr::GfVec3f(-size[0], -size[1], -size[2]), - pxr::GfVec3f(size[0], size[1], size[2]), - })); + pxr::VtArray( + {pxr::GfVec3f(-1, -1, -1), pxr::GfVec3f(1, 1, 1)})); + pxr::GfVec3f scale(static_cast(size[0]), static_cast(size[1]), + static_cast(size[2])); WriteScaleXformOp(box_path, scale); WriteXformOpOrder(box_path, pxr::VtArray{kTokens->xformOpScale}); 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 e8e97590..019d7d61 100644 --- a/test/experimental/usd/plugins/mjcf/mjcf_file_format_test.cc +++ b/test/experimental/usd/plugins/mjcf/mjcf_file_format_test.cc @@ -619,8 +619,10 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestGeomsPrims) { EXPECT_PRIM_VALID(stage, "/test/box_geom"); EXPECT_PRIM_IS_A(stage, "/test/box_geom", pxr::UsdGeomCube); // Box is a special case, it uses a UsdGeomCube and scales it with - // xformOp:scale. The radius is always set to 2. + // xformOp:scale. The radius is always set to 2 and the extent from -1 to 1. ExpectAttributeEqual(stage, "/test/box_geom.size", 2.0); + ExpectAttributeEqual(stage, "/test/box_geom.extent", + pxr::VtArray({{-1, -1, -1}, {1, 1, 1}})); ExpectAttributeEqual(stage, "/test/box_geom.xformOp:scale", pxr::GfVec3f(10.0, 20.0, 30.0)); // Sphere