Skip to content

Commit f5df466

Browse files
havesscopybara-github
authored andcommitted
Add support for visual gprims to USD parsing.
PiperOrigin-RevId: 784197335 Change-Id: I8eb155b7942209f372487f8268ad76310cf510ac
1 parent 2e13c64 commit f5df466

File tree

3 files changed

+125
-95
lines changed

3 files changed

+125
-95
lines changed

src/experimental/usd/kinematic_tree.cc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <pxr/usd/sdf/path.h>
2727
#include <pxr/usd/usd/common.h>
2828
#include <pxr/usd/usd/primRange.h>
29+
#include <pxr/usd/usdGeom/gprim.h>
2930
#include <pxr/usd/usdGeom/xformCache.h>
3031
#include <pxr/usd/usdPhysics/collisionAPI.h>
3132
#include <pxr/usd/usdPhysics/joint.h>
@@ -135,11 +136,13 @@ ExtractedPrims ExtractPrims(pxr::UsdStageRefPtr stage) {
135136
}
136137

137138
if (prim.HasAPI<pxr::UsdPhysicsCollisionAPI>()) {
138-
current_node->colliders.push_back(prim.GetPath());
139+
current_node->colliders.push_back(prim_path);
140+
} else if (prim.IsA<pxr::UsdGeomGprim>()) {
141+
current_node->visual_gprims.push_back(prim_path);
139142
}
140143

141144
if (prim.HasAPI<pxr::MjcPhysicsSiteAPI>()) {
142-
current_node->sites.push_back(prim.GetPath());
145+
current_node->sites.push_back(prim_path);
143146
// Sites should not have children.
144147
it.PruneChildren();
145148
}
@@ -159,7 +162,7 @@ ExtractedPrims ExtractPrims(pxr::UsdStageRefPtr stage) {
159162
}
160163

161164
if (prim.IsA<pxr::MjcPhysicsKeyframe>()) {
162-
root->keyframes.push_back(prim.GetPath());
165+
root->keyframes.push_back(prim_path);
163166
// Keyframes should not have children.
164167
it.PruneChildren();
165168
}
@@ -252,7 +255,6 @@ std::unique_ptr<Node> BuildKinematicTree(const pxr::UsdStageRefPtr stage) {
252255
return nullptr;
253256
}
254257
}
255-
256258
return world_root;
257259
}
258260

