Add missing attributes to MjcCollisionAPI USD schema.

PiperOrigin-RevId: 783006362
Change-Id: I02d51190d62bb9460863025cd16360427afc70c4
This commit is contained in:
Sam Haves
2025-07-14 12:44:54 -07:00
committed by Copybara-Service
parent ef013a0633
commit e441868dad
9 changed files with 502 additions and 18 deletions
@@ -97,6 +97,83 @@ UsdAttribute MjcPhysicsCollisionAPI::CreateShellInertiaAttr(
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
}
UsdAttribute MjcPhysicsCollisionAPI::GetPriorityAttr() const {
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcPriority);
}
UsdAttribute MjcPhysicsCollisionAPI::CreatePriorityAttr(
VtValue const &defaultValue, bool writeSparsely) const {
return UsdSchemaBase::_CreateAttr(
MjcPhysicsTokens->mjcPriority, SdfValueTypeNames->Int,
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
}
UsdAttribute MjcPhysicsCollisionAPI::GetConDimAttr() const {
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcCondim);
}
UsdAttribute MjcPhysicsCollisionAPI::CreateConDimAttr(
VtValue const &defaultValue, bool writeSparsely) const {
return UsdSchemaBase::_CreateAttr(
MjcPhysicsTokens->mjcCondim, SdfValueTypeNames->Int,
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
}
UsdAttribute MjcPhysicsCollisionAPI::GetSolMixAttr() const {
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcSolmix);
}
UsdAttribute MjcPhysicsCollisionAPI::CreateSolMixAttr(
VtValue const &defaultValue, bool writeSparsely) const {
return UsdSchemaBase::_CreateAttr(
MjcPhysicsTokens->mjcSolmix, SdfValueTypeNames->Double,
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
}
UsdAttribute MjcPhysicsCollisionAPI::GetSolRefAttr() const {
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcSolref);
}
UsdAttribute MjcPhysicsCollisionAPI::CreateSolRefAttr(
VtValue const &defaultValue, bool writeSparsely) const {
return UsdSchemaBase::_CreateAttr(
MjcPhysicsTokens->mjcSolref, SdfValueTypeNames->DoubleArray,
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
}
UsdAttribute MjcPhysicsCollisionAPI::GetSolImpAttr() const {
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcSolimp);
}
UsdAttribute MjcPhysicsCollisionAPI::CreateSolImpAttr(
VtValue const &defaultValue, bool writeSparsely) const {
return UsdSchemaBase::_CreateAttr(
MjcPhysicsTokens->mjcSolimp, SdfValueTypeNames->DoubleArray,
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
}
UsdAttribute MjcPhysicsCollisionAPI::GetMarginAttr() const {
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcMargin);
}
UsdAttribute MjcPhysicsCollisionAPI::CreateMarginAttr(
VtValue const &defaultValue, bool writeSparsely) const {
return UsdSchemaBase::_CreateAttr(
MjcPhysicsTokens->mjcMargin, SdfValueTypeNames->Double,
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
}
UsdAttribute MjcPhysicsCollisionAPI::GetGapAttr() const {
return GetPrim().GetAttribute(MjcPhysicsTokens->mjcGap);
}
UsdAttribute MjcPhysicsCollisionAPI::CreateGapAttr(VtValue const &defaultValue,
bool writeSparsely) const {
return UsdSchemaBase::_CreateAttr(
MjcPhysicsTokens->mjcGap, SdfValueTypeNames->Double,
/* custom = */ false, SdfVariabilityUniform, defaultValue, writeSparsely);
}
namespace {
static inline TfTokenVector _ConcatenateAttributeNames(
const TfTokenVector &left, const TfTokenVector &right) {
@@ -112,8 +189,11 @@ static inline TfTokenVector _ConcatenateAttributeNames(
const TfTokenVector &MjcPhysicsCollisionAPI::GetSchemaAttributeNames(
bool includeInherited) {
static TfTokenVector localNames = {
MjcPhysicsTokens->mjcGroup,
MjcPhysicsTokens->mjcShellinertia,
MjcPhysicsTokens->mjcGroup, MjcPhysicsTokens->mjcShellinertia,
MjcPhysicsTokens->mjcPriority, MjcPhysicsTokens->mjcCondim,
MjcPhysicsTokens->mjcSolmix, MjcPhysicsTokens->mjcSolref,
MjcPhysicsTokens->mjcSolimp, MjcPhysicsTokens->mjcMargin,
MjcPhysicsTokens->mjcGap,
};
static TfTokenVector allNames = _ConcatenateAttributeNames(
UsdAPISchemaBase::GetSchemaAttributeNames(true), localNames);
@@ -234,14 +234,42 @@ class "MjcCollisionAPI" (
doc = "API describing a MuJoCo collider."
)
{
uniform int mjc:condim = 3 (
displayName = "ConDim"
doc = "The dimensionality of the contact space for a dynamically generated contact pair is set to the maximum of the condim values of the two participating geoms."
)
uniform double mjc:gap = 0 (
displayName = "Gap"
doc = "This attribute is used to enable the generation of inactive contacts, i.e., contacts that are ignored by the constraint solver but are included in mjData.contact for the purpose of custom computations. When this value is positive, geom distances between margin and margin-gap correspond to such inactive contacts."
)
uniform int mjc:group = 0 (
displayName = "Group"
doc = "Integer MuJoCo group to which the collider belongs."
)
uniform double mjc:margin = 0 (
displayName = "Margin"
doc = "Distance threshold below which contacts are detected and included in the global array mjData.contact."
)
uniform int mjc:priority = 0 (
displayName = "Priority"
doc = "Priority determining how the properties of two colliders are combined to form the properties of the contact."
)
uniform bool mjc:shellinertia = 0 (
displayName = "Shell Inertia"
doc = "Enables handling of the inertia assuming mass is concentrated on the surface."
)
uniform double[] mjc:solimp = [0.9, 0.95, 0.001, 0.5, 2] (
displayName = "SolImp"
doc = "Specifies the weight used for averaging of contact parameters, and interacts with the priority attribute."
)
uniform double mjc:solmix = 1 (
displayName = "SolMix"
doc = "Specifies the weight used for averaging of contact parameters, and interacts with the priority attribute."
)
uniform double[] mjc:solref = [0.02, 1] (
displayName = "SolMix"
doc = "Specifies the weight used for averaging of contact parameters, and interacts with the priority attribute."
)
}
class "MjcMeshCollisionAPI" (
@@ -547,6 +547,7 @@ class "MjcCollisionAPI"
displayName = "Group"
doc = """Integer MuJoCo group to which the collider belongs."""
)
uniform bool mjc:shellinertia = False (
customData = {
string apiName = "ShellInertia"
@@ -554,6 +555,62 @@ class "MjcCollisionAPI"
displayName = "Shell Inertia"
doc = """Enables handling of the inertia assuming mass is concentrated on the surface."""
)
uniform int mjc:priority = 0 (
customData = {
string apiName = "Priority"
}
displayName = "Priority"
doc = """Priority determining how the properties of two colliders are combined to form the properties of the contact."""
)
uniform int mjc:condim = 3 (
customData = {
string apiName = "ConDim"
}
displayName = "ConDim"
doc = """The dimensionality of the contact space for a dynamically generated contact pair is set to the maximum of the condim values of the two participating geoms."""
)
uniform double mjc:solmix = 1.0 (
customData = {
string apiName = "SolMix"
}
displayName = "SolMix"
doc = """Specifies the weight used for averaging of contact parameters, and interacts with the priority attribute."""
)
uniform double[] mjc:solref = [0.02, 1.0] (
customData = {
string apiName = "SolRef"
}
displayName = "SolMix"
doc = """Specifies the weight used for averaging of contact parameters, and interacts with the priority attribute."""
)
uniform double[] mjc:solimp = [0.9, 0.95, 0.001, 0.5, 2.0] (
customData = {
string apiName = "SolImp"
}
displayName = "SolImp"
doc = """Specifies the weight used for averaging of contact parameters, and interacts with the priority attribute."""
)
uniform double mjc:margin = 0.0 (
customData = {
string apiName = "Margin"
}
displayName = "Margin"
doc = """Distance threshold below which contacts are detected and included in the global array mjData.contact."""
)
uniform double mjc:gap = 0.0 (
customData = {
string apiName = "Gap"
}
displayName = "Gap"
doc = """This attribute is used to enable the generation of inactive contacts, i.e., contacts that are ignored by the constraint solver but are included in mjData.contact for the purpose of custom computations. When this value is positive, geom distances between margin and margin-gap correspond to such inactive contacts."""
)
}
class "MjcMeshCollisionAPI"
@@ -46,6 +46,7 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
mjcArmature("mjc:armature", TfToken::Immortal),
mjcBiasPrm("mjc:biasPrm", TfToken::Immortal),
mjcBiasType("mjc:biasType", TfToken::Immortal),
mjcCondim("mjc:condim", TfToken::Immortal),
mjcCrankLength("mjc:crankLength", TfToken::Immortal),
mjcCtrl("mjc:ctrl", TfToken::Immortal),
mjcCtrlLimited("mjc:ctrlLimited", TfToken::Immortal),
@@ -83,6 +84,7 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
mjcFrictionloss("mjc:frictionloss", TfToken::Immortal),
mjcGainPrm("mjc:gainPrm", TfToken::Immortal),
mjcGainType("mjc:gainType", TfToken::Immortal),
mjcGap("mjc:gap", TfToken::Immortal),
mjcGear("mjc:gear", TfToken::Immortal),
mjcGroup("mjc:group", TfToken::Immortal),
mjcInertia("mjc:inertia", TfToken::Immortal),
@@ -122,6 +124,7 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
mjcOptionTolerance("mjc:option:tolerance", TfToken::Immortal),
mjcOptionViscosity("mjc:option:viscosity", TfToken::Immortal),
mjcOptionWind("mjc:option:wind", TfToken::Immortal),
mjcPriority("mjc:priority", TfToken::Immortal),
mjcQpos("mjc:qpos", TfToken::Immortal),
mjcQvel("mjc:qvel", TfToken::Immortal),
mjcRef("mjc:ref", TfToken::Immortal),
@@ -129,8 +132,11 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
mjcRollingfriction("mjc:rollingfriction", TfToken::Immortal),
mjcShellinertia("mjc:shellinertia", TfToken::Immortal),
mjcSliderSite("mjc:sliderSite", TfToken::Immortal),
mjcSolimp("mjc:solimp", TfToken::Immortal),
mjcSolimpfriction("mjc:solimpfriction", TfToken::Immortal),
mjcSolimplimit("mjc:solimplimit", TfToken::Immortal),
mjcSolmix("mjc:solmix", TfToken::Immortal),
mjcSolref("mjc:solref", TfToken::Immortal),
mjcSolreffriction("mjc:solreffriction", TfToken::Immortal),
mjcSolreflimit("mjc:solreflimit", TfToken::Immortal),
mjcSpringdamper("mjc:springdamper", TfToken::Immortal),
@@ -185,6 +191,7 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
mjcArmature,
mjcBiasPrm,
mjcBiasType,
mjcCondim,
mjcCrankLength,
mjcCtrl,
mjcCtrlLimited,
@@ -222,6 +229,7 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
mjcFrictionloss,
mjcGainPrm,
mjcGainType,
mjcGap,
mjcGear,
mjcGroup,
mjcInertia,
@@ -258,6 +266,7 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
mjcOptionTolerance,
mjcOptionViscosity,
mjcOptionWind,
mjcPriority,
mjcQpos,
mjcQvel,
mjcRef,
@@ -265,8 +274,11 @@ MjcPhysicsTokensType::MjcPhysicsTokensType()
mjcRollingfriction,
mjcShellinertia,
mjcSliderSite,
mjcSolimp,
mjcSolimpfriction,
mjcSolimplimit,
mjcSolmix,
mjcSolref,
mjcSolreffriction,
mjcSolreflimit,
mjcSpringdamper,
@@ -761,8 +761,7 @@ class ModelWriter {
ApplyApiSchema(data_, material_path,
pxr::UsdPhysicsTokens->PhysicsMaterialAPI);
ApplyApiSchema(data_, material_path,
MjcPhysicsTokens->MjcMaterialAPI);
ApplyApiSchema(data_, material_path, MjcPhysicsTokens->MjcMaterialAPI);
mjsGeom *geom_default = mjs_getDefault(geom->element)->geom;
if (geom->friction[0] != geom_default->friction[0]) {
@@ -1094,8 +1093,7 @@ class ModelWriter {
}
}
void WriteActuator(mjsActuator *actuator,
const pxr::SdfPath &parent_path) {
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)) {
@@ -1121,9 +1119,8 @@ class ModelWriter {
return;
}
CreateRelationshipSpec(data_, actuator_path,
MjcPhysicsTokens->mjcTarget, target_path,
pxr::SdfVariabilityUniform);
CreateRelationshipSpec(data_, actuator_path, MjcPhysicsTokens->mjcTarget,
target_path, pxr::SdfVariabilityUniform);
WriteUniformAttribute(actuator_path, pxr::SdfValueTypeNames->Int,
MjcPhysicsTokens->mjcGroup, actuator->group);
@@ -1132,9 +1129,8 @@ class ModelWriter {
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, refsite_path,
pxr::SdfVariabilityUniform);
CreateRelationshipSpec(data_, actuator_path, MjcPhysicsTokens->mjcRefSite,
refsite_path, pxr::SdfVariabilityUniform);
}
if (!actuator->slidersite->empty()) {
@@ -1158,8 +1154,8 @@ class ModelWriter {
} else if (value == mjLIMITED_FALSE) {
limited_token = pxr::MjcPhysicsTokens->false_;
}
WriteUniformAttribute(actuator_path, pxr::SdfValueTypeNames->Token,
token, limited_token);
WriteUniformAttribute(actuator_path, pxr::SdfValueTypeNames->Token, token,
limited_token);
}
const std::vector<std::pair<pxr::TfToken, double>>
@@ -1248,8 +1244,8 @@ class ModelWriter {
void WriteActuators() {
pxr::SdfPath scope_path =
CreatePrimSpec(data_, body_paths_[kWorldIndex],
kTokens->actuatorsScope, pxr::UsdGeomTokens->Scope);
CreatePrimSpec(data_, body_paths_[kWorldIndex], kTokens->actuatorsScope,
pxr::UsdGeomTokens->Scope);
mjsActuator *actuator =
mjs_asActuator(mjs_firstElement(spec_, mjOBJ_ACTUATOR));
while (actuator) {
@@ -1570,6 +1566,34 @@ class ModelWriter {
MjcPhysicsTokens->mjcShellinertia,
geom->typeinertia == mjtGeomInertia::mjINERTIA_SHELL);
WriteUniformAttribute(geom_path, pxr::SdfValueTypeNames->Int,
MjcPhysicsTokens->mjcPriority, geom->priority);
WriteUniformAttribute(geom_path, pxr::SdfValueTypeNames->Int,
MjcPhysicsTokens->mjcCondim, geom->condim);
WriteUniformAttribute(geom_path, pxr::SdfValueTypeNames->Double,
MjcPhysicsTokens->mjcSolmix, geom->solmix);
WriteUniformAttribute(geom_path, pxr::SdfValueTypeNames->Double,
MjcPhysicsTokens->mjcSolmix, geom->solmix);
WriteUniformAttribute(
geom_path, pxr::SdfValueTypeNames->DoubleArray,
MjcPhysicsTokens->mjcSolref,
pxr::VtArray<double>(geom->solref, geom->solref + mjNREF));
WriteUniformAttribute(
geom_path, pxr::SdfValueTypeNames->DoubleArray,
MjcPhysicsTokens->mjcSolimp,
pxr::VtArray<double>(geom->solimp, geom->solimp + mjNIMP));
WriteUniformAttribute(geom_path, pxr::SdfValueTypeNames->Double,
MjcPhysicsTokens->mjcMargin, geom->margin);
WriteUniformAttribute(geom_path, pxr::SdfValueTypeNames->Double,
MjcPhysicsTokens->mjcGap, geom->gap);
if (geom->mass >= mjMINVAL || geom->density >= mjMINVAL) {
ApplyApiSchema(data_, geom_path, pxr::UsdPhysicsTokens->PhysicsMassAPI);
}
+57
View File
@@ -584,6 +584,63 @@ void ParseMjcPhysicsCollisionAPI(
if (group_attr.HasAuthoredValue()) {
group_attr.Get(&geom->group);
}
auto priority_attr = collision_api.GetPriorityAttr();
if (priority_attr.HasAuthoredValue()) {
priority_attr.Get(&geom->priority);
}
auto condim_attr = collision_api.GetConDimAttr();
if (condim_attr.HasAuthoredValue()) {
condim_attr.Get(&geom->condim);
}
auto solmix_attr = collision_api.GetSolMixAttr();
if (solmix_attr.HasAuthoredValue()) {
solmix_attr.Get(&geom->solmix);
}
auto solref_attr = collision_api.GetSolRefAttr();
if (solref_attr.HasAuthoredValue()) {
pxr::VtDoubleArray solref;
solref_attr.Get(&solref);
if (solref.size() == mjNREF) {
for (int i = 0; i < mjNREF; ++i) {
geom->solref[i] = solref[i];
}
} else {
mju_warning(
"solref attribute for geom %s has incorrect size %zu, "
"expected %d.",
mjs_getName(geom->element)->c_str(), solref.size(), mjNREF);
}
}
auto solimp_attr = collision_api.GetSolImpAttr();
if (solimp_attr.HasAuthoredValue()) {
pxr::VtDoubleArray solimp;
solimp_attr.Get(&solimp);
if (solimp.size() == mjNIMP) {
for (int i = 0; i < mjNIMP; ++i) {
geom->solimp[i] = solimp[i];
}
} else {
mju_warning(
"solimp attribute for geom %s has incorrect size %zu, "
"expected %d.",
mjs_getName(geom->element)->c_str(), solimp.size(), mjNIMP);
}
}
auto margin_attr = collision_api.GetMarginAttr();
if (margin_attr.HasAuthoredValue()) {
margin_attr.Get(&geom->margin);
}
auto gap_attr = collision_api.GetGapAttr();
if (gap_attr.HasAuthoredValue()) {
gap_attr.Get(&geom->gap);
}
}
void ParseMjcPhysicsMeshCollisionAPI(