Initial support for writing UsdPhysics data starting with UsdPhysicsRigidbodyAPI support.

The SDF_FORMAT_ARGS `usdMjcfToggleUsdPhysics` is introduced to toggle writing UsdPhysics or not when converting. Off by default

PiperOrigin-RevId: 746467942
Change-Id: I26cb9a4c4ae2eef96163dab967a74f14940a2a6d
This commit is contained in:
Google DeepMind
2025-04-11 08:18:11 -07:00
committed by Copybara-Service
parent 006c18b1d8
commit 8e7457d7c6
7 changed files with 122 additions and 15 deletions
@@ -26,6 +26,7 @@
#include <pxr/base/tf/pathUtils.h>
#include <pxr/base/tf/registryManager.h>
#include <pxr/base/tf/staticTokens.h>
#include <pxr/base/tf/stringUtils.h>
#include <pxr/base/tf/type.h>
#include <pxr/base/work/loops.h>
#include <pxr/pxr.h>
@@ -145,9 +146,18 @@ bool UsdMjcfFileFormat::CanRead(const std::string &filePath) const {
}
bool UsdMjcfFileFormat::ReadImpl(pxr::SdfLayer *layer, mjSpec *spec) const {
auto data = InitData(layer->GetFileFormatArguments());
auto args = layer->GetFileFormatArguments();
auto success = mujoco::usd::WriteSpecToData(spec, data);
bool toggleUsdPhysics = false;
const auto it =
args.find(UsdMjcfFileFormatTokens->ToggleUsdPhysicsArg.GetString());
if (it != args.end()) {
toggleUsdPhysics = pxr::TfUnstringify<bool>(it->second);
}
auto data = InitData(args);
auto success = mujoco::usd::WriteSpecToData(spec, data, toggleUsdPhysics);
mj_deleteSpec(spec);
if (!success) {
return false;
@@ -27,10 +27,15 @@
PXR_NAMESPACE_OPEN_SCOPE
// clang-format off
// The Id should realistically be mjcf, but the id and extension need to match.
// So near term it just assumes the only .xml file we would import is MJCF.
#define USD_MJCF_FILE_FORMAT_TOKENS \
((Id, "xml"))((Version, "1.0"))((Target, "usd"))
#define USD_MJCF_FILE_FORMAT_TOKENS \
((Id, "xml")) \
((Version, "1.0")) \
((Target, "usd")) \
((ToggleUsdPhysicsArg, "usdMjcfToggleUsdPhysics"))
// clang-format on
TF_DECLARE_PUBLIC_TOKENS(UsdMjcfFileFormatTokens, USD_MJCF_FILE_FORMAT_TOKENS);
@@ -49,6 +49,7 @@
#include <pxr/usd/usdGeom/metrics.h>
#include <pxr/usd/usdGeom/tokens.h>
#include <pxr/usd/usdLux/tokens.h>
#include <pxr/usd/usdPhysics/tokens.h>
#include <pxr/usd/usdShade/tokens.h>
#include <pxr/usdImaging/usdImaging/tokens.h>
@@ -149,7 +150,7 @@ class ModelWriter {
}
~ModelWriter() { mj_deleteModel(model_); }
void Write() {
void Write(bool write_physics) {
// Create top level class holder.
class_path_ = CreateClassSpec(data_, pxr::SdfPath::AbsoluteRootPath(),
pxr::TfToken("__class__"));
@@ -173,7 +174,7 @@ class ModelWriter {
// Author mesh scope + mesh prims to be referenced.
WriteMeshes();
WriteMaterials();
WriteBodies();
WriteBodies(write_physics);
}
private:
@@ -977,7 +978,7 @@ class ModelWriter {
}
}
void WriteBody(mjsBody *body) {
void WriteBody(mjsBody *body, bool write_physics) {
int body_id = mjs_getId(body->element);
pxr::SdfPath parent_path =
CreateParentIfNotExists(body, body_paths_[kWorldIndex], data_);
@@ -990,6 +991,12 @@ class ModelWriter {
// bodies subcomponents.
SetPrimKind(data_, body_path, pxr::KindTokens->subcomponent);
// Apply the PhysicsRigidBodyAPI schema if we are writing physics.
if (write_physics) {
ApplyApiSchema(data_, body_path,
pxr::UsdPhysicsTokens->PhysicsRigidBodyAPI);
}
// Create classes if necessary
mjsDefault *spec_default = mjs_getDefault(body->element);
@@ -1028,14 +1035,14 @@ class ModelWriter {
body_paths_[body_id] = body_path;
}
void WriteBodies() {
void WriteBodies(bool write_physics) {
mjsBody *body = mjs_asBody(mjs_firstElement(spec_, mjOBJ_BODY));
while (body) {
// Only write a rigidbody if we are not the world body.
// We fall through since the world body might have static
// geom children.
if (mjs_getId(body->element) != kWorldIndex) {
WriteBody(body);
WriteBody(body, write_physics);
}
WriteSites(body);
WriteGeoms(body);
@@ -1061,7 +1068,8 @@ class ModelWriter {
namespace mujoco {
namespace usd {
bool WriteSpecToData(mjSpec *spec, pxr::SdfAbstractDataRefPtr &data) {
bool WriteSpecToData(mjSpec *spec, pxr::SdfAbstractDataRefPtr &data,
bool write_physics) {
// Create pseudo root first.
data->CreateSpec(pxr::SdfPath::AbsoluteRootPath(),
pxr::SdfSpecTypePseudoRoot);
@@ -1072,7 +1080,7 @@ bool WriteSpecToData(mjSpec *spec, pxr::SdfAbstractDataRefPtr &data) {
return false;
}
ModelWriter(spec, model, data).Write();
ModelWriter(spec, model, data).Write(write_physics);
return true;
}
@@ -25,7 +25,9 @@ namespace usd {
// Args:
// spec: mjSpec built programmatically or via parsed XML.
// data: SdfAbstractDataRefPtr that will be written to.
bool WriteSpecToData(mjSpec* spec, pxr::SdfAbstractDataRefPtr& data);
// write_physics: Whether to write physics data.
bool WriteSpecToData(mjSpec* spec, pxr::SdfAbstractDataRefPtr& data,
bool write_physics);
} // namespace usd
} // namespace mujoco