|
16 | 16 | #include <cstddef>
|
17 | 17 | #include <map>
|
18 | 18 | #include <memory>
|
| 19 | +#include <optional> |
19 | 20 | #include <string>
|
20 | 21 | #include <vector>
|
21 | 22 |
|
|
51 | 52 | #include <pxr/usd/usdGeom/cylinder.h>
|
52 | 53 | #include <pxr/usd/usdGeom/gprim.h>
|
53 | 54 | #include <pxr/usd/usdGeom/mesh.h>
|
| 55 | +#include <pxr/usd/usdGeom/metrics.h> |
54 | 56 | #include <pxr/usd/usdGeom/plane.h>
|
55 | 57 | #include <pxr/usd/usdGeom/primvar.h>
|
56 | 58 | #include <pxr/usd/usdGeom/primvarsAPI.h>
|
@@ -383,20 +385,55 @@ mjsMesh* ParseUsdMesh(mjSpec* spec, const pxr::UsdPrim& prim, mjsGeom* geom,
|
383 | 385 | return mesh;
|
384 | 386 | }
|
385 | 387 |
|
| 388 | +void SetGravityAttributes( |
| 389 | + mjSpec* spec, const pxr::UsdStageRefPtr stage, |
| 390 | + std::optional<pxr::GfVec3f> gravity_direction = std::nullopt, |
| 391 | + std::optional<float> gravity_magnitude = std::nullopt) { |
| 392 | + // Parse gravity and gravity direction. |
| 393 | + if (!gravity_direction.has_value()) { |
| 394 | + TfToken up_axis = pxr::UsdGeomGetStageUpAxis(stage); |
| 395 | + if (up_axis == pxr::UsdGeomTokens->y) { |
| 396 | + gravity_direction = pxr::GfVec3f(0, -1, 0); |
| 397 | + } else if (up_axis == pxr::UsdGeomTokens->z) { |
| 398 | + gravity_direction = pxr::GfVec3f(0, 0, -1); |
| 399 | + } else { |
| 400 | + mju_error("Invalid stage up axis token %s", up_axis.GetString().c_str()); |
| 401 | + } |
| 402 | + } |
| 403 | + |
| 404 | + if (!gravity_magnitude.has_value()) { |
| 405 | + gravity_magnitude = 9.81f / pxr::UsdGeomGetStageMetersPerUnit(stage); |
| 406 | + } |
| 407 | + |
| 408 | + pxr::GfVec3f gravity = gravity_direction.value() * gravity_magnitude.value(); |
| 409 | + |
| 410 | + spec->option.gravity[0] = gravity[0]; |
| 411 | + spec->option.gravity[1] = gravity[1]; |
| 412 | + spec->option.gravity[2] = gravity[2]; |
| 413 | +} |
| 414 | + |
386 | 415 | void ParseUsdPhysicsScene(mjSpec* spec,
|
387 | 416 | const pxr::UsdPhysicsScene& physics_scene) {
|
388 |
| - // Parse gravity and gravity direction. |
389 |
| - pxr::GfVec3f gravity_direction; |
390 |
| - physics_scene.GetGravityDirectionAttr().Get(&gravity_direction); |
| 417 | + std::optional<pxr::GfVec3f> gravity_direction = std::nullopt; |
| 418 | + std::optional<float> gravity_magnitude = std::nullopt; |
| 419 | + auto stage = physics_scene.GetPrim().GetStage(); |
391 | 420 |
|
392 |
| - float gravity_magnitude; |
393 |
| - physics_scene.GetGravityMagnitudeAttr().Get(&gravity_magnitude); |
| 421 | + // Parse gravity and gravity direction. |
| 422 | + auto gravity_direction_attr = physics_scene.GetGravityDirectionAttr(); |
| 423 | + if (gravity_direction_attr.HasAuthoredValue()) { |
| 424 | + pxr::GfVec3f authored_gravity_dir; |
| 425 | + gravity_direction_attr.Get(&authored_gravity_dir); |
| 426 | + gravity_direction = authored_gravity_dir; |
| 427 | + } |
394 | 428 |
|
395 |
| - gravity_direction *= gravity_magnitude; |
| 429 | + auto gravity_magnitude_attr = physics_scene.GetGravityMagnitudeAttr(); |
| 430 | + if (gravity_magnitude_attr.HasAuthoredValue()) { |
| 431 | + float authored_gravity_magnitude; |
| 432 | + gravity_magnitude_attr.Get(&authored_gravity_magnitude); |
| 433 | + gravity_magnitude = authored_gravity_magnitude; |
| 434 | + } |
396 | 435 |
|
397 |
| - spec->option.gravity[0] = gravity_direction[0]; |
398 |
| - spec->option.gravity[1] = gravity_direction[1]; |
399 |
| - spec->option.gravity[2] = gravity_direction[2]; |
| 436 | + SetGravityAttributes(spec, stage, gravity_direction, gravity_magnitude); |
400 | 437 |
|
401 | 438 | // Early exit if theres no MjcPhysicsSceneAPI applied.
|
402 | 439 | if (!physics_scene.GetPrim().HasAPI<pxr::MjcPhysicsSceneAPI>()) {
|
@@ -1724,6 +1761,10 @@ mjSpec* mj_parseUSDStage(const pxr::UsdStageRefPtr stage) {
|
1724 | 1761 | if (!root->physics_scene.IsEmpty()) {
|
1725 | 1762 | mujoco::usd::ParseUsdPhysicsScene(
|
1726 | 1763 | spec, pxr::UsdPhysicsScene::Get(stage, root->physics_scene));
|
| 1764 | + } else { |
| 1765 | + // If there is no physics scene we still need to infer the gravity vector |
| 1766 | + // from the stage up axis and units per meter metadata. |
| 1767 | + mujoco::usd::SetGravityAttributes(spec, stage); |
1727 | 1768 | }
|
1728 | 1769 |
|
1729 | 1770 | if (!root->keyframes.empty()) {
|
@@ -1754,4 +1795,3 @@ MJAPI mjSpec* mj_parseUSD(const char* identifier, const mjVFS* vfs, char* error,
|
1754 | 1795 | auto stage = pxr::UsdStage::Open(identifier);
|
1755 | 1796 | return mj_parseUSDStage(stage);
|
1756 | 1797 | }
|
1757 |
| - |
|
0 commit comments