diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1a3288b9..4762eb73 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -179,7 +179,7 @@ jobs: cp lib/libactuator.* ${{ matrix.tmpdir }}/mujoco_install/mujoco_plugin && cp lib/libelasticity.* ${{ matrix.tmpdir }}/mujoco_install/mujoco_plugin && cp lib/libsensor.* ${{ matrix.tmpdir }}/mujoco_install/mujoco_plugin && - cp lib/libsdf.* ${{ matrix.tmpdir }}/mujoco_install/mujoco_plugin + cp lib/libsdf_plugin.* ${{ matrix.tmpdir }}/mujoco_install/mujoco_plugin - name: Copy plugins (Windows) if: ${{ runner.os == 'Windows' }} working-directory: build diff --git a/CMakeLists.txt b/CMakeLists.txt index 087a81e7..3cab120d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,14 @@ option(MUJOCO_BUILD_EXAMPLES "Build samples for MuJoCo" ON) option(MUJOCO_BUILD_SIMULATE "Build simulate library for MuJoCo" ON) option(MUJOCO_BUILD_TESTS "Build tests for MuJoCo" ON) option(MUJOCO_TEST_PYTHON_UTIL "Build and test utility libraries for Python bindings" ON) +option(MUJOCO_BUILD_USD_PLUGINS "Build OpenUSD plugins" OFF) + +# USD libs to compile against. +set(MUJOCO_USD_ALLOWED_TARGET_VALUES "USD" "Houdini") +set(MUJOCO_USD_TARGET "USD" CACHE STRING "Select the USD target for the project.") +set_property(CACHE MUJOCO_USD_TARGET + PROPERTY STRINGS ${MUJOCO_USD_ALLOWED_TARGET_VALUES} +) if(APPLE AND (MUJOCO_BUILD_EXAMPLES OR MUJOCO_BUILD_SIMULATE)) enable_language(OBJC) @@ -181,6 +189,10 @@ if(MUJOCO_BUILD_EXAMPLES) add_subdirectory(sample) endif() +if(MUJOCO_BUILD_USD_PLUGINS) + add_subdirectory(src/experimental/usd/plugins) +endif() + if(BUILD_TESTING AND MUJOCO_BUILD_TESTS) enable_testing() add_subdirectory(test) diff --git a/plugin/sdf/CMakeLists.txt b/plugin/sdf/CMakeLists.txt index 3e216fc4..8b834971 100644 --- a/plugin/sdf/CMakeLists.txt +++ b/plugin/sdf/CMakeLists.txt @@ -34,19 +34,19 @@ set(MUJOCO_SDF_SRCS torus.h ) -add_library(sdf SHARED) -target_sources(sdf PRIVATE ${MUJOCO_SDF_SRCS}) -target_include_directories(sdf PRIVATE ${MUJOCO_SDF_INCLUDE}) -target_link_libraries(sdf PRIVATE mujoco SdfLib) +add_library(sdf_plugin SHARED) +target_sources(sdf_plugin PRIVATE ${MUJOCO_SDF_SRCS}) +target_include_directories(sdf_plugin PRIVATE ${MUJOCO_SDF_INCLUDE}) +target_link_libraries(sdf_plugin PRIVATE mujoco SdfLib) target_compile_options( - sdf + sdf_plugin PRIVATE ${AVX_COMPILE_OPTIONS} ${MUJOCO_MACOS_COMPILE_OPTIONS} ${EXTRA_COMPILE_OPTIONS} ${MUJOCO_CXX_FLAGS} ) target_link_options( - sdf + sdf_plugin PRIVATE ${MUJOCO_MACOS_LINK_OPTIONS} ${EXTRA_LINK_OPTIONS} diff --git a/src/experimental/usd/plugins/CMakeLists.txt b/src/experimental/usd/plugins/CMakeLists.txt new file mode 100644 index 00000000..6e506493 --- /dev/null +++ b/src/experimental/usd/plugins/CMakeLists.txt @@ -0,0 +1,137 @@ +# Copyright 2025 DeepMind Technologies Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# Plugin target name (used for library and plugInfo.json) +set(MJCF_PLUGIN_TARGET_NAME usdMjcf) + +add_library(${MJCF_PLUGIN_TARGET_NAME} SHARED + mjcf/mjcf_file_format.cc + mjcf/mjcf_file_format.h + mjcf/mujoco_to_usd.cc + mjcf/mujoco_to_usd.h + mjcf/utils.cc + mjcf/utils.h +) + +# We need to set the visibility to default until core type symbol visibility +# is resolved in OpenUSD https://github.com/PixarAnimationStudios/OpenUSD/issues/1475 +# Otherwise we will run into issues during composition on MacOS due to std::type_info +# comparisons failing for pxr::TfTokenVector and the like that we place in SdfAbstractData. +set_target_properties(${MJCF_PLUGIN_TARGET_NAME} PROPERTIES + OUTPUT_NAME ${MJCF_PLUGIN_TARGET_NAME} + CXX_VISIBILITY_PRESET default +) + +target_include_directories(${MJCF_PLUGIN_TARGET_NAME} PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}" +) + +if (MUJOCO_USD_TARGET STREQUAL "USD") + find_package(pxr REQUIRED) + + # --- Link Dependencies --- + # Link against the necessary OpenUSD components + target_link_libraries(${MJCF_PLUGIN_TARGET_NAME} PRIVATE + usd + ar + kind + tf + gf + vt + usdShade + usdLux + usdGeom + usdImaging + usdPhysics + mujoco + tinyxml2 + ) +elseif (MUJOCO_USD_TARGET STREQUAL "Houdini") + + if (NOT DEFINED ENV{HFS}) + message(FATAL_ERROR "Environment variable 'HFS' is not defined: $ENV{HFS}. Please run houdini_setup.") + endif() + + # In Houdini, the Houdini package we would typically use via find_package + # does not have all the USD dependencies that we need (namely UsdPhysics) + # so we need to manually link all the required libraries. + + set(HFS_ENV "$ENV{HFS}") + set(HOUDINI_LIBS "${HFS_ENV}/../Libraries") + get_filename_component(HOUDINI_LIBS "${HOUDINI_LIBS}" ABSOLUTE) # Normalize the path + target_link_directories(${MJCF_PLUGIN_TARGET_NAME} PRIVATE ${HOUDINI_LIBS}) + + target_include_directories(${MJCF_PLUGIN_TARGET_NAME} PRIVATE + "${HFS_ENV}/toolkit/include" + "${HFS_ENV}/toolkit/include/python3.11" + ) + + # Assume everyone using Houdini on 3.11 for now. + set(USD_MJCF_PYTHON_LIB python3.11) + set(USD_MJCF_PYTHON_LIB_NUMBER python311) + set(PYTHON_LIB "${HFS_ENV}/Frameworks/Python.framework/Versions/3.11/Python") + set(PXR_LIB_PREFIX "pxr_") + + # --- Link Dependencies --- + # Link against the necessary OpenUSD components + target_link_libraries(${MJCF_PLUGIN_TARGET_NAME} PRIVATE + ${PXR_LIB_PREFIX}usd + ${PXR_LIB_PREFIX}ar + ${PXR_LIB_PREFIX}kind + ${PXR_LIB_PREFIX}tf + ${PXR_LIB_PREFIX}gf + ${PXR_LIB_PREFIX}vt + ${PXR_LIB_PREFIX}sdf + ${PXR_LIB_PREFIX}usdShade + ${PXR_LIB_PREFIX}usdLux + ${PXR_LIB_PREFIX}usdGeom + ${PXR_LIB_PREFIX}usdImaging + ${PXR_LIB_PREFIX}usdPhysics + tbb + hboost_${USD_MJCF_PYTHON_LIB_NUMBER} + ${PYTHON_LIB} + mujoco + tinyxml2 + ) +endif() + + +# --- Generate plugInfo.json --- +if(CMAKE_SHARED_LIBRARY_PREFIX) + set(LIB_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX}) # Usually "lib" on Unix +else() + set(LIB_PREFIX "") +endif() +set(PLUG_INFO_LIBRARY_PATH "${LIB_PREFIX}${MJCF_PLUGIN_TARGET_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}") + +# --- Installation --- + +set(USD_PLUGIN_INSTALL_DIR_LIB ${CMAKE_INSTALL_LIBDIR}/usdMjcf) + +message(STATUS "Copying plugInfo.json to ${CMAKE_BINARY_DIR}/${USD_PLUGIN_INSTALL_DIR_LIB}/plugInfo.json") +configure_file( + mjcf/plugInfo.json + ${CMAKE_BINARY_DIR}/${USD_PLUGIN_INSTALL_DIR_LIB}/plugInfo.json +) + +install(FILES ${CMAKE_BINARY_DIR}/${USD_PLUGIN_INSTALL_DIR_LIB}/plugInfo.json DESTINATION ${USD_PLUGIN_INSTALL_DIR_LIB}) + +# Install shared lib and plugInfo to same location for simplicity. +install(TARGETS ${MJCF_PLUGIN_TARGET_NAME} + LIBRARY DESTINATION ${USD_PLUGIN_INSTALL_DIR_LIB} +) + +message(STATUS "USD MJCF Plugin will be installed to: ${CMAKE_INSTALL_PREFIX}/${USD_PLUGIN_INSTALL_DIR_LIB}") +message(STATUS "Make sure PXR_PLUGINPATH_NAME includes: ${CMAKE_INSTALL_PREFIX}/${USD_PLUGIN_INSTALL_DIR_LIB}") diff --git a/src/experimental/usd/plugins/mjcf/plugInfo.json b/src/experimental/usd/plugins/mjcf/plugInfo.json index 25869b76..da1f9ebd 100644 --- a/src/experimental/usd/plugins/mjcf/plugInfo.json +++ b/src/experimental/usd/plugins/mjcf/plugInfo.json @@ -15,7 +15,7 @@ } } }, - "LibraryPath": "", + "LibraryPath": "@PLUG_INFO_LIBRARY_PATH@", "Name": "usdMjcf", "ResourcePath": "", "Root": ".", diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0f92803d..a286a1c6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -100,3 +100,4 @@ add_subdirectory(user) add_subdirectory(xml) add_subdirectory(plugin/elasticity) add_subdirectory(plugin/actuator) +add_subdirectory(experimental) diff --git a/test/experimental/CMakeLists.txt b/test/experimental/CMakeLists.txt new file mode 100644 index 00000000..9f5100db --- /dev/null +++ b/test/experimental/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright 2021 DeepMind Technologies Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if(MUJOCO_BUILD_USD_PLUGINS AND MUJOCO_USD_TARGET STREQUAL "USD") + add_subdirectory(usd/plugins/mjcf) +endif() + + diff --git a/test/experimental/usd/plugins/mjcf/CMakeLists.txt b/test/experimental/usd/plugins/mjcf/CMakeLists.txt new file mode 100644 index 00000000..1b747aee --- /dev/null +++ b/test/experimental/usd/plugins/mjcf/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright 2025 DeepMind Technologies Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +find_package(pxr REQUIRED) + +add_library(usd_fixture STATIC fixture.h fixture.cc) +target_include_directories(usd_fixture PUBLIC ${MUJOCO_TEST_INCLUDE}) +target_compile_definitions(usd_fixture PUBLIC MJSTATIC) + +target_link_libraries( + usd_fixture + PUBLIC usd + tf + gtest + gmock + mujoco +) + +mujoco_test(mjcf_file_format_test ADDITIONAL_LINK_LIBRARIES usd tf usdGeom usdImaging usdPhysics usdShade usd_fixture)