diff --git a/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc b/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc index 25757654..e443149c 100644 --- a/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc +++ b/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc @@ -897,6 +897,29 @@ class ModelWriter { } } + // If geom rgba is not the default (0.5, 0.5, 0.5, 1), then set the + // displayColor attribute. + // No effort is made to properly handle the interaction between geom rgba + // and the material if both are specified. + if (geom->rgba[0] != 0.5f || geom->rgba[1] != 0.5f || + geom->rgba[2] != 0.5f || geom->rgba[3] != 1.0f) { + // Set the displayColor attribute. + pxr::SdfPath display_color_attr = CreateAttributeSpec( + data_, geom_path, pxr::UsdGeomTokens->primvarsDisplayColor, + pxr::SdfValueTypeNames->Color3fArray); + SetAttributeDefault(data_, display_color_attr, + pxr::VtArray{ + {geom->rgba[0], geom->rgba[1], geom->rgba[2]}}); + // Set the displayOpacity attribute, only if the opacity is not 1. + if (geom->rgba[3] != 1.0f) { + pxr::SdfPath display_opacity_attr = CreateAttributeSpec( + data_, geom_path, pxr::UsdGeomTokens->primvarsDisplayOpacity, + pxr::SdfValueTypeNames->FloatArray); + SetAttributeDefault(data_, display_opacity_attr, + pxr::VtArray{geom->rgba[3]}); + } + } + if (body_id == kWorldIndex) { SetPrimKind(data_, geom_path, pxr::KindTokens->component); } diff --git a/test/experimental/usd/plugins/mjcf/fixture.h b/test/experimental/usd/plugins/mjcf/fixture.h index 9ab5ffe1..d7b8cda1 100644 --- a/test/experimental/usd/plugins/mjcf/fixture.h +++ b/test/experimental/usd/plugins/mjcf/fixture.h @@ -60,6 +60,13 @@ .Get(&prim_purpose); \ EXPECT_EQ(prim_purpose, purpose); \ } + +#define EXPECT_ATTRIBUTE_HAS_VALUE(stage, path) \ + EXPECT_TRUE((stage)->GetAttributeAtPath(SdfPath(path)).HasValue()); + +#define EXPECT_ATTRIBUTE_HAS_NO_VALUE(stage, path) \ + EXPECT_FALSE((stage)->GetAttributeAtPath(SdfPath(path)).HasValue()); + namespace mujoco { pxr::SdfLayerRefPtr LoadLayer( 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 f5caeb19..f144da6e 100644 --- a/test/experimental/usd/plugins/mjcf/mjcf_file_format_test.cc +++ b/test/experimental/usd/plugins/mjcf/mjcf_file_format_test.cc @@ -140,6 +140,53 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestMaterials) { pxr::SdfAssetPath("textures/cube.png")); } +TEST_F(MjcfSdfFileFormatPluginTest, TestGeomRgba) { + static constexpr char kXml[] = R"( + + + + + + + + + )"; + + pxr::SdfLayerRefPtr layer = LoadLayer(kXml); + auto stage = pxr::UsdStage::Open(layer); + + EXPECT_PRIM_VALID(stage, "/test/sphere_red"); + ExpectAttributeEqual(stage, "/test/sphere_red.primvars:displayColor", + pxr::VtArray{{1, 0, 0}}); + EXPECT_ATTRIBUTE_HAS_NO_VALUE(stage, + "/test/sphere_red.primvars:displayOpacity"); + + // There's no mechanism in Mujoco to specify whether an attribute was set + // explicitly or not. We do the same as Mujoco does, which is to compare with + // the default value. + // Which explains why not setting rgba is the same as setting it to the + // default value of (0.5, 0.5, 0.5, 1). + EXPECT_PRIM_VALID(stage, "/test/sphere_default"); + EXPECT_ATTRIBUTE_HAS_NO_VALUE(stage, + "/test/sphere_default.primvars:displayColor"); + EXPECT_ATTRIBUTE_HAS_NO_VALUE(stage, + "/test/sphere_default.primvars:displayOpacity"); + + EXPECT_PRIM_VALID(stage, "/test/sphere_also_default"); + EXPECT_ATTRIBUTE_HAS_NO_VALUE( + stage, "/test/sphere_also_default.primvars:displayColor"); + EXPECT_ATTRIBUTE_HAS_NO_VALUE( + stage, "/test/sphere_also_default.primvars:displayOpacity"); + + EXPECT_PRIM_VALID(stage, "/test/sphere_almost_default"); + ExpectAttributeEqual(stage, + "/test/sphere_almost_default.primvars:displayColor", + pxr::VtArray{{0.5, 0.5, 0.5}}); + ExpectAttributeEqual(stage, + "/test/sphere_almost_default.primvars:displayOpacity", + pxr::VtArray{0.9}); +} + TEST_F(MjcfSdfFileFormatPluginTest, TestFaceVaryingMeshSourcesSimpleMjcfMesh) { static constexpr char kXml[] = R"(