src/experimental/usd/kinematic_tree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct Node {
3232
pxr::SdfPath physics_scene;
3333
std::vector<pxr::SdfPath> actuators;
3434
std::vector<pxr::SdfPath> joints;
35+
std::vector<pxr::SdfPath> visual_gprims;
3536
std::vector<pxr::SdfPath> colliders;
3637
std::vector<pxr::SdfPath> sites;
3738
std::vector<pxr::SdfPath> keyframes;

src/experimental/usd/usd_to_mjspec.cc

Lines changed: 118 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,15 @@
1616
#include <cstddef>
1717
#include <map>
1818
#include <memory>
19-
#include <optional>
2019
#include <string>
21-
#include <utility>
2220
#include <vector>
2321

2422
#include <mujoco/experimental/usd/mjcPhysics/actuator.h>
2523
#include <mujoco/experimental/usd/mjcPhysics/collisionAPI.h>
2624
#include <mujoco/experimental/usd/mjcPhysics/jointAPI.h>
2725
#include <mujoco/experimental/usd/mjcPhysics/keyframe.h>
28-
#include <mujoco/experimental/usd/mjcPhysics/meshCollisionAPI.h>
2926
#include <mujoco/experimental/usd/mjcPhysics/materialAPI.h>
27+
#include <mujoco/experimental/usd/mjcPhysics/meshCollisionAPI.h>
3028
#include <mujoco/experimental/usd/mjcPhysics/sceneAPI.h>
3129
#include <mujoco/experimental/usd/mjcPhysics/siteAPI.h>
3230
#include <mujoco/experimental/usd/mjcPhysics/tokens.h>
@@ -266,6 +264,56 @@ bool MaybeParseGeomPrimitive(const pxr::UsdPrim& prim, T* element,
266264
return true;
267265
}
268266

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+
269317
void ParseUsdPhysicsScene(mjSpec* spec,
270318
const pxr::UsdPhysicsScene& physics_scene) {
271319
// Parse gravity and gravity direction.
@@ -573,9 +621,9 @@ void ParseUsdPhysicsScene(mjSpec* spec,
573621
inertia_from_geom_attr.Get(&inertiafromgeom);
574622
if (inertiafromgeom == MjcPhysicsTokens->auto_) {
575623
spec->compiler.inertiafromgeom = mjINERTIAFROMGEOM_AUTO;
576-
} else if(inertiafromgeom == MjcPhysicsTokens->false_) {
624+
} else if (inertiafromgeom == MjcPhysicsTokens->false_) {
577625
spec->compiler.inertiafromgeom = mjINERTIAFROMGEOM_FALSE;
578-
} else if(inertiafromgeom == MjcPhysicsTokens->true_){
626+
} else if (inertiafromgeom == MjcPhysicsTokens->true_) {
579627
spec->compiler.inertiafromgeom = mjINERTIAFROMGEOM_TRUE;
580628
} else {
581629
mju_warning("Invalid inertiafromgeom token: %s",
@@ -1178,6 +1226,49 @@ void ParseMjcPhysicsMaterialAPI(
11781226
}
11791227
}
11801228

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+
11811272
void ParseUsdPhysicsCollider(mjSpec* spec,
11821273
const pxr::UsdPhysicsCollisionAPI& collision_api,
11831274
const pxr::UsdPrim& body_prim, mjsBody* parent,
@@ -1208,8 +1299,10 @@ void ParseUsdPhysicsCollider(mjSpec* spec,
12081299
pxr::UsdPrim bound_material_prim = bound_material.GetPrim();
12091300
if (bound_material_prim.HasAPI<pxr::UsdPhysicsMaterialAPI>() ||
12101301
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));
12131306
}
12141307
}
12151308

@@ -1220,84 +1313,15 @@ void ParseUsdPhysicsCollider(mjSpec* spec,
12201313
ParseUsdPhysicsMassAPIForGeom(geom, pxr::UsdPhysicsMassAPI(prim));
12211314
}
12221315

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);
12481317

12491318
SetLocalPoseFromPrim(prim, body_prim, geom, caches.xform_cache);
12501319

12511320
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));
13011325
}
13021326
}
13031327
}
@@ -1527,8 +1551,7 @@ using BodyPrimMap = std::map<pxr::SdfPath, std::vector<pxr::SdfPath>>;
15271551
// in the mjSpec.
15281552
void PopulateSpecFromTree(pxr::UsdStageRefPtr stage, mjSpec* spec,
15291553
mjsBody* parent_mj_body, const Node* parent_node,
1530-
const Node* current_node,
1531-
UsdCaches& caches) {
1554+
const Node* current_node, UsdCaches& caches) {
15321555
mjsBody* current_mj_body = nullptr;
15331556

15341557
if (!current_node->body_path.IsEmpty()) {
@@ -1562,16 +1585,21 @@ void PopulateSpecFromTree(pxr::UsdStageRefPtr stage, mjSpec* spec,
15621585
? stage->GetPseudoRoot()
15631586
: stage->GetPrimAtPath(current_node->body_path);
15641587

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+
15651593
for (const auto& collider_path : current_node->colliders) {
15661594
ParseUsdPhysicsCollider(
15671595
spec, pxr::UsdPhysicsCollisionAPI(stage->GetPrimAtPath(collider_path)),
15681596
body_prim_for_xform, current_mj_body, caches);
15691597
}
15701598

15711599
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);
15751603
}
15761604

15771605
// Recurse through children.
@@ -1589,10 +1617,8 @@ mjSpec* mj_parseUSDStage(const pxr::UsdStageRefPtr stage) {
15891617
std::unique_ptr<mujoco::usd::Node> root =
15901618
mujoco::usd::BuildKinematicTree(stage);
15911619

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.
15961622
if (!root->physics_scene.IsEmpty()) {
15971623
mujoco::usd::ParseUsdPhysicsScene(
15981624
spec, pxr::UsdPhysicsScene::Get(stage, root->physics_scene));
@@ -1612,8 +1638,9 @@ mjSpec* mj_parseUSDStage(const pxr::UsdStageRefPtr stage) {
16121638
}
16131639
}
16141640

1641+
// Set of caches to use for all queries when parsing.
1642+
mujoco::usd::UsdCaches caches;
16151643
// Then populate the kinematic tree.
1616-
pxr::UsdGeomXformCache xform_cache;
16171644
PopulateSpecFromTree(stage, spec, /*parent_mj_body=*/nullptr,
16181645
/*parent_node=*/nullptr, root.get(), caches);
16191646

0 commit comments

Comments
 (0)