Add MjcPhysicsSceneAPI support.

Still missing compiler settings but will follow up in a future CL. Tried to add full coverage for testing setting of attributes to non-default values.

PiperOrigin-RevId: 761636862
Change-Id: Id4b9486645b2600931556cdcb8dc71f28ec309cd
This commit is contained in:
Sam Haves
2025-05-21 13:02:32 -07:00
committed by Copybara-Service
parent bf1f8081c1
commit 62a9d5b98d
5 changed files with 829 additions and 35 deletions
@@ -0,0 +1,190 @@
// Copyright 2025 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <mujoco/mujoco.h>
#include "src/experimental/usd/mjcPhysics/sceneAPI.h"
#include "test/fixture.h"
#include <pxr/base/gf/vec3d.h>
#include <pxr/base/vt/types.h>
#include <pxr/usd/sdf/path.h>
#include <pxr/usd/usd/common.h>
#include <pxr/usd/usd/stage.h>
#include <pxr/usd/usdPhysics/scene.h>
namespace mujoco {
namespace {
using pxr::SdfPath;
using MjcPhysicsSceneTest = MujocoTest;
using testing::NotNull;
// clang-format off
#define EXPECT_TYPE_USD_FALLBACK_EQ_MODEL_DEFAULT(type, usd_attr, mjc_attr) \
{ \
type value; \
mjc_phys_scene.Get##usd_attr##Attr().Get(&value); \
EXPECT_EQ((mjtNum)value, default_model->opt.mjc_attr); \
}
#define EXPECT_REAL_USD_FALLBACK_EQ_MODEL_DEFAULT(usd_attr, mjc_attr) \
EXPECT_TYPE_USD_FALLBACK_EQ_MODEL_DEFAULT(double, usd_attr, mjc_attr)
#define EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(usd_attr, mjc_flag) \
{ \
bool flag; \
mjc_phys_scene.Get##usd_attr##Attr().Get(&flag); \
EXPECT_NE(flag, default_model->opt.disableflags & (mjc_flag)); \
}
#define EXPECT_ENABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(usd_attr, mjc_flag) \
{ \
bool flag; \
mjc_phys_scene.Get##usd_attr##Attr().Get(&flag); \
EXPECT_EQ(flag, default_model->opt.enableflags & (mjc_flag)); \
}
#define EXPECT_INT_USD_FALLBACK_EQ_MODEL_DEFAULT(usd_attr, mjc_attr) \
EXPECT_TYPE_USD_FALLBACK_EQ_MODEL_DEFAULT(int, usd_attr, mjc_attr)
#define EXPECT_VEC3_USD_FALLBACK_EQ_MODEL_DEFAULT(usd_attr, mjc_attr) \
{ \
pxr::GfVec3d value; \
mjc_phys_scene.Get##usd_attr##Attr().Get(&value); \
EXPECT_EQ(value[0], default_model->opt.mjc_attr[0]); \
EXPECT_EQ(value[1], default_model->opt.mjc_attr[1]); \
EXPECT_EQ(value[2], default_model->opt.mjc_attr[2]); \
}
#define EXPECT_TYPE_ARR_USD_FALLBACK_EQ_MODEL_DEFAULT(type, usd_attr, mjc_attr)\
{ \
pxr::Vt##type##Array mjc_attr; \
mjc_phys_scene.Get##usd_attr##Attr().Get(&mjc_attr); \
EXPECT_THAT( \
mjc_attr, \
testing::ElementsAreArray(default_model->opt.mjc_attr) \
); \
}
#define EXPECT_REAL_ARR_USD_FALLBACK_EQ_MODEL_DEFAULT(usd_attr, mjc_attr)\
EXPECT_TYPE_ARR_USD_FALLBACK_EQ_MODEL_DEFAULT(Double, usd_attr, mjc_attr)
#define EXPECT_INT_ARR_USD_FALLBACK_EQ_MODEL_DEFAULT(usd_attr, mjc_attr)\
EXPECT_TYPE_ARR_USD_FALLBACK_EQ_MODEL_DEFAULT(Int, usd_attr, mjc_attr)
// clang-format on
TEST_F(MjcPhysicsSceneTest, TestDefaults) {
auto stage = pxr::UsdStage::CreateInMemory();
auto physics_scene =
pxr::UsdPhysicsScene::Define(stage, SdfPath("/World/PhysicsScene"));
auto mjc_phys_scene = pxr::MjcPhysicsSceneAPI::Apply(physics_scene.GetPrim());
mjSpec* empty_spec = mj_makeSpec();
mjModel* default_model = mj_compile(empty_spec, nullptr);
EXPECT_THAT(default_model, NotNull());
// Check that all the USD schema fallback values are the same
// as the model defaults.
// If this test is failing due to an update of defaults in Mujoco you need to
// update mjcPhysics/schema.usda.
EXPECT_REAL_USD_FALLBACK_EQ_MODEL_DEFAULT(Timestep, timestep);
EXPECT_REAL_USD_FALLBACK_EQ_MODEL_DEFAULT(ApiRate, apirate);
EXPECT_REAL_USD_FALLBACK_EQ_MODEL_DEFAULT(ImpRatio, impratio);
EXPECT_VEC3_USD_FALLBACK_EQ_MODEL_DEFAULT(Wind, wind);
EXPECT_VEC3_USD_FALLBACK_EQ_MODEL_DEFAULT(Magnetic, magnetic);
EXPECT_REAL_USD_FALLBACK_EQ_MODEL_DEFAULT(Density, density);
EXPECT_REAL_USD_FALLBACK_EQ_MODEL_DEFAULT(Viscosity, viscosity);
EXPECT_REAL_USD_FALLBACK_EQ_MODEL_DEFAULT(OMargin, o_margin);
EXPECT_REAL_ARR_USD_FALLBACK_EQ_MODEL_DEFAULT(OSolRef, o_solref);
EXPECT_REAL_ARR_USD_FALLBACK_EQ_MODEL_DEFAULT(OSolImp, o_solimp);
EXPECT_REAL_ARR_USD_FALLBACK_EQ_MODEL_DEFAULT(OFriction, o_friction);
EXPECT_INT_USD_FALLBACK_EQ_MODEL_DEFAULT(Iterations, iterations);
EXPECT_REAL_USD_FALLBACK_EQ_MODEL_DEFAULT(Tolerance, tolerance);
EXPECT_INT_USD_FALLBACK_EQ_MODEL_DEFAULT(LSIterations, ls_iterations);
EXPECT_REAL_USD_FALLBACK_EQ_MODEL_DEFAULT(LSTolerance, ls_tolerance);
EXPECT_INT_USD_FALLBACK_EQ_MODEL_DEFAULT(NoslipIterations, noslip_iterations);
EXPECT_REAL_USD_FALLBACK_EQ_MODEL_DEFAULT(NoslipTolerance, noslip_tolerance);
EXPECT_INT_USD_FALLBACK_EQ_MODEL_DEFAULT(CCDIterations, ccd_iterations);
EXPECT_REAL_USD_FALLBACK_EQ_MODEL_DEFAULT(CCDTolerance, ccd_tolerance);
EXPECT_INT_USD_FALLBACK_EQ_MODEL_DEFAULT(SDFIterations, sdf_iterations);
EXPECT_INT_USD_FALLBACK_EQ_MODEL_DEFAULT(SDFInitPoints, sdf_initpoints);
// We store the actuator disable groups as an array of integers, but the
// model stores it as a bitmask.
pxr::VtIntArray actuator_group_disable;
mjc_phys_scene.GetActuatorGroupDisableAttr().Get(&actuator_group_disable);
int bitmask = 0;
for (int ind : actuator_group_disable) {
bitmask |= 1 << ind;
}
EXPECT_EQ(default_model->opt.disableactuator, bitmask);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(ConstraintFlag,
mjDSBL_CONSTRAINT);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(EqualityFlag,
mjDSBL_EQUALITY);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(FrictionLossFlag,
mjDSBL_FRICTIONLOSS);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(LimitFlag, mjDSBL_LIMIT);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(ContactFlag,
mjDSBL_CONTACT);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(PassiveFlag,
mjDSBL_PASSIVE);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(GravityFlag,
mjDSBL_GRAVITY);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(ClampCtrlFlag,
mjDSBL_CLAMPCTRL);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(WarmStartFlag,
mjDSBL_WARMSTART);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(FilterParentFlag,
mjDSBL_FILTERPARENT);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(ActuationFlag,
mjDSBL_ACTUATION);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(RefSafeFlag,
mjDSBL_REFSAFE);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(SensorFlag, mjDSBL_SENSOR);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(MidPhaseFlag,
mjDSBL_MIDPHASE);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(NativeCCDFlag,
mjDSBL_NATIVECCD);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(EulerDampFlag,
mjDSBL_EULERDAMP);
EXPECT_DISABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(AutoResetFlag,
mjDSBL_AUTORESET);
EXPECT_ENABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(OverrideFlag,
mjENBL_OVERRIDE);
EXPECT_ENABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(EnergyFlag, mjENBL_ENERGY);
EXPECT_ENABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(FwdinvFlag, mjENBL_FWDINV);
EXPECT_ENABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(InvDiscreteFlag,
mjENBL_INVDISCRETE);
EXPECT_ENABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(MultiCCDFlag,
mjENBL_MULTICCD);
EXPECT_ENABLE_FLAG_USD_FALLBACK_EQ_MODEL_DEFAULT(IslandFlag, mjENBL_ISLAND);
mj_deleteModel(default_model);
mj_deleteSpec(empty_spec);
}
} // namespace
} // namespace mujoco
@@ -19,9 +19,11 @@
#include <gtest/gtest.h>
#include "src/experimental/usd/mjcPhysics/sceneAPI.h"
#include "src/experimental/usd/mjcPhysics/siteAPI.h"
#include "src/experimental/usd/mjcPhysics/tokens.h"
#include "test/experimental/usd/test_utils.h"
#include "test/fixture.h"
#include <pxr/base/gf/vec2f.h>
#include <pxr/base/gf/vec3d.h>
#include <pxr/base/gf/vec3f.h>
#include <pxr/base/tf/staticData.h>
#include <pxr/base/tf/staticTokens.h>
@@ -49,6 +51,7 @@
#include <pxr/usd/usdPhysics/collisionAPI.h>
#include <pxr/usd/usdPhysics/meshCollisionAPI.h>
#include <pxr/usd/usdPhysics/rigidBodyAPI.h>
#include <pxr/usd/usdPhysics/scene.h>
#include <pxr/usd/usdPhysics/tokens.h>
PXR_NAMESPACE_OPEN_SCOPE
@@ -63,6 +66,8 @@ namespace mujoco {
namespace usd {
namespace {
using pxr::MjcPhysicsSiteAPI;
using pxr::MjcPhysicsTokens;
using pxr::SdfPath;
using MjcfSdfFileFormatPluginTest = MujocoTest;
@@ -499,6 +504,417 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestGeomsPrims) {
pxr::GfVec3f(10.0, 20.0, 30.0));
}
static const pxr::SdfPath kPhysicsScenePrimPath("/test/PhysicsScene");
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimTimestep) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option timestep="0.005"> </option>
</mujoco>
)"));
ExpectAttributeEqual(
stage,
kPhysicsScenePrimPath.AppendProperty(MjcPhysicsTokens->mjcOptionTimestep),
0.005);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimCone) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option cone="elliptic"> </option>
</mujoco>
)"));
ExpectAttributeEqual(
stage,
kPhysicsScenePrimPath.AppendProperty(MjcPhysicsTokens->mjcOptionCone),
MjcPhysicsTokens->elliptic);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimWind) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option wind="1 2 3"> </option>
</mujoco>
)"));
ExpectAttributeEqual(
stage,
kPhysicsScenePrimPath.AppendProperty(MjcPhysicsTokens->mjcOptionWind),
pxr::GfVec3d(1, 2, 3));
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimApirate) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option apirate="1.2"> </option>
</mujoco>
)"));
ExpectAttributeEqual(
stage,
kPhysicsScenePrimPath.AppendProperty(MjcPhysicsTokens->mjcOptionApirate),
1.2);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimImpratio) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option impratio="0.8"> </option>
</mujoco>
)"));
ExpectAttributeEqual(
stage,
kPhysicsScenePrimPath.AppendProperty(MjcPhysicsTokens->mjcOptionImpratio),
0.8);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimMagnetic) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option magnetic="1 2 3"> </option>
</mujoco>
)"));
ExpectAttributeEqual(
stage,
kPhysicsScenePrimPath.AppendProperty(MjcPhysicsTokens->mjcOptionMagnetic),
pxr::GfVec3d(1, 2, 3));
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimDensity) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option density="1.2"> </option>
</mujoco>
)"));
ExpectAttributeEqual(
stage,
kPhysicsScenePrimPath.AppendProperty(MjcPhysicsTokens->mjcOptionDensity),
1.2);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimViscosity) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option viscosity="0.8"> </option>
</mujoco>
)"));
ExpectAttributeEqual(stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionViscosity),
0.8);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimO_margin) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option o_margin="0.001"> </option>
</mujoco>
)"));
ExpectAttributeEqual(
stage,
kPhysicsScenePrimPath.AppendProperty(MjcPhysicsTokens->mjcOptionO_margin),
0.001);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimO_solref) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option o_solref="0.1 0.2"> </option>
</mujoco>
)"));
ExpectAttributeEqual(
stage,
kPhysicsScenePrimPath.AppendProperty(MjcPhysicsTokens->mjcOptionO_solref),
pxr::VtArray<double>({0.1, 0.2}));
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimO_solimp) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option o_solimp="0.1 0.2 0.3 0.4 0.5"> </option>
</mujoco>
)"));
ExpectAttributeEqual(
stage,
kPhysicsScenePrimPath.AppendProperty(MjcPhysicsTokens->mjcOptionO_solimp),
pxr::VtArray<double>({0.1, 0.2, 0.3, 0.4, 0.5}));
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimTolerance) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option tolerance="0.0012"> </option>
</mujoco>
)"));
ExpectAttributeEqual(stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionTolerance),
0.0012);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimLSTolerance) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option ls_tolerance="0.0034"> </option>
</mujoco>
)"));
ExpectAttributeEqual(stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionLs_tolerance),
0.0034);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimNoslipTolerance) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option noslip_tolerance="0.0056"> </option>
</mujoco>
)"));
ExpectAttributeEqual(stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionNoslip_tolerance),
0.0056);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimCCDTolerance) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option ccd_tolerance="0.0078"> </option>
</mujoco>
)"));
ExpectAttributeEqual(stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionCcd_tolerance),
0.0078);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimOFriction) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option o_friction="0.1 0.2 0.3 0.4 0.5"> </option>
</mujoco>
)"));
ExpectAttributeEqual(stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionO_friction),
pxr::VtArray<double>({0.1, 0.2, 0.3, 0.4, 0.5}));
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimIntegrator) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option integrator="RK4"> </option>
</mujoco>
)"));
ExpectAttributeEqual(stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionIntegrator),
MjcPhysicsTokens->rk4);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimJacobian) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option jacobian="sparse"> </option>
</mujoco>
)"));
ExpectAttributeEqual(
stage,
kPhysicsScenePrimPath.AppendProperty(MjcPhysicsTokens->mjcOptionJacobian),
MjcPhysicsTokens->sparse);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimSolver) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option solver="CG"> </option>
</mujoco>
)"));
ExpectAttributeEqual(
stage,
kPhysicsScenePrimPath.AppendProperty(MjcPhysicsTokens->mjcOptionSolver),
MjcPhysicsTokens->cg);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimIterations) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option iterations="10"> </option>
</mujoco>
)"));
ExpectAttributeEqual(stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionIterations),
10);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimLSIterations) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option ls_iterations="20"> </option>
</mujoco>
)"));
ExpectAttributeEqual(stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionLs_iterations),
20);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimNoslipIterations) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option noslip_iterations="30"> </option>
</mujoco>
)"));
ExpectAttributeEqual(stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionNoslip_iterations),
30);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimCCDIterations) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option ccd_iterations="40"> </option>
</mujoco>
)"));
ExpectAttributeEqual(stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionCcd_iterations),
40);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimSDFInitPoints) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option sdf_initpoints="50"> </option>
</mujoco>
)"));
ExpectAttributeEqual(stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionSdf_initpoints),
50);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimSDFIterations) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option sdf_iterations="60"> </option>
</mujoco>
)"));
ExpectAttributeEqual(stage,
kPhysicsScenePrimPath.AppendProperty(
MjcPhysicsTokens->mjcOptionSdf_iterations),
60);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimDisableFlags) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option>
<flag
constraint="disable"
equality="disable"
frictionloss="disable"
limit="disable"
contact="disable"
passive="disable"
gravity="disable"
clampctrl="disable"
warmstart="disable"
filterparent="disable"
actuation="disable"
refsafe="disable"
sensor="disable"
midphase="disable"
nativeccd="disable"
eulerdamp="disable"
autoreset="disable"
/>
</option>
</mujoco>
)"));
const std::vector<pxr::TfToken> kFlags = {
MjcPhysicsTokens->mjcFlagConstraint,
MjcPhysicsTokens->mjcFlagEquality,
MjcPhysicsTokens->mjcFlagFrictionloss,
MjcPhysicsTokens->mjcFlagLimit,
MjcPhysicsTokens->mjcFlagContact,
MjcPhysicsTokens->mjcFlagPassive,
MjcPhysicsTokens->mjcFlagGravity,
MjcPhysicsTokens->mjcFlagClampctrl,
MjcPhysicsTokens->mjcFlagWarmstart,
MjcPhysicsTokens->mjcFlagFilterparent,
MjcPhysicsTokens->mjcFlagActuation,
MjcPhysicsTokens->mjcFlagRefsafe,
MjcPhysicsTokens->mjcFlagSensor,
MjcPhysicsTokens->mjcFlagMidphase,
MjcPhysicsTokens->mjcFlagNativeccd,
MjcPhysicsTokens->mjcFlagEulerdamp,
MjcPhysicsTokens->mjcFlagAutoreset,
};
for (const auto& flag : kFlags) {
ExpectAttributeEqual(stage, kPhysicsScenePrimPath.AppendProperty(flag),
false);
}
}
TEST_F(MjcfSdfFileFormatPluginTest, TestPhysicsScenePrimEnableFlags) {
auto stage = pxr::UsdStage::Open(LoadLayer(R"(
<mujoco model="test">
<option>
<flag
override="enable"
energy="enable"
fwdinv="enable"
invdiscrete="enable"
multiccd="enable"
island="enable"
/>
</option>
</mujoco>
)"));
// clang-format off
const std::vector<pxr::TfToken> kFlags = {
MjcPhysicsTokens->mjcFlagOverride,
MjcPhysicsTokens->mjcFlagEnergy,
MjcPhysicsTokens->mjcFlagFwdinv,
MjcPhysicsTokens->mjcFlagInvdiscrete,
MjcPhysicsTokens->mjcFlagMulticcd,
MjcPhysicsTokens->mjcFlagIsland,
};
// clang-format on
for (const auto& flag : kFlags) {
ExpectAttributeEqual(stage, kPhysicsScenePrimPath.AppendProperty(flag),
true);
}
}
static constexpr char kSiteXml[] = R"(
<mujoco model="test">
<worldbody>
@@ -520,28 +936,28 @@ TEST_F(MjcfSdfFileFormatPluginTest, TestSitePrimsAuthored) {
auto stage = pxr::UsdStage::Open(layer);
EXPECT_PRIM_VALID(stage, "/test/box_site");
EXPECT_PRIM_IS_A(stage, "/test/box_site", pxr::UsdGeomCube);
EXPECT_PRIM_API_APPLIED(stage, "/test/box_site", pxr::MjcPhysicsSiteAPI);
EXPECT_PRIM_API_APPLIED(stage, "/test/box_site", MjcPhysicsSiteAPI);
EXPECT_PRIM_VALID(stage, "/test/ball/ball/sphere_site");
EXPECT_PRIM_IS_A(stage, "/test/ball/ball/sphere_site", pxr::UsdGeomSphere);
EXPECT_PRIM_API_APPLIED(stage, "/test/ball/ball/sphere_site",
pxr::MjcPhysicsSiteAPI);
MjcPhysicsSiteAPI);
EXPECT_PRIM_VALID(stage, "/test/ball/ball/capsule_site");
EXPECT_PRIM_IS_A(stage, "/test/ball/ball/capsule_site", pxr::UsdGeomCapsule);
EXPECT_PRIM_API_APPLIED(stage, "/test/ball/ball/capsule_site",
pxr::MjcPhysicsSiteAPI);
MjcPhysicsSiteAPI);
EXPECT_PRIM_VALID(stage, "/test/ball/ball/cylinder_site");
EXPECT_PRIM_IS_A(stage, "/test/ball/ball/cylinder_site",
pxr::UsdGeomCylinder);
EXPECT_PRIM_API_APPLIED(stage, "/test/ball/ball/cylinder_site",
pxr::MjcPhysicsSiteAPI);
MjcPhysicsSiteAPI);
EXPECT_PRIM_VALID(stage, "/test/ball/ball/ellipsoid_site");
EXPECT_PRIM_IS_A(stage, "/test/ball/ball/ellipsoid_site", pxr::UsdGeomSphere);
EXPECT_PRIM_API_APPLIED(stage, "/test/ball/ball/ellipsoid_site",
pxr::MjcPhysicsSiteAPI);
MjcPhysicsSiteAPI);
}
TEST_F(MjcfSdfFileFormatPluginTest, TestSitePrimsPurpose) {
+2 -2
View File
@@ -44,9 +44,9 @@ pxr::SdfLayerRefPtr LoadLayer(
template <>
void ExpectAttributeEqual<pxr::SdfAssetPath>(pxr::UsdStageRefPtr stage,
const char* path,
pxr::SdfPath path,
const pxr::SdfAssetPath& value) {
auto attr = stage->GetAttributeAtPath(pxr::SdfPath(path));
auto attr = stage->GetAttributeAtPath(path);
EXPECT_TRUE(attr.IsValid());
pxr::SdfAssetPath attr_value;
attr.Get(&attr_value);
+8 -2
View File
@@ -74,7 +74,7 @@ pxr::SdfLayerRefPtr LoadLayer(
const pxr::SdfFileFormat::FileFormatArguments& args = {});
template <typename T>
void ExpectAttributeEqual(pxr::UsdStageRefPtr stage, const char* path,
void ExpectAttributeEqual(pxr::UsdStageRefPtr stage, pxr::SdfPath path,
const T& value) {
auto attr = stage->GetAttributeAtPath(pxr::SdfPath(path));
EXPECT_TRUE(attr.IsValid()) << "Attribute " << path << " is not valid";
@@ -84,13 +84,19 @@ void ExpectAttributeEqual(pxr::UsdStageRefPtr stage, const char* path,
<< attr_value << ". Expected: " << value;
}
template <typename T>
void ExpectAttributeEqual(pxr::UsdStageRefPtr stage, const char* path,
const T& value) {
ExpectAttributeEqual(stage, pxr::SdfPath(path), value);
}
// Specialization for SdfAssetPath, so that we can compare only the asset path
// and not care about whatever the resolved path is.
// Otherwise the default operator== would fail because it tests for equality of
// the asset path AND the resolved path.
template <>
void ExpectAttributeEqual<pxr::SdfAssetPath>(pxr::UsdStageRefPtr stage,
const char* path,
pxr::SdfPath,
const pxr::SdfAssetPath& value);
void ExpectAttributeHasConnection(pxr::UsdStageRefPtr stage, const char* path,