From 9319956a16da0d9940f82b24d9784f9cb91a1757 Mon Sep 17 00:00:00 2001 From: Sam Haves Date: Mon, 3 Nov 2025 04:15:31 -0800 Subject: [PATCH] Modify mujoco_to_usd to operate on SdfLayer intead of SdfAbstractData. Since we don't do any on demand data loading for USD and always convert everything it should be safe to use the SdfLayer API instead of the SdfAbstractData API. This enables other codepaths such as the USD writer class to reuse the same logic to generate USD specification from an mjSpec. PiperOrigin-RevId: 827431722 Change-Id: I60a581e0c9577164a4a66229ea9dcb8912afcf74 --- .../usd/plugins/mjcf/mjcf_file_format.cc | 7 +- .../usd/plugins/mjcf/mujoco_to_usd.cc | 1030 ++++++++--------- .../usd/plugins/mjcf/mujoco_to_usd.h | 8 +- src/experimental/usd/plugins/mjcf/utils.cc | 179 +-- src/experimental/usd/plugins/mjcf/utils.h | 102 +- 5 files changed, 621 insertions(+), 705 deletions(-) diff --git a/src/experimental/usd/plugins/mjcf/mjcf_file_format.cc b/src/experimental/usd/plugins/mjcf/mjcf_file_format.cc index f9c78252..4fcdc505 100644 --- a/src/experimental/usd/plugins/mjcf/mjcf_file_format.cc +++ b/src/experimental/usd/plugins/mjcf/mjcf_file_format.cc @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -236,13 +237,15 @@ bool UsdMjcfFileFormat::ReadImpl(pxr::SdfLayer *layer, mjSpec *spec) const { auto args = layer->GetFileFormatArguments(); auto data = InitData(args); - auto success = mujoco::usd::WriteSpecToData(spec, data); + pxr::SdfChangeBlock block; + pxr::SdfLayerRefPtr spec_layer = pxr::SdfLayer::CreateAnonymous(); + auto success = mujoco::usd::WriteSpecToData(spec, spec_layer); mj_deleteSpec(spec); if (!success) { return false; } - _SetLayerData(layer, data); + layer->TransferContent(spec_layer); return true; } diff --git a/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc b/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc index 4a444914..8c268618 100644 --- a/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc +++ b/src/experimental/usd/plugins/mjcf/mujoco_to_usd.cc @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -153,7 +154,6 @@ using mujoco::usd::SetAttributeMetadata; using mujoco::usd::SetAttributeTimeSample; using mujoco::usd::SetLayerMetadata; using mujoco::usd::SetPrimKind; -using mujoco::usd::SetPrimMetadata; using mujoco::usd::SetPrimPurpose; pxr::GfMatrix4d MujocoPosQuatToTransform(double *pos, double *quat) { @@ -174,8 +174,8 @@ pxr::GfMatrix4d MujocoPosQuatToTransform(double *pos, double *quat) { class ModelWriter { public: - ModelWriter(mjSpec *spec, mjModel *model, pxr::SdfAbstractDataRefPtr &data) - : spec_(spec), model_(model), data_(data), class_path_("/Bad_Path") { + ModelWriter(mjSpec *spec, mjModel *model, pxr::SdfLayerRefPtr layer) + : spec_(spec), model_(model), layer_(layer), class_path_("/Bad_Path") { body_paths_ = std::vector(model->nbody); site_paths_ = std::vector(model->nsite); joint_paths_ = std::vector(model->njnt); @@ -184,23 +184,20 @@ class ModelWriter { void Write() { // Create top level class holder. - class_path_ = CreateClassSpec(data_, pxr::SdfPath::AbsoluteRootPath(), - pxr::TfToken("__class__")); + class_path_ = CreateClassSpec(layer_, pxr::SdfPath::AbsoluteRootPath(), + pxr::TfToken("__class__"))->GetPath(); // Create the world body. - body_paths_[kWorldIndex] = WriteWorldBody(kWorldIndex); - - SetLayerMetadata(data_, pxr::SdfFieldKeys->Documentation, - "Generated by mujoco model writer."); - // Mujoco is Z up by default. - SetLayerMetadata(data_, pxr::UsdGeomTokens->upAxis, pxr::UsdGeomTokens->z); - // Mujoco is authored in meters by default. - SetLayerMetadata(data_, pxr::UsdGeomTokens->metersPerUnit, - pxr::UsdGeomLinearUnits::meters); + body_paths_[kWorldIndex] = WriteWorldBody(kWorldIndex)->GetPath(); + layer_->SetDocumentation("Generated by mujoco model writer."); // Set the world body to be the default prim for referencing/payloads. - SetLayerMetadata(data_, pxr::SdfFieldKeys->DefaultPrim, - body_paths_[kWorldIndex].GetNameToken()); + layer_->SetDefaultPrim(body_paths_[kWorldIndex].GetNameToken()); + // Mujoco is Z up by default. + SetLayerMetadata(layer_, pxr::UsdGeomTokens->upAxis, pxr::UsdGeomTokens->z); + // Mujoco is authored in meters by default. + SetLayerMetadata(layer_, pxr::UsdGeomTokens->metersPerUnit, + pxr::UsdGeomLinearUnits::meters); WritePhysicsScene(); @@ -215,10 +212,8 @@ class ModelWriter { private: mjSpec *spec_; mjModel *model_; + pxr::SdfLayerRefPtr layer_; - // This is a handle to the Sdf data to be written into the generated USD - // layer. - pxr::SdfAbstractDataRefPtr &data_; // Path to top level class spec that all classes should be children of. pxr::SdfPath class_path_; // Mapping from Mujoco body id to SdfPath. @@ -257,8 +252,8 @@ class ModelWriter { std::string name = valid_base_name; pxr::SdfPath test_path = parent_path.AppendChild(pxr::TfToken(name)); int count = 1; - while (data_->HasSpec(test_path) && - data_->GetSpecType(test_path) == pxr::SdfSpecType::SdfSpecTypePrim) { + while (layer_->HasSpec(test_path) && + layer_->GetSpecType(test_path) == pxr::SdfSpecType::SdfSpecTypePrim) { name = pxr::TfStringPrintf("%s_%d", valid_base_name.c_str(), count++); test_path = parent_path.AppendChild(pxr::TfToken(name)); } @@ -277,41 +272,41 @@ class ModelWriter { pxr::TfToken body_name; }; - void WriteScaleXformOp(const pxr::SdfPath &prim_path, + void WriteScaleXformOp(const pxr::SdfPrimSpecHandle prim_spec, const pxr::GfVec3f &scale) { - pxr::SdfPath scale_attr_path = - CreateAttributeSpec(data_, prim_path, kTokens->xformOpScale, + auto scale_attr_spec = + CreateAttributeSpec(layer_, prim_spec, kTokens->xformOpScale, pxr::SdfValueTypeNames->Float3); - SetAttributeDefault(data_, scale_attr_path, scale); + SetAttributeDefault(layer_, scale_attr_spec, scale); } - void WriteTransformXformOp(const pxr::SdfPath &prim_path, + void WriteTransformXformOp(const pxr::SdfPrimSpecHandle prim_spec, const pxr::GfMatrix4d &transform) { - pxr::SdfPath transform_op_path = - CreateAttributeSpec(data_, prim_path, kTokens->xformOpTransform, + auto transform_op_spec = + CreateAttributeSpec(layer_, prim_spec, kTokens->xformOpTransform, pxr::SdfValueTypeNames->Matrix4d); - SetAttributeDefault(data_, transform_op_path, transform); + SetAttributeDefault(layer_, transform_op_spec, transform); } - void WriteXformOpOrder(const pxr::SdfPath &prim_path, + void WriteXformOpOrder(const pxr::SdfPrimSpecHandle prim_spec, const pxr::VtArray &order) { - pxr::SdfPath xform_op_order_path = - CreateAttributeSpec(data_, prim_path, pxr::UsdGeomTokens->xformOpOrder, + auto xform_op_order_spec = + CreateAttributeSpec(layer_, prim_spec, pxr::UsdGeomTokens->xformOpOrder, pxr::SdfValueTypeNames->TokenArray); - SetAttributeDefault(data_, xform_op_order_path, order); + SetAttributeDefault(layer_, xform_op_order_spec, order); } template - void WriteUniformAttribute(const pxr::SdfPath &prim_path, + void WriteUniformAttribute(const pxr::SdfPrimSpecHandle prim_spec, const pxr::SdfValueTypeName &value_type_name, const pxr::TfToken &token, const T &value) { - pxr::SdfPath attr_path = CreateAttributeSpec( - data_, prim_path, token, value_type_name, pxr::SdfVariabilityUniform); - SetAttributeDefault(data_, attr_path, value); + auto attr_spec = CreateAttributeSpec( + layer_, prim_spec, token, value_type_name, pxr::SdfVariabilityUniform); + SetAttributeDefault(layer_, attr_spec, value); } template - void WriteColorAndOpacityAttributes(const pxr::SdfPath &prim_path, + void WriteColorAndOpacityAttributes(const pxr::SdfPrimSpecHandle prim_spec, const T &element) { // If rgba is not the default (0.5, 0.5, 0.5, 1), then set the // displayColor attribute. @@ -320,56 +315,56 @@ class ModelWriter { if (element->rgba[0] != 0.5f || element->rgba[1] != 0.5f || element->rgba[2] != 0.5f || element->rgba[3] != 1.0f) { // Set the displayColor attribute. - pxr::SdfPath display_color_attr = CreateAttributeSpec( - data_, prim_path, pxr::UsdGeomTokens->primvarsDisplayColor, + auto display_color_attr = CreateAttributeSpec( + layer_, prim_spec, pxr::UsdGeomTokens->primvarsDisplayColor, pxr::SdfValueTypeNames->Color3fArray); SetAttributeDefault( - data_, display_color_attr, + layer_, display_color_attr, pxr::VtArray{ {element->rgba[0], element->rgba[1], element->rgba[2]}}); // Set the displayOpacity attribute, only if the opacity is not 1. if (element->rgba[3] != 1.0f) { - pxr::SdfPath display_opacity_attr = CreateAttributeSpec( - data_, prim_path, pxr::UsdGeomTokens->primvarsDisplayOpacity, + auto display_opacity_attr = CreateAttributeSpec( + layer_, prim_spec, pxr::UsdGeomTokens->primvarsDisplayOpacity, pxr::SdfValueTypeNames->FloatArray); - SetAttributeDefault(data_, display_opacity_attr, + SetAttributeDefault(layer_, display_opacity_attr, pxr::VtArray{element->rgba[3]}); } } } - void PrependToXformOpOrder(const pxr::SdfPath &prim_path, + void PrependToXformOpOrder(const pxr::SdfPrimSpecHandle prim_spec, const pxr::VtArray &order) { auto xform_op_order_path = - prim_path.AppendProperty(pxr::UsdGeomTokens->xformOpOrder); - if (!data_->HasSpec(xform_op_order_path)) { - WriteXformOpOrder(prim_path, order); + prim_spec->GetPath().AppendProperty(pxr::UsdGeomTokens->xformOpOrder); + if (!prim_spec->HasField(pxr::UsdGeomTokens->xformOpOrder)) { + WriteXformOpOrder(prim_spec, order); return; } auto existing_order = - data_->Get(xform_op_order_path, pxr::SdfFieldKeys->Default) - .UncheckedGet>(); + prim_spec->GetField(pxr::UsdGeomTokens->xformOpOrder).UncheckedGet>(); + prim_spec->GetField(pxr::UsdGeomTokens->xformOpOrder).Get>(); pxr::VtArray new_order(order.size() + existing_order.size()); std::copy(order.begin(), order.end(), new_order.begin()); std::copy(existing_order.begin(), existing_order.end(), new_order.begin() + order.size()); - SetAttributeDefault(data_, xform_op_order_path, new_order); + SetAttributeDefault(layer_, layer_->GetAttributeAtPath(xform_op_order_path), new_order); } void WriteMesh(const mjsMesh *mesh, const pxr::SdfPath &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 = - CreatePrimSpec(data_, subcomponent_path, kTokens->sourceMesh, + auto subcomponent_spec = + CreatePrimSpec(layer_, parent_path, name, pxr::UsdGeomTokens->Xform); + auto mesh_spec = + CreatePrimSpec(layer_, subcomponent_spec->GetPath(), kTokens->sourceMesh, pxr::UsdGeomTokens->Mesh); - mesh_paths_[*mjs_getName(mesh->element)] = subcomponent_path; + mesh_paths_[*mjs_getName(mesh->element)] = subcomponent_spec->GetPath(); - ApplyApiSchema(data_, mesh_path, MjcPhysicsTokens->MjcMeshCollisionAPI); + ApplyApiSchema(layer_, mesh_spec, MjcPhysicsTokens->MjcMeshCollisionAPI); pxr::TfToken inertia = MjcPhysicsTokens->legacy; if (mesh->inertia == mjtMeshInertia::mjMESH_INERTIA_EXACT) { @@ -380,10 +375,10 @@ class ModelWriter { inertia = MjcPhysicsTokens->shell; } - WriteUniformAttribute(mesh_path, pxr::SdfValueTypeNames->Token, + WriteUniformAttribute(mesh_spec, pxr::SdfValueTypeNames->Token, MjcPhysicsTokens->mjcInertia, inertia); - WriteUniformAttribute(mesh_path, pxr::SdfValueTypeNames->Int, + WriteUniformAttribute(mesh_spec, pxr::SdfValueTypeNames->Int, MjcPhysicsTokens->mjcMaxhullvert, mesh->maxhullvert); // NOTE: The geometry data taken from the spec is the post-compilation @@ -399,10 +394,10 @@ class ModelWriter { points.emplace_back(&model_->mesh_vert[i]); } - pxr::SdfPath points_attr_path = - CreateAttributeSpec(data_, mesh_path, pxr::UsdGeomTokens->points, + auto points_attr = + CreateAttributeSpec(layer_, mesh_spec, pxr::UsdGeomTokens->points, pxr::SdfValueTypeNames->Vector3fArray); - SetAttributeDefault(data_, points_attr_path, points); + SetAttributeDefault(layer_, points_attr, points); // NOTE: nface is never 0. int nface = model_->mesh_facenum[mesh_id]; @@ -414,20 +409,20 @@ class ModelWriter { faces.push_back(model_->mesh_face[i + 1]); faces.push_back(model_->mesh_face[i + 2]); } - pxr::SdfPath face_vertex_idx_attr_path = CreateAttributeSpec( - data_, mesh_path, pxr::UsdGeomTokens->faceVertexIndices, + auto face_vertex_idx_attr= CreateAttributeSpec( + layer_, mesh_spec, pxr::UsdGeomTokens->faceVertexIndices, pxr::SdfValueTypeNames->IntArray); - SetAttributeDefault(data_, face_vertex_idx_attr_path, faces); + SetAttributeDefault(layer_, face_vertex_idx_attr, faces); pxr::VtArray vertex_counts; for (int i = 0; i < nface; ++i) { // Mujoco is always triangles. vertex_counts.push_back(3); } - pxr::SdfPath face_vertex_counts_attr_path = CreateAttributeSpec( - data_, mesh_path, pxr::UsdGeomTokens->faceVertexCounts, + auto face_vertex_counts_attr= CreateAttributeSpec( + layer_, mesh_spec, pxr::UsdGeomTokens->faceVertexCounts, pxr::SdfValueTypeNames->IntArray); - SetAttributeDefault(data_, face_vertex_counts_attr_path, vertex_counts); + SetAttributeDefault(layer_, face_vertex_counts_attr, vertex_counts); if (model_->mesh_normalnum[mesh_id]) { // We have to convert from Mujoco's indexed normals to USD's faceVarying @@ -440,12 +435,11 @@ class ModelWriter { int normal_adr = normal_start_adr + model_->mesh_facenormal[i]; normals.emplace_back(&model_->mesh_normal[normal_adr * 3]); } - pxr::SdfPath normals_attr_path = - CreateAttributeSpec(data_, mesh_path, pxr::UsdGeomTokens->normals, + auto normals_attr= + CreateAttributeSpec(layer_, mesh_spec, pxr::UsdGeomTokens->normals, pxr::SdfValueTypeNames->Vector3fArray); - SetAttributeDefault(data_, normals_attr_path, normals); - SetAttributeMetadata(data_, normals_attr_path, - pxr::UsdGeomTokens->interpolation, + SetAttributeDefault(layer_, normals_attr, normals); + normals_attr->SetField(pxr::UsdGeomTokens->interpolation, pxr::UsdGeomTokens->faceVarying); } @@ -465,30 +459,29 @@ class ModelWriter { texcoords.push_back(uv); } - pxr::SdfPath texcoords_attr_path = - CreateAttributeSpec(data_, mesh_path, kTokens->primvarsSt, + auto texcoords_attr= + CreateAttributeSpec(layer_, mesh_spec, kTokens->primvarsSt, pxr::SdfValueTypeNames->TexCoord2fArray); - SetAttributeDefault(data_, texcoords_attr_path, texcoords); - SetAttributeMetadata(data_, texcoords_attr_path, - pxr::UsdGeomTokens->interpolation, + SetAttributeDefault(layer_, texcoords_attr, texcoords); + texcoords_attr->SetField(pxr::UsdGeomTokens->interpolation, pxr::UsdGeomTokens->faceVarying); } // Default subdivision scheme is catmull clark so explicitly set it // to none here. - pxr::SdfPath subdivision_scheme_path = CreateAttributeSpec( - data_, mesh_path, pxr::UsdGeomTokens->subdivisionScheme, + auto subdivision_scheme= CreateAttributeSpec( + layer_, mesh_spec, pxr::UsdGeomTokens->subdivisionScheme, pxr::SdfValueTypeNames->Token); - SetAttributeDefault(data_, subdivision_scheme_path, + SetAttributeDefault(layer_, subdivision_scheme, pxr::UsdGeomTokens->none); } void WritePhysicsScene() { - pxr::SdfPath physics_scene_path = CreatePrimSpec( - data_, body_paths_[kWorldIndex], pxr::UsdPhysicsTokens->PhysicsScene, + auto physics_scene_spec = CreatePrimSpec( + layer_, body_paths_[kWorldIndex], pxr::UsdPhysicsTokens->PhysicsScene, pxr::UsdPhysicsTokens->PhysicsScene); - ApplyApiSchema(data_, physics_scene_path, MjcPhysicsTokens->MjcSceneAPI); + ApplyApiSchema(layer_, physics_scene_spec, MjcPhysicsTokens->MjcSceneAPI); const std::vector> option_double_attributes = { @@ -506,7 +499,7 @@ class ModelWriter { {MjcPhysicsTokens->mjcOptionO_margin, spec_->option.o_margin}, }; for (const auto &[token, value] : option_double_attributes) { - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Double, token, value); } @@ -523,55 +516,55 @@ class ModelWriter { spec_->option.sdf_initpoints}, }; for (const auto &[token, value] : option_int_attributes) { - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Int, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Int, token, value); } - pxr::SdfPath cone_attr = CreateAttributeSpec( - data_, physics_scene_path, MjcPhysicsTokens->mjcOptionCone, + auto cone_attr = CreateAttributeSpec( + layer_, physics_scene_spec, MjcPhysicsTokens->mjcOptionCone, pxr::SdfValueTypeNames->Token, pxr::SdfVariabilityUniform); switch (spec_->option.cone) { case mjCONE_PYRAMIDAL: - SetAttributeDefault(data_, cone_attr, MjcPhysicsTokens->pyramidal); + SetAttributeDefault(layer_, cone_attr, MjcPhysicsTokens->pyramidal); break; case mjCONE_ELLIPTIC: - SetAttributeDefault(data_, cone_attr, MjcPhysicsTokens->elliptic); + SetAttributeDefault(layer_, cone_attr, MjcPhysicsTokens->elliptic); break; default: break; } - pxr::SdfPath jacobian_attr = CreateAttributeSpec( - data_, physics_scene_path, MjcPhysicsTokens->mjcOptionJacobian, + auto jacobian_attr = CreateAttributeSpec( + layer_, physics_scene_spec, MjcPhysicsTokens->mjcOptionJacobian, pxr::SdfValueTypeNames->Token, pxr::SdfVariabilityUniform); switch (spec_->option.jacobian) { case mjJAC_AUTO: - SetAttributeDefault(data_, jacobian_attr, MjcPhysicsTokens->auto_); + SetAttributeDefault(layer_, jacobian_attr, MjcPhysicsTokens->auto_); break; case mjJAC_DENSE: - SetAttributeDefault(data_, jacobian_attr, MjcPhysicsTokens->dense); + SetAttributeDefault(layer_, jacobian_attr, MjcPhysicsTokens->dense); break; case mjJAC_SPARSE: - SetAttributeDefault(data_, jacobian_attr, MjcPhysicsTokens->sparse); + SetAttributeDefault(layer_, jacobian_attr, MjcPhysicsTokens->sparse); break; default: break; } - pxr::SdfPath solver_attr = CreateAttributeSpec( - data_, physics_scene_path, MjcPhysicsTokens->mjcOptionSolver, + auto solver_attr = CreateAttributeSpec( + layer_, physics_scene_spec, MjcPhysicsTokens->mjcOptionSolver, pxr::SdfValueTypeNames->Token, pxr::SdfVariabilityUniform); switch (spec_->option.solver) { case mjSOL_NEWTON: - SetAttributeDefault(data_, solver_attr, MjcPhysicsTokens->newton); + SetAttributeDefault(layer_, solver_attr, MjcPhysicsTokens->newton); break; case mjSOL_PGS: - SetAttributeDefault(data_, solver_attr, MjcPhysicsTokens->pgs); + SetAttributeDefault(layer_, solver_attr, MjcPhysicsTokens->pgs); break; case mjSOL_CG: - SetAttributeDefault(data_, solver_attr, MjcPhysicsTokens->cg); + SetAttributeDefault(layer_, solver_attr, MjcPhysicsTokens->cg); break; default: break; @@ -583,50 +576,50 @@ class ModelWriter { // normalization. float gravity_magnitude = gravity.Normalize(); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Float, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Float, pxr::UsdPhysicsTokens->physicsGravityMagnitude, gravity_magnitude); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Vector3f, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Vector3f, pxr::UsdPhysicsTokens->physicsGravityDirection, gravity); pxr::GfVec3d wind(spec_->option.wind[0], spec_->option.wind[1], spec_->option.wind[2]); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Double3, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Double3, MjcPhysicsTokens->mjcOptionWind, wind); pxr::GfVec3d magnetic(spec_->option.magnetic[0], spec_->option.magnetic[1], spec_->option.magnetic[2]); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Double3, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Double3, MjcPhysicsTokens->mjcOptionMagnetic, magnetic); pxr::VtArray o_solref(spec_->option.o_solref, spec_->option.o_solref + mjNREF); - WriteUniformAttribute(physics_scene_path, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcOptionO_solref, o_solref); pxr::VtArray o_solimp(spec_->option.o_solimp, spec_->option.o_solimp + mjNIMP); - WriteUniformAttribute(physics_scene_path, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcOptionO_solimp, o_solimp); pxr::VtArray o_friction(spec_->option.o_friction, spec_->option.o_friction + 5); - WriteUniformAttribute(physics_scene_path, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcOptionO_friction, o_friction); - pxr::SdfPath integrator_attr = CreateAttributeSpec( - data_, physics_scene_path, MjcPhysicsTokens->mjcOptionIntegrator, + auto integrator_attr = CreateAttributeSpec( + layer_, physics_scene_spec, MjcPhysicsTokens->mjcOptionIntegrator, pxr::SdfValueTypeNames->Token, pxr::SdfVariabilityUniform); switch (spec_->option.integrator) { case mjINT_EULER: - SetAttributeDefault(data_, integrator_attr, MjcPhysicsTokens->euler); + SetAttributeDefault(layer_, integrator_attr, MjcPhysicsTokens->euler); break; case mjINT_RK4: - SetAttributeDefault(data_, integrator_attr, MjcPhysicsTokens->rk4); + SetAttributeDefault(layer_, integrator_attr, MjcPhysicsTokens->rk4); break; default: break; @@ -636,7 +629,7 @@ class ModelWriter { int flags = enable ? spec_->option.enableflags : spec_->option.disableflags; bool value = enable ? (flags & flag) : !(flags & flag); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Bool, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Bool, token, value); }; @@ -675,40 +668,40 @@ class ModelWriter { } // Compiler attributes - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Bool, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Bool, MjcPhysicsTokens->mjcCompilerAutoLimits, (bool)spec_->compiler.autolimits); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcCompilerBoundMass, spec_->compiler.boundmass); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcCompilerBoundInertia, spec_->compiler.boundinertia); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcCompilerSetTotalMass, spec_->compiler.settotalmass); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Bool, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Bool, MjcPhysicsTokens->mjcCompilerUseThread, (bool)spec_->compiler.usethread); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Bool, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Bool, MjcPhysicsTokens->mjcCompilerBalanceInertia, (bool)spec_->compiler.balanceinertia); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Token, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Token, MjcPhysicsTokens->mjcCompilerAngle, spec_->compiler.degree ? MjcPhysicsTokens->degree : MjcPhysicsTokens->radian); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Bool, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Bool, MjcPhysicsTokens->mjcCompilerFitAABB, (bool)spec_->compiler.fitaabb); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Bool, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Bool, MjcPhysicsTokens->mjcCompilerFuseStatic, (bool)spec_->compiler.fusestatic); @@ -720,101 +713,102 @@ class ModelWriter { mjINERTIAFROMGEOM_FALSE) { // mjINERTIA_FALSE inertiafromgeom_token = MjcPhysicsTokens->false_; } - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Token, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Token, MjcPhysicsTokens->mjcCompilerInertiaFromGeom, inertiafromgeom_token); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Bool, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Bool, MjcPhysicsTokens->mjcCompilerAlignFree, (bool)spec_->compiler.alignfree); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Int, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Int, MjcPhysicsTokens->mjcCompilerInertiaGroupRangeMin, spec_->compiler.inertiagrouprange[0]); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Int, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Int, MjcPhysicsTokens->mjcCompilerInertiaGroupRangeMax, spec_->compiler.inertiagrouprange[1]); - WriteUniformAttribute(physics_scene_path, pxr::SdfValueTypeNames->Bool, + WriteUniformAttribute(physics_scene_spec, pxr::SdfValueTypeNames->Bool, MjcPhysicsTokens->mjcCompilerSaveInertial, (bool)spec_->compiler.saveinertial); } void WriteMeshes() { // Create a scope for the meshes to keep things organized - pxr::SdfPath scope_path = - CreatePrimSpec(data_, body_paths_[kWorldIndex], kTokens->meshScope, + auto scope = + CreatePrimSpec(layer_, body_paths_[kWorldIndex], kTokens->meshScope, pxr::UsdGeomTokens->Scope); // Make the mesh scope invisible since they will be referenced by the bits // that should be visible. - SetPrimMetadata(data_, scope_path, pxr::SdfFieldKeys->Active, false); + scope->SetField(pxr::SdfFieldKeys->Active, false); mjsMesh *mesh = mjs_asMesh(mjs_firstElement(spec_, mjOBJ_MESH)); while (mesh) { - WriteMesh(mesh, scope_path); + WriteMesh(mesh, scope->GetPath()); mesh = mjs_asMesh(mjs_nextElement(spec_, mesh->element)); } } - pxr::SdfPath AddUVTextureShader(const pxr::SdfPath &material_path, - const pxr::TfToken &name) { - pxr::SdfPath uvmap_shader_path = - CreatePrimSpec(data_, material_path, name, pxr::UsdShadeTokens->Shader); + pxr::SdfAttributeSpecHandle AddUVTextureShader( + const pxr::SdfPrimSpecHandle material_spec, const pxr::TfToken &name) { + auto uvmap_shader_spec = + CreatePrimSpec(layer_, material_spec->GetPath(), name, pxr::UsdShadeTokens->Shader); - pxr::SdfPath uvmap_info_id_attr = CreateAttributeSpec( - data_, uvmap_shader_path, pxr::UsdShadeTokens->infoId, + auto uvmap_info_id_attr = CreateAttributeSpec( + layer_, uvmap_shader_spec, pxr::UsdShadeTokens->infoId, pxr::SdfValueTypeNames->Token, pxr::SdfVariabilityUniform); - SetAttributeDefault(data_, uvmap_info_id_attr, + SetAttributeDefault(layer_, uvmap_info_id_attr, pxr::UsdImagingTokens->UsdPrimvarReader_float2); - pxr::SdfPath uvmap_varname_attr = - CreateAttributeSpec(data_, uvmap_shader_path, kTokens->inputsVarname, + auto uvmap_varname_attr = + CreateAttributeSpec(layer_, uvmap_shader_spec, kTokens->inputsVarname, pxr::SdfValueTypeNames->Token); - SetAttributeDefault(data_, uvmap_varname_attr, kTokens->st); + SetAttributeDefault(layer_, uvmap_varname_attr, kTokens->st); - pxr::SdfPath uvmap_st_output_attr = - CreateAttributeSpec(data_, uvmap_shader_path, kTokens->outputsSt, + auto uvmap_st_output_attr = + CreateAttributeSpec(layer_, uvmap_shader_spec, kTokens->outputsSt, pxr::SdfValueTypeNames->Float2); return uvmap_st_output_attr; } - std::vector AddTextureShader( - const pxr::SdfPath &material_path, const char *texture_file, - const pxr::TfToken &name, const pxr::SdfPath &uvmap_st_output_attr, + std::vector AddTextureShader( + const pxr::SdfPrimSpecHandle material_spec, const char *texture_file, + const pxr::TfToken &name, + const pxr::SdfAttributeSpecHandle uvmap_st_output_attr, const std::vector &output_channels) { - pxr::SdfPath texture_shader_path = - CreatePrimSpec(data_, material_path, name, pxr::UsdShadeTokens->Shader); - pxr::SdfPath texture_info_id_attr = CreateAttributeSpec( - data_, texture_shader_path, pxr::UsdShadeTokens->infoId, + auto texture_shader_spec = + CreatePrimSpec(layer_, material_spec->GetPath(), name, pxr::UsdShadeTokens->Shader); + auto texture_info_id_attr = CreateAttributeSpec( + layer_, texture_shader_spec, pxr::UsdShadeTokens->infoId, pxr::SdfValueTypeNames->Token, pxr::SdfVariabilityUniform); - SetAttributeDefault(data_, texture_info_id_attr, + SetAttributeDefault(layer_, texture_info_id_attr, pxr::UsdImagingTokens->UsdUVTexture); - pxr::SdfPath texture_file_attr = - CreateAttributeSpec(data_, texture_shader_path, kTokens->inputsFile, + auto texture_file_attr = + CreateAttributeSpec(layer_, texture_shader_spec, kTokens->inputsFile, pxr::SdfValueTypeNames->Asset); - SetAttributeDefault(data_, texture_file_attr, + SetAttributeDefault(layer_, texture_file_attr, pxr::SdfAssetPath(texture_file)); - pxr::SdfPath texture_st_input_attr = - CreateAttributeSpec(data_, texture_shader_path, kTokens->inputsSt, + auto texture_st_input_attr = + CreateAttributeSpec(layer_, texture_shader_spec, kTokens->inputsSt, pxr::SdfValueTypeNames->Float2); - AddAttributeConnection(data_, texture_st_input_attr, uvmap_st_output_attr); + AddAttributeConnection(layer_, texture_st_input_attr, uvmap_st_output_attr); - pxr::SdfPath texture_wrap_s_attr = - CreateAttributeSpec(data_, texture_shader_path, kTokens->inputsWrapS, + auto texture_wrap_s_attr = + CreateAttributeSpec(layer_, texture_shader_spec, kTokens->inputsWrapS, pxr::SdfValueTypeNames->Token); - SetAttributeDefault(data_, texture_wrap_s_attr, kTokens->repeat); + SetAttributeDefault(layer_, texture_wrap_s_attr, kTokens->repeat); - pxr::SdfPath texture_wrap_t_attr = - CreateAttributeSpec(data_, texture_shader_path, kTokens->inputsWrapT, + auto texture_wrap_t_attr = + CreateAttributeSpec(layer_, texture_shader_spec, kTokens->inputsWrapT, pxr::SdfValueTypeNames->Token); - SetAttributeDefault(data_, texture_wrap_t_attr, kTokens->repeat); + SetAttributeDefault(layer_, texture_wrap_t_attr, kTokens->repeat); - std::vector texture_output_attrs; + std::vector texture_output_attrs; for (const auto &output_channel : output_channels) { pxr::SdfValueTypeName value_type; if (output_channel == kTokens->outputsRgb) { @@ -824,49 +818,51 @@ class ModelWriter { value_type = pxr::SdfValueTypeNames->Float; } texture_output_attrs.push_back(CreateAttributeSpec( - data_, texture_shader_path, output_channel, value_type)); + layer_, texture_shader_spec, output_channel, value_type)); } return texture_output_attrs; } - pxr::SdfPath WritePhysicsMaterial(mjsGeom *geom) { + pxr::SdfPrimSpecHandle WritePhysicsMaterial(mjsGeom *geom) { pxr::SdfPath scope_path = body_paths_[kWorldIndex].AppendChild(kTokens->physicsMaterialsScope); - if (!data_->HasSpec(scope_path)) { - CreatePrimSpec(data_, body_paths_[kWorldIndex], - kTokens->physicsMaterialsScope, pxr::UsdGeomTokens->Scope); + pxr::SdfPrimSpecHandle scope_spec = layer_->GetPrimAtPath(scope_path); + if (!scope_spec) { + scope_spec = CreatePrimSpec(layer_, body_paths_[kWorldIndex], + kTokens->physicsMaterialsScope, + pxr::UsdGeomTokens->Scope); } auto name = GetAvailablePrimName(*mjs_getName(geom->element), pxr::UsdShadeTokens->Material, scope_path); - pxr::SdfPath material_path = - CreatePrimSpec(data_, scope_path, name, pxr::UsdShadeTokens->Material); + auto material_spec = + CreatePrimSpec(layer_, scope_spec->GetPath(), name, pxr::UsdShadeTokens->Material); - ApplyApiSchema(data_, material_path, + ApplyApiSchema(layer_, material_spec, pxr::UsdPhysicsTokens->PhysicsMaterialAPI); - ApplyApiSchema(data_, material_path, MjcPhysicsTokens->MjcMaterialAPI); + ApplyApiSchema(layer_, material_spec, MjcPhysicsTokens->MjcMaterialAPI); mjsGeom *geom_default = mjs_getDefault(geom->element)->geom; if (geom->friction[0] != geom_default->friction[0]) { // Since MuJoCo has no concept of static friction, only write dynamic // friction to remain truthful to how MuJoCo perceives the data. - WriteUniformAttribute(material_path, pxr::SdfValueTypeNames->Float, + WriteUniformAttribute(material_spec, pxr::SdfValueTypeNames->Float, pxr::UsdPhysicsTokens->physicsDynamicFriction, (float)geom->friction[0]); } if (geom->friction[1] != geom_default->friction[1]) { - WriteUniformAttribute(material_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(material_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcTorsionalfriction, geom->friction[1]); } if (geom->friction[2] != geom_default->friction[2]) { - WriteUniformAttribute(material_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(material_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcRollingfriction, geom->friction[2]); } - return material_path; + return material_spec; } void WriteMaterial(mjsMaterial *material, const pxr::SdfPath &parent_path) { @@ -874,58 +870,58 @@ class ModelWriter { auto name = GetAvailablePrimName(*mjs_getName(material->element), pxr::UsdShadeTokens->Material, parent_path); - pxr::SdfPath material_path = - CreatePrimSpec(data_, parent_path, name, pxr::UsdShadeTokens->Material); + auto material_spec = + CreatePrimSpec(layer_, parent_path, name, pxr::UsdShadeTokens->Material); // Create a Shader prim "PreviewSurface" under the Material prim. - pxr::SdfPath preview_surface_shader_path = - CreatePrimSpec(data_, material_path, kTokens->previewSurface, + auto preview_surface_shader_spec = + CreatePrimSpec(layer_, material_spec->GetPath(), kTokens->previewSurface, pxr::UsdShadeTokens->Shader); // Set the Shader'sinfoId attribute to UsdPreviewSurface, a standard surface // shader. - pxr::SdfPath info_id_attr = CreateAttributeSpec( - data_, preview_surface_shader_path, pxr::UsdShadeTokens->infoId, + auto info_id_attr = CreateAttributeSpec( + layer_, preview_surface_shader_spec, pxr::UsdShadeTokens->infoId, pxr::SdfValueTypeNames->Token, pxr::SdfVariabilityUniform); - SetAttributeDefault(data_, info_id_attr, + SetAttributeDefault(layer_, info_id_attr, pxr::UsdImagingTokens->UsdPreviewSurface); // Connect material's surface output to the preview surface's surface // output. - pxr::SdfPath surface_output_attr = CreateAttributeSpec( - data_, preview_surface_shader_path, pxr::UsdShadeTokens->outputsSurface, + auto surface_output_attr = CreateAttributeSpec( + layer_, preview_surface_shader_spec, pxr::UsdShadeTokens->outputsSurface, pxr::SdfValueTypeNames->Token); - pxr::SdfPath material_surface_output_attr = CreateAttributeSpec( - data_, material_path, pxr::UsdShadeTokens->outputsSurface, + auto material_surface_output_attr = CreateAttributeSpec( + layer_, material_spec, pxr::UsdShadeTokens->outputsSurface, pxr::SdfValueTypeNames->Token); - AddAttributeConnection(data_, material_surface_output_attr, + AddAttributeConnection(layer_, material_surface_output_attr, surface_output_attr); // Connect material's displacement output to the preview surface's // displacement output. - pxr::SdfPath displacement_output_attr = - CreateAttributeSpec(data_, preview_surface_shader_path, + auto displacement_output_attr = + CreateAttributeSpec(layer_, preview_surface_shader_spec, pxr::UsdShadeTokens->outputsDisplacement, pxr::SdfValueTypeNames->Token); - pxr::SdfPath material_displacement_output_attr = CreateAttributeSpec( - data_, material_path, pxr::UsdShadeTokens->outputsDisplacement, + auto material_displacement_output_attr = CreateAttributeSpec( + layer_, material_spec, pxr::UsdShadeTokens->outputsDisplacement, pxr::SdfValueTypeNames->Token); - AddAttributeConnection(data_, material_displacement_output_attr, + AddAttributeConnection(layer_, material_displacement_output_attr, displacement_output_attr); // Add an st (uv) Shader, a prim var reader for the UV coordinates. - const pxr::SdfPath &uvmap_st_output_attr = - AddUVTextureShader(material_path, pxr::TfToken("uvmap")); + const pxr::SdfAttributeSpecHandle &uvmap_st_output_attr = + AddUVTextureShader(material_spec, pxr::TfToken("uvmap")); const mjStringVec &textures = *(material->textures); // Set the values of metallic, roughness and occlusion. These can come from // an ORM packed texture, as individual textures, or as a values defined in // mjsMaterial_ (with the exception of occlusion). - pxr::SdfPath metallic_attr = CreateAttributeSpec( - data_, preview_surface_shader_path, kTokens->inputsMetallic, + auto metallic_attr = CreateAttributeSpec( + layer_, preview_surface_shader_spec, kTokens->inputsMetallic, pxr::SdfValueTypeNames->Float); - pxr::SdfPath roughness_attr = CreateAttributeSpec( - data_, preview_surface_shader_path, kTokens->inputsRoughness, + auto roughness_attr = CreateAttributeSpec( + layer_, preview_surface_shader_spec, kTokens->inputsRoughness, pxr::SdfValueTypeNames->Float); // Find the occlusion, roughness, and metallic textures. if (mjTEXROLE_ORM < textures.size()) { @@ -944,53 +940,54 @@ class ModelWriter { if (orm_texture) { // Create the ORM shader and connect its output to the preview // surface ORM attrs. - const std::vector orm_output_attrs = AddTextureShader( - material_path, orm_texture->file->c_str(), - pxr::TfToken("orm_packed"), uvmap_st_output_attr, - {kTokens->outputsR, kTokens->outputsG, kTokens->outputsB}); + const std::vector orm_output_attrs = + AddTextureShader( + material_spec, orm_texture->file->c_str(), + pxr::TfToken("orm_packed"), uvmap_st_output_attr, + {kTokens->outputsR, kTokens->outputsG, kTokens->outputsB}); if (orm_output_attrs.size() == 3) { - pxr::SdfPath occlusion_attr = CreateAttributeSpec( - data_, preview_surface_shader_path, kTokens->inputsOcclusion, + auto occlusion_attr = CreateAttributeSpec( + layer_, preview_surface_shader_spec, kTokens->inputsOcclusion, pxr::SdfValueTypeNames->Float); - AddAttributeConnection(data_, occlusion_attr, orm_output_attrs[0]); - AddAttributeConnection(data_, roughness_attr, orm_output_attrs[1]); - AddAttributeConnection(data_, metallic_attr, orm_output_attrs[2]); + AddAttributeConnection(layer_, occlusion_attr, orm_output_attrs[0]); + AddAttributeConnection(layer_, roughness_attr, orm_output_attrs[1]); + AddAttributeConnection(layer_, metallic_attr, orm_output_attrs[2]); } } else { if (metallic_texture) { - const std::vector metallic_output_attrs = - AddTextureShader(material_path, metallic_texture->file->c_str(), + const std::vector metallic_output_attrs = + AddTextureShader(material_spec, metallic_texture->file->c_str(), pxr::TfToken("metallic"), uvmap_st_output_attr, {kTokens->outputsRgb}); if (metallic_output_attrs.size() == 1) { - AddAttributeConnection(data_, metallic_attr, + AddAttributeConnection(layer_, metallic_attr, metallic_output_attrs[0]); } } else { - SetAttributeDefault(data_, metallic_attr, material->metallic); + SetAttributeDefault(layer_, metallic_attr, material->metallic); } if (roughness_texture) { - const std::vector roughness_output_attrs = - AddTextureShader(material_path, roughness_texture->file->c_str(), + const std::vector roughness_output_attrs = + AddTextureShader(material_spec, roughness_texture->file->c_str(), pxr::TfToken("roughness"), uvmap_st_output_attr, {kTokens->outputsRgb}); if (roughness_output_attrs.size() == 1) { - AddAttributeConnection(data_, roughness_attr, + AddAttributeConnection(layer_, roughness_attr, roughness_output_attrs[0]); } } else { - SetAttributeDefault(data_, roughness_attr, material->roughness); + SetAttributeDefault(layer_, roughness_attr, material->roughness); } if (occlusion_texture) { - pxr::SdfPath occlusion_attr = CreateAttributeSpec( - data_, preview_surface_shader_path, kTokens->inputsOcclusion, + auto occlusion_attr = CreateAttributeSpec( + layer_, preview_surface_shader_spec, kTokens->inputsOcclusion, pxr::SdfValueTypeNames->Float); - const std::vector occlusion_output_attrs = - AddTextureShader(material_path, occlusion_texture->file->c_str(), + const std::vector occlusion_output_attrs = + AddTextureShader(material_spec, occlusion_texture->file->c_str(), pxr::TfToken("occlusion"), uvmap_st_output_attr, {kTokens->outputsRgb}); if (occlusion_output_attrs.size() == 1) { - AddAttributeConnection(data_, occlusion_attr, + AddAttributeConnection(layer_, occlusion_attr, occlusion_output_attrs[0]); } } @@ -1002,17 +999,17 @@ class ModelWriter { mjsTexture *normal_texture = mjs_asTexture( mjs_findElement(spec_, mjOBJ_TEXTURE, normal_texture_name.c_str())); if (normal_texture) { - pxr::SdfPath normal_attr = CreateAttributeSpec( - data_, preview_surface_shader_path, kTokens->inputsNormal, + auto normal_attr = CreateAttributeSpec( + layer_, preview_surface_shader_spec, kTokens->inputsNormal, pxr::SdfValueTypeNames->Normal3f); // Create the normal map shader and connect its output to the preview // surface normal attr. - const std::vector normal_map_output_attrs = - AddTextureShader(material_path, normal_texture->file->c_str(), + const std::vector normal_map_output_attrs = + AddTextureShader(material_spec, normal_texture->file->c_str(), pxr::TfToken("normal"), uvmap_st_output_attr, {kTokens->outputsRgb}); if (normal_map_output_attrs.size() == 1) { - AddAttributeConnection(data_, normal_attr, + AddAttributeConnection(layer_, normal_attr, normal_map_output_attrs[0]); } } @@ -1024,15 +1021,15 @@ class ModelWriter { mjsTexture *emissive_texture = mjs_asTexture( mjs_findElement(spec_, mjOBJ_TEXTURE, emissive_texture_name.c_str())); if (emissive_texture) { - pxr::SdfPath emissive_attr = CreateAttributeSpec( - data_, preview_surface_shader_path, kTokens->inputsEmissiveColor, + auto emissive_attr = CreateAttributeSpec( + layer_, preview_surface_shader_spec, kTokens->inputsEmissiveColor, pxr::SdfValueTypeNames->Color3f); - const std::vector emissive_map_output_attrs = - AddTextureShader(material_path, emissive_texture->file->c_str(), + const std::vector emissive_map_output_attrs = + AddTextureShader(material_spec, emissive_texture->file->c_str(), pxr::TfToken("emissive"), uvmap_st_output_attr, {kTokens->outputsRgb}); if (emissive_map_output_attrs.size() == 1) { - AddAttributeConnection(data_, emissive_attr, + AddAttributeConnection(layer_, emissive_attr, emissive_map_output_attrs[0]); } } @@ -1040,8 +1037,8 @@ class ModelWriter { // Set the value of diffuse color. This can come from a diffuse texture // or as a value defined in mjsMaterial_. - pxr::SdfPath diffuse_color_attr = CreateAttributeSpec( - data_, preview_surface_shader_path, kTokens->inputsDiffuseColor, + auto diffuse_color_attr = CreateAttributeSpec( + layer_, preview_surface_shader_spec, kTokens->inputsDiffuseColor, pxr::SdfValueTypeNames->Color3f); // Find the main texture if specified. @@ -1051,17 +1048,18 @@ class ModelWriter { if (main_texture) { // Create the texture shader and connect it to the diffuse color // attribute. - const std::vector texture_diffuse_output_attrs = - AddTextureShader(material_path, main_texture->file->c_str(), - pxr::TfToken("diffuse"), uvmap_st_output_attr, - {kTokens->outputsRgb}); + const std::vector + texture_diffuse_output_attrs = + AddTextureShader(material_spec, main_texture->file->c_str(), + pxr::TfToken("diffuse"), uvmap_st_output_attr, + {kTokens->outputsRgb}); if (texture_diffuse_output_attrs.size() == 1) { - AddAttributeConnection(data_, diffuse_color_attr, + AddAttributeConnection(layer_, diffuse_color_attr, texture_diffuse_output_attrs[0]); } } else { // If no texture is specified, use the rgba diffuse color. - SetAttributeDefault(data_, diffuse_color_attr, + SetAttributeDefault(layer_, diffuse_color_attr, pxr::GfVec3f(material->rgba[0], material->rgba[1], material->rgba[2])); } @@ -1069,14 +1067,14 @@ class ModelWriter { void WriteMaterials() { // Create a scope for the meshes to keep things organized - pxr::SdfPath scope_path = - CreatePrimSpec(data_, body_paths_[kWorldIndex], kTokens->materialsScope, + auto scope = + CreatePrimSpec(layer_, body_paths_[kWorldIndex], kTokens->materialsScope, pxr::UsdGeomTokens->Scope); mjsMaterial *material = mjs_asMaterial(mjs_firstElement(spec_, mjOBJ_MATERIAL)); while (material) { - WriteMaterial(material, scope_path); + WriteMaterial(material, scope->GetPath()); material = mjs_asMaterial(mjs_nextElement(spec_, material->element)); } } @@ -1090,65 +1088,67 @@ class ModelWriter { const auto keyframe_name = pxr::TfToken(pxr::TfMakeValidIdentifier( name.empty() ? MjcPhysicsTokens->MjcKeyframe : name)); pxr::SdfPath keyframe_path = parent_path.AppendChild(keyframe_name); - if (!data_->HasSpec(keyframe_path)) { - CreatePrimSpec(data_, parent_path, keyframe_name, - pxr::MjcPhysicsTokens->MjcKeyframe); - } - auto set_attribute_data = [&](const pxr::SdfPath &attr_path, + auto keyframe_spec = + layer_->HasSpec(keyframe_path) + ? layer_->GetPrimAtPath(keyframe_path) + : CreatePrimSpec(layer_, parent_path, keyframe_name, + pxr::MjcPhysicsTokens->MjcKeyframe); + + auto set_attribute_data = [&](const pxr::SdfAttributeSpecHandle &attr_spec, const pxr::VtDoubleArray &value, mjsKey *keyframe) { // If the keyframe time is the default, and there are no other keyframes // set the attribute at the default time code. if (keyframe->time == 0 && keyframes.size() == 1) { - SetAttributeDefault(data_, attr_path, value); + SetAttributeDefault(layer_, attr_spec, value); } else { - SetAttributeTimeSample(data_, attr_path, keyframe->time, value); + SetAttributeTimeSample(layer_, attr_spec, keyframe->time, value); } }; for (auto *keyframe : keyframes) { - pxr::SdfPath qpos_attr_path = - CreateAttributeSpec(data_, keyframe_path, MjcPhysicsTokens->mjcQpos, + auto qpos_attr = + CreateAttributeSpec(layer_, keyframe_spec, MjcPhysicsTokens->mjcQpos, pxr::SdfValueTypeNames->DoubleArray); set_attribute_data( - qpos_attr_path, + qpos_attr, pxr::VtDoubleArray(keyframe->qpos->begin(), keyframe->qpos->end()), keyframe); - pxr::SdfPath qvel_attr_path = - CreateAttributeSpec(data_, keyframe_path, MjcPhysicsTokens->mjcQvel, + auto qvel_attr = + CreateAttributeSpec(layer_, keyframe_spec, MjcPhysicsTokens->mjcQvel, pxr::SdfValueTypeNames->DoubleArray); set_attribute_data( - qvel_attr_path, + qvel_attr, pxr::VtDoubleArray(keyframe->qvel->begin(), keyframe->qvel->end()), keyframe); - pxr::SdfPath act_attr_path = - CreateAttributeSpec(data_, keyframe_path, MjcPhysicsTokens->mjcAct, + auto act_attr = + CreateAttributeSpec(layer_, keyframe_spec, MjcPhysicsTokens->mjcAct, pxr::SdfValueTypeNames->DoubleArray); set_attribute_data( - act_attr_path, + act_attr, pxr::VtDoubleArray(keyframe->act->begin(), keyframe->act->end()), keyframe); - pxr::SdfPath ctrl_attr_path = - CreateAttributeSpec(data_, keyframe_path, MjcPhysicsTokens->mjcCtrl, + auto ctrl_attr = + CreateAttributeSpec(layer_, keyframe_spec, MjcPhysicsTokens->mjcCtrl, pxr::SdfValueTypeNames->DoubleArray); set_attribute_data( - ctrl_attr_path, + ctrl_attr, pxr::VtDoubleArray(keyframe->ctrl->begin(), keyframe->ctrl->end()), keyframe); - pxr::SdfPath mpos_attr_path = - CreateAttributeSpec(data_, keyframe_path, MjcPhysicsTokens->mjcMpos, + auto mpos_attr = + CreateAttributeSpec(layer_, keyframe_spec, MjcPhysicsTokens->mjcMpos, pxr::SdfValueTypeNames->DoubleArray); set_attribute_data( - mpos_attr_path, + mpos_attr, pxr::VtDoubleArray(keyframe->mpos->begin(), keyframe->mpos->end()), keyframe); - pxr::SdfPath mquat_attr_path = - CreateAttributeSpec(data_, keyframe_path, MjcPhysicsTokens->mjcMquat, + auto mquat_attr_path = + CreateAttributeSpec(layer_, keyframe_spec, MjcPhysicsTokens->mjcMquat, pxr::SdfValueTypeNames->DoubleArray); set_attribute_data( mquat_attr_path, @@ -1168,19 +1168,22 @@ class ModelWriter { keyframe = mjs_asKey(mjs_nextElement(spec_, keyframe->element)); } - pxr::SdfPath scope_path = - CreatePrimSpec(data_, body_paths_[kWorldIndex], kTokens->keyframesScope, + auto scope = + CreatePrimSpec(layer_, body_paths_[kWorldIndex], kTokens->keyframesScope, pxr::UsdGeomTokens->Scope); for (const auto &[keyframe_name, keyframes] : keyframes_map) { - WriteKeyframesWithName(keyframe_name, keyframes, scope_path); + WriteKeyframesWithName(keyframe_name, keyframes, scope->GetPath()); } } void WriteActuator(mjsActuator *actuator, const pxr::SdfPath &parent_path) { - pxr::TfToken valid_name = GetValidPrimName(*mjs_getName(actuator->element)); - pxr::SdfPath actuator_path = parent_path.AppendChild(valid_name); - if (!data_->HasSpec(actuator_path)) { - CreatePrimSpec(data_, parent_path, valid_name, + const pxr::TfToken valid_name = GetValidPrimName(*mjs_getName(actuator->element)); + const pxr::SdfPath actuator_path = parent_path.AppendChild(valid_name); + pxr::SdfPrimSpecHandle actuator_spec; + if (layer_->HasSpec(actuator_path)) { + actuator_spec = layer_->GetPrimAtPath(actuator_path); + } else { + actuator_spec = CreatePrimSpec(layer_, parent_path, valid_name, pxr::MjcPhysicsTokens->MjcActuator); } @@ -1202,17 +1205,17 @@ class ModelWriter { return; } - CreateRelationshipSpec(data_, actuator_path, MjcPhysicsTokens->mjcTarget, + CreateRelationshipSpec(layer_, actuator_spec, MjcPhysicsTokens->mjcTarget, target_path, pxr::SdfVariabilityUniform); - WriteUniformAttribute(actuator_path, pxr::SdfValueTypeNames->Int, + WriteUniformAttribute(actuator_spec, pxr::SdfValueTypeNames->Int, MjcPhysicsTokens->mjcGroup, actuator->group); if (!actuator->refsite->empty()) { int refsite_id = mj_name2id(model_, mjOBJ_SITE, actuator->refsite->c_str()); pxr::SdfPath refsite_path = site_paths_[refsite_id]; - CreateRelationshipSpec(data_, actuator_path, MjcPhysicsTokens->mjcRefSite, + CreateRelationshipSpec(layer_, actuator_spec, MjcPhysicsTokens->mjcRefSite, refsite_path, pxr::SdfVariabilityUniform); } @@ -1220,7 +1223,7 @@ class ModelWriter { int slidersite_id = mj_name2id(model_, mjOBJ_SITE, actuator->slidersite->c_str()); pxr::SdfPath slidersite_path = site_paths_[slidersite_id]; - CreateRelationshipSpec(data_, actuator_path, + CreateRelationshipSpec(layer_, actuator_spec, MjcPhysicsTokens->mjcSliderSite, slidersite_path, pxr::SdfVariabilityUniform); } @@ -1237,7 +1240,7 @@ class ModelWriter { } else if (value == mjLIMITED_FALSE) { limited_token = pxr::MjcPhysicsTokens->false_; } - WriteUniformAttribute(actuator_path, pxr::SdfValueTypeNames->Token, token, + WriteUniformAttribute(actuator_spec, pxr::SdfValueTypeNames->Token, token, limited_token); } @@ -1254,21 +1257,21 @@ class ModelWriter { {MjcPhysicsTokens->mjcCrankLength, actuator->cranklength}, }; for (const auto &[token, value] : actuator_double_attributes) { - WriteUniformAttribute(actuator_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(actuator_spec, pxr::SdfValueTypeNames->Double, token, value); } - WriteUniformAttribute(actuator_path, pxr::SdfValueTypeNames->Int, + WriteUniformAttribute(actuator_spec, pxr::SdfValueTypeNames->Int, MjcPhysicsTokens->mjcActDim, actuator->actdim); - WriteUniformAttribute(actuator_path, pxr::SdfValueTypeNames->Bool, + WriteUniformAttribute(actuator_spec, pxr::SdfValueTypeNames->Bool, MjcPhysicsTokens->mjcActEarly, (bool)actuator->actearly); - WriteUniformAttribute(actuator_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(actuator_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcInheritRange, actuator->inheritrange); WriteUniformAttribute( - actuator_path, pxr::SdfValueTypeNames->DoubleArray, + actuator_spec, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcGear, pxr::VtDoubleArray(actuator->gear, actuator->gear + 6)); @@ -1286,10 +1289,10 @@ class ModelWriter { } else if (actuator->dyntype == mjtDyn::mjDYN_USER) { dyn_type = MjcPhysicsTokens->user; } - WriteUniformAttribute(actuator_path, pxr::SdfValueTypeNames->Token, + WriteUniformAttribute(actuator_spec, pxr::SdfValueTypeNames->Token, MjcPhysicsTokens->mjcDynType, dyn_type); WriteUniformAttribute( - actuator_path, pxr::SdfValueTypeNames->DoubleArray, + actuator_spec, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcDynPrm, pxr::VtDoubleArray(actuator->dynprm, actuator->dynprm + 10)); @@ -1303,10 +1306,10 @@ class ModelWriter { } else if (actuator->gaintype == mjtGain::mjGAIN_USER) { gain_type = MjcPhysicsTokens->user; } - WriteUniformAttribute(actuator_path, pxr::SdfValueTypeNames->Token, + WriteUniformAttribute(actuator_spec, pxr::SdfValueTypeNames->Token, MjcPhysicsTokens->mjcGainType, gain_type); WriteUniformAttribute( - actuator_path, pxr::SdfValueTypeNames->DoubleArray, + actuator_spec, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcGainPrm, pxr::VtDoubleArray(actuator->gainprm, actuator->gainprm + 10)); @@ -1320,108 +1323,108 @@ class ModelWriter { } else if (actuator->biastype == mjtBias::mjBIAS_USER) { bias_type = MjcPhysicsTokens->user; } - WriteUniformAttribute(actuator_path, pxr::SdfValueTypeNames->Token, + WriteUniformAttribute(actuator_spec, pxr::SdfValueTypeNames->Token, MjcPhysicsTokens->mjcBiasType, bias_type); WriteUniformAttribute( - actuator_path, pxr::SdfValueTypeNames->DoubleArray, + actuator_spec, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcBiasPrm, pxr::VtDoubleArray(actuator->biasprm, actuator->biasprm + 10)); } void WriteActuators() { - pxr::SdfPath scope_path = - CreatePrimSpec(data_, body_paths_[kWorldIndex], kTokens->actuatorsScope, + auto scope = + CreatePrimSpec(layer_, body_paths_[kWorldIndex], kTokens->actuatorsScope, pxr::UsdGeomTokens->Scope); mjsActuator *actuator = mjs_asActuator(mjs_firstElement(spec_, mjOBJ_ACTUATOR)); while (actuator) { - WriteActuator(actuator, scope_path); + WriteActuator(actuator, scope->GetPath()); actuator = mjs_asActuator(mjs_nextElement(spec_, actuator->element)); } } - pxr::SdfPath WriteMeshGeom(const mjsGeom *geom, + pxr::SdfPrimSpecHandle WriteMeshGeom(const mjsGeom *geom, const pxr::SdfPath &body_path) { std::string mj_name = mjs_getName(geom->element)->empty() ? *geom->meshname : *mjs_getName(geom->element); auto name = GetAvailablePrimName(mj_name, pxr::UsdGeomTokens->Mesh, body_path); - pxr::SdfPath subcomponent_path = - CreatePrimSpec(data_, body_path, name, pxr::UsdGeomTokens->Xform); + auto subcomponent_spec = + CreatePrimSpec(layer_, body_path, name, pxr::UsdGeomTokens->Xform); // Reference the mesh asset written in WriteMeshes. - AddPrimReference(data_, subcomponent_path, mesh_paths_[*geom->meshname]); + AddPrimReference(layer_, subcomponent_spec, mesh_paths_[*geom->meshname]); // We want to use instancing with meshes, and it requires creating a parent // scope to be referenced, with the Mesh prim as a child. // To be able to actually manipulate the Mesh prim, we need to create and // return the corresponding `over` prim as a child of the referencing prim. - pxr::SdfPath over_mesh_path = - CreatePrimSpec(data_, subcomponent_path, kTokens->sourceMesh, + auto over_mesh_spec = + CreatePrimSpec(layer_, subcomponent_spec->GetPath(), kTokens->sourceMesh, pxr::UsdGeomTokens->Mesh, pxr::SdfSpecifierOver); - return over_mesh_path; + return over_mesh_spec; } - pxr::SdfPath WriteSiteGeom(const mjsSite *site, + pxr::SdfPrimSpecHandle WriteSiteGeom(const mjsSite *site, const pxr::SdfPath &body_path) { auto name = GetAvailablePrimName(*mjs_getName(site->element), pxr::UsdGeomTokens->Cube, body_path); int site_idx = mjs_getId(site->element); const mjtNum *size = &model_->site_size[site_idx * 3]; - pxr::SdfPath site_path; + pxr::SdfPrimSpecHandle site_spec; switch (site->type) { case mjGEOM_BOX: - site_path = WriteBox(name, size, body_path); + site_spec = WriteBox(name, size, body_path); break; case mjGEOM_SPHERE: - site_path = WriteSphere(name, size, body_path); + site_spec = WriteSphere(name, size, body_path); break; case mjGEOM_CAPSULE: - site_path = WriteCapsule(name, size, body_path); + site_spec = WriteCapsule(name, size, body_path); break; case mjGEOM_CYLINDER: - site_path = WriteCylinder(name, size, body_path); + site_spec = WriteCylinder(name, size, body_path); break; case mjGEOM_ELLIPSOID: - site_path = WriteEllipsoid(name, size, body_path); + site_spec = WriteEllipsoid(name, size, body_path); break; default: break; } - return site_path; + return site_spec; } - pxr::SdfPath WriteBox(const pxr::TfToken &name, const mjtNum *size, + pxr::SdfPrimSpecHandle WriteBox(const pxr::TfToken &name, const mjtNum *size, const pxr::SdfPath &body_path) { - pxr::SdfPath box_path = - CreatePrimSpec(data_, body_path, name, pxr::UsdGeomTokens->Cube); + pxr::SdfPrimSpecHandle box_spec = + CreatePrimSpec(layer_, body_path, name, pxr::UsdGeomTokens->Cube); // 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, + auto size_attr_spec = + CreateAttributeSpec(layer_, box_spec, pxr::UsdGeomTokens->size, pxr::SdfValueTypeNames->Double); - SetAttributeDefault(data_, size_attr_path, 2.0); + SetAttributeDefault(layer_, size_attr_spec, 2.0); - pxr::SdfPath extent_attr_path = - CreateAttributeSpec(data_, box_path, pxr::UsdGeomTokens->extent, + auto extent_attr_spec = + CreateAttributeSpec(layer_, box_spec, pxr::UsdGeomTokens->extent, pxr::SdfValueTypeNames->Float3Array); - SetAttributeDefault(data_, extent_attr_path, + SetAttributeDefault(layer_, extent_attr_spec, 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, + WriteScaleXformOp(box_spec, scale); + WriteXformOpOrder(box_spec, pxr::VtArray{kTokens->xformOpScale}); - return box_path; + return box_spec; } - pxr::SdfPath WriteBoxGeom(const mjsGeom *geom, + pxr::SdfPrimSpecHandle WriteBoxGeom(const mjsGeom *geom, const pxr::SdfPath &body_path) { auto name = GetAvailablePrimName(*mjs_getName(geom->element), pxr::UsdGeomTokens->Cube, body_path); @@ -1431,25 +1434,25 @@ class ModelWriter { return WriteBox(name, geom_size, body_path); } - pxr::SdfPath WriteCapsule(const pxr::TfToken name, const mjtNum *size, + pxr::SdfPrimSpecHandle WriteCapsule(const pxr::TfToken name, const mjtNum *size, const pxr::SdfPath &body_path) { - pxr::SdfPath capsule_path = - CreatePrimSpec(data_, body_path, name, pxr::UsdGeomTokens->Capsule); + auto capsule_spec = + CreatePrimSpec(layer_, body_path, name, pxr::UsdGeomTokens->Capsule); - pxr::SdfPath radius_attr_path = - CreateAttributeSpec(data_, capsule_path, pxr::UsdGeomTokens->radius, + auto radius_attr_spec = + CreateAttributeSpec(layer_, capsule_spec, pxr::UsdGeomTokens->radius, pxr::SdfValueTypeNames->Double); - SetAttributeDefault(data_, radius_attr_path, (double)size[0]); + SetAttributeDefault(layer_, radius_attr_spec, (double)size[0]); - pxr::SdfPath height_attr_path = - CreateAttributeSpec(data_, capsule_path, pxr::UsdGeomTokens->height, + auto height_attr_spec = + CreateAttributeSpec(layer_, capsule_spec, pxr::UsdGeomTokens->height, pxr::SdfValueTypeNames->Double); // MuJoCo uses half sizes. - SetAttributeDefault(data_, height_attr_path, (double)(size[1] * 2)); - return capsule_path; + SetAttributeDefault(layer_, height_attr_spec, (double)(size[1] * 2)); + return capsule_spec; } - pxr::SdfPath WriteCapsuleGeom(const mjsGeom *geom, + pxr::SdfPrimSpecHandle WriteCapsuleGeom(const mjsGeom *geom, const pxr::SdfPath &body_path) { auto name = GetAvailablePrimName(*mjs_getName(geom->element), pxr::UsdGeomTokens->Capsule, body_path); @@ -1459,25 +1462,25 @@ class ModelWriter { return WriteCapsule(name, geom_size, body_path); } - pxr::SdfPath WriteCylinder(const pxr::TfToken name, const mjtNum *size, + pxr::SdfPrimSpecHandle WriteCylinder(const pxr::TfToken name, const mjtNum *size, const pxr::SdfPath &body_path) { - pxr::SdfPath cylinder_path = - CreatePrimSpec(data_, body_path, name, pxr::UsdGeomTokens->Cylinder); + auto cylinder_spec = + CreatePrimSpec(layer_, body_path, name, pxr::UsdGeomTokens->Cylinder); - pxr::SdfPath radius_attr_path = - CreateAttributeSpec(data_, cylinder_path, pxr::UsdGeomTokens->radius, + auto radius_attr_spec = + CreateAttributeSpec(layer_, cylinder_spec, pxr::UsdGeomTokens->radius, pxr::SdfValueTypeNames->Double); - SetAttributeDefault(data_, radius_attr_path, (double)size[0]); + SetAttributeDefault(layer_, radius_attr_spec, (double)size[0]); - pxr::SdfPath height_attr_path = - CreateAttributeSpec(data_, cylinder_path, pxr::UsdGeomTokens->height, + auto height_attr_spec = + CreateAttributeSpec(layer_, cylinder_spec, pxr::UsdGeomTokens->height, pxr::SdfValueTypeNames->Double); // MuJoCo uses half sizes. - SetAttributeDefault(data_, height_attr_path, (double)(size[1] * 2)); - return cylinder_path; + SetAttributeDefault(layer_, height_attr_spec, (double)(size[1] * 2)); + return cylinder_spec; } - pxr::SdfPath WriteCylinderGeom(const mjsGeom *geom, + pxr::SdfPrimSpecHandle WriteCylinderGeom(const mjsGeom *geom, const pxr::SdfPath &body_path) { auto name = GetAvailablePrimName(*mjs_getName(geom->element), pxr::UsdGeomTokens->Cylinder, body_path); @@ -1487,27 +1490,27 @@ class ModelWriter { return WriteCylinder(name, geom_size, body_path); } - pxr::SdfPath WriteEllipsoid(const pxr::TfToken name, const mjtNum *size, + pxr::SdfPrimSpecHandle WriteEllipsoid(const pxr::TfToken name, const mjtNum *size, const pxr::SdfPath &body_path) { - pxr::SdfPath ellipsoid_path = - CreatePrimSpec(data_, body_path, name, pxr::UsdGeomTokens->Sphere); + auto ellipsoid_spec = + CreatePrimSpec(layer_, body_path, name, pxr::UsdGeomTokens->Sphere); pxr::GfVec3f scale = {static_cast(size[0]), static_cast(size[1]), static_cast(size[2])}; - pxr::SdfPath radius_attr_path = - CreateAttributeSpec(data_, ellipsoid_path, pxr::UsdGeomTokens->radius, + auto radius_attr_spec = + CreateAttributeSpec(layer_, ellipsoid_spec, pxr::UsdGeomTokens->radius, pxr::SdfValueTypeNames->Double); - SetAttributeDefault(data_, radius_attr_path, 1.0); + SetAttributeDefault(layer_, radius_attr_spec, 1.0); - WriteScaleXformOp(ellipsoid_path, scale); - WriteXformOpOrder(ellipsoid_path, + WriteScaleXformOp(ellipsoid_spec, scale); + WriteXformOpOrder(ellipsoid_spec, pxr::VtArray{kTokens->xformOpScale}); - return ellipsoid_path; + return ellipsoid_spec; } - pxr::SdfPath WriteEllipsoidGeom(const mjsGeom *geom, + pxr::SdfPrimSpecHandle WriteEllipsoidGeom(const mjsGeom *geom, const pxr::SdfPath &body_path) { auto name = GetAvailablePrimName(*mjs_getName(geom->element), pxr::UsdGeomTokens->Sphere, body_path); @@ -1517,19 +1520,19 @@ class ModelWriter { return WriteEllipsoid(name, geom_size, body_path); } - pxr::SdfPath WriteSphere(const pxr::TfToken name, const mjtNum *size, + pxr::SdfPrimSpecHandle WriteSphere(const pxr::TfToken name, const mjtNum *size, const pxr::SdfPath &body_path) { - pxr::SdfPath sphere_path = - CreatePrimSpec(data_, body_path, name, pxr::UsdGeomTokens->Sphere); + auto sphere_spec = + CreatePrimSpec(layer_, body_path, name, pxr::UsdGeomTokens->Sphere); - pxr::SdfPath radius_attr_path = - CreateAttributeSpec(data_, sphere_path, pxr::UsdGeomTokens->radius, + auto radius_attr_spec = + CreateAttributeSpec(layer_, sphere_spec, pxr::UsdGeomTokens->radius, pxr::SdfValueTypeNames->Double); - SetAttributeDefault(data_, radius_attr_path, (double)size[0]); - return sphere_path; + SetAttributeDefault(layer_, radius_attr_spec, (double)size[0]); + return sphere_spec; } - pxr::SdfPath WriteSphereGeom(const mjsGeom *geom, + pxr::SdfPrimSpecHandle WriteSphereGeom(const mjsGeom *geom, const pxr::SdfPath &body_path) { auto name = GetAvailablePrimName(*mjs_getName(geom->element), pxr::UsdGeomTokens->Sphere, body_path); @@ -1538,10 +1541,10 @@ class ModelWriter { return WriteSphere(name, geom_size, body_path); } - pxr::SdfPath WritePlane(const pxr::TfToken &name, const mjtNum *size, + pxr::SdfPrimSpecHandle WritePlane(const pxr::TfToken &name, const mjtNum *size, const pxr::SdfPath &body_path) { - pxr::SdfPath plane_path = - CreatePrimSpec(data_, body_path, name, pxr::UsdGeomTokens->Plane); + auto plane_spec = + CreatePrimSpec(layer_, body_path, name, pxr::UsdGeomTokens->Plane); // MuJoCo uses half sizes. // Note that UsdGeomPlane is infinite for simulation purposes but can have @@ -1549,24 +1552,24 @@ class ModelWriter { double width = size[0] * 2.0; double length = size[1] * 2.0; - pxr::SdfPath width_attr_path = - CreateAttributeSpec(data_, plane_path, pxr::UsdGeomTokens->width, + auto width_attr_spec = + CreateAttributeSpec(layer_, plane_spec, pxr::UsdGeomTokens->width, pxr::SdfValueTypeNames->Double); - SetAttributeDefault(data_, width_attr_path, width); + SetAttributeDefault(layer_, width_attr_spec, width); - pxr::SdfPath length_attr_path = - CreateAttributeSpec(data_, plane_path, pxr::UsdGeomTokens->length, + auto length_attr_spec = + CreateAttributeSpec(layer_, plane_spec, pxr::UsdGeomTokens->length, pxr::SdfValueTypeNames->Double); - SetAttributeDefault(data_, length_attr_path, length); + SetAttributeDefault(layer_, length_attr_spec, length); // MuJoCo plane is always a XY plane with +Z up. // UsdGeomPlane is also a XY plane if axis is 'Z', which is default. // So no need to set axis attribute explicitly. - return plane_path; + return plane_spec; } - pxr::SdfPath WritePlaneGeom(const mjsGeom *geom, + pxr::SdfPrimSpecHandle WritePlaneGeom(const mjsGeom *geom, const pxr::SdfPath &body_path) { auto name = GetAvailablePrimName(*mjs_getName(geom->element), pxr::UsdGeomTokens->Plane, body_path); @@ -1583,54 +1586,54 @@ class ModelWriter { // Create a geom primitive and set its purpose to guide so it won't be // rendered. - pxr::SdfPath site_path = WriteSiteGeom(site, body_path); - SetPrimPurpose(data_, site_path, pxr::UsdGeomTokens->guide); + auto site_spec = WriteSiteGeom(site, body_path); + SetPrimPurpose(layer_, site_spec, pxr::UsdGeomTokens->guide); - ApplyApiSchema(data_, site_path, MjcPhysicsTokens->MjcSiteAPI); + ApplyApiSchema(layer_, site_spec, MjcPhysicsTokens->MjcSiteAPI); - WriteUniformAttribute(site_path, pxr::SdfValueTypeNames->Int, + WriteUniformAttribute(site_spec, pxr::SdfValueTypeNames->Int, MjcPhysicsTokens->mjcGroup, site->group); - WriteColorAndOpacityAttributes(site_path, site); + WriteColorAndOpacityAttributes(site_spec, site); int site_id = mjs_getId(site->element); auto transform = MujocoPosQuatToTransform(&model_->site_pos[3 * site_id], &model_->site_quat[4 * site_id]); - WriteTransformXformOp(site_path, transform); + WriteTransformXformOp(site_spec, transform); PrependToXformOpOrder( - site_path, pxr::VtArray{kTokens->xformOpTransform}); + site_spec, pxr::VtArray{kTokens->xformOpTransform}); - site_paths_[site_id] = site_path; + site_paths_[site_id] = site_spec->GetPath(); } void WriteGeom(mjsGeom *geom, const mjsBody *body) { const int body_id = mjs_getId(body->element); const auto &body_path = body_paths_[body_id]; - pxr::SdfPath geom_path; + pxr::SdfPrimSpecHandle geom_spec; int geom_id = mjs_getId(geom->element); switch (geom->type) { case mjGEOM_PLANE: - geom_path = WritePlaneGeom(geom, body_path); + geom_spec = WritePlaneGeom(geom, body_path); break; case mjGEOM_MESH: - geom_path = WriteMeshGeom(geom, body_path); + geom_spec = WriteMeshGeom(geom, body_path); break; case mjGEOM_BOX: - geom_path = WriteBoxGeom(geom, body_path); + geom_spec = WriteBoxGeom(geom, body_path); break; case mjGEOM_CAPSULE: - geom_path = WriteCapsuleGeom(geom, body_path); + geom_spec = WriteCapsuleGeom(geom, body_path); break; case mjGEOM_CYLINDER: - geom_path = WriteCylinderGeom(geom, body_path); + geom_spec = WriteCylinderGeom(geom, body_path); break; case mjGEOM_ELLIPSOID: - geom_path = WriteEllipsoidGeom(geom, body_path); + geom_spec = WriteEllipsoidGeom(geom, body_path); break; case mjGEOM_SPHERE: - geom_path = WriteSphereGeom(geom, body_path); + geom_spec = WriteSphereGeom(geom, body_path); break; default: TF_WARN(UnsupportedGeomTypeError, "Unsupported geom type for geom %d", @@ -1638,78 +1641,78 @@ class ModelWriter { return; } - WriteUniformAttribute(geom_path, pxr::SdfValueTypeNames->Int, + WriteUniformAttribute(geom_spec, pxr::SdfValueTypeNames->Int, MjcPhysicsTokens->mjcGroup, geom->group); if (model_->geom_contype[geom_id] == 0 && model_->geom_conaffinity[geom_id] == 0) { // If the geom is purely visual, apply the imageable API. - ApplyApiSchema(data_, geom_path, MjcPhysicsTokens->MjcImageableAPI); + ApplyApiSchema(layer_, geom_spec, MjcPhysicsTokens->MjcImageableAPI); } // Apply the physics schemas if we are writing physics and the // geom participates in collisions. if (model_->geom_contype[geom_id] != 0 || model_->geom_conaffinity[geom_id] != 0) { - ApplyApiSchema(data_, geom_path, + ApplyApiSchema(layer_, geom_spec, pxr::UsdPhysicsTokens->PhysicsCollisionAPI); - ApplyApiSchema(data_, geom_path, MjcPhysicsTokens->MjcCollisionAPI); + ApplyApiSchema(layer_, geom_spec, MjcPhysicsTokens->MjcCollisionAPI); WriteUniformAttribute( - geom_path, pxr::SdfValueTypeNames->Bool, + geom_spec, pxr::SdfValueTypeNames->Bool, MjcPhysicsTokens->mjcShellinertia, geom->typeinertia == mjtGeomInertia::mjINERTIA_SHELL); - WriteUniformAttribute(geom_path, pxr::SdfValueTypeNames->Int, + WriteUniformAttribute(geom_spec, pxr::SdfValueTypeNames->Int, MjcPhysicsTokens->mjcPriority, geom->priority); - WriteUniformAttribute(geom_path, pxr::SdfValueTypeNames->Int, + WriteUniformAttribute(geom_spec, pxr::SdfValueTypeNames->Int, MjcPhysicsTokens->mjcCondim, geom->condim); - WriteUniformAttribute(geom_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(geom_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcSolmix, geom->solmix); - WriteUniformAttribute(geom_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(geom_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcSolmix, geom->solmix); WriteUniformAttribute( - geom_path, pxr::SdfValueTypeNames->DoubleArray, + geom_spec, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcSolref, pxr::VtArray(geom->solref, geom->solref + mjNREF)); WriteUniformAttribute( - geom_path, pxr::SdfValueTypeNames->DoubleArray, + geom_spec, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcSolimp, pxr::VtArray(geom->solimp, geom->solimp + mjNIMP)); - WriteUniformAttribute(geom_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(geom_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcMargin, geom->margin); - WriteUniformAttribute(geom_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(geom_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcGap, geom->gap); if (geom->mass >= mjMINVAL || geom->density >= mjMINVAL) { - ApplyApiSchema(data_, geom_path, pxr::UsdPhysicsTokens->PhysicsMassAPI); + ApplyApiSchema(layer_, geom_spec, pxr::UsdPhysicsTokens->PhysicsMassAPI); } if (geom->mass >= mjMINVAL) { - pxr::SdfPath mass_attr = CreateAttributeSpec( - data_, geom_path, pxr::UsdPhysicsTokens->physicsMass, + auto mass_attr_spec = CreateAttributeSpec( + layer_, geom_spec, pxr::UsdPhysicsTokens->physicsMass, pxr::SdfValueTypeNames->Float, pxr::SdfVariabilityUniform); // Make sure to cast to float here since mjtNum might be a double. - SetAttributeDefault(data_, mass_attr, (float)geom->mass); + SetAttributeDefault(layer_, mass_attr_spec, (float)geom->mass); } // Even though density is not used for mass computation when mass exists // we want to retain the information anyways. if (geom->density >= mjMINVAL) { - pxr::SdfPath density_attr = CreateAttributeSpec( - data_, geom_path, pxr::UsdPhysicsTokens->physicsDensity, + auto density_attr_spec = CreateAttributeSpec( + layer_, geom_spec, pxr::UsdPhysicsTokens->physicsDensity, pxr::SdfValueTypeNames->Float, pxr::SdfVariabilityUniform); // Make sure to cast to float here since mjtNum might be a double. - SetAttributeDefault(data_, density_attr, (float)geom->density); + SetAttributeDefault(layer_, density_attr_spec, (float)geom->density); } mjsDefault *geom_default = mjs_getDefault(geom->element); @@ -1717,48 +1720,48 @@ class ModelWriter { if (geom->friction[0] != geom_default->geom->friction[0] || geom->friction[1] != geom_default->geom->friction[1] || geom->friction[2] != geom_default->geom->friction[2]) { - pxr::SdfPath physics_material_path = WritePhysicsMaterial(geom); - ApplyApiSchema(data_, geom_path, - pxr::UsdShadeTokens->MaterialBindingAPI); + auto physics_material_spec = WritePhysicsMaterial(geom); + ApplyApiSchema(layer_, geom_spec, pxr::UsdShadeTokens->MaterialBindingAPI); // Bind the material to this geom. CreateRelationshipSpec( - data_, geom_path, pxr::UsdShadeTokens->materialBinding, - physics_material_path, pxr::SdfVariabilityUniform); + layer_, geom_spec, + pxr::UsdShadeTokens->materialBinding, physics_material_spec->GetPath(), + pxr::SdfVariabilityUniform); } // For meshes, also apply PhysicsMeshCollisionAPI and set the // approximation attribute. if (geom->type == mjGEOM_MESH) { - ApplyApiSchema(data_, geom_path, + ApplyApiSchema(layer_, geom_spec, pxr::UsdPhysicsTokens->PhysicsMeshCollisionAPI); // Note: MuJoCo documentation states that for collision purposes, meshes // are always replaced with their convex hulls. Therefore, we set the // approximation attribute to convexHull explicitly. - pxr::SdfPath approximation_attr = CreateAttributeSpec( - data_, geom_path, pxr::UsdPhysicsTokens->physicsApproximation, + auto approximation_attr_spec = CreateAttributeSpec( + layer_, geom_spec, pxr::UsdPhysicsTokens->physicsApproximation, pxr::SdfValueTypeNames->Token, pxr::SdfVariabilityUniform); - SetAttributeDefault(data_, approximation_attr, + SetAttributeDefault(layer_, approximation_attr_spec, pxr::UsdPhysicsTokens->convexHull); } } else { // Currently imageable only has a group API. But since it's the same // naming in MjcCollisionsAPI we've already set it earlier in this // function. - ApplyApiSchema(data_, geom_path, MjcPhysicsTokens->MjcImageableAPI); + ApplyApiSchema(layer_, geom_spec, MjcPhysicsTokens->MjcImageableAPI); } mjsDefault *spec_default = mjs_getDefault(geom->element); pxr::TfToken valid_class_name = GetValidPrimName(*mjs_getName(spec_default->element)); pxr::SdfPath geom_class_path = class_path_.AppendChild(valid_class_name); - if (!data_->HasSpec(geom_class_path)) { - pxr::SdfPath class_path = - CreateClassSpec(data_, class_path_, valid_class_name); - auto visibility_attr = - CreateAttributeSpec(data_, class_path, pxr::UsdGeomTokens->visibility, + if (!layer_->HasSpec(geom_class_path)) { + auto class_spec = + CreateClassSpec(layer_, class_path_, valid_class_name); + auto visibility_attr_spec = + CreateAttributeSpec(layer_, class_spec, pxr::UsdGeomTokens->visibility, pxr::SdfValueTypeNames->Token); - SetAttributeDefault(data_, visibility_attr, + SetAttributeDefault(layer_, visibility_attr_spec, pxr::UsdGeomTokens->inherited); } @@ -1768,30 +1771,30 @@ class ModelWriter { body_paths_[kWorldIndex] .AppendChild(kTokens->materialsScope) .AppendChild(GetValidPrimName(*geom->material)); - if (data_->HasSpec(material_path)) { - ApplyApiSchema(data_, geom_path, + if (layer_->HasSpec(material_path)) { + ApplyApiSchema(layer_, geom_spec, pxr::UsdShadeTokens->MaterialBindingAPI); // Bind the material to this geom. - CreateRelationshipSpec(data_, geom_path, + CreateRelationshipSpec(layer_, geom_spec, pxr::UsdShadeTokens->materialBinding, material_path, pxr::SdfVariabilityUniform); } } - WriteColorAndOpacityAttributes(geom_path, geom); + WriteColorAndOpacityAttributes(geom_spec, geom); if (body_id == kWorldIndex) { - SetPrimKind(data_, geom_path, pxr::KindTokens->component); + SetPrimKind(layer_, geom_spec, pxr::KindTokens->component); } // Inherit from class. - AddPrimInherit(data_, geom_path, geom_class_path); + AddPrimInherit(layer_, geom_spec, geom_class_path); auto transform = MujocoPosQuatToTransform(&model_->geom_pos[3 * geom_id], &model_->geom_quat[4 * geom_id]); - WriteTransformXformOp(geom_path, transform); + WriteTransformXformOp(geom_spec, transform); PrependToXformOpOrder( - geom_path, pxr::VtArray{kTokens->xformOpTransform}); + geom_spec, pxr::VtArray{kTokens->xformOpTransform}); } void WriteSites(mjsBody *body) { @@ -1869,7 +1872,7 @@ class ModelWriter { auto joint_name = joint ? *mjs_getName(joint->element) : "FixedJoint"; pxr::TfToken joint_name_token = GetAvailablePrimName(joint_name, kTokens->joint, body1_path_usd); - pxr::SdfPath joint_path = CreatePrimSpec(data_, body1_path_usd, + auto joint_spec = CreatePrimSpec(layer_, body1_path_usd, joint_name_token, joint_prim_type); // Set body0 and body1 relationships @@ -1877,11 +1880,11 @@ class ModelWriter { // keeping the body0 relationship empty. if (body0_id_usd != kWorldIndex) { const pxr::SdfPath &body0_path_usd = body_paths_[body0_id_usd]; - CreateRelationshipSpec(data_, joint_path, + CreateRelationshipSpec(layer_, joint_spec, pxr::UsdPhysicsTokens->physicsBody0, body0_path_usd, pxr::SdfVariabilityUniform); } - CreateRelationshipSpec(data_, joint_path, + CreateRelationshipSpec(layer_, joint_spec, pxr::UsdPhysicsTokens->physicsBody1, body1_path_usd, pxr::SdfVariabilityUniform); @@ -1900,23 +1903,23 @@ class ModelWriter { pxr::GfRotation(pxr::GfVec3f::ZAxis(), mj_jnt_axis).GetQuat()); SetAttributeDefault( - data_, - CreateAttributeSpec(data_, joint_path, + layer_, + CreateAttributeSpec(layer_, joint_spec, pxr::UsdPhysicsTokens->physicsLocalPos1, pxr::SdfValueTypeNames->Float3), local_pos1); if (joint_prim_type == pxr::UsdPhysicsTokens->PhysicsRevoluteJoint || joint_prim_type == pxr::UsdPhysicsTokens->PhysicsPrismaticJoint) { SetAttributeDefault( - data_, - CreateAttributeSpec(data_, joint_path, + layer_, + CreateAttributeSpec(layer_, joint_spec, pxr::UsdPhysicsTokens->physicsLocalRot1, pxr::SdfValueTypeNames->Quatf), local_rot1); } else { SetAttributeDefault( - data_, - CreateAttributeSpec(data_, joint_path, + layer_, + CreateAttributeSpec(layer_, joint_spec, pxr::UsdPhysicsTokens->physicsLocalRot1, pxr::SdfValueTypeNames->Quatf), pxr::GfQuatf::GetIdentity()); @@ -1934,8 +1937,8 @@ class ModelWriter { pxr::GfVec3f local_pos0(jnt_pos_parent_local); SetAttributeDefault( - data_, - CreateAttributeSpec(data_, joint_path, + layer_, + CreateAttributeSpec(layer_, joint_spec, pxr::UsdPhysicsTokens->physicsLocalPos0, pxr::SdfValueTypeNames->Float3), local_pos0); @@ -1947,8 +1950,8 @@ class ModelWriter { .GetQuat()); SetAttributeDefault( - data_, - CreateAttributeSpec(data_, joint_path, + layer_, + CreateAttributeSpec(layer_, joint_spec, pxr::UsdPhysicsTokens->physicsLocalRot0, pxr::SdfValueTypeNames->Quatf), other_rot0); @@ -1956,8 +1959,8 @@ class ModelWriter { // Fixed joints have no frame and no axis per se. We simply need the // rotation quaternion of the body its on. SetAttributeDefault( - data_, - CreateAttributeSpec(data_, joint_path, + layer_, + CreateAttributeSpec(layer_, joint_spec, pxr::UsdPhysicsTokens->physicsLocalRot0, pxr::SdfValueTypeNames->Quatf), body1_transform_local.ExtractRotationQuat()); @@ -1971,8 +1974,8 @@ class ModelWriter { // The joint motion occurs around/along the Z-axis of the joint frame // established by localRot0/1. SetAttributeDefault( - data_, - CreateAttributeSpec(data_, joint_path, + layer_, + CreateAttributeSpec(layer_, joint_spec, pxr::UsdPhysicsTokens->physicsAxis, pxr::SdfValueTypeNames->Token), pxr::UsdPhysicsTokens->z); // "Z" axis @@ -1988,27 +1991,27 @@ class ModelWriter { lower_limit *= (180.0 / mjPI); upper_limit *= (180.0 / mjPI); SetAttributeDefault( - data_, - CreateAttributeSpec(data_, joint_path, + layer_, + CreateAttributeSpec(layer_, joint_spec, pxr::UsdPhysicsTokens->physicsLowerLimit, pxr::SdfValueTypeNames->Float), lower_limit); SetAttributeDefault( - data_, - CreateAttributeSpec(data_, joint_path, + layer_, + CreateAttributeSpec(layer_, joint_spec, pxr::UsdPhysicsTokens->physicsUpperLimit, pxr::SdfValueTypeNames->Float), upper_limit); } else if (type == mjJNT_SLIDE) { SetAttributeDefault( - data_, - CreateAttributeSpec(data_, joint_path, + layer_, + CreateAttributeSpec(layer_, joint_spec, pxr::UsdPhysicsTokens->physicsLowerLimit, pxr::SdfValueTypeNames->Float), lower_limit); SetAttributeDefault( - data_, - CreateAttributeSpec(data_, joint_path, + layer_, + CreateAttributeSpec(layer_, joint_spec, pxr::UsdPhysicsTokens->physicsUpperLimit, pxr::SdfValueTypeNames->Float), upper_limit); @@ -2016,46 +2019,46 @@ class ModelWriter { } // Finally write the mjcPhysicsJointAPI attributes. - ApplyApiSchema(data_, joint_path, MjcPhysicsTokens->MjcJointAPI); + ApplyApiSchema(layer_, joint_spec, MjcPhysicsTokens->MjcJointAPI); - WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Int, + WriteUniformAttribute(joint_spec, pxr::SdfValueTypeNames->Int, MjcPhysicsTokens->mjcGroup, joint->group); WriteUniformAttribute( - joint_path, pxr::SdfValueTypeNames->DoubleArray, + joint_spec, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcSpringdamper, pxr::VtArray(joint->springdamper, joint->springdamper + 2)); - WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->DoubleArray, + WriteUniformAttribute(joint_spec, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcSolreflimit, pxr::VtArray(joint->solref_limit, joint->solref_limit + mjNREF)); - WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->DoubleArray, + WriteUniformAttribute(joint_spec, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcSolimplimit, pxr::VtArray(joint->solimp_limit, joint->solimp_limit + mjNIMP)); WriteUniformAttribute( - joint_path, pxr::SdfValueTypeNames->DoubleArray, + joint_spec, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcSolreffriction, pxr::VtArray(joint->solref_friction, joint->solref_friction + mjNREF)); WriteUniformAttribute( - joint_path, pxr::SdfValueTypeNames->DoubleArray, + joint_spec, pxr::SdfValueTypeNames->DoubleArray, MjcPhysicsTokens->mjcSolimpfriction, pxr::VtArray(joint->solimp_friction, joint->solimp_friction + mjNIMP)); - WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(joint_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcStiffness, joint->stiffness); - WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(joint_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcActuatorfrcrangeMin, joint->actfrcrange[0]); - WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(joint_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcActuatorfrcrangeMax, joint->actfrcrange[1]); @@ -2065,35 +2068,35 @@ class ModelWriter { } else if (joint->actfrclimited == mjLIMITED_FALSE) { actuatorfrclimited_token = MjcPhysicsTokens->false_; } - WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Token, + WriteUniformAttribute(joint_spec, pxr::SdfValueTypeNames->Token, MjcPhysicsTokens->mjcActuatorfrclimited, actuatorfrclimited_token); - WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Bool, + WriteUniformAttribute(joint_spec, pxr::SdfValueTypeNames->Bool, MjcPhysicsTokens->mjcActuatorgravcomp, static_cast(joint->actgravcomp)); - WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(joint_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcMargin, joint->margin); - WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(joint_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcRef, joint->ref); - WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(joint_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcSpringref, joint->springref); - WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(joint_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcArmature, joint->armature); - WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(joint_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcDamping, joint->damping); - WriteUniformAttribute(joint_path, pxr::SdfValueTypeNames->Double, + WriteUniformAttribute(joint_spec, pxr::SdfValueTypeNames->Double, MjcPhysicsTokens->mjcFrictionloss, joint->frictionloss); } if (joint_id >= 0) { - joint_paths_[joint_id] = joint_path; + joint_paths_[joint_id] = joint_spec->GetPath(); } } @@ -2103,14 +2106,14 @@ class ModelWriter { pxr::UsdGeomTokens->Camera, body_path); // Create a root Xform for the world body with the model name if it exists // otherwise called 'World'. - pxr::SdfPath camera_path = - CreatePrimSpec(data_, body_path, name, pxr::UsdGeomTokens->Camera); + auto camera_spec = + CreatePrimSpec(layer_, body_path, name, pxr::UsdGeomTokens->Camera); int cam_id = mjs_getId(spec_cam->element); auto transform = MujocoPosQuatToTransform(&model_->cam_pos[3 * cam_id], &model_->cam_quat[4 * cam_id]); - WriteTransformXformOp(camera_path, transform); - WriteXformOpOrder(camera_path, + WriteTransformXformOp(camera_spec, transform); + WriteXformOpOrder(camera_spec, pxr::VtArray{kTokens->xformOpTransform}); // If the camera intrinsics are specified, then it is important that we @@ -2134,15 +2137,15 @@ class ModelWriter { (cam_sensorsize[0] / 2.f - cam_intrinsic[2]) : vertical_apperture * aspect_ratio; - WriteUniformAttribute(camera_path, pxr::SdfValueTypeNames->Float2, + WriteUniformAttribute(camera_spec, pxr::SdfValueTypeNames->Float2, pxr::UsdGeomTokens->clippingRange, pxr::GfVec2f(znear, zfar)); - WriteUniformAttribute(camera_path, pxr::SdfValueTypeNames->Float, + WriteUniformAttribute(camera_spec, pxr::SdfValueTypeNames->Float, pxr::UsdGeomTokens->focalLength, znear); - WriteUniformAttribute(camera_path, pxr::SdfValueTypeNames->Float, + WriteUniformAttribute(camera_spec, pxr::SdfValueTypeNames->Float, pxr::UsdGeomTokens->verticalAperture, vertical_apperture); - WriteUniformAttribute(camera_path, pxr::SdfValueTypeNames->Float, + WriteUniformAttribute(camera_spec, pxr::SdfValueTypeNames->Float, pxr::UsdGeomTokens->horizontalAperture, horizontal_aperture); } @@ -2161,14 +2164,14 @@ class ModelWriter { kTokens->light, body_path); // Create a root Xform for the world body with the model name if it exists // otherwise called 'World'. - pxr::SdfPath light_path = - CreatePrimSpec(data_, body_path, name, pxr::UsdLuxTokens->SphereLight); + auto light_spec = + CreatePrimSpec(layer_, body_path, name, pxr::UsdLuxTokens->SphereLight); int light_id = mjs_getId(light->element); auto transform = MujocoPosQuatToTransform(&model_->light_pos[3 * light_id], &model_->light_dir[4 * light_id]); - WriteTransformXformOp(light_path, transform); - WriteXformOpOrder(light_path, + WriteTransformXformOp(light_spec, transform); + WriteXformOpOrder(light_spec, pxr::VtArray{kTokens->xformOpTransform}); } @@ -2189,13 +2192,13 @@ class ModelWriter { pxr::TfToken body_name = GetValidPrimName(*mjs_getName(body->element)); // Create Xform prim for body. - pxr::SdfPath body_path = CreatePrimSpec(data_, parent_path, body_name, + auto body_spec = CreatePrimSpec(layer_, parent_path, body_name, pxr::UsdGeomTokens->Xform); // The parent_path will be a component which makes the actual articulated // bodies subcomponents. auto kind = parent_id == kWorldIndex ? pxr::KindTokens->component : pxr::KindTokens->subcomponent; - SetPrimKind(data_, body_path, kind); + SetPrimKind(layer_, body_spec, 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. @@ -2205,7 +2208,7 @@ class ModelWriter { // there are multiple children. if (parent_parent_id == kWorldIndex && articulation_roots_.find(parent_id) == articulation_roots_.end()) { - ApplyApiSchema(data_, parent_path, + ApplyApiSchema(layer_, layer_->GetPrimAtPath(parent_path), pxr::UsdPhysicsTokens->PhysicsArticulationRootAPI); articulation_roots_.insert(parent_id); } @@ -2224,32 +2227,32 @@ class ModelWriter { // User might have specified the inertia via fullinertia and the // compiler has extracted all values properly. So leverage those // instead of doing the computation ourselves here. - ApplyApiSchema(data_, body_path, pxr::UsdPhysicsTokens->PhysicsMassAPI); - WriteUniformAttribute(body_path, pxr::SdfValueTypeNames->Float, + ApplyApiSchema(layer_, body_spec, pxr::UsdPhysicsTokens->PhysicsMassAPI); + WriteUniformAttribute(body_spec, pxr::SdfValueTypeNames->Float, pxr::UsdPhysicsTokens->physicsMass, (float)model_->body_mass[body_id]); mjtNum *body_ipos = &model_->body_ipos[body_id * 3]; pxr::GfVec3f inertial_pos(body_ipos[0], body_ipos[1], body_ipos[2]); - WriteUniformAttribute(body_path, pxr::SdfValueTypeNames->Point3f, + WriteUniformAttribute(body_spec, pxr::SdfValueTypeNames->Point3f, pxr::UsdPhysicsTokens->physicsCenterOfMass, inertial_pos); mjtNum *body_iquat = &model_->body_iquat[body_id * 4]; pxr::GfQuatf inertial_frame(body_iquat[0], body_iquat[1], body_iquat[2], body_iquat[3]); - WriteUniformAttribute(body_path, pxr::SdfValueTypeNames->Quatf, + WriteUniformAttribute(body_spec, pxr::SdfValueTypeNames->Quatf, pxr::UsdPhysicsTokens->physicsPrincipalAxes, inertial_frame); mjtNum *inertia = &model_->body_inertia[body_id * 3]; pxr::GfVec3f diag_inertia(inertia[0], inertia[1], inertia[2]); - WriteUniformAttribute(body_path, pxr::SdfValueTypeNames->Float3, + WriteUniformAttribute(body_spec, pxr::SdfValueTypeNames->Float3, pxr::UsdPhysicsTokens->physicsDiagonalInertia, diag_inertia); } - ApplyApiSchema(data_, body_path, + ApplyApiSchema(layer_, body_spec, pxr::UsdPhysicsTokens->PhysicsRigidBodyAPI); // Create classes if necessary @@ -2258,32 +2261,31 @@ class ModelWriter { pxr::TfToken body_class_name = GetValidPrimName(*mjs_getName(spec_default->element)); pxr::SdfPath body_class_path = class_path_.AppendChild(body_class_name); - if (!data_->HasSpec(body_class_path)) { - CreateClassSpec(data_, class_path_, body_class_name); + if (!layer_->HasSpec(body_class_path)) { + CreateClassSpec(layer_, class_path_, body_class_name); } // Create XformOp attribute for body transform. - pxr::SdfPath xform_op_path = - CreateAttributeSpec(data_, body_path, kTokens->xformOpTransform, + auto xform_op_spec = + CreateAttributeSpec(layer_, body_spec, kTokens->xformOpTransform, pxr::SdfValueTypeNames->Matrix4d); // mjModel will have all frames already accounted for so no need to worry // about them here. auto body_xform = MujocoPosQuatToTransform(&model_->body_pos[body_id * 3], &model_->body_quat[body_id * 4]); - SetAttributeDefault(data_, xform_op_path, body_xform); + SetAttributeDefault(layer_, xform_op_spec, body_xform); // Create XformOpOrder attribute for body transform order. // For us this is simply the transform we authored above. - WriteXformOpOrder(body_path, + WriteXformOpOrder(body_spec, pxr::VtArray{kTokens->xformOpTransform}); pxr::VtDictionary customData; customData[kTokens->body_name] = *mjs_getName(body->element); - SetPrimMetadata(data_, body_path, pxr::SdfFieldKeys->CustomData, - customData); + body_spec->SetField(pxr::SdfFieldKeys->CustomData, customData); - body_paths_[body_id] = body_path; + body_paths_[body_id] = body_spec->GetPath(); } void WriteBodies() { @@ -2304,35 +2306,31 @@ class ModelWriter { } } - pxr::SdfPath WriteWorldBody(const size_t body_index) { + pxr::SdfPrimSpecHandle WriteWorldBody(const size_t body_index) { // Create a root Xform for the world body with the model name if it exists // otherwise called 'World'. auto name = GetAvailablePrimName(*spec_->modelname, kTokens->world, pxr::SdfPath::AbsoluteRootPath()); - pxr::SdfPath world_group_path = - CreatePrimSpec(data_, pxr::SdfPath::AbsoluteRootPath(), name, + auto world_group_spec = + CreatePrimSpec(layer_, pxr::SdfPath::AbsoluteRootPath(), name, pxr::UsdGeomTokens->Xform); - SetPrimKind(data_, world_group_path, pxr::KindTokens->group); + SetPrimKind(layer_, world_group_spec, pxr::KindTokens->group); - return world_group_path; + return world_group_spec; } }; namespace mujoco { namespace usd { -bool WriteSpecToData(mjSpec *spec, pxr::SdfAbstractDataRefPtr &data) { - // Create pseudo root first. - data->CreateSpec(pxr::SdfPath::AbsoluteRootPath(), - pxr::SdfSpecTypePseudoRoot); - +bool WriteSpecToData(mjSpec *spec, pxr::SdfLayerRefPtr layer) { mjModel *model = mj_compile(spec, nullptr); if (model == nullptr) { TF_ERROR(MujocoCompilationError, "%s", mjs_getError(spec)); return false; } - ModelWriter(spec, model, data).Write(); + ModelWriter(spec, model, layer).Write(); return true; } diff --git a/src/experimental/usd/plugins/mjcf/mujoco_to_usd.h b/src/experimental/usd/plugins/mjcf/mujoco_to_usd.h index 4c5934c6..6c4205be 100644 --- a/src/experimental/usd/plugins/mjcf/mujoco_to_usd.h +++ b/src/experimental/usd/plugins/mjcf/mujoco_to_usd.h @@ -16,16 +16,16 @@ #define MUJOCO_SRC_EXPERIMENTAL_USD_PLUGINS_MJCF_MUJOCO_TO_USD_H_ #include -#include +#include namespace mujoco { namespace usd { -// Given an mjSpec, write it to a SdfAbstractData. +// Given an mjSpec, writes a USD representation of the data to the given layer. // // Args: // spec: mjSpec built programmatically or via parsed XML. -// data: SdfAbstractDataRefPtr that will be written to. -bool WriteSpecToData(mjSpec* spec, pxr::SdfAbstractDataRefPtr& data); +// layer: SdfLayerRefPtr that will be written to. +bool WriteSpecToData(mjSpec* spec, pxr::SdfLayerRefPtr layer); } // namespace usd } // namespace mujoco diff --git a/src/experimental/usd/plugins/mjcf/utils.cc b/src/experimental/usd/plugins/mjcf/utils.cc index db2eae85..b8c5f894 100644 --- a/src/experimental/usd/plugins/mjcf/utils.cc +++ b/src/experimental/usd/plugins/mjcf/utils.cc @@ -15,13 +15,16 @@ #include "mjcf/utils.h" #include -#include #include -#include +#include +#include +#include #include #include +#include #include +#include #include #include #include @@ -30,184 +33,122 @@ namespace { template -void AppendChild(pxr::SdfAbstractDataRefPtr& data, const pxr::SdfPath& specPath, - const pxr::TfToken& childKey, const T& child) { - // Get existing children. - std::vector children; - pxr::SdfAbstractDataTypedValue> getter(&children); - data->Has(specPath, childKey, &getter); - - children.push_back(child); - data->Set(specPath, childKey, - pxr::SdfAbstractDataConstTypedValue>(&children)); -} - -template -void AppendListOp(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& spec_path, const pxr::TfToken& field, +void AppendListOp(pxr::SdfLayerRefPtr layer, + const pxr::SdfPrimSpecHandle& prim_spec, const pxr::TfToken& field, const T& item) { - // Get existing list op. - pxr::SdfListOp list_op; - pxr::SdfAbstractDataTypedValue> getter(&list_op); - data->Has(spec_path, field, &getter); - - auto items = list_op.GetExplicitItems(); + pxr::SdfListOp listOp = + prim_spec->GetInfo(field).Get>(); + auto items = listOp.GetExplicitItems(); items.push_back(item); - list_op.SetExplicitItems(items); - data->Set(spec_path, field, - pxr::SdfAbstractDataConstTypedValue>(&list_op)); + listOp.SetExplicitItems(items); + prim_spec->SetInfo(field, pxr::VtValue::Take(listOp)); } template -void PrependListOp(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& spec_path, const pxr::TfToken& field, +void PrependListOp(pxr::SdfLayerRefPtr layer, + const pxr::SdfPrimSpecHandle& prim_spec, const pxr::TfToken& field, const T& item) { - // Get existing list op. - pxr::SdfListOp listOp; - pxr::SdfAbstractDataTypedValue> getter(&listOp); - data->Has(spec_path, field, &getter); - + pxr::SdfListOp listOp = + prim_spec->GetInfo(field).Get>(); auto prependedItems = listOp.GetPrependedItems(); prependedItems.insert(prependedItems.begin(), item); listOp.SetPrependedItems(prependedItems); - data->Set(spec_path, field, - pxr::SdfAbstractDataConstTypedValue>(&listOp)); + prim_spec->SetInfo(field, pxr::VtValue::Take(listOp)); } } // namespace namespace mujoco { namespace usd { -pxr::SdfPath CreatePrimSpec(pxr::SdfAbstractDataRefPtr& data, +pxr::SdfPrimSpecHandle CreatePrimSpec(pxr::SdfLayerRefPtr layer, const pxr::SdfPath& parent_path, const pxr::TfToken& name, const pxr::TfToken& type, pxr::SdfSpecifier specifier) { const pxr::SdfPath prim_path = parent_path.AppendChild(name); - data->CreateSpec(prim_path, pxr::SdfSpecTypePrim); - data->Set(prim_path, pxr::SdfFieldKeys->Specifier, - pxr::SdfAbstractDataConstTypedValue(&specifier)); + pxr::SdfPrimSpecHandle prim_spec = pxr::SdfCreatePrimInLayer(layer, prim_path); + layer->SetField(prim_path, pxr::SdfFieldKeys->Specifier, specifier); if (!type.IsEmpty()) { - data->Set(prim_path, pxr::SdfFieldKeys->TypeName, - pxr::SdfAbstractDataConstTypedValue(&type)); + layer->SetField(prim_path, pxr::SdfFieldKeys->TypeName, type); } - AppendChild(data, parent_path, pxr::SdfChildrenKeys->PrimChildren, name); - - return prim_path; + return prim_spec; } -pxr::SdfPath CreateAttributeSpec(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& prim_path, +pxr::SdfAttributeSpecHandle CreateAttributeSpec(pxr::SdfLayerRefPtr layer, + const pxr::SdfPrimSpecHandle& prim_spec, const pxr::TfToken& name, const pxr::SdfValueTypeName& type_name, pxr::SdfVariability variability) { - const pxr::SdfPath propertyPath = prim_path.AppendProperty(name); + const pxr::SdfPath propertyPath = prim_spec->GetPath().AppendProperty(name); // Early exit if the attribute spec already exists. - if (data->HasSpec(propertyPath)) { - return propertyPath; + if (layer->HasSpec(propertyPath)) { + return layer->GetAttributeAtPath(propertyPath); } - data->CreateSpec(propertyPath, pxr::SdfSpecTypeAttribute); + auto spec = pxr::SdfAttributeSpec::New(prim_spec, + name, type_name, variability); - pxr::TfToken typeNameToken = type_name.GetAsToken(); - data->Set(propertyPath, pxr::SdfFieldKeys->TypeName, - pxr::SdfAbstractDataConstTypedValue(&typeNameToken)); - if (variability != pxr::SdfVariabilityVarying) { - data->Set( - propertyPath, pxr::SdfFieldKeys->Variability, - pxr::SdfAbstractDataConstTypedValue(&variability)); - } - - AppendChild(data, prim_path, pxr::SdfChildrenKeys->PropertyChildren, name); - - return propertyPath; + return spec; } -pxr::SdfPath CreateRelationshipSpec(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& prim_path, +pxr::SdfRelationshipSpecHandle CreateRelationshipSpec(pxr::SdfLayerRefPtr layer, + const pxr::SdfPrimSpecHandle& prim_spec, const pxr::TfToken& relationship_name, const pxr::SdfPath& relationship_path, pxr::SdfVariability variability) { - pxr::SdfPath prop_path = prim_path.AppendProperty(relationship_name); - data->CreateSpec(prop_path, pxr::SdfSpecTypeRelationship); - if (variability != pxr::SdfVariabilityVarying) { - data->Set( - prop_path, pxr::SdfFieldKeys->Variability, - pxr::SdfAbstractDataConstTypedValue(&variability)); - } + auto spec = pxr::SdfRelationshipSpec::New(prim_spec, relationship_name); + spec->GetTargetPathList().Append(relationship_path); - AppendChild(data, prim_path, pxr::SdfChildrenKeys->PropertyChildren, - relationship_name); - - AppendChild(data, prop_path, pxr::SdfChildrenKeys->RelationshipTargetChildren, - relationship_path); - AppendListOp(data, prop_path, pxr::SdfFieldKeys->TargetPaths, - relationship_path); - - pxr::SdfPath target_path = prop_path.AppendTarget(relationship_path); - data->CreateSpec(target_path, pxr::SdfSpecTypeRelationshipTarget); - - return prop_path; + return spec; } -pxr::SdfPath CreateClassSpec(pxr::SdfAbstractDataRefPtr& data, +pxr::SdfPrimSpecHandle CreateClassSpec(pxr::SdfLayerRefPtr layer, const pxr::SdfPath& prim_path, const pxr::TfToken& class_name) { pxr::SdfPath class_path = prim_path.AppendChild(class_name); - pxr::SdfSpecifier class_specifier = pxr::SdfSpecifier::SdfSpecifierClass; - data->CreateSpec(class_path, pxr::SdfSpecTypePrim); - data->Set( - class_path, pxr::SdfFieldKeys->Specifier, - pxr::SdfAbstractDataConstTypedValue(&class_specifier)); + pxr::SdfPrimSpecHandle prim_spec = pxr::SdfCreatePrimInLayer(layer, class_path); + layer->SetField(class_path, pxr::SdfFieldKeys->Specifier, pxr::SdfSpecifier::SdfSpecifierClass); - AppendChild(data, prim_path, pxr::SdfChildrenKeys->PrimChildren, class_name); - - return class_path; + return prim_spec; } -void AddAttributeConnection(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& attribute_path, - const pxr::SdfPath& target_attribute_path) { - AppendChild(data, attribute_path, pxr::SdfChildrenKeys->ConnectionChildren, - target_attribute_path); - AppendListOp(data, attribute_path, pxr::SdfFieldKeys->ConnectionPaths, - target_attribute_path); - - data->CreateSpec(attribute_path.AppendTarget(target_attribute_path), - pxr::SdfSpecTypeConnection); +void AddAttributeConnection(pxr::SdfLayerRefPtr layer, + const pxr::SdfAttributeSpecHandle& attribute_spec, + const pxr::SdfAttributeSpecHandle& target_attribute_spec) { + attribute_spec->GetConnectionPathList().GetExplicitItems() = {target_attribute_spec->GetPath()}; } -void AddPrimReference(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& prim_path, +void AddPrimReference(pxr::SdfLayerRefPtr layer, + const pxr::SdfPrimSpecHandle& prim_spec, const pxr::SdfPath& referenced_prim_path) { - PrependListOp(data, prim_path, pxr::SdfFieldKeys->References, + PrependListOp(layer, prim_spec, pxr::SdfFieldKeys->References, pxr::SdfReference("", referenced_prim_path)); } -void AddPrimInherit(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& prim_path, +void AddPrimInherit(pxr::SdfLayerRefPtr layer, + const pxr::SdfPrimSpecHandle& prim_spec, const pxr::SdfPath& class_path) { - PrependListOp(data, prim_path, pxr::SdfFieldKeys->InheritPaths, class_path); + PrependListOp(layer, prim_spec, pxr::SdfFieldKeys->InheritPaths, class_path); } -void ApplyApiSchema(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& prim_path, +void ApplyApiSchema(pxr::SdfLayerRefPtr layer, + const pxr::SdfPrimSpecHandle& prim_spec, const pxr::TfToken& schema_name) { - PrependListOp(data, prim_path, pxr::UsdTokens->apiSchemas, schema_name); + PrependListOp(layer, prim_spec, pxr::UsdTokens->apiSchemas, schema_name); } -void SetPrimKind(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& prim_path, pxr::TfToken kind) { - SetPrimMetadata(data, prim_path, pxr::TfToken("kind"), kind); +void SetPrimKind(pxr::SdfLayerRefPtr layer, + const pxr::SdfPrimSpecHandle& prim_spec, pxr::TfToken kind) { + prim_spec->SetField(pxr::SdfFieldKeys->Kind, kind); } -void SetPrimPurpose(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& prim_path, pxr::TfToken purpose) { - const pxr::SdfPath attr_path = CreateAttributeSpec( - data, prim_path, pxr::UsdGeomTokens->purpose, +void SetPrimPurpose(pxr::SdfLayerRefPtr layer, + const pxr::SdfPrimSpecHandle& prim_spec, pxr::TfToken purpose) { + const pxr::SdfAttributeSpecHandle& attr = CreateAttributeSpec( + layer, prim_spec, pxr::UsdGeomTokens->purpose, pxr::SdfValueTypeNames->Token, pxr::SdfVariabilityUniform); - SetAttributeDefault(data, attr_path, purpose); + SetAttributeDefault(layer, attr, purpose); } } // namespace usd diff --git a/src/experimental/usd/plugins/mjcf/utils.h b/src/experimental/usd/plugins/mjcf/utils.h index 5b7ad71c..671963fb 100644 --- a/src/experimental/usd/plugins/mjcf/utils.h +++ b/src/experimental/usd/plugins/mjcf/utils.h @@ -15,11 +15,11 @@ #ifndef MUJOCO_SRC_EXPERIMENTAL_USD_PLUGINS_MJCF_UTILS_H_ #define MUJOCO_SRC_EXPERIMENTAL_USD_PLUGINS_MJCF_UTILS_H_ -#include - #include #include -#include +#include +#include +#include #include #include #include @@ -29,123 +29,97 @@ namespace mujoco { namespace usd { // Create a prim spec and append it as a child of parent_path. -pxr::SdfPath CreatePrimSpec( - pxr::SdfAbstractDataRefPtr& data, const pxr::SdfPath& parent_path, +pxr::SdfPrimSpecHandle CreatePrimSpec( + pxr::SdfLayerRefPtr layer, const pxr::SdfPath& parent_path, const pxr::TfToken& name, const pxr::TfToken& type = pxr::TfToken(), pxr::SdfSpecifier specifier = pxr::SdfSpecifier::SdfSpecifierDef); // Create an attribute spec and append it as a child of parent_path. // By default the attribute will be varying. -pxr::SdfPath CreateAttributeSpec( - pxr::SdfAbstractDataRefPtr& data, const pxr::SdfPath& prim_path, +pxr::SdfAttributeSpecHandle CreateAttributeSpec( + pxr::SdfLayerRefPtr layer, const pxr::SdfPrimSpecHandle& prim_spec, const pxr::TfToken& name, const pxr::SdfValueTypeName& type_name, pxr::SdfVariability variability = pxr::SdfVariabilityVarying); // Create a relationship spec and append it as a child of prim_path. -pxr::SdfPath CreateRelationshipSpec( - pxr::SdfAbstractDataRefPtr& data, const pxr::SdfPath& prim_path, +pxr::SdfRelationshipSpecHandle CreateRelationshipSpec( + pxr::SdfLayerRefPtr layer, const pxr::SdfPrimSpecHandle& prim_spec, const pxr::TfToken& relationship_name, const pxr::SdfPath& relationship_path, pxr::SdfVariability variability = pxr::SdfVariabilityVarying); -pxr::SdfPath CreateClassSpec(pxr::SdfAbstractDataRefPtr& data, +pxr::SdfPrimSpecHandle CreateClassSpec(pxr::SdfLayerRefPtr layer, const pxr::SdfPath& prim_path, const pxr::TfToken& class_name); -void AddAttributeConnection(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& attribute_path, - const pxr::SdfPath& target_attribute_path); +void AddAttributeConnection(pxr::SdfLayerRefPtr layer, + const pxr::SdfAttributeSpecHandle& attribute_spec, + const pxr::SdfAttributeSpecHandle& target_attribute_spec); -void AddPrimReference(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& prim_path, +void AddPrimReference(pxr::SdfLayerRefPtr layer, + const pxr::SdfPrimSpecHandle& prim_spec, const pxr::SdfPath& referenced_prim_path); -void AddPrimInherit(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& prim_path, +void AddPrimInherit(pxr::SdfLayerRefPtr layer, + const pxr::SdfPrimSpecHandle& prim_spec, const pxr::SdfPath& class_path); -void ApplyApiSchema(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& prim_path, +void ApplyApiSchema(pxr::SdfLayerRefPtr layer, + const pxr::SdfPrimSpecHandle& prim_spec, const pxr::TfToken& schema_name); -void SetPrimKind(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& prim_path, pxr::TfToken kind); +void SetPrimKind(pxr::SdfLayerRefPtr layer, + const pxr::SdfPrimSpecHandle& prim_spec, pxr::TfToken kind); -void SetPrimPurpose(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& prim_path, pxr::TfToken purpose); +void SetPrimPurpose(pxr::SdfLayerRefPtr layer, + const pxr::SdfPrimSpecHandle& prim_spec, pxr::TfToken purpose); // Set the value specified by key on any field at field_path. template -void SetField(pxr::SdfAbstractDataRefPtr& data, const pxr::SdfPath& field_path, +void SetField(pxr::SdfLayerRefPtr layer, const pxr::SdfPath& field_path, const pxr::TfToken key, T&& value) { - using Deduced = typename std::remove_reference_t; - const auto typed_val = pxr::SdfAbstractDataConstTypedValue(&value); - const pxr::SdfAbstractDataConstValue& untyped_val = typed_val; - - data->Set(field_path, key, untyped_val); + layer->SetField(field_path, key, value); } // Set the value specified by key on any field at field_path. template -void SetFieldTimeSample(pxr::SdfAbstractDataRefPtr& data, +void SetFieldTimeSample(pxr::SdfLayerRefPtr layer, const pxr::SdfPath& field_path, double time, T&& value) { - using Deduced = typename std::remove_reference_t; - const auto typed_val = pxr::SdfAbstractDataConstTypedValue(&value); - const pxr::SdfAbstractDataConstValue& untyped_val = typed_val; - - pxr::VtValue vt_value; - untyped_val.GetValue(&vt_value); - // NOTE: SetTimeSample doesn't accept an SdfAbstractDataConstValue yet. - data->SetTimeSample(field_path, time, vt_value); + layer->SetTimeSample(field_path, time, value); } + // Set the value specified by key on an attribute spec at attribute_path. template -void SetAttribute(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& attribute_path, const pxr::TfToken key, - T&& value) { - SetField(data, attribute_path, key, value); -} - -// Set the value specified by key on a prim spec at prim_path. -template -void SetPrimMetadata(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& prim_path, const pxr::TfToken key, - T&& value) { - SetAttribute(data, prim_path, key, value); -} - -// Set the value specified by key on an attribute spec at attribute_path. -template -void SetAttributeMetadata(pxr::SdfAbstractDataRefPtr& data, +void SetAttributeMetadata(pxr::SdfLayerRefPtr layer, const pxr::SdfPath& attribute_path, const pxr::TfToken key, T&& value) { - SetAttribute(data, attribute_path, key, value); + SetAttribute(layer, attribute_path, key, value); } // Set the default value on an attribute spec at attribute_path. template -void SetAttributeDefault(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& attribute_path, +void SetAttributeDefault(pxr::SdfLayerRefPtr layer, + const pxr::SdfAttributeSpecHandle& attribute, T&& default_value) { - SetAttribute(data, attribute_path, pxr::SdfFieldKeys->Default, default_value); + attribute->SetField(pxr::SdfFieldKeys->Default, default_value); } // Set the default value on an attribute spec at attribute_path. template -void SetAttributeTimeSample(pxr::SdfAbstractDataRefPtr& data, - const pxr::SdfPath& attribute_path, +void SetAttributeTimeSample(pxr::SdfLayerRefPtr layer, + const pxr::SdfAttributeSpecHandle& attr_spec, double time, T&& default_value) { - SetFieldTimeSample(data, attribute_path, time, default_value); + layer->SetTimeSample(attr_spec->GetPath(), time, default_value); } // Set the value specified by key on the root layer. template -void SetLayerMetadata(pxr::SdfAbstractDataRefPtr& data, const pxr::TfToken& key, +void SetLayerMetadata(pxr::SdfLayerRefPtr layer, const pxr::TfToken& key, T&& value) { - SetAttribute(data, pxr::SdfPath::AbsoluteRootPath(), key, value); + layer->SetField(pxr::SdfPath::AbsoluteRootPath(), key, value); } } // namespace usd