16
16
#include < cstddef>
17
17
#include < map>
18
18
#include < memory>
19
- #include < optional>
20
19
#include < string>
21
- #include < utility>
22
20
#include < vector>
23
21
24
22
#include < mujoco/experimental/usd/mjcPhysics/actuator.h>
25
23
#include < mujoco/experimental/usd/mjcPhysics/collisionAPI.h>
26
24
#include < mujoco/experimental/usd/mjcPhysics/jointAPI.h>
27
25
#include < mujoco/experimental/usd/mjcPhysics/keyframe.h>
28
- #include < mujoco/experimental/usd/mjcPhysics/meshCollisionAPI.h>
29
26
#include < mujoco/experimental/usd/mjcPhysics/materialAPI.h>
27
+ #include < mujoco/experimental/usd/mjcPhysics/meshCollisionAPI.h>
30
28
#include < mujoco/experimental/usd/mjcPhysics/sceneAPI.h>
31
29
#include < mujoco/experimental/usd/mjcPhysics/siteAPI.h>
32
30
#include < mujoco/experimental/usd/mjcPhysics/tokens.h>
@@ -266,6 +264,56 @@ bool MaybeParseGeomPrimitive(const pxr::UsdPrim& prim, T* element,
266
264
return true ;
267
265
}
268
266
267
+ mjsMesh* ParseUsdMesh (mjSpec* spec, const pxr::UsdPrim& prim, mjsGeom* geom) {
268
+ if (!prim.IsA <pxr::UsdGeomMesh>()) {
269
+ return nullptr ;
270
+ }
271
+ geom->type = mjGEOM_MESH;
272
+ pxr::UsdGeomMesh usd_mesh (prim);
273
+ std::vector<float > uservert;
274
+ std::vector<int > userface;
275
+
276
+ pxr::VtVec3fArray points;
277
+ usd_mesh.GetPointsAttr ().Get (&points);
278
+
279
+ uservert.reserve (points.size () * 3 );
280
+ for (const auto & pt : points) {
281
+ uservert.push_back (pt[0 ]);
282
+ uservert.push_back (pt[1 ]);
283
+ uservert.push_back (pt[2 ]);
284
+ }
285
+
286
+ pxr::VtIntArray indices;
287
+ usd_mesh.GetFaceVertexIndicesAttr ().Get (&indices);
288
+ pxr::VtIntArray counts;
289
+ usd_mesh.GetFaceVertexCountsAttr ().Get (&counts);
290
+
291
+ userface.reserve (indices.size ());
292
+ int vtx_idx = 0 ;
293
+ for (int count : counts) {
294
+ int k = 1 ;
295
+ // If the prim is a triangle create a triangle fan rooted
296
+ // at the first index.
297
+ while (k < count - 1 ) {
298
+ userface.push_back (indices[vtx_idx]);
299
+ userface.push_back (indices[vtx_idx + k]);
300
+ userface.push_back (indices[vtx_idx + k + 1 ]);
301
+ k++;
302
+ }
303
+ vtx_idx += count;
304
+ }
305
+
306
+ mjsMesh* mesh = mjs_addMesh (spec, nullptr );
307
+
308
+ std::string mesh_name = usd_mesh.GetPath ().GetAsString ();
309
+ mjs_setName (mesh->element , mesh_name.c_str ());
310
+ mjs_setFloat (mesh->uservert , uservert.data (), uservert.size ());
311
+ mjs_setInt (mesh->userface , userface.data (), userface.size ());
312
+
313
+ mjs_setString (geom->meshname , mesh_name.c_str ());
314
+ return mesh;
315
+ }
316
+
269
317
void ParseUsdPhysicsScene (mjSpec* spec,
270
318
const pxr::UsdPhysicsScene& physics_scene) {
271
319
// Parse gravity and gravity direction.
@@ -573,9 +621,9 @@ void ParseUsdPhysicsScene(mjSpec* spec,
573
621
inertia_from_geom_attr.Get (&inertiafromgeom);
574
622
if (inertiafromgeom == MjcPhysicsTokens->auto_ ) {
575
623
spec->compiler .inertiafromgeom = mjINERTIAFROMGEOM_AUTO;
576
- } else if (inertiafromgeom == MjcPhysicsTokens->false_ ) {
624
+ } else if (inertiafromgeom == MjcPhysicsTokens->false_ ) {
577
625
spec->compiler .inertiafromgeom = mjINERTIAFROMGEOM_FALSE;
578
- } else if (inertiafromgeom == MjcPhysicsTokens->true_ ){
626
+ } else if (inertiafromgeom == MjcPhysicsTokens->true_ ) {
579
627
spec->compiler .inertiafromgeom = mjINERTIAFROMGEOM_TRUE;
580
628
} else {
581
629
mju_warning (" Invalid inertiafromgeom token: %s" ,
@@ -1178,6 +1226,49 @@ void ParseMjcPhysicsMaterialAPI(
1178
1226
}
1179
1227
}
1180
1228
1229
+ void ParseDisplayColorAndOpacity (const pxr::UsdPrim& prim, mjsGeom* geom) {
1230
+ // Convert displayColor and displayOpacity to rgba.
1231
+ // We want to support primvar inheritance, hence FindPrimvarWithInheritance.
1232
+ pxr::UsdGeomPrimvarsAPI primvarsAPI (prim);
1233
+ pxr::UsdGeomPrimvar displayColorPrimvar =
1234
+ primvarsAPI.FindPrimvarWithInheritance (
1235
+ pxr::UsdGeomTokens->primvarsDisplayColor );
1236
+ pxr::UsdGeomPrimvar displayOpacityPrimvar =
1237
+ primvarsAPI.FindPrimvarWithInheritance (
1238
+ pxr::UsdGeomTokens->primvarsDisplayOpacity );
1239
+ if (displayColorPrimvar.HasAuthoredValue ()) {
1240
+ pxr::VtArray<pxr::GfVec3f> display_color;
1241
+ displayColorPrimvar.Get (&display_color);
1242
+ if (!display_color.empty ()) {
1243
+ geom->rgba [0 ] = display_color[0 ][0 ];
1244
+ geom->rgba [1 ] = display_color[0 ][1 ];
1245
+ geom->rgba [2 ] = display_color[0 ][2 ];
1246
+ }
1247
+ }
1248
+ if (displayOpacityPrimvar.HasAuthoredValue ()) {
1249
+ pxr::VtArray<float > display_opacity;
1250
+ displayOpacityPrimvar.Get (&display_opacity);
1251
+ if (!display_opacity.empty ()) {
1252
+ geom->rgba [3 ] = display_opacity[0 ];
1253
+ }
1254
+ }
1255
+ }
1256
+
1257
+ void ParseUsdGeomGprim (mjSpec* spec, const pxr::UsdPrim& gprim,
1258
+ const pxr::UsdPrim& body_prim, mjsBody* parent,
1259
+ UsdCaches& caches) {
1260
+ mjsGeom* geom = mjs_addGeom (parent, nullptr );
1261
+ mjs_setName (geom->element , gprim.GetPath ().GetAsString ().c_str ());
1262
+ geom->contype = 0 ;
1263
+ geom->conaffinity = 0 ;
1264
+
1265
+ ParseDisplayColorAndOpacity (gprim, geom);
1266
+ SetLocalPoseFromPrim (gprim, body_prim, geom, caches.xform_cache );
1267
+ if (!MaybeParseGeomPrimitive (gprim, geom, caches.xform_cache )) {
1268
+ ParseUsdMesh (spec, gprim, geom);
1269
+ }
1270
+ }
1271
+
1181
1272
void ParseUsdPhysicsCollider (mjSpec* spec,
1182
1273
const pxr::UsdPhysicsCollisionAPI& collision_api,
1183
1274
const pxr::UsdPrim& body_prim, mjsBody* parent,
@@ -1208,8 +1299,10 @@ void ParseUsdPhysicsCollider(mjSpec* spec,
1208
1299
pxr::UsdPrim bound_material_prim = bound_material.GetPrim ();
1209
1300
if (bound_material_prim.HasAPI <pxr::UsdPhysicsMaterialAPI>() ||
1210
1301
bound_material_prim.HasAPI <pxr::MjcPhysicsMaterialAPI>()) {
1211
- ParseUsdPhysicsMaterialAPI (geom, pxr::UsdPhysicsMaterialAPI (bound_material_prim));
1212
- ParseMjcPhysicsMaterialAPI (geom, pxr::MjcPhysicsMaterialAPI (bound_material_prim));
1302
+ ParseUsdPhysicsMaterialAPI (
1303
+ geom, pxr::UsdPhysicsMaterialAPI (bound_material_prim));
1304
+ ParseMjcPhysicsMaterialAPI (
1305
+ geom, pxr::MjcPhysicsMaterialAPI (bound_material_prim));
1213
1306
}
1214
1307
}
1215
1308
@@ -1220,84 +1313,15 @@ void ParseUsdPhysicsCollider(mjSpec* spec,
1220
1313
ParseUsdPhysicsMassAPIForGeom (geom, pxr::UsdPhysicsMassAPI (prim));
1221
1314
}
1222
1315
1223
- // Convert displayColor and displayOpacity to rgba.
1224
- // We want to support primvar inheritance, hence FindPrimvarWithInheritance.
1225
- pxr::UsdGeomPrimvarsAPI primvarsAPI (prim);
1226
- pxr::UsdGeomPrimvar displayColorPrimvar =
1227
- primvarsAPI.FindPrimvarWithInheritance (
1228
- pxr::UsdGeomTokens->primvarsDisplayColor );
1229
- pxr::UsdGeomPrimvar displayOpacityPrimvar =
1230
- primvarsAPI.FindPrimvarWithInheritance (
1231
- pxr::UsdGeomTokens->primvarsDisplayOpacity );
1232
- if (displayColorPrimvar.HasAuthoredValue ()) {
1233
- pxr::VtArray<pxr::GfVec3f> display_color;
1234
- displayColorPrimvar.Get (&display_color);
1235
- if (!display_color.empty ()) {
1236
- geom->rgba [0 ] = display_color[0 ][0 ];
1237
- geom->rgba [1 ] = display_color[0 ][1 ];
1238
- geom->rgba [2 ] = display_color[0 ][2 ];
1239
- }
1240
- }
1241
- if (displayOpacityPrimvar.HasAuthoredValue ()) {
1242
- pxr::VtArray<float > display_opacity;
1243
- displayOpacityPrimvar.Get (&display_opacity);
1244
- if (!display_opacity.empty ()) {
1245
- geom->rgba [3 ] = display_opacity[0 ];
1246
- }
1247
- }
1316
+ ParseDisplayColorAndOpacity (prim, geom);
1248
1317
1249
1318
SetLocalPoseFromPrim (prim, body_prim, geom, caches.xform_cache );
1250
1319
1251
1320
if (!MaybeParseGeomPrimitive (prim, geom, caches.xform_cache )) {
1252
- if (prim.IsA <pxr::UsdGeomMesh>()) {
1253
- geom->type = mjGEOM_MESH;
1254
- pxr::UsdGeomMesh usd_mesh (prim);
1255
- std::vector<float > uservert;
1256
- std::vector<int > userface;
1257
-
1258
- pxr::VtVec3fArray points;
1259
- usd_mesh.GetPointsAttr ().Get (&points);
1260
-
1261
- uservert.reserve (points.size () * 3 );
1262
- for (const auto & pt : points) {
1263
- uservert.push_back (pt[0 ]);
1264
- uservert.push_back (pt[1 ]);
1265
- uservert.push_back (pt[2 ]);
1266
- }
1267
-
1268
- pxr::VtIntArray indices;
1269
- usd_mesh.GetFaceVertexIndicesAttr ().Get (&indices);
1270
- pxr::VtIntArray counts;
1271
- usd_mesh.GetFaceVertexCountsAttr ().Get (&counts);
1272
-
1273
- userface.reserve (indices.size ());
1274
- int vtx_idx = 0 ;
1275
- for (int count : counts) {
1276
- int k = 1 ;
1277
- // If the prim is a triangle create a triangle fan rooted
1278
- // at the first index.
1279
- while (k < count - 1 ) {
1280
- userface.push_back (indices[vtx_idx]);
1281
- userface.push_back (indices[vtx_idx + k]);
1282
- userface.push_back (indices[vtx_idx + k + 1 ]);
1283
- k++;
1284
- }
1285
- vtx_idx += count;
1286
- }
1287
-
1288
- mjsMesh* mesh = mjs_addMesh (spec, nullptr );
1289
-
1290
- if (prim.HasAPI <pxr::MjcPhysicsMeshCollisionAPI>()) {
1291
- ParseMjcPhysicsMeshCollisionAPI (mesh,
1292
- pxr::MjcPhysicsMeshCollisionAPI (prim));
1293
- }
1294
-
1295
- std::string mesh_name = usd_mesh.GetPath ().GetAsString ();
1296
- mjs_setName (mesh->element , mesh_name.c_str ());
1297
- mjs_setFloat (mesh->uservert , uservert.data (), uservert.size ());
1298
- mjs_setInt (mesh->userface , userface.data (), userface.size ());
1299
-
1300
- mjs_setString (geom->meshname , mesh_name.c_str ());
1321
+ mjsMesh* mesh = ParseUsdMesh (spec, prim, geom);
1322
+ if (mesh != nullptr && prim.HasAPI <pxr::MjcPhysicsMeshCollisionAPI>()) {
1323
+ ParseMjcPhysicsMeshCollisionAPI (mesh,
1324
+ pxr::MjcPhysicsMeshCollisionAPI (prim));
1301
1325
}
1302
1326
}
1303
1327
}
@@ -1527,8 +1551,7 @@ using BodyPrimMap = std::map<pxr::SdfPath, std::vector<pxr::SdfPath>>;
1527
1551
// in the mjSpec.
1528
1552
void PopulateSpecFromTree (pxr::UsdStageRefPtr stage, mjSpec* spec,
1529
1553
mjsBody* parent_mj_body, const Node* parent_node,
1530
- const Node* current_node,
1531
- UsdCaches& caches) {
1554
+ const Node* current_node, UsdCaches& caches) {
1532
1555
mjsBody* current_mj_body = nullptr ;
1533
1556
1534
1557
if (!current_node->body_path .IsEmpty ()) {
@@ -1562,16 +1585,21 @@ void PopulateSpecFromTree(pxr::UsdStageRefPtr stage, mjSpec* spec,
1562
1585
? stage->GetPseudoRoot ()
1563
1586
: stage->GetPrimAtPath (current_node->body_path );
1564
1587
1588
+ for (const auto & gprim_path : current_node->visual_gprims ) {
1589
+ ParseUsdGeomGprim (spec, stage->GetPrimAtPath (gprim_path),
1590
+ body_prim_for_xform, current_mj_body, caches);
1591
+ }
1592
+
1565
1593
for (const auto & collider_path : current_node->colliders ) {
1566
1594
ParseUsdPhysicsCollider (
1567
1595
spec, pxr::UsdPhysicsCollisionAPI (stage->GetPrimAtPath (collider_path)),
1568
1596
body_prim_for_xform, current_mj_body, caches);
1569
1597
}
1570
1598
1571
1599
for (const auto & site_path : current_node->sites ) {
1572
- ParseMjcPhysicsSite (spec,
1573
- pxr::MjcPhysicsSiteAPI (stage->GetPrimAtPath (site_path)),
1574
- body_prim_for_xform, current_mj_body, caches.xform_cache );
1600
+ ParseMjcPhysicsSite (
1601
+ spec, pxr::MjcPhysicsSiteAPI (stage->GetPrimAtPath (site_path)),
1602
+ body_prim_for_xform, current_mj_body, caches.xform_cache );
1575
1603
}
1576
1604
1577
1605
// Recurse through children.
@@ -1589,10 +1617,8 @@ mjSpec* mj_parseUSDStage(const pxr::UsdStageRefPtr stage) {
1589
1617
std::unique_ptr<mujoco::usd::Node> root =
1590
1618
mujoco::usd::BuildKinematicTree (stage);
1591
1619
1592
- // Set of caches to use for all queries when parsing.
1593
- mujoco::usd::UsdCaches caches;
1594
-
1595
- // First parse the physics scene.
1620
+ // First parse the physics scene and other root elements such as keyframes
1621
+ // and actuators.
1596
1622
if (!root->physics_scene .IsEmpty ()) {
1597
1623
mujoco::usd::ParseUsdPhysicsScene (
1598
1624
spec, pxr::UsdPhysicsScene::Get (stage, root->physics_scene ));
@@ -1612,8 +1638,9 @@ mjSpec* mj_parseUSDStage(const pxr::UsdStageRefPtr stage) {
1612
1638
}
1613
1639
}
1614
1640
1641
+ // Set of caches to use for all queries when parsing.
1642
+ mujoco::usd::UsdCaches caches;
1615
1643
// Then populate the kinematic tree.
1616
- pxr::UsdGeomXformCache xform_cache;
1617
1644
PopulateSpecFromTree (stage, spec, /* parent_mj_body=*/ nullptr ,
1618
1645
/* parent_node=*/ nullptr , root.get (), caches);
1619
1646
0 commit comments