Merge remote-tracking branch 'upstream/main' into tendons

This commit is contained in:
Abhishek Joshi
2024-07-04 15:10:29 -05:00
143 changed files with 7752 additions and 3408 deletions
+3
View File
@@ -148,6 +148,7 @@ jobs:
cd build && cd build &&
cmake .. cmake ..
-DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_BUILD_TYPE:STRING=Release
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION:BOOL=OFF
-DCMAKE_INSTALL_PREFIX:STRING=${{ matrix.tmpdir }}/mujoco_install -DCMAKE_INSTALL_PREFIX:STRING=${{ matrix.tmpdir }}/mujoco_install
-DMUJOCO_BUILD_EXAMPLES:BOOL=OFF -DMUJOCO_BUILD_EXAMPLES:BOOL=OFF
${{ matrix.cmake_args }} ${{ matrix.cmake_args }}
@@ -192,6 +193,7 @@ jobs:
cd build && cd build &&
cmake .. cmake ..
-DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_BUILD_TYPE:STRING=Release
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION:BOOL=OFF
-Dmujoco_ROOT:STRING=${{ matrix.tmpdir }}/mujoco_install -Dmujoco_ROOT:STRING=${{ matrix.tmpdir }}/mujoco_install
${{ matrix.cmake_args }} ${{ matrix.cmake_args }}
- name: Build samples - name: Build samples
@@ -204,6 +206,7 @@ jobs:
cd build && cd build &&
cmake .. cmake ..
-DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_BUILD_TYPE:STRING=Release
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION:BOOL=OFF
-Dmujoco_ROOT:STRING=${{ matrix.tmpdir }}/mujoco_install -Dmujoco_ROOT:STRING=${{ matrix.tmpdir }}/mujoco_install
${{ matrix.cmake_args }} ${{ matrix.cmake_args }}
- name: Build simulate - name: Build simulate
+1 -1
View File
@@ -41,7 +41,7 @@ release can be found in the [changelog] in the latest branch.
There are two easy ways to get started with MuJoCo: There are two easy ways to get started with MuJoCo:
1. **Run `simulate` on your machine.** 1. **Run `simulate` on your machine.**
[This video](https://www.youtube.com/watch?v=0ORsj_E17B0) shows a screen capture [This video](https://www.youtube.com/watch?v=P83tKA1iz2Y) shows a screen capture
of `simulate`, MuJoCo's native interactive viewer. Follow the steps described in of `simulate`, MuJoCo's native interactive viewer. Follow the steps described in
the [Getting Started] section of the documentation to get `simulate` running on the [Getting Started] section of the documentation to get `simulate` running on
your machine. your machine.
+4
View File
@@ -104,6 +104,10 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang
endif() endif()
endif() endif()
if(NOT CMAKE_INTERPROCEDURAL_OPTIMIZATION AND (CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug"))
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
endif()
include(MujocoHarden) include(MujocoHarden)
set(EXTRA_COMPILE_OPTIONS ${EXTRA_COMPILE_OPTIONS} ${MUJOCO_HARDEN_COMPILE_OPTIONS}) set(EXTRA_COMPILE_OPTIONS ${EXTRA_COMPILE_OPTIONS} ${MUJOCO_HARDEN_COMPILE_OPTIONS})
set(EXTRA_LINK_OPTIONS ${EXTRA_LINK_OPTIONS} ${MUJOCO_HARDEN_LINK_OPTIONS}) set(EXTRA_LINK_OPTIONS ${EXTRA_LINK_OPTIONS} ${MUJOCO_HARDEN_LINK_OPTIONS})
+8 -6
View File
@@ -414,12 +414,6 @@ shown in the table below. Their names are in the format ``mjKEY_XXX``. They corr
- 50 - 50
- The maximum depth of each body and mesh bounding volume hierarchy. If this large limit is exceeded, a warning - The maximum depth of each body and mesh bounding volume hierarchy. If this large limit is exceeded, a warning
is raised and ray casting may not be possible. For a balanced hierarchy, this implies 1E15 bounding volumes. is raised and ray casting may not be possible. For a balanced hierarchy, this implies 1E15 bounding volumes.
* - ``mjMAXVFS``
- 200
- The maximal number of characters in the name of each file in the virtual file system.
* - ``mjMAXVFSNAME``
- 100
- The maximal number of characters in the name of each file in the virtual file system.
* - ``mjNEQDATA`` * - ``mjNEQDATA``
- 11 - 11
- The maximal number of real-valued parameters used to define each equality constraint. Determines the size of - The maximal number of real-valued parameters used to define each equality constraint. Determines the size of
@@ -534,6 +528,14 @@ shown in the table below. Their names are in the format ``mjKEY_XXX``. They corr
Macros Macros
^^^^^^ ^^^^^^
.. _mjUSESINGLE:
mjUSESINGLE
~~~~~~~~~~~
Compile-time flag, see :ref:`mjtNum`.
.. _mjDISABLED: .. _mjDISABLED:
mjDISABLED mjDISABLED
+27 -11
View File
@@ -54,24 +54,28 @@ The two types below are defined in `mjtnum.h <https://github.com/google-deepmind
mjtNum mjtNum
^^^^^^ ^^^^^^
This is the floating-point type used throughout the simulator. If the symbol ``mjUSEDOUBLE`` is defined in This is the floating-point type used throughout the simulator. When using the default build configuration, ``mjtNum`` is
``mjmodel.h``, this type is defined as ``double``, otherwise it is defined as ``float``. Currently only the defined as ``double``. If the symbol ``mjUSESINGLE`` is defined, ``mjtNum`` is defined as ``float``.
double-precision version of MuJoCo is distributed, although the entire code base works with single-precision as well.
We may release the single-precision version in the future for efficiency reasons, but the double-precision version
will always be available. Thus it is safe to write user code assuming double precision. However, our preference is to
write code that works with either single or double precision. To this end we provide math utility functions that are
always defined with the correct floating-point type.
Note that changing ``mjUSEDOUBLE`` in ``mjtnum.h`` will not change how the library was compiled, and instead will Currently only the double-precision version of MuJoCo is distributed, although the entire code base works with
single-precision as well. We may release the single-precision version in the future, but the
double-precision version will always be available. Thus it is safe to write user code assuming double precision.
However, our preference is to write code that works with either single or double precision. To this end we provide math
utility functions that are always defined with the correct floating-point type.
Note that changing ``mjUSESINGLE`` in ``mjtnum.h`` will not change how the library was compiled, and instead will
result in numerous link errors. In general, the header files distributed with precompiled MuJoCo should never be result in numerous link errors. In general, the header files distributed with precompiled MuJoCo should never be
changed by the user. changed by the user.
.. code-block:: C .. code-block:: C
#ifdef mjUSEDOUBLE // floating point data type and minval
typedef double mjtNum; #ifndef mjUSESINGLE
typedef double mjtNum;
#define mjMINVAL 1E-15 // minimum value in any denominator
#else #else
typedef float mjtNum; typedef float mjtNum;
#define mjMINVAL 1E-15f
#endif #endif
@@ -578,6 +582,18 @@ Item types used in the UI framework.
.. mujoco-include:: mjtItem .. mujoco-include:: mjtItem
.. _mjtSection:
mjtSection
~~~~~~~~~~
State of a UI section.
.. mujoco-include:: mjtSection
.. _tySpecEnums: .. _tySpecEnums:
Spec Spec
+236 -29
View File
@@ -1203,7 +1203,7 @@ mj_defaultVFS
.. mujoco-include:: mj_defaultVFS .. mujoco-include:: mj_defaultVFS
Initialize VFS to empty (no deallocation). Initialize an empty VFS, mj_deleteVFS must be called to deallocate the VFS.
.. _mj_addFileVFS: .. _mj_addFileVFS:
@@ -1224,15 +1224,6 @@ mj_addBufferVFS
Add file to VFS from buffer, return 0: success, 1: full, 2: repeated name, -1: failed to load. Add file to VFS from buffer, return 0: success, 1: full, 2: repeated name, -1: failed to load.
.. _mj_findFileVFS:
mj_findFileVFS
~~~~~~~~~~~~~~
.. mujoco-include:: mj_findFileVFS
Return file index in VFS, or -1 if not found in VFS.
.. _mj_deleteFileVFS: .. _mj_deleteFileVFS:
mj_deleteFileVFS mj_deleteFileVFS
@@ -1249,16 +1240,7 @@ mj_deleteVFS
.. mujoco-include:: mj_deleteVFS .. mujoco-include:: mj_deleteVFS
Delete all files from VFS. Delete all files from VFS and deallocates VFS internal memory.
.. _mj_makeEmptyFileVFS:
mj_makeEmptyFileVFS
~~~~~~~~~~~~~~~~~~~
.. mujoco-include:: mj_makeEmptyFileVFS
deprecated: use mj_copyBufferVFS.
.. _Initialization: .. _Initialization:
@@ -4131,6 +4113,15 @@ mjs_findFrame
Find frame by name. Find frame by name.
.. _mjs_findKeyframe:
mjs_findKeyframe
~~~~~~~~~~~~~~~~
.. mujoco-include:: mjs_findKeyframe
Find keyframe by name.
.. _mjs_getDefault: .. _mjs_getDefault:
mjs_getDefault mjs_getDefault
@@ -4185,6 +4176,231 @@ mjs_nextChild
Return body's next child of the same type; return NULL if child is last. Return body's next child of the same type; return NULL if child is last.
.. _mjs_firstElement:
mjs_firstElement
~~~~~~~~~~~~~~~~
.. mujoco-include:: mjs_firstElement
Return spec's first element of selected type.
.. _mjs_nextElement:
mjs_nextElement
~~~~~~~~~~~~~~~
.. mujoco-include:: mjs_nextElement
Return spec's next element; return NULL if element is last.
.. _mjs_asBody:
mjs_asBody
~~~~~~~~~~
.. mujoco-include:: mjs_asBody
Safely cast an element as mjsBody, or return NULL if the element is not an mjsBody.
.. _mjs_asGeom:
mjs_asGeom
~~~~~~~~~~
.. mujoco-include:: mjs_asGeom
Safely cast an element as mjsGeom, or return NULL if the element is not an mjsGeom.
.. _mjs_asJoint:
mjs_asJoint
~~~~~~~~~~~
.. mujoco-include:: mjs_asJoint
Safely cast an element as mjsJoint, or return NULL if the element is not an mjsJoint.
.. _mjs_asSite:
mjs_asSite
~~~~~~~~~~
.. mujoco-include:: mjs_asSite
Safely cast an element as mjsSite, or return NULL if the element is not an mjsSite.
.. _mjs_asCamera:
mjs_asCamera
~~~~~~~~~~~~
.. mujoco-include:: mjs_asCamera
Safely cast an element as mjsCamera, or return NULL if the element is not an mjsCamera.
.. _mjs_asLight:
mjs_asLight
~~~~~~~~~~~
.. mujoco-include:: mjs_asLight
Safely cast an element as mjsLight, or return NULL if the element is not an mjsLight.
.. _mjs_asFrame:
mjs_asFrame
~~~~~~~~~~~
.. mujoco-include:: mjs_asFrame
Safely cast an element as mjsFrame, or return NULL if the element is not an mjsFrame.
.. _mjs_asActuator:
mjs_asActuator
~~~~~~~~~~~~~~
.. mujoco-include:: mjs_asActuator
Safely cast an element as mjsActuator, or return NULL if the element is not an mjsActuator.
.. _mjs_asSensor:
mjs_asSensor
~~~~~~~~~~~~
.. mujoco-include:: mjs_asSensor
Safely cast an element as mjsSensor, or return NULL if the element is not an mjsSensor.
.. _mjs_asFlex:
mjs_asFlex
~~~~~~~~~~
.. mujoco-include:: mjs_asFlex
Safely cast an element as mjsFlex, or return NULL if the element is not an mjsFlex.
.. _mjs_asPair:
mjs_asPair
~~~~~~~~~~
.. mujoco-include:: mjs_asPair
Safely cast an element as mjsPair, or return NULL if the element is not an mjsPair.
.. _mjs_asEquality:
mjs_asEquality
~~~~~~~~~~~~~~
.. mujoco-include:: mjs_asEquality
Safely cast an element as mjsEquality, or return NULL if the element is not an mjsEquality.
.. _mjs_asExclude:
mjs_asExclude
~~~~~~~~~~~~~
.. mujoco-include:: mjs_asExclude
Safely cast an element as mjsExclude, or return NULL if the element is not an mjsExclude.
.. _mjs_asTendon:
mjs_asTendon
~~~~~~~~~~~~
.. mujoco-include:: mjs_asTendon
Safely cast an element as mjsTendon, or return NULL if the element is not an mjsTendon.
.. _mjs_asNumeric:
mjs_asNumeric
~~~~~~~~~~~~~
.. mujoco-include:: mjs_asNumeric
Safely cast an element as mjsNumeric, or return NULL if the element is not an mjsNumeric.
.. _mjs_asText:
mjs_asText
~~~~~~~~~~
.. mujoco-include:: mjs_asText
Safely cast an element as mjsText, or return NULL if the element is not an mjsText.
.. _mjs_asTuple:
mjs_asTuple
~~~~~~~~~~~
.. mujoco-include:: mjs_asTuple
Safely cast an element as mjsTuple, or return NULL if the element is not an mjsTuple.
.. _mjs_asKey:
mjs_asKey
~~~~~~~~~
.. mujoco-include:: mjs_asKey
Safely cast an element as mjsKey, or return NULL if the element is not an mjsKey.
.. _mjs_asMesh:
mjs_asMesh
~~~~~~~~~~
.. mujoco-include:: mjs_asMesh
Safely cast an element as mjsMesh, or return NULL if the element is not an mjsMesh.
.. _mjs_asHField:
mjs_asHField
~~~~~~~~~~~~
.. mujoco-include:: mjs_asHField
Safely cast an element as mjsHField, or return NULL if the element is not an mjsHField.
.. _mjs_asSkin:
mjs_asSkin
~~~~~~~~~~
.. mujoco-include:: mjs_asSkin
Safely cast an element as mjsSkin, or return NULL if the element is not an mjsSkin.
.. _mjs_asTexture:
mjs_asTexture
~~~~~~~~~~~~~
.. mujoco-include:: mjs_asTexture
Safely cast an element as mjsTexture, or return NULL if the element is not an mjsTexture.
.. _mjs_asMaterial:
mjs_asMaterial
~~~~~~~~~~~~~~
.. mujoco-include:: mjs_asMaterial
Safely cast an element as mjsMaterial, or return NULL if the element is not an mjsMaterial.
.. _AttributeSetters: .. _AttributeSetters:
Attribute setters Attribute setters
@@ -4341,15 +4557,6 @@ mjs_resolveOrientation
Resolve alternative orientations to quat, return error if any. Resolve alternative orientations to quat, return error if any.
.. _mjs_fullInertia:
mjs_fullInertia
~~~~~~~~~~~~~~~
.. mujoco-include:: mjs_fullInertia
Compute quat and diag inertia from full inertia matrix, return error if any.
.. _ElementInitialization: .. _ElementInitialization:
Element initialization Element initialization
+21 -15
View File
@@ -1564,17 +1564,21 @@ still be specified here but this functionality is now deprecated and will be rem
This and the remaining attributes control the generation of procedural textures. If the value of this attribute is This and the remaining attributes control the generation of procedural textures. If the value of this attribute is
different from "none", the texture is treated as procedural and any file names are ignored. The keywords have the different from "none", the texture is treated as procedural and any file names are ignored. The keywords have the
following meaning: following meaning:
The **gradient** type generates a color gradient from rgb1 to rgb2. The interpolation in color space is done through
a sigmoid function. For cube and skybox textures the gradient is along the +Y axis, i.e., from top to bottom for
skybox rendering.
The **checker** type generates a 2-by-2 checker pattern with alternating colors given by rgb1 to rgb2. This is **gradient**
suitable for rendering ground planes and also for marking objects with rotational symmetries. Note that 2d textures Generates a color gradient from rgb1 to rgb2. The interpolation in color space is done through
can be scaled so as to repeat the pattern as many times as necessary. For cube and skybox textures, the checker a sigmoid function. For cube and skybox textures the gradient is along the +Y axis, i.e., from top to bottom for
pattern is painted on each side of the cube. skybox rendering.
The **flat** type fills the entire texture with rgb1, except for the bottom face of cube and skybox textures which is **checker**
filled with rgb2. Generates a 2-by-2 checker pattern with alternating colors given by rgb1 and rgb2. This is suitable for rendering
ground planes and also for marking objects with rotational symmetries. Note that 2d textures can be scaled so as
to repeat the pattern as many times as necessary. For cube and skybox textures, the checker pattern is painted on
each side of the cube.
**flat**
Fills the entire texture with rgb1, except for the bottom face of cube and skybox textures which is
filled with rgb2.
.. _asset-texture-rgb1: .. _asset-texture-rgb1:
@@ -1604,21 +1608,23 @@ still be specified here but this functionality is now deprecated and will be rem
:at:`random`: :at-val:`real, "0.01"` :at:`random`: :at-val:`real, "0.01"`
When the mark attribute is set to "random", this attribute determines the probability of turning on each pixel. Note When the mark attribute is set to "random", this attribute determines the probability of turning on each pixel. Note
that larger textures have more pixels, and the probability here is applied independently to each pixel - thus the that larger textures have more pixels, and the probability here is applied independently to each pixel -- thus the
texture size and probability need to be adjusted jointly. Together with a gradient skybox texture, this can create texture size and probability need to be adjusted jointly. Together with a gradient skybox texture, this can create
the appearance of a night sky with stars. the appearance of a night sky with stars. The random number generator is initialized with a fixed seed.
.. _asset-texture-width: .. _asset-texture-width:
:at:`width`: :at-val:`int, "0"` :at:`width`: :at-val:`int, "0"`
The width of the procedural texture, i.e., the number of columns in the image. For cube and skybox procedural The width of a procedural texture, i.e., the number of columns in the image. Larger values usually result in higher
textures the width and height must be equal. Larger values usually result in higher quality images, although in some quality images, although in some cases (e.g. checker patterns) small values are sufficient. For textures loaded from
cases (e.g. checker patterns) small values are sufficient. files, this attribute is ignored.
.. _asset-texture-height: .. _asset-texture-height:
:at:`height`: :at-val:`int, "0"` :at:`height`: :at-val:`int, "0"`
The height of the procedural texture, i.e., the number of rows in the image. The height of the procedural texture, i.e., the number of rows in the image. For cube and skybox textures, this
attribute is ignored and the height is set to 6 times the width. For textures loaded from files, this attribute is
ignored.
.. _asset-texture-hflip: .. _asset-texture-hflip:
+53 -13
View File
@@ -7,30 +7,70 @@ Upcoming version (not yet released)
General General
^^^^^^^ ^^^^^^^
1. Added a new API for :doc:`procedural model manipulation<programming/modeledit>`. Fixes :github:issue:`364`. .. admonition:: Breaking API changes
:class: attention
1. Removed deprecated ``mj_makeEmptyFileVFS`` and ``mj_findFileVFS`` functions. The constants ``mjMAXVFS`` and
``mjMAXVFSNAME`` are also removed as they are no longer needed.
**Migration:** Use :ref:`mj_addBufferVFS` to copy a buffer into a VFS file directly.
2. Calls to :ref:`mj_defaultVFS` may allocate memory inside VFS, and the corresponding
:ref:`mj_deleteVFS` must be called to deallocate any internal allocated memory.
3. Deprecated :ref:`mju_rotVecMat` and :ref:`mju_rotVecMatT` in favor of :ref:`mju_mulMatVec3` and
:ref:`mju_mulMatTVec3`. These function names and argument order are more consistent with the rest of the API.
The older functions have been removed from the Python bindings and will be removed from the C API in the next
release.
4. The :ref:`VFS<Virtualfilesystem>` implementation has been rewritten in C++ and is now considerably more efficient in
speed and memory footprint.
5. Added a new API for :doc:`procedural model manipulation<programming/modeledit>`. Fixes :github:issue:`364`.
Still missing: Still missing:
- Detailed documentation. - Detailed documentation.
- Python bindings.
.. youtube:: ZXBTEIDWHhs .. youtube:: ZXBTEIDWHhs
:align: right :align: right
:width: 240px :width: 240px
2. Added support for orthographic cameras. This is available for both fixed cameras and the free camera, using the 6. Added support for orthographic cameras. This is available for both fixed cameras and the free camera, using the
:ref:`camera/orthographic<body-camera-orthographic>` and :ref:`global/orthographic<visual-global-orthographic>` :ref:`camera/orthographic<body-camera-orthographic>` and :ref:`global/orthographic<visual-global-orthographic>`
attributes, respectively. attributes, respectively.
3. Added :ref:`maxhullvert<asset-mesh-maxhullvert>`, the maximum number of vertices in a mesh's convex hull. 7. Added :ref:`maxhullvert<asset-mesh-maxhullvert>`, the maximum number of vertices in a mesh's convex hull.
4. Added :ref:`mj_setKeyframe` for saving the current state into a model keyframe. 8. Added :ref:`mj_setKeyframe` for saving the current state into a model keyframe.
5. Added support for ``ball`` joints in the URDF parser ("spherical" in URDF). 9. Added support for ``ball`` joints in the URDF parser ("spherical" in URDF).
6. Deprecated :ref:`mju_rotVecMat` and :ref:`mju_rotVecMatT` in favor of :ref:`mju_mulMatVec3` and 10. Replaced ``mjUSEDOUBLE`` which was previously hard-coded in
:ref:`mju_mulMatTVec3`. These functions names and argument ordering are more consistent with the rest of the API. `mjtnum.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjtnum.h>`__
with the build-time flag ``mjUSESINGLE``. If this symbol is not defined, MuJoCo will use double-precision floating
point, as usual. If ``mjUSESINGLE`` is defined, MuJoCo will use single-precision floating point. See :ref:`mjtNum`.
Relatedly, fixed various type errors that prevented building with single-precision.
11. Quaternions in ``mjData->qpos`` and ``mjData->mocap_quat`` are no longer normalized in-place by
:ref:`mj_kinematics`. Instead they are normalized when they are used. After the first step, quaternions in
``mjData->qpos`` will be normalized.
MJX MJX
~~~ ~~~
7. Added support for :ref:`elliptic friction cones<option-cone>`. 12. Added support for :ref:`elliptic friction cones<option-cone>`.
8. Fixed a bug that resulted in less-optimal linesearch solutions for some difficult constraint settings. 13. Fixed a bug that resulted in less-optimal linesearch solutions for some difficult constraint settings.
9. Fixed a bug in the Newton solver that sometimes resulted in less-optimal gradients. 14. Fixed a bug in the Newton solver that sometimes resulted in less-optimal gradients.
.. youtube:: P83tKA1iz2Y
:align: right
:width: 360px
Simulate
^^^^^^^^
15. Added improved tutorial video.
16. Improved the Brownian noise generator.
|br| |br| |br| |br|
Python bindings
^^^^^^^^^^^^^^^
17. Fixed a memory leak when using ``copy.deepcopy()`` on a ``mujoco.MjData`` instance (:github:issue:`1572`).
Version 3.1.6 (Jun 3, 2024) Version 3.1.6 (Jun 3, 2024)
--------------------------- ---------------------------
@@ -199,10 +239,10 @@ General
:at:`ctrlrange` or :at:`actrange` (respectively), according to the range of the transmission :at:`ctrlrange` or :at:`actrange` (respectively), according to the range of the transmission
target (joint or tendon). See :ref:`position/inheritrange<actuator-position-inheritrange>` for target (joint or tendon). See :ref:`position/inheritrange<actuator-position-inheritrange>` for
details. details.
2. Deprecated :ref:`mj_makeEmptyFileVFS` in favor of :ref:`mj_addBufferVFS`. :ref:`mjVFS` now computes checksums of 2. Deprecated ``mj_makeEmptyFileVFS`` in favor of :ref:`mj_addBufferVFS`. :ref:`mjVFS` now computes checksums of
its internal file buffers. :ref:`mj_addBufferVFS` allocates an empty buffer with a given name in an mjVFS and its internal file buffers. :ref:`mj_addBufferVFS` allocates an empty buffer with a given name in an mjVFS and
copies the data buffer into it, combining and replacing the deprecated two-step process of calling copies the data buffer into it, combining and replacing the deprecated two-step process of calling
:ref:`mj_makeEmptyFileVFS` followed by a direct copy into the given mjVFS internal file buffer. ``mj_makeEmptyFileVFS`` followed by a direct copy into the given mjVFS internal file buffer.
3. Added :ref:`mj_angmomMat` which computes the ``3 x nv`` angular momentum matrix :math:`H(q)`, providing the linear 3. Added :ref:`mj_angmomMat` which computes the ``3 x nv`` angular momentum matrix :math:`H(q)`, providing the linear
mapping from generalized velocities to subtree angular momentum :math:`h = H \dot q`. Contribution by mapping from generalized velocities to subtree angular momentum :math:`h = H \dot q`. Contribution by
:github:user:`v-r-a`. :github:user:`v-r-a`.
+144 -115
View File
@@ -139,29 +139,29 @@ struct mjData_ {
int nplugin; // number of plugin instances int nplugin; // number of plugin instances
// stack pointer // stack pointer
size_t pstack; // first available mjtNum address in stack size_t pstack; // first available byte in stack
size_t pbase; // value of pstack when mj_markStack was last called size_t pbase; // value of pstack when mj_markStack was last called
// arena pointer // arena pointer
size_t parena; // first available byte in arena size_t parena; // first available byte in arena
// memory utilization stats // memory utilization statistics
size_t maxuse_stack; // maximum stack allocation in bytes size_t maxuse_stack; // maximum stack allocation in bytes
size_t maxuse_threadstack[mjMAXTHREAD]; // maximum stack allocation per thread in bytes size_t maxuse_threadstack[mjMAXTHREAD]; // maximum stack allocation per thread in bytes
size_t maxuse_arena; // maximum arena allocation in bytes size_t maxuse_arena; // maximum arena allocation in bytes
int maxuse_con; // maximum number of contacts int maxuse_con; // maximum number of contacts
int maxuse_efc; // maximum number of scalar constraints int maxuse_efc; // maximum number of scalar constraints
// diagnostics
mjWarningStat warning[mjNWARNING]; // warning statistics
mjTimerStat timer[mjNTIMER]; // timer statistics
// solver statistics // solver statistics
mjSolverStat solver[mjNISLAND*mjNSOLVER]; // solver statistics per island, per iteration mjSolverStat solver[mjNISLAND*mjNSOLVER]; // solver statistics per island, per iteration
int solver_nisland; // number of islands processed by solver int solver_nisland; // number of islands processed by solver
int solver_niter[mjNISLAND]; // number of solver iterations, per island int solver_niter[mjNISLAND]; // number of solver iterations, per island
int solver_nnz[mjNISLAND]; // number of non-zeros in Hessian or efc_AR, per island int solver_nnz[mjNISLAND]; // number of nonzeros in Hessian or efc_AR, per island
mjtNum solver_fwdinv[2]; // forward-inverse comparison: qfrc, efc mjtNum solver_fwdinv[2]; // forward-inverse comparison: qfrc, efc
// diagnostics
mjWarningStat warning[mjNWARNING]; // warning statistics
mjTimerStat timer[mjNTIMER]; // timer statistics
// variable sizes // variable sizes
int ne; // number of equality constraints int ne; // number of equality constraints
@@ -179,8 +179,8 @@ struct mjData_ {
//-------------------- end of info header //-------------------- end of info header
// buffers // buffers
void* buffer; // main buffer; all pointers point in it (nbuffer bytes) void* buffer; // main buffer; all pointers point in it (nbuffer bytes)
void* arena; // arena+stack buffer (nstack*sizeof(mjtNum) bytes) void* arena; // arena+stack buffer (narena bytes)
//-------------------- main inputs and outputs of the computation //-------------------- main inputs and outputs of the computation
@@ -274,7 +274,7 @@ struct mjData_ {
// computed by mj_collisionTree // computed by mj_collisionTree
mjtNum* bvh_aabb_dyn; // global bounding box (center, size) (nbvhdynamic x 6) mjtNum* bvh_aabb_dyn; // global bounding box (center, size) (nbvhdynamic x 6)
mjtByte* bvh_active; // volume has been added to collisions (nbvh x 1) mjtByte* bvh_active; // was bounding volume checked for collision (nbvh x 1)
//-------------------- POSITION, VELOCITY dependent //-------------------- POSITION, VELOCITY dependent
@@ -344,7 +344,7 @@ struct mjData_ {
//-------------------- arena-allocated: POSITION dependent //-------------------- arena-allocated: POSITION dependent
// computed by mj_collision // computed by mj_collision
mjContact* contact; // list of all detected contacts (ncon x 1) mjContact* contact; // array of all detected contacts (ncon x 1)
// computed by mj_makeConstraint // computed by mj_makeConstraint
int* efc_type; // constraint type (mjtConstraint) (nefc x 1) int* efc_type; // constraint type (mjtConstraint) (nefc x 1)
@@ -394,11 +394,11 @@ struct mjData_ {
//-------------------- arena-allocated: POSITION, VELOCITY, CONTROL/ACCELERATION dependent //-------------------- arena-allocated: POSITION, VELOCITY, CONTROL/ACCELERATION dependent
// computed by mj_fwdConstraint/mj_inverse // computed by mj_fwdConstraint/mj_inverse
mjtNum* efc_b; // linear cost term: J*qacc_smooth - aref (nefc x 1) mjtNum* efc_b; // linear cost term: J*qacc_smooth - aref (nefc x 1)
mjtNum* efc_force; // constraint force in constraint space (nefc x 1) mjtNum* efc_force; // constraint force in constraint space (nefc x 1)
int* efc_state; // constraint state (mjtConstraintState) (nefc x 1) int* efc_state; // constraint state (mjtConstraintState) (nefc x 1)
// ThreadPool for multithreaded operations // thread pool pointer
uintptr_t threadpool; uintptr_t threadpool;
}; };
typedef struct mjData_ mjData; typedef struct mjData_ mjData;
@@ -699,11 +699,7 @@ struct mjLROpt_ { // options for mj_setLengthRange()
}; };
typedef struct mjLROpt_ mjLROpt; typedef struct mjLROpt_ mjLROpt;
struct mjVFS_ { // virtual file system for loading from memory struct mjVFS_ { // virtual file system for loading from memory
int nfile; // number of files present void* impl_; // internal pointer to VFS memory
char filename[mjMAXVFS][mjMAXVFSNAME]; // file name without path
size_t filesize[mjMAXVFS]; // file size in bytes
void* filedata[mjMAXVFS]; // buffer with file data
uint64_t filestamp[mjMAXVFS]; // checksum of the file data
}; };
typedef struct mjVFS_ mjVFS; typedef struct mjVFS_ mjVFS;
struct mjOption_ { // physics options struct mjOption_ { // physics options
@@ -1220,7 +1216,7 @@ struct mjModel_ {
int* tex_pathadr; // address of texture asset path; -1: none (ntex x 1) int* tex_pathadr; // address of texture asset path; -1: none (ntex x 1)
// materials // materials
int* mat_texid; // texture id; -1: none (nmat x 1) int* mat_texid; // indices of textures; -1: none (nmat x mjNTEXMAT)
mjtByte* mat_texuniform; // make texture cube uniform (nmat x 1) mjtByte* mat_texuniform; // make texture cube uniform (nmat x 1)
float* mat_texrepeat; // texture repetition for 2d mapping (nmat x 2) float* mat_texrepeat; // texture repetition for 2d mapping (nmat x 2)
float* mat_emission; // emission (x rgb) (nmat x 1) float* mat_emission; // emission (x rgb) (nmat x 1)
@@ -1512,92 +1508,97 @@ struct mjrRect_ { // OpenGL rectangle
int height; // height (usually buffer height) int height; // height (usually buffer height)
}; };
typedef struct mjrRect_ mjrRect; typedef struct mjrRect_ mjrRect;
struct mjrContext_ { // custom OpenGL context struct mjrContext_ { // custom OpenGL context
// parameters copied from mjVisual // parameters copied from mjVisual
float lineWidth; // line width for wireframe rendering float lineWidth; // line width for wireframe rendering
float shadowClip; // clipping radius for directional lights float shadowClip; // clipping radius for directional lights
float shadowScale; // fraction of light cutoff for spot lights float shadowScale; // fraction of light cutoff for spot lights
float fogStart; // fog start = stat.extent * vis.map.fogstart float fogStart; // fog start = stat.extent * vis.map.fogstart
float fogEnd; // fog end = stat.extent * vis.map.fogend float fogEnd; // fog end = stat.extent * vis.map.fogend
float fogRGBA[4]; // fog rgba float fogRGBA[4]; // fog rgba
int shadowSize; // size of shadow map texture int shadowSize; // size of shadow map texture
int offWidth; // width of offscreen buffer int offWidth; // width of offscreen buffer
int offHeight; // height of offscreen buffer int offHeight; // height of offscreen buffer
int offSamples; // number of offscreen buffer multisamples int offSamples; // number of offscreen buffer multisamples
// parameters specified at creation // parameters specified at creation
int fontScale; // font scale int fontScale; // font scale
int auxWidth[mjNAUX]; // auxiliary buffer width int auxWidth[mjNAUX]; // auxiliary buffer width
int auxHeight[mjNAUX]; // auxiliary buffer height int auxHeight[mjNAUX]; // auxiliary buffer height
int auxSamples[mjNAUX]; // auxiliary buffer multisamples int auxSamples[mjNAUX]; // auxiliary buffer multisamples
// offscreen rendering objects // offscreen rendering objects
unsigned int offFBO; // offscreen framebuffer object unsigned int offFBO; // offscreen framebuffer object
unsigned int offFBO_r; // offscreen framebuffer for resolving multisamples unsigned int offFBO_r; // offscreen framebuffer for resolving multisamples
unsigned int offColor; // offscreen color buffer unsigned int offColor; // offscreen color buffer
unsigned int offColor_r; // offscreen color buffer for resolving multisamples unsigned int offColor_r; // offscreen color buffer for resolving multisamples
unsigned int offDepthStencil; // offscreen depth and stencil buffer unsigned int offDepthStencil; // offscreen depth and stencil buffer
unsigned int offDepthStencil_r; // offscreen depth and stencil buffer for resolving multisamples unsigned int offDepthStencil_r; // offscreen depth and stencil buffer for multisamples
// shadow rendering objects // shadow rendering objects
unsigned int shadowFBO; // shadow map framebuffer object unsigned int shadowFBO; // shadow map framebuffer object
unsigned int shadowTex; // shadow map texture unsigned int shadowTex; // shadow map texture
// auxiliary buffers // auxiliary buffers
unsigned int auxFBO[mjNAUX]; // auxiliary framebuffer object unsigned int auxFBO[mjNAUX]; // auxiliary framebuffer object
unsigned int auxFBO_r[mjNAUX]; // auxiliary framebuffer object for resolving unsigned int auxFBO_r[mjNAUX]; // auxiliary framebuffer object for resolving
unsigned int auxColor[mjNAUX]; // auxiliary color buffer unsigned int auxColor[mjNAUX]; // auxiliary color buffer
unsigned int auxColor_r[mjNAUX];// auxiliary color buffer for resolving unsigned int auxColor_r[mjNAUX]; // auxiliary color buffer for resolving
// materials with textures
int mat_texid[mjMAXMATERIAL*mjNTEXMAT]; // material texture ids (-1: no texture)
int mat_texuniform[mjMAXMATERIAL]; // texture repetition for 2d mapping
int mat_texrepeat[mjMAXMATERIAL*2]; // texture repetition for 2d mapping
// texture objects and info // texture objects and info
int ntexture; // number of allocated textures int ntexture; // number of allocated textures
int textureType[100]; // type of texture (mjtTexture) (ntexture) int textureType[mjMAXTEXTURE]; // type of texture (mjtTexture) (ntexture)
unsigned int texture[100]; // texture names unsigned int texture[mjMAXTEXTURE]; // texture names
// displaylist starting positions // displaylist starting positions
unsigned int basePlane; // all planes from model unsigned int basePlane; // all planes from model
unsigned int baseMesh; // all meshes from model unsigned int baseMesh; // all meshes from model
unsigned int baseHField; // all hfields from model unsigned int baseHField; // all height fields from model
unsigned int baseBuiltin; // all buildin geoms, with quality from model unsigned int baseBuiltin; // all builtin geoms, with quality from model
unsigned int baseFontNormal; // normal font unsigned int baseFontNormal; // normal font
unsigned int baseFontShadow; // shadow font unsigned int baseFontShadow; // shadow font
unsigned int baseFontBig; // big font unsigned int baseFontBig; // big font
// displaylist ranges // displaylist ranges
int rangePlane; // all planes from model int rangePlane; // all planes from model
int rangeMesh; // all meshes from model int rangeMesh; // all meshes from model
int rangeHField; // all hfields from model int rangeHField; // all hfields from model
int rangeBuiltin; // all builtin geoms, with quality from model int rangeBuiltin; // all builtin geoms, with quality from model
int rangeFont; // all characters in font int rangeFont; // all characters in font
// skin VBOs // skin VBOs
int nskin; // number of skins int nskin; // number of skins
unsigned int* skinvertVBO; // skin vertex position VBOs (nskin) unsigned int* skinvertVBO; // skin vertex position VBOs (nskin)
unsigned int* skinnormalVBO; // skin vertex normal VBOs (nskin) unsigned int* skinnormalVBO; // skin vertex normal VBOs (nskin)
unsigned int* skintexcoordVBO; // skin vertex texture coordinate VBOs (nskin) unsigned int* skintexcoordVBO; // skin vertex texture coordinate VBOs (nskin)
unsigned int* skinfaceVBO; // skin face index VBOs (nskin) unsigned int* skinfaceVBO; // skin face index VBOs (nskin)
// character info // character info
int charWidth[127]; // character widths: normal and shadow int charWidth[127]; // character widths: normal and shadow
int charWidthBig[127]; // chacarter widths: big int charWidthBig[127]; // chacarter widths: big
int charHeight; // character heights: normal and shadow int charHeight; // character heights: normal and shadow
int charHeightBig; // character heights: big int charHeightBig; // character heights: big
// capabilities // capabilities
int glInitialized; // is OpenGL initialized int glInitialized; // is OpenGL initialized
int windowAvailable; // is default/window framebuffer available int windowAvailable; // is default/window framebuffer available
int windowSamples; // number of samples for default/window framebuffer int windowSamples; // number of samples for default/window framebuffer
int windowStereo; // is stereo available for default/window framebuffer int windowStereo; // is stereo available for default/window framebuffer
int windowDoublebuffer; // is default/window framebuffer double buffered int windowDoublebuffer; // is default/window framebuffer double buffered
// framebuffer // framebuffer
int currentBuffer; // currently active framebuffer: mjFB_WINDOW or mjFB_OFFSCREEN int currentBuffer; // currently active framebuffer: mjFB_WINDOW or mjFB_OFFSCREEN
// pixel output format // pixel output format
int readPixelFormat; // default color pixel format for mjr_readPixels int readPixelFormat; // default color pixel format for mjr_readPixels
// depth output format // depth output format
int readDepthMap; // depth mapping: mjDEPTH_ZERONEAR or mjDEPTH_ZEROFAR int readDepthMap; // depth mapping: mjDEPTH_ZERONEAR or mjDEPTH_ZEROFAR
}; };
typedef struct mjrContext_ mjrContext; typedef struct mjrContext_ mjrContext;
typedef enum mjtGeomInertia_ { // type of inertia inference typedef enum mjtGeomInertia_ { // type of inertia inference
@@ -1649,7 +1650,7 @@ typedef struct mjSpec_ { // model specification
mjtByte strippath; // automatically strip paths from mesh files mjtByte strippath; // automatically strip paths from mesh files
mjtByte fitaabb; // meshfit to aabb instead of inertia box mjtByte fitaabb; // meshfit to aabb instead of inertia box
mjtByte degree; // angles in radians or degrees mjtByte degree; // angles in radians or degrees
char euler[3]; // sequence for euler rotations char eulerseq[3]; // sequence for euler rotations
mjString* meshdir; // mesh and hfield directory mjString* meshdir; // mesh and hfield directory
mjString* texturedir; // texture directory mjString* texturedir; // texture directory
mjtByte discardvisual; // discard visual geoms in parser mjtByte discardvisual; // discard visual geoms in parser
@@ -1743,7 +1744,6 @@ typedef struct mjsFrame_ { // frame specification
typedef struct mjsJoint_ { // joint specification typedef struct mjsJoint_ { // joint specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
mjtJoint type; // joint type mjtJoint type; // joint type
// kinematics // kinematics
@@ -1781,7 +1781,6 @@ typedef struct mjsJoint_ { // joint specification
typedef struct mjsGeom_ { // geom specification typedef struct mjsGeom_ { // geom specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // classname
mjtGeom type; // geom type mjtGeom type; // geom type
// frame, size // frame, size
@@ -1828,7 +1827,6 @@ typedef struct mjsGeom_ { // geom specification
typedef struct mjsSite_ { // site specification typedef struct mjsSite_ { // site specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
// frame, size // frame, size
double pos[3]; // position double pos[3]; // position
@@ -1850,7 +1848,6 @@ typedef struct mjsSite_ { // site specification
typedef struct mjsCamera_ { // camera specification typedef struct mjsCamera_ { // camera specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
// extrinsics // extrinsics
double pos[3]; // position double pos[3]; // position
@@ -1878,7 +1875,6 @@ typedef struct mjsCamera_ { // camera specification
typedef struct mjsLight_ { // light specification typedef struct mjsLight_ { // light specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
// frame // frame
double pos[3]; // position double pos[3]; // position
@@ -1904,7 +1900,6 @@ typedef struct mjsLight_ { // light specification
typedef struct mjsFlex_ { // flex specification typedef struct mjsFlex_ { // flex specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
// contact properties // contact properties
int contype; // contact type int contype; // contact type
@@ -1943,7 +1938,6 @@ typedef struct mjsFlex_ { // flex specification
typedef struct mjsMesh_ { // mesh specification typedef struct mjsMesh_ { // mesh specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
mjString* content_type; // content type of file mjString* content_type; // content type of file
mjString* file; // mesh file mjString* file; // mesh file
double refpos[3]; // reference position double refpos[3]; // reference position
@@ -1974,7 +1968,6 @@ typedef struct mjsHField_ { // height field specification
typedef struct mjsSkin_ { // skin specification typedef struct mjsSkin_ { // skin specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
mjString* file; // skin file mjString* file; // skin file
mjString* material; // name of material used for rendering mjString* material; // name of material used for rendering
float rgba[4]; // rgba when material is omitted float rgba[4]; // rgba when material is omitted
@@ -1999,7 +1992,6 @@ typedef struct mjsSkin_ { // skin specification
typedef struct mjsTexture_ { // texture specification typedef struct mjsTexture_ { // texture specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
mjtTexture type; // texture type mjtTexture type; // texture type
// method 1: builtin // method 1: builtin
@@ -2031,7 +2023,6 @@ typedef struct mjsTexture_ { // texture specification
typedef struct mjsMaterial_ { // material specification typedef struct mjsMaterial_ { // material specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
mjString* texture; // name of texture (empty: none) mjString* texture; // name of texture (empty: none)
mjtByte texuniform; // make texture cube uniform mjtByte texuniform; // make texture cube uniform
float texrepeat[2]; // texture repetition for 2D mapping float texrepeat[2]; // texture repetition for 2D mapping
@@ -2047,7 +2038,6 @@ typedef struct mjsMaterial_ { // material specification
typedef struct mjsPair_ { // pair specification typedef struct mjsPair_ { // pair specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
mjString* geomname1; // name of geom 1 mjString* geomname1; // name of geom 1
mjString* geomname2; // name of geom 2 mjString* geomname2; // name of geom 2
@@ -2071,7 +2061,6 @@ typedef struct mjsExclude_ { // exclude specification
typedef struct mjsEquality_ { // equality specification typedef struct mjsEquality_ { // equality specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
mjtEq type; // constraint type mjtEq type; // constraint type
double data[mjNEQDATA]; // type-dependent data double data[mjNEQDATA]; // type-dependent data
mjtByte active; // is equality initially active mjtByte active; // is equality initially active
@@ -2084,7 +2073,6 @@ typedef struct mjsEquality_ { // equality specification
typedef struct mjsTendon_ { // tendon specification typedef struct mjsTendon_ { // tendon specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
// stiffness, damping, friction // stiffness, damping, friction
double stiffness; // stiffness coefficient double stiffness; // stiffness coefficient
@@ -2118,7 +2106,6 @@ typedef struct mjsWrap_ { // wrapping object specification
typedef struct mjsActuator_ { // actuator specification typedef struct mjsActuator_ { // actuator specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
// gain, bias // gain, bias
mjtGain gaintype; // gain type mjtGain gaintype; // gain type
@@ -2160,7 +2147,6 @@ typedef struct mjsActuator_ { // actuator specification
typedef struct mjsSensor_ { // sensor specification typedef struct mjsSensor_ { // sensor specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
// sensor definition // sensor definition
mjtSensor type; // type of sensor mjtSensor type; // type of sensor
@@ -2286,6 +2272,11 @@ typedef enum mjtItem_ { // UI item type
mjNITEM // number of item types mjNITEM // number of item types
} mjtItem; } mjtItem;
typedef enum mjtSection_ { // UI section state
mjSECT_CLOSED = 0, // closed state (regular section)
mjSECT_OPEN, // open state (regular section)
mjSECT_FIXED // fixed section: always open, no title
} mjtSection;
struct mjuiState_ { // mouse and keyboard state struct mjuiState_ { // mouse and keyboard state
// constants set by user // constants set by user
int nrect; // number of rectangles used int nrect; // number of rectangles used
@@ -2333,6 +2324,8 @@ struct mjuiThemeSpacing_ { // UI visualization theme spacing
int scroll; // scrollbar width int scroll; // scrollbar width
int label; // label width int label; // label width
int section; // section gap int section; // section gap
int cornersect; // corner radius for section
int cornersep; // corner radius for separator
int itemside; // item side gap int itemside; // item side gap
int itemmid; // item middle gap int itemmid; // item middle gap
int itemver; // item vertical gap int itemver; // item vertical gap
@@ -2346,9 +2339,14 @@ struct mjuiThemeColor_ { // UI visualization theme color
float master[3]; // master background float master[3]; // master background
float thumb[3]; // scrollbar thumb float thumb[3]; // scrollbar thumb
float secttitle[3]; // section title float secttitle[3]; // section title
float secttitle2[3]; // section title: bottom color
float secttitlecheck[3]; // section title with checkbox
float secttitlecheck2[3]; // section title with checkbox: bottom color
float sectfont[3]; // section font float sectfont[3]; // section font
float sectsymbol[3]; // section symbol float sectsymbol[3]; // section symbol
float sectpane[3]; // section pane float sectpane[3]; // section pane
float separator[3]; // separator title
float separator2[3]; // separator title: bottom color
float shortcut[3]; // shortcut background float shortcut[3]; // shortcut background
float fontactive[3]; // font active float fontactive[3]; // font active
float fontinactive[3]; // font inactive float fontinactive[3]; // font inactive
@@ -2398,6 +2396,7 @@ struct mjuiItem_ { // UI item
void *pdata; // data pointer (type-specific) void *pdata; // data pointer (type-specific)
int sectionid; // id of section containing item int sectionid; // id of section containing item
int itemid; // id of item within section int itemid; // id of item within section
int userid; // user-supplied id (for event handling)
// type-specific properties // type-specific properties
union { union {
@@ -2409,20 +2408,23 @@ struct mjuiItem_ { // UI item
// internal // internal
mjrRect rect; // rectangle occupied by item mjrRect rect; // rectangle occupied by item
int skip; // item skipped due to closed separator
}; };
typedef struct mjuiItem_ mjuiItem; typedef struct mjuiItem_ mjuiItem;
struct mjuiSection_ { // UI section struct mjuiSection_ { // UI section
// properties // properties
char name[mjMAXUINAME]; // name char name[mjMAXUINAME]; // name
int state; // 0: closed, 1: open int state; // section state (mjtSection)
int modifier; // 0: none, 1: control, 2: shift; 4: alt int modifier; // 0: none, 1: control, 2: shift; 4: alt
int shortcut; // shortcut key; 0: undefined int shortcut; // shortcut key; 0: undefined
int checkbox; // 0: none, 1: hidden, 2: unchecked, 2: checked
int nitem; // number of items in use int nitem; // number of items in use
mjuiItem item[mjMAXUIITEM]; // preallocated array of items mjuiItem item[mjMAXUIITEM]; // preallocated array of items
// internal // internal
mjrRect rtitle; // rectangle occupied by title mjrRect rtitle; // rectangle occupied by title
mjrRect rcontent; // rectangle occupied by content mjrRect rcontent; // rectangle occupied by content
int lastclick; // last mouse click over this section
}; };
typedef struct mjuiSection_ mjuiSection; typedef struct mjuiSection_ mjuiSection;
struct mjUI_ { // entire UI struct mjUI_ { // entire UI
@@ -2441,10 +2443,12 @@ struct mjUI_ { // entire UI
int maxheight; // height when all sections open int maxheight; // height when all sections open
int scroll; // scroll from top of UI int scroll; // scroll from top of UI
// mouse focus // mouse focus and count
int mousesect; // 0: none, -1: scroll, otherwise 1+section int mousesect; // 0: none, -1: scroll, otherwise 1+section
int mouseitem; // item within section int mouseitem; // item within section
int mousehelp; // help button down: print shortcuts int mousehelp; // help button down: print shortcuts
int mouseclicks; // number of mouse clicks over UI
int mousesectcheck; // 0: none, otherwise 1+section
// keyboard focus and edit // keyboard focus and edit
int editsect; // 0: none, otherwise 1+section int editsect; // 0: none, otherwise 1+section
@@ -2465,6 +2469,7 @@ struct mjuiDef_ { // table passed to mjui_add()
int state; // state int state; // state
void* pdata; // pointer to data void* pdata; // pointer to data
char other[mjMAXUITEXT]; // string with type-specific properties char other[mjMAXUITEXT]; // string with type-specific properties
int otherint; // int with type-specific properties
}; };
typedef struct mjuiDef_ mjuiDef; typedef struct mjuiDef_ mjuiDef;
typedef enum mjtCatBit_ { // bitflags for mjvGeom category typedef enum mjtCatBit_ { // bitflags for mjvGeom category
@@ -2635,21 +2640,22 @@ struct mjvGeom_ { // abstract geom
int objtype; // mujoco object type; mjOBJ_UNKNOWN for decor int objtype; // mujoco object type; mjOBJ_UNKNOWN for decor
int objid; // mujoco object id; -1 for decor int objid; // mujoco object id; -1 for decor
int category; // visual category int category; // visual category
int texid; // texture id; -1: no texture int matid; // material id; -1: no textured material
int texuniform; // uniform cube mapping
int texcoord; // mesh or flex geom has texture coordinates int texcoord; // mesh or flex geom has texture coordinates
int segid; // segmentation id; -1: not shown int segid; // segmentation id; -1: not shown
// OpenGL info // spatial transform
float texrepeat[2]; // texture repetition for 2D mapping
float size[3]; // size parameters float size[3]; // size parameters
float pos[3]; // Cartesian position float pos[3]; // Cartesian position
float mat[9]; // Cartesian orientation float mat[9]; // Cartesian orientation
// material properties
float rgba[4]; // color and transparency float rgba[4]; // color and transparency
float emission; // emission coef float emission; // emission coef
float specular; // specular coef float specular; // specular coef
float shininess; // shininess coef float shininess; // shininess coef
float reflectance; // reflectance coef float reflectance; // reflectance coef
char label[100]; // text label char label[100]; // text label
// transparency rendering (set internally) // transparency rendering (set internally)
@@ -2782,7 +2788,7 @@ struct mjvFigure_ { // abstract 2D figure passed to OpenGL rendere
// line data // line data
int linepnt[mjMAXLINE]; // number of points in line; (0) disable int linepnt[mjMAXLINE]; // number of points in line; (0) disable
float linedata[mjMAXLINE][2*mjMAXLINEPNT]; // line data (x,y) float linedata[mjMAXLINE][2*mjMAXLINEPNT]; // line data (x,y)
// output from renderer // output from renderer
int xaxispixel[2]; // range of x-axis in pixels int xaxispixel[2]; // range of x-axis in pixels
@@ -3068,10 +3074,8 @@ typedef struct mjvSceneState_ mjvSceneState;
void mj_defaultVFS(mjVFS* vfs); void mj_defaultVFS(mjVFS* vfs);
int mj_addFileVFS(mjVFS* vfs, const char* directory, const char* filename); int mj_addFileVFS(mjVFS* vfs, const char* directory, const char* filename);
int mj_addBufferVFS(mjVFS* vfs, const char* name, const void* buffer, int nbuffer); int mj_addBufferVFS(mjVFS* vfs, const char* name, const void* buffer, int nbuffer);
int mj_findFileVFS(const mjVFS* vfs, const char* filename);
int mj_deleteFileVFS(mjVFS* vfs, const char* filename); int mj_deleteFileVFS(mjVFS* vfs, const char* filename);
void mj_deleteVFS(mjVFS* vfs); void mj_deleteVFS(mjVFS* vfs);
int mj_makeEmptyFileVFS(mjVFS* vfs, const char* filename, int filesize);
mjModel* mj_loadXML(const char* filename, const mjVFS* vfs, char* error, int error_sz); mjModel* mj_loadXML(const char* filename, const mjVFS* vfs, char* error, int error_sz);
mjSpec* mj_parseXML(const char* filename, const mjVFS* vfs, char* error, int error_sz); mjSpec* mj_parseXML(const char* filename, const mjVFS* vfs, char* error, int error_sz);
mjSpec* mj_parseXMLString(const char* xml, const mjVFS* vfs, char* error, int error_sz); mjSpec* mj_parseXMLString(const char* xml, const mjVFS* vfs, char* error, int error_sz);
@@ -3525,7 +3529,7 @@ mjsText* mjs_addText(mjSpec* s);
mjsTuple* mjs_addTuple(mjSpec* s); mjsTuple* mjs_addTuple(mjSpec* s);
mjsKey* mjs_addKey(mjSpec* s); mjsKey* mjs_addKey(mjSpec* s);
mjsPlugin* mjs_addPlugin(mjSpec* s); mjsPlugin* mjs_addPlugin(mjSpec* s);
mjsDefault* mjs_addDefault(mjSpec* s, const char* classname, int parentid, int* id); mjsDefault* mjs_addDefault(mjSpec* s, const char* classname, const mjsDefault* parent);
mjsMesh* mjs_addMesh(mjSpec* s, mjsDefault* def); mjsMesh* mjs_addMesh(mjSpec* s, mjsDefault* def);
mjsHField* mjs_addHField(mjSpec* s); mjsHField* mjs_addHField(mjSpec* s);
mjsSkin* mjs_addSkin(mjSpec* s); mjsSkin* mjs_addSkin(mjSpec* s);
@@ -3536,12 +3540,38 @@ mjsBody* mjs_findBody(mjSpec* s, const char* name);
mjsBody* mjs_findChild(mjsBody* body, const char* name); mjsBody* mjs_findChild(mjsBody* body, const char* name);
mjsMesh* mjs_findMesh(mjSpec* s, const char* name); mjsMesh* mjs_findMesh(mjSpec* s, const char* name);
mjsFrame* mjs_findFrame(mjSpec* s, const char* name); mjsFrame* mjs_findFrame(mjSpec* s, const char* name);
mjsKey* mjs_findKeyframe(mjSpec* s, const char* name);
mjsDefault* mjs_getDefault(mjsElement* element); mjsDefault* mjs_getDefault(mjsElement* element);
mjsDefault* mjs_findDefault(mjSpec* s, const char* classname); mjsDefault* mjs_findDefault(mjSpec* s, const char* classname);
mjsDefault* mjs_getSpecDefault(mjSpec* s); mjsDefault* mjs_getSpecDefault(mjSpec* s);
int mjs_getId(mjsElement* element); int mjs_getId(mjsElement* element);
mjsElement* mjs_firstChild(mjsBody* body, mjtObj type); mjsElement* mjs_firstChild(mjsBody* body, mjtObj type);
mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child); mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child);
mjsElement* mjs_firstElement(mjSpec* s, mjtObj type);
mjsElement* mjs_nextElement(mjSpec* s, mjsElement* element);
mjsBody* mjs_asBody(mjsElement* element);
mjsGeom* mjs_asGeom(mjsElement* element);
mjsJoint* mjs_asJoint(mjsElement* element);
mjsSite* mjs_asSite(mjsElement* element);
mjsCamera* mjs_asCamera(mjsElement* element);
mjsLight* mjs_asLight(mjsElement* element);
mjsFrame* mjs_asFrame(mjsElement* element);
mjsActuator* mjs_asActuator(mjsElement* element);
mjsSensor* mjs_asSensor(mjsElement* element);
mjsFlex* mjs_asFlex(mjsElement* element);
mjsPair* mjs_asPair(mjsElement* element);
mjsEquality* mjs_asEquality(mjsElement* element);
mjsExclude* mjs_asExclude(mjsElement* element);
mjsTendon* mjs_asTendon(mjsElement* element);
mjsNumeric* mjs_asNumeric(mjsElement* element);
mjsText* mjs_asText(mjsElement* element);
mjsTuple* mjs_asTuple(mjsElement* element);
mjsKey* mjs_asKey(mjsElement* element);
mjsMesh* mjs_asMesh(mjsElement* element);
mjsHField* mjs_asHField(mjsElement* element);
mjsSkin* mjs_asSkin(mjsElement* element);
mjsTexture* mjs_asTexture(mjsElement* element);
mjsMaterial* mjs_asMaterial(mjsElement* element);
void mjs_setString(mjString* dest, const char* text); void mjs_setString(mjString* dest, const char* text);
void mjs_setStringVec(mjStringVec* dest, const char* text); void mjs_setStringVec(mjStringVec* dest, const char* text);
mjtByte mjs_setInStringVec(mjStringVec* dest, int i, const char* text); mjtByte mjs_setInStringVec(mjStringVec* dest, int i, const char* text);
@@ -3559,7 +3589,6 @@ void mjs_setDefault(mjsElement* element, mjsDefault* def);
void mjs_setFrame(mjsElement* dest, mjsFrame* frame); void mjs_setFrame(mjsElement* dest, mjsFrame* frame);
const char* mjs_resolveOrientation(double quat[4], mjtByte degree, const char* sequence, const char* mjs_resolveOrientation(double quat[4], mjtByte degree, const char* sequence,
const mjsOrientation* orientation); const mjsOrientation* orientation);
const char* mjs_fullInertia(double quat[4], double inertia[3], const double fullinertia[6]);
void mjs_defaultSpec(mjSpec* spec); void mjs_defaultSpec(mjSpec* spec);
void mjs_defaultOrientation(mjsOrientation* orient); void mjs_defaultOrientation(mjsOrientation* orient);
void mjs_defaultBody(mjsBody* body); void mjs_defaultBody(mjsBody* body);
+2 -2
View File
@@ -84,7 +84,7 @@ data plots. The model file can be specified as a command-line argument, or loade
functionality. This code sample uses the native UI to render various controls, and provides an functionality. This code sample uses the native UI to render various controls, and provides an
illustration of how the new UI framework is intended to be used. Below is a screen-capture of ``simulate`` in action: illustration of how the new UI framework is intended to be used. Below is a screen-capture of ``simulate`` in action:
.. youtube:: 0ORsj_E17B0 .. youtube:: P83tKA1iz2Y
:width: 95% :width: 95%
:align: center :align: center
@@ -94,7 +94,7 @@ selected object by holding Ctrl and dragging the mouse. Dragging the mouse alone
are keyboard shortcuts for pausing the simulation, resetting, and re-loading the model file. The latter functionality is are keyboard shortcuts for pausing the simulation, resetting, and re-loading the model file. The latter functionality is
very useful while editing the model in an XML editor. very useful while editing the model in an XML editor.
The code is quite long yet reasonably commented, so it is best to just read it. Here we provide a high-level overview. The code is long yet reasonably commented, so it is best to just read it. Here we provide a high-level overview.
The ``main()`` function initializes both MuJoCo and GLFW, opens a window, and install GLFW callbacks for mouse and The ``main()`` function initializes both MuJoCo and GLFW, opens a window, and install GLFW callbacks for mouse and
keyboard handling. Note that there is no render callback; GLFW puts the user in charge, instead of running a rendering keyboard handling. Note that there is no render callback; GLFW puts the user in charge, instead of running a rendering
loop behind the scenes. The main loop handles UI events and rendering. The simulation is handled in a background loop behind the scenes. The main loop handles UI events and rendering. The simulation is handled in a background
+23 -23
View File
@@ -167,29 +167,29 @@ struct mjData_ {
int nplugin; // number of plugin instances int nplugin; // number of plugin instances
// stack pointer // stack pointer
size_t pstack; // first available mjtNum address in stack size_t pstack; // first available byte in stack
size_t pbase; // value of pstack when mj_markStack was last called size_t pbase; // value of pstack when mj_markStack was last called
// arena pointer // arena pointer
size_t parena; // first available byte in arena size_t parena; // first available byte in arena
// memory utilization stats // memory utilization statistics
size_t maxuse_stack; // maximum stack allocation in bytes size_t maxuse_stack; // maximum stack allocation in bytes
size_t maxuse_threadstack[mjMAXTHREAD]; // maximum stack allocation per thread in bytes size_t maxuse_threadstack[mjMAXTHREAD]; // maximum stack allocation per thread in bytes
size_t maxuse_arena; // maximum arena allocation in bytes size_t maxuse_arena; // maximum arena allocation in bytes
int maxuse_con; // maximum number of contacts int maxuse_con; // maximum number of contacts
int maxuse_efc; // maximum number of scalar constraints int maxuse_efc; // maximum number of scalar constraints
// diagnostics
mjWarningStat warning[mjNWARNING]; // warning statistics
mjTimerStat timer[mjNTIMER]; // timer statistics
// solver statistics // solver statistics
mjSolverStat solver[mjNISLAND*mjNSOLVER]; // solver statistics per island, per iteration mjSolverStat solver[mjNISLAND*mjNSOLVER]; // solver statistics per island, per iteration
int solver_nisland; // number of islands processed by solver int solver_nisland; // number of islands processed by solver
int solver_niter[mjNISLAND]; // number of solver iterations, per island int solver_niter[mjNISLAND]; // number of solver iterations, per island
int solver_nnz[mjNISLAND]; // number of non-zeros in Hessian or efc_AR, per island int solver_nnz[mjNISLAND]; // number of nonzeros in Hessian or efc_AR, per island
mjtNum solver_fwdinv[2]; // forward-inverse comparison: qfrc, efc mjtNum solver_fwdinv[2]; // forward-inverse comparison: qfrc, efc
// diagnostics
mjWarningStat warning[mjNWARNING]; // warning statistics
mjTimerStat timer[mjNTIMER]; // timer statistics
// variable sizes // variable sizes
int ne; // number of equality constraints int ne; // number of equality constraints
@@ -207,8 +207,8 @@ struct mjData_ {
//-------------------- end of info header //-------------------- end of info header
// buffers // buffers
void* buffer; // main buffer; all pointers point in it (nbuffer bytes) void* buffer; // main buffer; all pointers point in it (nbuffer bytes)
void* arena; // arena+stack buffer (nstack*sizeof(mjtNum) bytes) void* arena; // arena+stack buffer (narena bytes)
//-------------------- main inputs and outputs of the computation //-------------------- main inputs and outputs of the computation
@@ -302,7 +302,7 @@ struct mjData_ {
// computed by mj_collisionTree // computed by mj_collisionTree
mjtNum* bvh_aabb_dyn; // global bounding box (center, size) (nbvhdynamic x 6) mjtNum* bvh_aabb_dyn; // global bounding box (center, size) (nbvhdynamic x 6)
mjtByte* bvh_active; // volume has been added to collisions (nbvh x 1) mjtByte* bvh_active; // was bounding volume checked for collision (nbvh x 1)
//-------------------- POSITION, VELOCITY dependent //-------------------- POSITION, VELOCITY dependent
@@ -372,7 +372,7 @@ struct mjData_ {
//-------------------- arena-allocated: POSITION dependent //-------------------- arena-allocated: POSITION dependent
// computed by mj_collision // computed by mj_collision
mjContact* contact; // list of all detected contacts (ncon x 1) mjContact* contact; // array of all detected contacts (ncon x 1)
// computed by mj_makeConstraint // computed by mj_makeConstraint
int* efc_type; // constraint type (mjtConstraint) (nefc x 1) int* efc_type; // constraint type (mjtConstraint) (nefc x 1)
@@ -422,11 +422,11 @@ struct mjData_ {
//-------------------- arena-allocated: POSITION, VELOCITY, CONTROL/ACCELERATION dependent //-------------------- arena-allocated: POSITION, VELOCITY, CONTROL/ACCELERATION dependent
// computed by mj_fwdConstraint/mj_inverse // computed by mj_fwdConstraint/mj_inverse
mjtNum* efc_b; // linear cost term: J*qacc_smooth - aref (nefc x 1) mjtNum* efc_b; // linear cost term: J*qacc_smooth - aref (nefc x 1)
mjtNum* efc_force; // constraint force in constraint space (nefc x 1) mjtNum* efc_force; // constraint force in constraint space (nefc x 1)
int* efc_state; // constraint state (mjtConstraintState) (nefc x 1) int* efc_state; // constraint state (mjtConstraintState) (nefc x 1)
// ThreadPool for multithreaded operations // thread pool pointer
uintptr_t threadpool; uintptr_t threadpool;
}; };
typedef struct mjData_ mjData; typedef struct mjData_ mjData;
+3 -9
View File
@@ -29,8 +29,6 @@
#define mjMAXIMP 0.9999 // maximum constraint impedance #define mjMAXIMP 0.9999 // maximum constraint impedance
#define mjMAXCONPAIR 50 // maximum number of contacts per geom pair #define mjMAXCONPAIR 50 // maximum number of contacts per geom pair
#define mjMAXTREEDEPTH 50 // maximum bounding volume hierarchy depth #define mjMAXTREEDEPTH 50 // maximum bounding volume hierarchy depth
#define mjMAXVFS 2000 // maximum number of files in virtual file system
#define mjMAXVFSNAME 1000 // maximum filename size in virtual file system
//---------------------------------- sizes --------------------------------------------------------- //---------------------------------- sizes ---------------------------------------------------------
@@ -44,7 +42,7 @@
#define mjNIMP 5 // number of solver impedance parameters #define mjNIMP 5 // number of solver impedance parameters
#define mjNSOLVER 200 // size of one mjData.solver array #define mjNSOLVER 200 // size of one mjData.solver array
#define mjNISLAND 20 // number of mjData.solver arrays #define mjNISLAND 20 // number of mjData.solver arrays
#define mjNTEXMAT 6 // number of textures per material
//---------------------------------- enum types (mjt) ---------------------------------------------- //---------------------------------- enum types (mjt) ----------------------------------------------
@@ -399,11 +397,7 @@ typedef struct mjLROpt_ mjLROpt;
//---------------------------------- mjVFS --------------------------------------------------------- //---------------------------------- mjVFS ---------------------------------------------------------
struct mjVFS_ { // virtual file system for loading from memory struct mjVFS_ { // virtual file system for loading from memory
int nfile; // number of files present void* impl_; // internal pointer to VFS memory
char filename[mjMAXVFS][mjMAXVFSNAME]; // file name without path
size_t filesize[mjMAXVFS]; // file size in bytes
void* filedata[mjMAXVFS]; // buffer with file data
uint64_t filestamp[mjMAXVFS]; // checksum of the file data
}; };
typedef struct mjVFS_ mjVFS; typedef struct mjVFS_ mjVFS;
@@ -935,7 +929,7 @@ struct mjModel_ {
int* tex_pathadr; // address of texture asset path; -1: none (ntex x 1) int* tex_pathadr; // address of texture asset path; -1: none (ntex x 1)
// materials // materials
int* mat_texid; // texture id; -1: none (nmat x 1) int* mat_texid; // indices of textures; -1: none (nmat x mjNTEXMAT)
mjtByte* mat_texuniform; // make texture cube uniform (nmat x 1) mjtByte* mat_texuniform; // make texture cube uniform (nmat x 1)
float* mat_texrepeat; // texture repetition for 2d mapping (nmat x 2) float* mat_texrepeat; // texture repetition for 2d mapping (nmat x 2)
float* mat_emission; // emission (x rgb) (nmat x 1) float* mat_emission; // emission (x rgb) (nmat x 1)
+67 -61
View File
@@ -15,14 +15,15 @@
#ifndef MUJOCO_MJRENDER_H_ #ifndef MUJOCO_MJRENDER_H_
#define MUJOCO_MJRENDER_H_ #define MUJOCO_MJRENDER_H_
#include <mujoco/mjmodel.h>
#if defined(__cplusplus) #if defined(__cplusplus)
extern "C" { extern "C" {
#endif #endif
#define mjNAUX 10 // number of auxiliary buffers #define mjNAUX 10 // number of auxiliary buffers
#define mjMAXTEXTURE 1000 // maximum number of textures #define mjMAXTEXTURE 100 // maximum number of textures
#define mjMAXMATERIAL 100 // maximum number of materials with textures
//---------------------------------- primitive types (mjt) ----------------------------------------- //---------------------------------- primitive types (mjt) -----------------------------------------
@@ -76,92 +77,97 @@ typedef struct mjrRect_ mjrRect;
//---------------------------------- mjrContext ---------------------------------------------------- //---------------------------------- mjrContext ----------------------------------------------------
struct mjrContext_ { // custom OpenGL context struct mjrContext_ { // custom OpenGL context
// parameters copied from mjVisual // parameters copied from mjVisual
float lineWidth; // line width for wireframe rendering float lineWidth; // line width for wireframe rendering
float shadowClip; // clipping radius for directional lights float shadowClip; // clipping radius for directional lights
float shadowScale; // fraction of light cutoff for spot lights float shadowScale; // fraction of light cutoff for spot lights
float fogStart; // fog start = stat.extent * vis.map.fogstart float fogStart; // fog start = stat.extent * vis.map.fogstart
float fogEnd; // fog end = stat.extent * vis.map.fogend float fogEnd; // fog end = stat.extent * vis.map.fogend
float fogRGBA[4]; // fog rgba float fogRGBA[4]; // fog rgba
int shadowSize; // size of shadow map texture int shadowSize; // size of shadow map texture
int offWidth; // width of offscreen buffer int offWidth; // width of offscreen buffer
int offHeight; // height of offscreen buffer int offHeight; // height of offscreen buffer
int offSamples; // number of offscreen buffer multisamples int offSamples; // number of offscreen buffer multisamples
// parameters specified at creation // parameters specified at creation
int fontScale; // font scale int fontScale; // font scale
int auxWidth[mjNAUX]; // auxiliary buffer width int auxWidth[mjNAUX]; // auxiliary buffer width
int auxHeight[mjNAUX]; // auxiliary buffer height int auxHeight[mjNAUX]; // auxiliary buffer height
int auxSamples[mjNAUX]; // auxiliary buffer multisamples int auxSamples[mjNAUX]; // auxiliary buffer multisamples
// offscreen rendering objects // offscreen rendering objects
unsigned int offFBO; // offscreen framebuffer object unsigned int offFBO; // offscreen framebuffer object
unsigned int offFBO_r; // offscreen framebuffer for resolving multisamples unsigned int offFBO_r; // offscreen framebuffer for resolving multisamples
unsigned int offColor; // offscreen color buffer unsigned int offColor; // offscreen color buffer
unsigned int offColor_r; // offscreen color buffer for resolving multisamples unsigned int offColor_r; // offscreen color buffer for resolving multisamples
unsigned int offDepthStencil; // offscreen depth and stencil buffer unsigned int offDepthStencil; // offscreen depth and stencil buffer
unsigned int offDepthStencil_r; // offscreen depth and stencil buffer for resolving multisamples unsigned int offDepthStencil_r; // offscreen depth and stencil buffer for multisamples
// shadow rendering objects // shadow rendering objects
unsigned int shadowFBO; // shadow map framebuffer object unsigned int shadowFBO; // shadow map framebuffer object
unsigned int shadowTex; // shadow map texture unsigned int shadowTex; // shadow map texture
// auxiliary buffers // auxiliary buffers
unsigned int auxFBO[mjNAUX]; // auxiliary framebuffer object unsigned int auxFBO[mjNAUX]; // auxiliary framebuffer object
unsigned int auxFBO_r[mjNAUX]; // auxiliary framebuffer object for resolving unsigned int auxFBO_r[mjNAUX]; // auxiliary framebuffer object for resolving
unsigned int auxColor[mjNAUX]; // auxiliary color buffer unsigned int auxColor[mjNAUX]; // auxiliary color buffer
unsigned int auxColor_r[mjNAUX];// auxiliary color buffer for resolving unsigned int auxColor_r[mjNAUX]; // auxiliary color buffer for resolving
// materials with textures
int mat_texid[mjMAXMATERIAL*mjNTEXMAT]; // material texture ids (-1: no texture)
int mat_texuniform[mjMAXMATERIAL]; // texture repetition for 2d mapping
int mat_texrepeat[mjMAXMATERIAL*2]; // texture repetition for 2d mapping
// texture objects and info // texture objects and info
int ntexture; // number of allocated textures int ntexture; // number of allocated textures
int textureType[100]; // type of texture (mjtTexture) (ntexture) int textureType[mjMAXTEXTURE]; // type of texture (mjtTexture) (ntexture)
unsigned int texture[100]; // texture names unsigned int texture[mjMAXTEXTURE]; // texture names
// displaylist starting positions // displaylist starting positions
unsigned int basePlane; // all planes from model unsigned int basePlane; // all planes from model
unsigned int baseMesh; // all meshes from model unsigned int baseMesh; // all meshes from model
unsigned int baseHField; // all hfields from model unsigned int baseHField; // all height fields from model
unsigned int baseBuiltin; // all buildin geoms, with quality from model unsigned int baseBuiltin; // all builtin geoms, with quality from model
unsigned int baseFontNormal; // normal font unsigned int baseFontNormal; // normal font
unsigned int baseFontShadow; // shadow font unsigned int baseFontShadow; // shadow font
unsigned int baseFontBig; // big font unsigned int baseFontBig; // big font
// displaylist ranges // displaylist ranges
int rangePlane; // all planes from model int rangePlane; // all planes from model
int rangeMesh; // all meshes from model int rangeMesh; // all meshes from model
int rangeHField; // all hfields from model int rangeHField; // all hfields from model
int rangeBuiltin; // all builtin geoms, with quality from model int rangeBuiltin; // all builtin geoms, with quality from model
int rangeFont; // all characters in font int rangeFont; // all characters in font
// skin VBOs // skin VBOs
int nskin; // number of skins int nskin; // number of skins
unsigned int* skinvertVBO; // skin vertex position VBOs (nskin) unsigned int* skinvertVBO; // skin vertex position VBOs (nskin)
unsigned int* skinnormalVBO; // skin vertex normal VBOs (nskin) unsigned int* skinnormalVBO; // skin vertex normal VBOs (nskin)
unsigned int* skintexcoordVBO; // skin vertex texture coordinate VBOs (nskin) unsigned int* skintexcoordVBO; // skin vertex texture coordinate VBOs (nskin)
unsigned int* skinfaceVBO; // skin face index VBOs (nskin) unsigned int* skinfaceVBO; // skin face index VBOs (nskin)
// character info // character info
int charWidth[127]; // character widths: normal and shadow int charWidth[127]; // character widths: normal and shadow
int charWidthBig[127]; // chacarter widths: big int charWidthBig[127]; // chacarter widths: big
int charHeight; // character heights: normal and shadow int charHeight; // character heights: normal and shadow
int charHeightBig; // character heights: big int charHeightBig; // character heights: big
// capabilities // capabilities
int glInitialized; // is OpenGL initialized int glInitialized; // is OpenGL initialized
int windowAvailable; // is default/window framebuffer available int windowAvailable; // is default/window framebuffer available
int windowSamples; // number of samples for default/window framebuffer int windowSamples; // number of samples for default/window framebuffer
int windowStereo; // is stereo available for default/window framebuffer int windowStereo; // is stereo available for default/window framebuffer
int windowDoublebuffer; // is default/window framebuffer double buffered int windowDoublebuffer; // is default/window framebuffer double buffered
// framebuffer // framebuffer
int currentBuffer; // currently active framebuffer: mjFB_WINDOW or mjFB_OFFSCREEN int currentBuffer; // currently active framebuffer: mjFB_WINDOW or mjFB_OFFSCREEN
// pixel output format // pixel output format
int readPixelFormat; // default color pixel format for mjr_readPixels int readPixelFormat; // default color pixel format for mjr_readPixels
// depth output format // depth output format
int readDepthMap; // depth mapping: mjDEPTH_ZERONEAR or mjDEPTH_ZEROFAR int readDepthMap; // depth mapping: mjDEPTH_ZERONEAR or mjDEPTH_ZEROFAR
}; };
typedef struct mjrContext_ mjrContext; typedef struct mjrContext_ mjrContext;
+1 -16
View File
@@ -118,7 +118,7 @@ typedef struct mjSpec_ { // model specification
mjtByte strippath; // automatically strip paths from mesh files mjtByte strippath; // automatically strip paths from mesh files
mjtByte fitaabb; // meshfit to aabb instead of inertia box mjtByte fitaabb; // meshfit to aabb instead of inertia box
mjtByte degree; // angles in radians or degrees mjtByte degree; // angles in radians or degrees
char euler[3]; // sequence for euler rotations char eulerseq[3]; // sequence for euler rotations
mjString* meshdir; // mesh and hfield directory mjString* meshdir; // mesh and hfield directory
mjString* texturedir; // texture directory mjString* texturedir; // texture directory
mjtByte discardvisual; // discard visual geoms in parser mjtByte discardvisual; // discard visual geoms in parser
@@ -222,7 +222,6 @@ typedef struct mjsFrame_ { // frame specification
typedef struct mjsJoint_ { // joint specification typedef struct mjsJoint_ { // joint specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
mjtJoint type; // joint type mjtJoint type; // joint type
// kinematics // kinematics
@@ -262,7 +261,6 @@ typedef struct mjsJoint_ { // joint specification
typedef struct mjsGeom_ { // geom specification typedef struct mjsGeom_ { // geom specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // classname
mjtGeom type; // geom type mjtGeom type; // geom type
// frame, size // frame, size
@@ -311,7 +309,6 @@ typedef struct mjsGeom_ { // geom specification
typedef struct mjsSite_ { // site specification typedef struct mjsSite_ { // site specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
// frame, size // frame, size
double pos[3]; // position double pos[3]; // position
@@ -335,7 +332,6 @@ typedef struct mjsSite_ { // site specification
typedef struct mjsCamera_ { // camera specification typedef struct mjsCamera_ { // camera specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
// extrinsics // extrinsics
double pos[3]; // position double pos[3]; // position
@@ -365,7 +361,6 @@ typedef struct mjsCamera_ { // camera specification
typedef struct mjsLight_ { // light specification typedef struct mjsLight_ { // light specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
// frame // frame
double pos[3]; // position double pos[3]; // position
@@ -393,7 +388,6 @@ typedef struct mjsLight_ { // light specification
typedef struct mjsFlex_ { // flex specification typedef struct mjsFlex_ { // flex specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
// contact properties // contact properties
int contype; // contact type int contype; // contact type
@@ -434,7 +428,6 @@ typedef struct mjsFlex_ { // flex specification
typedef struct mjsMesh_ { // mesh specification typedef struct mjsMesh_ { // mesh specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
mjString* content_type; // content type of file mjString* content_type; // content type of file
mjString* file; // mesh file mjString* file; // mesh file
double refpos[3]; // reference position double refpos[3]; // reference position
@@ -470,7 +463,6 @@ typedef struct mjsHField_ { // height field specification
typedef struct mjsSkin_ { // skin specification typedef struct mjsSkin_ { // skin specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
mjString* file; // skin file mjString* file; // skin file
mjString* material; // name of material used for rendering mjString* material; // name of material used for rendering
float rgba[4]; // rgba when material is omitted float rgba[4]; // rgba when material is omitted
@@ -497,7 +489,6 @@ typedef struct mjsSkin_ { // skin specification
typedef struct mjsTexture_ { // texture specification typedef struct mjsTexture_ { // texture specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
mjtTexture type; // texture type mjtTexture type; // texture type
// method 1: builtin // method 1: builtin
@@ -531,7 +522,6 @@ typedef struct mjsTexture_ { // texture specification
typedef struct mjsMaterial_ { // material specification typedef struct mjsMaterial_ { // material specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
mjString* texture; // name of texture (empty: none) mjString* texture; // name of texture (empty: none)
mjtByte texuniform; // make texture cube uniform mjtByte texuniform; // make texture cube uniform
float texrepeat[2]; // texture repetition for 2D mapping float texrepeat[2]; // texture repetition for 2D mapping
@@ -549,7 +539,6 @@ typedef struct mjsMaterial_ { // material specification
typedef struct mjsPair_ { // pair specification typedef struct mjsPair_ { // pair specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
mjString* geomname1; // name of geom 1 mjString* geomname1; // name of geom 1
mjString* geomname2; // name of geom 2 mjString* geomname2; // name of geom 2
@@ -577,7 +566,6 @@ typedef struct mjsExclude_ { // exclude specification
typedef struct mjsEquality_ { // equality specification typedef struct mjsEquality_ { // equality specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
mjtEq type; // constraint type mjtEq type; // constraint type
double data[mjNEQDATA]; // type-dependent data double data[mjNEQDATA]; // type-dependent data
mjtByte active; // is equality initially active mjtByte active; // is equality initially active
@@ -592,7 +580,6 @@ typedef struct mjsEquality_ { // equality specification
typedef struct mjsTendon_ { // tendon specification typedef struct mjsTendon_ { // tendon specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
// stiffness, damping, friction // stiffness, damping, friction
double stiffness; // stiffness coefficient double stiffness; // stiffness coefficient
@@ -630,7 +617,6 @@ typedef struct mjsWrap_ { // wrapping object specification
typedef struct mjsActuator_ { // actuator specification typedef struct mjsActuator_ { // actuator specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
// gain, bias // gain, bias
mjtGain gaintype; // gain type mjtGain gaintype; // gain type
@@ -674,7 +660,6 @@ typedef struct mjsActuator_ { // actuator specification
typedef struct mjsSensor_ { // sensor specification typedef struct mjsSensor_ { // sensor specification
mjsElement* element; // element type mjsElement* element; // element type
mjString* name; // name mjString* name; // name
mjString* classname; // class name
// sensor definition // sensor definition
mjtSensor type; // type of sensor mjtSensor type; // type of sensor
+1 -5
View File
@@ -17,12 +17,8 @@
//---------------------------------- floating-point definition ------------------------------------- //---------------------------------- floating-point definition -------------------------------------
// compile-time configuration options
#define mjUSEDOUBLE // single or double precision for mjtNum
// floating point data type and minval // floating point data type and minval
#ifdef mjUSEDOUBLE #ifndef mjUSESINGLE
typedef double mjtNum; typedef double mjtNum;
#define mjMINVAL 1E-15 // minimum value in any denominator #define mjMINVAL 1E-15 // minimum value in any denominator
#else #else
+24 -2
View File
@@ -26,6 +26,7 @@
#define mjMAXUIRECT 25 // maximum number of rectangles #define mjMAXUIRECT 25 // maximum number of rectangles
#define mjSEPCLOSED 1000 // closed state of adjustable separator #define mjSEPCLOSED 1000 // closed state of adjustable separator
#define mjPRESERVE 2000 // preserve section or separator state
// key codes matching GLFW (user must remap for other frameworks) // key codes matching GLFW (user must remap for other frameworks)
@@ -106,6 +107,13 @@ typedef enum mjtItem_ { // UI item type
} mjtItem; } mjtItem;
typedef enum mjtSection_ { // UI section state
mjSECT_CLOSED = 0, // closed state (regular section)
mjSECT_OPEN, // open state (regular section)
mjSECT_FIXED // fixed section: always open, no title
} mjtSection;
// predicate function: set enable/disable based on item category // predicate function: set enable/disable based on item category
typedef int (*mjfItemEnable)(int category, void* data); typedef int (*mjfItemEnable)(int category, void* data);
@@ -163,6 +171,8 @@ struct mjuiThemeSpacing_ { // UI visualization theme spacing
int scroll; // scrollbar width int scroll; // scrollbar width
int label; // label width int label; // label width
int section; // section gap int section; // section gap
int cornersect; // corner radius for section
int cornersep; // corner radius for separator
int itemside; // item side gap int itemside; // item side gap
int itemmid; // item middle gap int itemmid; // item middle gap
int itemver; // item vertical gap int itemver; // item vertical gap
@@ -180,9 +190,14 @@ struct mjuiThemeColor_ { // UI visualization theme color
float master[3]; // master background float master[3]; // master background
float thumb[3]; // scrollbar thumb float thumb[3]; // scrollbar thumb
float secttitle[3]; // section title float secttitle[3]; // section title
float secttitle2[3]; // section title: bottom color
float secttitlecheck[3]; // section title with checkbox
float secttitlecheck2[3]; // section title with checkbox: bottom color
float sectfont[3]; // section font float sectfont[3]; // section font
float sectsymbol[3]; // section symbol float sectsymbol[3]; // section symbol
float sectpane[3]; // section pane float sectpane[3]; // section pane
float separator[3]; // separator title
float separator2[3]; // separator title: bottom color
float shortcut[3]; // shortcut background float shortcut[3]; // shortcut background
float fontactive[3]; // font active float fontactive[3]; // font active
float fontinactive[3]; // font inactive float fontinactive[3]; // font inactive
@@ -236,6 +251,7 @@ struct mjuiItem_ { // UI item
void *pdata; // data pointer (type-specific) void *pdata; // data pointer (type-specific)
int sectionid; // id of section containing item int sectionid; // id of section containing item
int itemid; // id of item within section int itemid; // id of item within section
int userid; // user-supplied id (for event handling)
// type-specific properties // type-specific properties
union { union {
@@ -247,6 +263,7 @@ struct mjuiItem_ { // UI item
// internal // internal
mjrRect rect; // rectangle occupied by item mjrRect rect; // rectangle occupied by item
int skip; // item skipped due to closed separator
}; };
typedef struct mjuiItem_ mjuiItem; typedef struct mjuiItem_ mjuiItem;
@@ -256,15 +273,17 @@ typedef struct mjuiItem_ mjuiItem;
struct mjuiSection_ { // UI section struct mjuiSection_ { // UI section
// properties // properties
char name[mjMAXUINAME]; // name char name[mjMAXUINAME]; // name
int state; // 0: closed, 1: open int state; // section state (mjtSection)
int modifier; // 0: none, 1: control, 2: shift; 4: alt int modifier; // 0: none, 1: control, 2: shift; 4: alt
int shortcut; // shortcut key; 0: undefined int shortcut; // shortcut key; 0: undefined
int checkbox; // 0: none, 1: hidden, 2: unchecked, 2: checked
int nitem; // number of items in use int nitem; // number of items in use
mjuiItem item[mjMAXUIITEM]; // preallocated array of items mjuiItem item[mjMAXUIITEM]; // preallocated array of items
// internal // internal
mjrRect rtitle; // rectangle occupied by title mjrRect rtitle; // rectangle occupied by title
mjrRect rcontent; // rectangle occupied by content mjrRect rcontent; // rectangle occupied by content
int lastclick; // last mouse click over this section
}; };
typedef struct mjuiSection_ mjuiSection; typedef struct mjuiSection_ mjuiSection;
@@ -287,10 +306,12 @@ struct mjUI_ { // entire UI
int maxheight; // height when all sections open int maxheight; // height when all sections open
int scroll; // scroll from top of UI int scroll; // scroll from top of UI
// mouse focus // mouse focus and count
int mousesect; // 0: none, -1: scroll, otherwise 1+section int mousesect; // 0: none, -1: scroll, otherwise 1+section
int mouseitem; // item within section int mouseitem; // item within section
int mousehelp; // help button down: print shortcuts int mousehelp; // help button down: print shortcuts
int mouseclicks; // number of mouse clicks over UI
int mousesectcheck; // 0: none, otherwise 1+section
// keyboard focus and edit // keyboard focus and edit
int editsect; // 0: none, otherwise 1+section int editsect; // 0: none, otherwise 1+section
@@ -315,6 +336,7 @@ struct mjuiDef_ { // table passed to mjui_add()
int state; // state int state; // state
void* pdata; // pointer to data void* pdata; // pointer to data
char other[mjMAXUITEXT]; // string with type-specific properties char other[mjMAXUITEXT]; // string with type-specific properties
int otherint; // int with type-specific properties
}; };
typedef struct mjuiDef_ mjuiDef; typedef struct mjuiDef_ mjuiDef;
+6 -5
View File
@@ -230,21 +230,22 @@ struct mjvGeom_ { // abstract geom
int objtype; // mujoco object type; mjOBJ_UNKNOWN for decor int objtype; // mujoco object type; mjOBJ_UNKNOWN for decor
int objid; // mujoco object id; -1 for decor int objid; // mujoco object id; -1 for decor
int category; // visual category int category; // visual category
int texid; // texture id; -1: no texture int matid; // material id; -1: no textured material
int texuniform; // uniform cube mapping
int texcoord; // mesh or flex geom has texture coordinates int texcoord; // mesh or flex geom has texture coordinates
int segid; // segmentation id; -1: not shown int segid; // segmentation id; -1: not shown
// OpenGL info // spatial transform
float texrepeat[2]; // texture repetition for 2D mapping
float size[3]; // size parameters float size[3]; // size parameters
float pos[3]; // Cartesian position float pos[3]; // Cartesian position
float mat[9]; // Cartesian orientation float mat[9]; // Cartesian orientation
// material properties
float rgba[4]; // color and transparency float rgba[4]; // color and transparency
float emission; // emission coef float emission; // emission coef
float specular; // specular coef float specular; // specular coef
float shininess; // shininess coef float shininess; // shininess coef
float reflectance; // reflectance coef float reflectance; // reflectance coef
char label[100]; // text label char label[100]; // text label
// transparency rendering (set internally) // transparency rendering (set internally)
@@ -393,7 +394,7 @@ struct mjvFigure_ { // abstract 2D figure passed to OpenGL rendere
// line data // line data
int linepnt[mjMAXLINE]; // number of points in line; (0) disable int linepnt[mjMAXLINE]; // number of points in line; (0) disable
float linedata[mjMAXLINE][2*mjMAXLINEPNT]; // line data (x,y) float linedata[mjMAXLINE][2*mjMAXLINEPNT]; // line data (x,y)
// output from renderer // output from renderer
int xaxispixel[2]; // range of x-axis in pixels int xaxispixel[2]; // range of x-axis in pixels
+1 -1
View File
@@ -413,7 +413,7 @@
X ( int, tex_adr, ntex, 1 ) \ X ( int, tex_adr, ntex, 1 ) \
X ( mjtByte, tex_rgb, ntexdata, 1 ) \ X ( mjtByte, tex_rgb, ntexdata, 1 ) \
XMJV( int, tex_pathadr, ntex, 1 ) \ XMJV( int, tex_pathadr, ntex, 1 ) \
XMJV( int, mat_texid, nmat, 1 ) \ XMJV( int, mat_texid, nmat, mjNTEXMAT ) \
XMJV( mjtByte, mat_texuniform, nmat, 1 ) \ XMJV( mjtByte, mat_texuniform, nmat, 1 ) \
XMJV( float, mat_texrepeat, nmat, 2 ) \ XMJV( float, mat_texrepeat, nmat, 2 ) \
XMJV( float, mat_emission, nmat, 1 ) \ XMJV( float, mat_emission, nmat, 1 ) \
+82 -13
View File
@@ -74,7 +74,7 @@ MJAPI extern const char* mjRNDSTRING[mjNRNDFLAG][3];
//---------------------------------- Virtual file system ------------------------------------------- //---------------------------------- Virtual file system -------------------------------------------
// Initialize VFS to empty (no deallocation). // Initialize an empty VFS, mj_deleteVFS must be called to deallocate the VFS.
MJAPI void mj_defaultVFS(mjVFS* vfs); MJAPI void mj_defaultVFS(mjVFS* vfs);
// Add file to VFS, return 0: success, 1: full, 2: repeated name, -1: failed to load. // Add file to VFS, return 0: success, 1: full, 2: repeated name, -1: failed to load.
@@ -83,18 +83,12 @@ MJAPI int mj_addFileVFS(mjVFS* vfs, const char* directory, const char* filename)
// Add file to VFS from buffer, return 0: success, 1: full, 2: repeated name, -1: failed to load. // Add file to VFS from buffer, return 0: success, 1: full, 2: repeated name, -1: failed to load.
MJAPI int mj_addBufferVFS(mjVFS* vfs, const char* name, const void* buffer, int nbuffer); MJAPI int mj_addBufferVFS(mjVFS* vfs, const char* name, const void* buffer, int nbuffer);
// Return file index in VFS, or -1 if not found in VFS.
MJAPI int mj_findFileVFS(const mjVFS* vfs, const char* filename);
// Delete file from VFS, return 0: success, -1: not found in VFS. // Delete file from VFS, return 0: success, -1: not found in VFS.
MJAPI int mj_deleteFileVFS(mjVFS* vfs, const char* filename); MJAPI int mj_deleteFileVFS(mjVFS* vfs, const char* filename);
// Delete all files from VFS. // Delete all files from VFS and deallocates VFS internal memory.
MJAPI void mj_deleteVFS(mjVFS* vfs); MJAPI void mj_deleteVFS(mjVFS* vfs);
// deprecated: use mj_copyBufferVFS.
MJAPI int mj_makeEmptyFileVFS(mjVFS* vfs, const char* filename, int filesize);
//---------------------------------- Parse and compile --------------------------------------------- //---------------------------------- Parse and compile ---------------------------------------------
@@ -893,7 +887,7 @@ MJAPI int mjs_isWarning(mjSpec* s);
//---------------------------------- Standard math ------------------------------------------------- //---------------------------------- Standard math -------------------------------------------------
#ifdef mjUSEDOUBLE #if !defined(mjUSESINGLE)
#define mju_sqrt sqrt #define mju_sqrt sqrt
#define mju_exp exp #define mju_exp exp
#define mju_sin sin #define mju_sin sin
@@ -1498,7 +1492,7 @@ MJAPI mjsKey* mjs_addKey(mjSpec* s);
MJAPI mjsPlugin* mjs_addPlugin(mjSpec* s); MJAPI mjsPlugin* mjs_addPlugin(mjSpec* s);
// Add default. // Add default.
MJAPI mjsDefault* mjs_addDefault(mjSpec* s, const char* classname, int parentid, int* id); MJAPI mjsDefault* mjs_addDefault(mjSpec* s, const char* classname, const mjsDefault* parent);
//---------------------------------- Assets -------------------------------------------------------- //---------------------------------- Assets --------------------------------------------------------
@@ -1536,6 +1530,9 @@ MJAPI mjsMesh* mjs_findMesh(mjSpec* s, const char* name);
// Find frame by name. // Find frame by name.
MJAPI mjsFrame* mjs_findFrame(mjSpec* s, const char* name); MJAPI mjsFrame* mjs_findFrame(mjSpec* s, const char* name);
// Find keyframe by name.
MJAPI mjsKey* mjs_findKeyframe(mjSpec* s, const char* name);
// Get default corresponding to an element. // Get default corresponding to an element.
MJAPI mjsDefault* mjs_getDefault(mjsElement* element); MJAPI mjsDefault* mjs_getDefault(mjsElement* element);
@@ -1554,6 +1551,81 @@ MJAPI mjsElement* mjs_firstChild(mjsBody* body, mjtObj type);
// Return body's next child of the same type; return NULL if child is last. // Return body's next child of the same type; return NULL if child is last.
MJAPI mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child); MJAPI mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child);
// Return spec's first element of selected type.
MJAPI mjsElement* mjs_firstElement(mjSpec* s, mjtObj type);
// Return spec's next element; return NULL if element is last.
MJAPI mjsElement* mjs_nextElement(mjSpec* s, mjsElement* element);
// Safely cast an element as mjsBody, or return NULL if the element is not an mjsBody.
MJAPI mjsBody* mjs_asBody(mjsElement* element);
// Safely cast an element as mjsGeom, or return NULL if the element is not an mjsGeom.
MJAPI mjsGeom* mjs_asGeom(mjsElement* element);
// Safely cast an element as mjsJoint, or return NULL if the element is not an mjsJoint.
MJAPI mjsJoint* mjs_asJoint(mjsElement* element);
// Safely cast an element as mjsSite, or return NULL if the element is not an mjsSite.
MJAPI mjsSite* mjs_asSite(mjsElement* element);
// Safely cast an element as mjsCamera, or return NULL if the element is not an mjsCamera.
MJAPI mjsCamera* mjs_asCamera(mjsElement* element);
// Safely cast an element as mjsLight, or return NULL if the element is not an mjsLight.
MJAPI mjsLight* mjs_asLight(mjsElement* element);
// Safely cast an element as mjsFrame, or return NULL if the element is not an mjsFrame.
MJAPI mjsFrame* mjs_asFrame(mjsElement* element);
// Safely cast an element as mjsActuator, or return NULL if the element is not an mjsActuator.
MJAPI mjsActuator* mjs_asActuator(mjsElement* element);
// Safely cast an element as mjsSensor, or return NULL if the element is not an mjsSensor.
MJAPI mjsSensor* mjs_asSensor(mjsElement* element);
// Safely cast an element as mjsFlex, or return NULL if the element is not an mjsFlex.
MJAPI mjsFlex* mjs_asFlex(mjsElement* element);
// Safely cast an element as mjsPair, or return NULL if the element is not an mjsPair.
MJAPI mjsPair* mjs_asPair(mjsElement* element);
// Safely cast an element as mjsEquality, or return NULL if the element is not an mjsEquality.
MJAPI mjsEquality* mjs_asEquality(mjsElement* element);
// Safely cast an element as mjsExclude, or return NULL if the element is not an mjsExclude.
MJAPI mjsExclude* mjs_asExclude(mjsElement* element);
// Safely cast an element as mjsTendon, or return NULL if the element is not an mjsTendon.
MJAPI mjsTendon* mjs_asTendon(mjsElement* element);
// Safely cast an element as mjsNumeric, or return NULL if the element is not an mjsNumeric.
MJAPI mjsNumeric* mjs_asNumeric(mjsElement* element);
// Safely cast an element as mjsText, or return NULL if the element is not an mjsText.
MJAPI mjsText* mjs_asText(mjsElement* element);
// Safely cast an element as mjsTuple, or return NULL if the element is not an mjsTuple.
MJAPI mjsTuple* mjs_asTuple(mjsElement* element);
// Safely cast an element as mjsKey, or return NULL if the element is not an mjsKey.
MJAPI mjsKey* mjs_asKey(mjsElement* element);
// Safely cast an element as mjsMesh, or return NULL if the element is not an mjsMesh.
MJAPI mjsMesh* mjs_asMesh(mjsElement* element);
// Safely cast an element as mjsHField, or return NULL if the element is not an mjsHField.
MJAPI mjsHField* mjs_asHField(mjsElement* element);
// Safely cast an element as mjsSkin, or return NULL if the element is not an mjsSkin.
MJAPI mjsSkin* mjs_asSkin(mjsElement* element);
// Safely cast an element as mjsTexture, or return NULL if the element is not an mjsTexture.
MJAPI mjsTexture* mjs_asTexture(mjsElement* element);
// Safely cast an element as mjsMaterial, or return NULL if the element is not an mjsMaterial.
MJAPI mjsMaterial* mjs_asMaterial(mjsElement* element);
//---------------------------------- Attribute setters --------------------------------------------- //---------------------------------- Attribute setters ---------------------------------------------
@@ -1612,9 +1684,6 @@ MJAPI void mjs_setFrame(mjsElement* dest, mjsFrame* frame);
MJAPI const char* mjs_resolveOrientation(double quat[4], mjtByte degree, const char* sequence, MJAPI const char* mjs_resolveOrientation(double quat[4], mjtByte degree, const char* sequence,
const mjsOrientation* orientation); const mjsOrientation* orientation);
// Compute quat and diag inertia from full inertia matrix, return error if any.
MJAPI const char* mjs_fullInertia(double quat[4], double inertia[3], const double fullinertia[6]);
//---------------------------------- Element initialization --------------------------------------- //---------------------------------- Element initialization ---------------------------------------
+9 -3
View File
@@ -166,9 +166,15 @@ class MjStructVisitor:
elif (node.get('kind') == 'TypedefDecl' and elif (node.get('kind') == 'TypedefDecl' and
node['type']['qualType'].startswith('struct mj') and node['type']['qualType'].startswith('struct mj') and
node['name'] not in _EXCLUDED): node['name'] not in _EXCLUDED):
struct = self._structs[node['type']['qualType']] declname = node['type']['qualType']
self._typedefs[node['name']] = ast_nodes.StructDecl( try:
name=node['name'], declname=struct.declname, fields=struct.fields) struct = self._structs[declname]
except KeyError:
self._typedefs[node['name']] = ast_nodes.StructDecl(
name=node['name'], declname=declname, fields=())
else:
self._typedefs[node['name']] = ast_nodes.StructDecl(
name=node['name'], declname=struct.declname, fields=struct.fields)
def resolve_all_anonymous(self) -> None: def resolve_all_anonymous(self) -> None:
"""Replaces anonymous struct placeholders with corresponding decl.""" """Replaces anonymous struct placeholders with corresponding decl."""
+10
View File
@@ -800,4 +800,14 @@ ENUMS: Mapping[str, EnumDecl] = dict([
('mjNITEM', 14), ('mjNITEM', 14),
]), ]),
)), )),
('mjtSection',
EnumDecl(
name='mjtSection',
declname='enum mjtSection_',
values=dict([
('mjSECT_CLOSED', 0),
('mjSECT_OPEN', 1),
('mjSECT_FIXED', 2),
]),
)),
]) ])
+436 -83
View File
@@ -38,7 +38,7 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
), ),
), ),
), ),
doc='Initialize VFS to empty (no deallocation).', doc='Initialize an empty VFS, mj_deleteVFS must be called to deallocate the VFS.', # pylint: disable=line-too-long
)), )),
('mj_addFileVFS', ('mj_addFileVFS',
FunctionDecl( FunctionDecl(
@@ -96,26 +96,6 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
), ),
doc='Add file to VFS from buffer, return 0: success, 1: full, 2: repeated name, -1: failed to load.', # pylint: disable=line-too-long doc='Add file to VFS from buffer, return 0: success, 1: full, 2: repeated name, -1: failed to load.', # pylint: disable=line-too-long
)), )),
('mj_findFileVFS',
FunctionDecl(
name='mj_findFileVFS',
return_type=ValueType(name='int'),
parameters=(
FunctionParameterDecl(
name='vfs',
type=PointerType(
inner_type=ValueType(name='mjVFS', is_const=True),
),
),
FunctionParameterDecl(
name='filename',
type=PointerType(
inner_type=ValueType(name='char', is_const=True),
),
),
),
doc='Return file index in VFS, or -1 if not found in VFS.',
)),
('mj_deleteFileVFS', ('mj_deleteFileVFS',
FunctionDecl( FunctionDecl(
name='mj_deleteFileVFS', name='mj_deleteFileVFS',
@@ -148,31 +128,7 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
), ),
), ),
), ),
doc='Delete all files from VFS.', doc='Delete all files from VFS and deallocates VFS internal memory.',
)),
('mj_makeEmptyFileVFS',
FunctionDecl(
name='mj_makeEmptyFileVFS',
return_type=ValueType(name='int'),
parameters=(
FunctionParameterDecl(
name='vfs',
type=PointerType(
inner_type=ValueType(name='mjVFS'),
),
),
FunctionParameterDecl(
name='filename',
type=PointerType(
inner_type=ValueType(name='char', is_const=True),
),
),
FunctionParameterDecl(
name='filesize',
type=ValueType(name='int'),
),
),
doc='deprecated: use mj_copyBufferVFS.',
)), )),
('mj_loadXML', ('mj_loadXML',
FunctionDecl( FunctionDecl(
@@ -9543,13 +9499,9 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
), ),
), ),
FunctionParameterDecl( FunctionParameterDecl(
name='parentid', name='parent',
type=ValueType(name='int'),
),
FunctionParameterDecl(
name='id',
type=PointerType( type=PointerType(
inner_type=ValueType(name='int'), inner_type=ValueType(name='mjsDefault', is_const=True),
), ),
), ),
), ),
@@ -9751,6 +9703,28 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
), ),
doc='Find frame by name.', doc='Find frame by name.',
)), )),
('mjs_findKeyframe',
FunctionDecl(
name='mjs_findKeyframe',
return_type=PointerType(
inner_type=ValueType(name='mjsKey'),
),
parameters=(
FunctionParameterDecl(
name='s',
type=PointerType(
inner_type=ValueType(name='mjSpec'),
),
),
FunctionParameterDecl(
name='name',
type=PointerType(
inner_type=ValueType(name='char', is_const=True),
),
),
),
doc='Find keyframe by name.',
)),
('mjs_getDefault', ('mjs_getDefault',
FunctionDecl( FunctionDecl(
name='mjs_getDefault', name='mjs_getDefault',
@@ -9861,6 +9835,416 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
), ),
doc="Return body's next child of the same type; return NULL if child is last.", # pylint: disable=line-too-long doc="Return body's next child of the same type; return NULL if child is last.", # pylint: disable=line-too-long
)), )),
('mjs_firstElement',
FunctionDecl(
name='mjs_firstElement',
return_type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
parameters=(
FunctionParameterDecl(
name='s',
type=PointerType(
inner_type=ValueType(name='mjSpec'),
),
),
FunctionParameterDecl(
name='type',
type=ValueType(name='mjtObj'),
),
),
doc="Return spec's first element of selected type.",
)),
('mjs_nextElement',
FunctionDecl(
name='mjs_nextElement',
return_type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
parameters=(
FunctionParameterDecl(
name='s',
type=PointerType(
inner_type=ValueType(name='mjSpec'),
),
),
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc="Return spec's next element; return NULL if element is last.",
)),
('mjs_asBody',
FunctionDecl(
name='mjs_asBody',
return_type=PointerType(
inner_type=ValueType(name='mjsBody'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsBody, or return NULL if the element is not an mjsBody.', # pylint: disable=line-too-long
)),
('mjs_asGeom',
FunctionDecl(
name='mjs_asGeom',
return_type=PointerType(
inner_type=ValueType(name='mjsGeom'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsGeom, or return NULL if the element is not an mjsGeom.', # pylint: disable=line-too-long
)),
('mjs_asJoint',
FunctionDecl(
name='mjs_asJoint',
return_type=PointerType(
inner_type=ValueType(name='mjsJoint'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsJoint, or return NULL if the element is not an mjsJoint.', # pylint: disable=line-too-long
)),
('mjs_asSite',
FunctionDecl(
name='mjs_asSite',
return_type=PointerType(
inner_type=ValueType(name='mjsSite'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsSite, or return NULL if the element is not an mjsSite.', # pylint: disable=line-too-long
)),
('mjs_asCamera',
FunctionDecl(
name='mjs_asCamera',
return_type=PointerType(
inner_type=ValueType(name='mjsCamera'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsCamera, or return NULL if the element is not an mjsCamera.', # pylint: disable=line-too-long
)),
('mjs_asLight',
FunctionDecl(
name='mjs_asLight',
return_type=PointerType(
inner_type=ValueType(name='mjsLight'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsLight, or return NULL if the element is not an mjsLight.', # pylint: disable=line-too-long
)),
('mjs_asFrame',
FunctionDecl(
name='mjs_asFrame',
return_type=PointerType(
inner_type=ValueType(name='mjsFrame'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsFrame, or return NULL if the element is not an mjsFrame.', # pylint: disable=line-too-long
)),
('mjs_asActuator',
FunctionDecl(
name='mjs_asActuator',
return_type=PointerType(
inner_type=ValueType(name='mjsActuator'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsActuator, or return NULL if the element is not an mjsActuator.', # pylint: disable=line-too-long
)),
('mjs_asSensor',
FunctionDecl(
name='mjs_asSensor',
return_type=PointerType(
inner_type=ValueType(name='mjsSensor'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsSensor, or return NULL if the element is not an mjsSensor.', # pylint: disable=line-too-long
)),
('mjs_asFlex',
FunctionDecl(
name='mjs_asFlex',
return_type=PointerType(
inner_type=ValueType(name='mjsFlex'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsFlex, or return NULL if the element is not an mjsFlex.', # pylint: disable=line-too-long
)),
('mjs_asPair',
FunctionDecl(
name='mjs_asPair',
return_type=PointerType(
inner_type=ValueType(name='mjsPair'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsPair, or return NULL if the element is not an mjsPair.', # pylint: disable=line-too-long
)),
('mjs_asEquality',
FunctionDecl(
name='mjs_asEquality',
return_type=PointerType(
inner_type=ValueType(name='mjsEquality'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsEquality, or return NULL if the element is not an mjsEquality.', # pylint: disable=line-too-long
)),
('mjs_asExclude',
FunctionDecl(
name='mjs_asExclude',
return_type=PointerType(
inner_type=ValueType(name='mjsExclude'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsExclude, or return NULL if the element is not an mjsExclude.', # pylint: disable=line-too-long
)),
('mjs_asTendon',
FunctionDecl(
name='mjs_asTendon',
return_type=PointerType(
inner_type=ValueType(name='mjsTendon'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsTendon, or return NULL if the element is not an mjsTendon.', # pylint: disable=line-too-long
)),
('mjs_asNumeric',
FunctionDecl(
name='mjs_asNumeric',
return_type=PointerType(
inner_type=ValueType(name='mjsNumeric'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsNumeric, or return NULL if the element is not an mjsNumeric.', # pylint: disable=line-too-long
)),
('mjs_asText',
FunctionDecl(
name='mjs_asText',
return_type=PointerType(
inner_type=ValueType(name='mjsText'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsText, or return NULL if the element is not an mjsText.', # pylint: disable=line-too-long
)),
('mjs_asTuple',
FunctionDecl(
name='mjs_asTuple',
return_type=PointerType(
inner_type=ValueType(name='mjsTuple'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsTuple, or return NULL if the element is not an mjsTuple.', # pylint: disable=line-too-long
)),
('mjs_asKey',
FunctionDecl(
name='mjs_asKey',
return_type=PointerType(
inner_type=ValueType(name='mjsKey'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsKey, or return NULL if the element is not an mjsKey.', # pylint: disable=line-too-long
)),
('mjs_asMesh',
FunctionDecl(
name='mjs_asMesh',
return_type=PointerType(
inner_type=ValueType(name='mjsMesh'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsMesh, or return NULL if the element is not an mjsMesh.', # pylint: disable=line-too-long
)),
('mjs_asHField',
FunctionDecl(
name='mjs_asHField',
return_type=PointerType(
inner_type=ValueType(name='mjsHField'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsHField, or return NULL if the element is not an mjsHField.', # pylint: disable=line-too-long
)),
('mjs_asSkin',
FunctionDecl(
name='mjs_asSkin',
return_type=PointerType(
inner_type=ValueType(name='mjsSkin'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsSkin, or return NULL if the element is not an mjsSkin.', # pylint: disable=line-too-long
)),
('mjs_asTexture',
FunctionDecl(
name='mjs_asTexture',
return_type=PointerType(
inner_type=ValueType(name='mjsTexture'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsTexture, or return NULL if the element is not an mjsTexture.', # pylint: disable=line-too-long
)),
('mjs_asMaterial',
FunctionDecl(
name='mjs_asMaterial',
return_type=PointerType(
inner_type=ValueType(name='mjsMaterial'),
),
parameters=(
FunctionParameterDecl(
name='element',
type=PointerType(
inner_type=ValueType(name='mjsElement'),
),
),
),
doc='Safely cast an element as mjsMaterial, or return NULL if the element is not an mjsMaterial.', # pylint: disable=line-too-long
)),
('mjs_setString', ('mjs_setString',
FunctionDecl( FunctionDecl(
name='mjs_setString', name='mjs_setString',
@@ -10216,37 +10600,6 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
), ),
doc='Resolve alternative orientations to quat, return error if any.', doc='Resolve alternative orientations to quat, return error if any.',
)), )),
('mjs_fullInertia',
FunctionDecl(
name='mjs_fullInertia',
return_type=PointerType(
inner_type=ValueType(name='char', is_const=True),
),
parameters=(
FunctionParameterDecl(
name='quat',
type=ArrayType(
inner_type=ValueType(name='double'),
extents=(4,),
),
),
FunctionParameterDecl(
name='inertia',
type=ArrayType(
inner_type=ValueType(name='double'),
extents=(3,),
),
),
FunctionParameterDecl(
name='fullinertia',
type=ArrayType(
inner_type=ValueType(name='double', is_const=True),
extents=(6,),
),
),
),
doc='Compute quat and diag inertia from full inertia matrix, return error if any.', # pylint: disable=line-too-long
)),
('mjs_defaultSpec', ('mjs_defaultSpec',
FunctionDecl( FunctionDecl(
name='mjs_defaultSpec', name='mjs_defaultSpec',
+147 -188
View File
@@ -91,43 +91,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
declname='struct mjVFS_', declname='struct mjVFS_',
fields=( fields=(
StructFieldDecl( StructFieldDecl(
name='nfile', name='impl_',
type=ValueType(name='int'), type=PointerType(
doc='number of files present', inner_type=ValueType(name='void'),
),
StructFieldDecl(
name='filename',
type=ArrayType(
inner_type=ValueType(name='char'),
extents=(2000, 1000),
), ),
doc='file name without path', doc='internal pointer to VFS memory',
),
StructFieldDecl(
name='filesize',
type=ArrayType(
inner_type=ValueType(name='size_t'),
extents=(2000,),
),
doc='file size in bytes',
),
StructFieldDecl(
name='filedata',
type=ArrayType(
inner_type=PointerType(
inner_type=ValueType(name='void'),
),
extents=(2000,),
),
doc='buffer with file data',
),
StructFieldDecl(
name='filestamp',
type=ArrayType(
inner_type=ValueType(name='uint64_t'),
extents=(2000,),
),
doc='checksum of the file data',
), ),
), ),
)), )),
@@ -2950,7 +2918,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=PointerType( type=PointerType(
inner_type=ValueType(name='int'), inner_type=ValueType(name='int'),
), ),
doc='texture id; -1: none (nmat x 1)', doc='indices of textures; -1: none (nmat x mjNTEXMAT)', # pylint: disable=line-too-long
), ),
StructFieldDecl( StructFieldDecl(
name='mat_texuniform', name='mat_texuniform',
@@ -4183,7 +4151,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([
StructFieldDecl( StructFieldDecl(
name='pstack', name='pstack',
type=ValueType(name='size_t'), type=ValueType(name='size_t'),
doc='first available mjtNum address in stack', doc='first available byte in stack',
), ),
StructFieldDecl( StructFieldDecl(
name='pbase', name='pbase',
@@ -4223,22 +4191,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='int'), type=ValueType(name='int'),
doc='maximum number of scalar constraints', doc='maximum number of scalar constraints',
), ),
StructFieldDecl(
name='warning',
type=ArrayType(
inner_type=ValueType(name='mjWarningStat'),
extents=(8,),
),
doc='warning statistics',
),
StructFieldDecl(
name='timer',
type=ArrayType(
inner_type=ValueType(name='mjTimerStat'),
extents=(15,),
),
doc='timer statistics',
),
StructFieldDecl( StructFieldDecl(
name='solver', name='solver',
type=ArrayType( type=ArrayType(
@@ -4266,7 +4218,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([
inner_type=ValueType(name='int'), inner_type=ValueType(name='int'),
extents=(20,), extents=(20,),
), ),
doc='number of non-zeros in Hessian or efc_AR, per island', doc='number of nonzeros in Hessian or efc_AR, per island',
), ),
StructFieldDecl( StructFieldDecl(
name='solver_fwdinv', name='solver_fwdinv',
@@ -4276,6 +4228,22 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='forward-inverse comparison: qfrc, efc', doc='forward-inverse comparison: qfrc, efc',
), ),
StructFieldDecl(
name='warning',
type=ArrayType(
inner_type=ValueType(name='mjWarningStat'),
extents=(8,),
),
doc='warning statistics',
),
StructFieldDecl(
name='timer',
type=ArrayType(
inner_type=ValueType(name='mjTimerStat'),
extents=(15,),
),
doc='timer statistics',
),
StructFieldDecl( StructFieldDecl(
name='ne', name='ne',
type=ValueType(name='int'), type=ValueType(name='int'),
@@ -4329,14 +4297,14 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=PointerType( type=PointerType(
inner_type=ValueType(name='void'), inner_type=ValueType(name='void'),
), ),
doc='main buffer; all pointers point in it (nbuffer bytes)', # pylint: disable=line-too-long doc='main buffer; all pointers point in it (nbuffer bytes)', # pylint: disable=line-too-long
), ),
StructFieldDecl( StructFieldDecl(
name='arena', name='arena',
type=PointerType( type=PointerType(
inner_type=ValueType(name='void'), inner_type=ValueType(name='void'),
), ),
doc='arena+stack buffer (nstack*sizeof(mjtNum) bytes)', # pylint: disable=line-too-long doc='arena+stack buffer (narena bytes)', # pylint: disable=line-too-long
), ),
StructFieldDecl( StructFieldDecl(
name='qpos', name='qpos',
@@ -4756,7 +4724,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=PointerType( type=PointerType(
inner_type=ValueType(name='mjtByte'), inner_type=ValueType(name='mjtByte'),
), ),
doc='volume has been added to collisions (nbvh x 1)', # pylint: disable=line-too-long doc='was bounding volume checked for collision (nbvh x 1)', # pylint: disable=line-too-long
), ),
StructFieldDecl( StructFieldDecl(
name='flexedge_velocity', name='flexedge_velocity',
@@ -4987,7 +4955,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=PointerType( type=PointerType(
inner_type=ValueType(name='mjContact'), inner_type=ValueType(name='mjContact'),
), ),
doc='list of all detected contacts (ncon x 1)', # pylint: disable=line-too-long doc='array of all detected contacts (ncon x 1)', # pylint: disable=line-too-long
), ),
StructFieldDecl( StructFieldDecl(
name='efc_type', name='efc_type',
@@ -5239,26 +5207,26 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=PointerType( type=PointerType(
inner_type=ValueType(name='mjtNum'), inner_type=ValueType(name='mjtNum'),
), ),
doc='linear cost term: J*qacc_smooth - aref (nefc x 1)', # pylint: disable=line-too-long doc='linear cost term: J*qacc_smooth - aref (nefc x 1)', # pylint: disable=line-too-long
), ),
StructFieldDecl( StructFieldDecl(
name='efc_force', name='efc_force',
type=PointerType( type=PointerType(
inner_type=ValueType(name='mjtNum'), inner_type=ValueType(name='mjtNum'),
), ),
doc='constraint force in constraint space (nefc x 1)', # pylint: disable=line-too-long doc='constraint force in constraint space (nefc x 1)', # pylint: disable=line-too-long
), ),
StructFieldDecl( StructFieldDecl(
name='efc_state', name='efc_state',
type=PointerType( type=PointerType(
inner_type=ValueType(name='int'), inner_type=ValueType(name='int'),
), ),
doc='constraint state (mjtConstraintState) (nefc x 1)', # pylint: disable=line-too-long doc='constraint state (mjtConstraintState) (nefc x 1)', # pylint: disable=line-too-long
), ),
StructFieldDecl( StructFieldDecl(
name='threadpool', name='threadpool',
type=ValueType(name='uintptr_t'), type=ValueType(name='uintptr_t'),
doc='ThreadPool for multithreaded operations', doc='thread pool pointer',
), ),
), ),
)), )),
@@ -5483,14 +5451,9 @@ STRUCTS: Mapping[str, StructDecl] = dict([
doc='visual category', doc='visual category',
), ),
StructFieldDecl( StructFieldDecl(
name='texid', name='matid',
type=ValueType(name='int'), type=ValueType(name='int'),
doc='texture id; -1: no texture', doc='material id; -1: no textured material',
),
StructFieldDecl(
name='texuniform',
type=ValueType(name='int'),
doc='uniform cube mapping',
), ),
StructFieldDecl( StructFieldDecl(
name='texcoord', name='texcoord',
@@ -5502,14 +5465,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='int'), type=ValueType(name='int'),
doc='segmentation id; -1: not shown', doc='segmentation id; -1: not shown',
), ),
StructFieldDecl(
name='texrepeat',
type=ArrayType(
inner_type=ValueType(name='float'),
extents=(2,),
),
doc='texture repetition for 2D mapping',
),
StructFieldDecl( StructFieldDecl(
name='size', name='size',
type=ArrayType( type=ArrayType(
@@ -7957,7 +7912,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([
StructFieldDecl( StructFieldDecl(
name='offDepthStencil_r', name='offDepthStencil_r',
type=ValueType(name='unsigned int'), type=ValueType(name='unsigned int'),
doc='offscreen depth and stencil buffer for resolving multisamples', # pylint: disable=line-too-long doc='offscreen depth and stencil buffer for multisamples',
), ),
StructFieldDecl( StructFieldDecl(
name='shadowFBO', name='shadowFBO',
@@ -8001,6 +7956,30 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='auxiliary color buffer for resolving', doc='auxiliary color buffer for resolving',
), ),
StructFieldDecl(
name='mat_texid',
type=ArrayType(
inner_type=ValueType(name='int'),
extents=(600,),
),
doc='material texture ids (-1: no texture)',
),
StructFieldDecl(
name='mat_texuniform',
type=ArrayType(
inner_type=ValueType(name='int'),
extents=(100,),
),
doc='texture repetition for 2d mapping',
),
StructFieldDecl(
name='mat_texrepeat',
type=ArrayType(
inner_type=ValueType(name='int'),
extents=(200,),
),
doc='texture repetition for 2d mapping',
),
StructFieldDecl( StructFieldDecl(
name='ntexture', name='ntexture',
type=ValueType(name='int'), type=ValueType(name='int'),
@@ -8035,12 +8014,12 @@ STRUCTS: Mapping[str, StructDecl] = dict([
StructFieldDecl( StructFieldDecl(
name='baseHField', name='baseHField',
type=ValueType(name='unsigned int'), type=ValueType(name='unsigned int'),
doc='all hfields from model', doc='all height fields from model',
), ),
StructFieldDecl( StructFieldDecl(
name='baseBuiltin', name='baseBuiltin',
type=ValueType(name='unsigned int'), type=ValueType(name='unsigned int'),
doc='all buildin geoms, with quality from model', doc='all builtin geoms, with quality from model',
), ),
StructFieldDecl( StructFieldDecl(
name='baseFontNormal', name='baseFontNormal',
@@ -8255,7 +8234,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([
doc='angles in radians or degrees', doc='angles in radians or degrees',
), ),
StructFieldDecl( StructFieldDecl(
name='euler', name='eulerseq',
type=ArrayType( type=ArrayType(
inner_type=ValueType(name='char'), inner_type=ValueType(name='char'),
extents=(3,), extents=(3,),
@@ -8719,13 +8698,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='class name',
),
StructFieldDecl( StructFieldDecl(
name='type', name='type',
type=ValueType(name='mjtJoint'), type=ValueType(name='mjtJoint'),
@@ -8893,13 +8865,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='classname',
),
StructFieldDecl( StructFieldDecl(
name='type', name='type',
type=ValueType(name='mjtGeom'), type=ValueType(name='mjtGeom'),
@@ -9108,13 +9073,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='class name',
),
StructFieldDecl( StructFieldDecl(
name='pos', name='pos',
type=ArrayType( type=ArrayType(
@@ -9212,13 +9170,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='class name',
),
StructFieldDecl( StructFieldDecl(
name='pos', name='pos',
type=ArrayType( type=ArrayType(
@@ -9358,13 +9309,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='class name',
),
StructFieldDecl( StructFieldDecl(
name='pos', name='pos',
type=ArrayType( type=ArrayType(
@@ -9483,13 +9427,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='class name',
),
StructFieldDecl( StructFieldDecl(
name='contype', name='contype',
type=ValueType(name='int'), type=ValueType(name='int'),
@@ -9665,13 +9602,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='class name',
),
StructFieldDecl( StructFieldDecl(
name='content_type', name='content_type',
type=PointerType( type=PointerType(
@@ -9862,13 +9792,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='class name',
),
StructFieldDecl( StructFieldDecl(
name='file', name='file',
type=PointerType( type=PointerType(
@@ -9985,13 +9908,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='class name',
),
StructFieldDecl( StructFieldDecl(
name='type', name='type',
type=ValueType(name='mjtTexture'), type=ValueType(name='mjtTexture'),
@@ -10121,13 +10037,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='class name',
),
StructFieldDecl( StructFieldDecl(
name='texture', name='texture',
type=PointerType( type=PointerType(
@@ -10214,13 +10123,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='class name',
),
StructFieldDecl( StructFieldDecl(
name='geomname1', name='geomname1',
type=PointerType( type=PointerType(
@@ -10352,13 +10254,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='class name',
),
StructFieldDecl( StructFieldDecl(
name='type', name='type',
type=ValueType(name='mjtEq'), type=ValueType(name='mjtEq'),
@@ -10435,13 +10330,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='class name',
),
StructFieldDecl( StructFieldDecl(
name='stiffness', name='stiffness',
type=ValueType(name='double'), type=ValueType(name='double'),
@@ -10596,13 +10484,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='class name',
),
StructFieldDecl( StructFieldDecl(
name='gaintype', name='gaintype',
type=ValueType(name='mjtGain'), type=ValueType(name='mjtGain'),
@@ -10793,13 +10674,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='name', doc='name',
), ),
StructFieldDecl(
name='classname',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='class name',
),
StructFieldDecl( StructFieldDecl(
name='type', name='type',
type=ValueType(name='mjtSensor'), type=ValueType(name='mjtSensor'),
@@ -11350,6 +11224,16 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='int'), type=ValueType(name='int'),
doc='section gap', doc='section gap',
), ),
StructFieldDecl(
name='cornersect',
type=ValueType(name='int'),
doc='corner radius for section',
),
StructFieldDecl(
name='cornersep',
type=ValueType(name='int'),
doc='corner radius for separator',
),
StructFieldDecl( StructFieldDecl(
name='itemside', name='itemside',
type=ValueType(name='int'), type=ValueType(name='int'),
@@ -11416,6 +11300,30 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='section title', doc='section title',
), ),
StructFieldDecl(
name='secttitle2',
type=ArrayType(
inner_type=ValueType(name='float'),
extents=(3,),
),
doc='section title: bottom color',
),
StructFieldDecl(
name='secttitlecheck',
type=ArrayType(
inner_type=ValueType(name='float'),
extents=(3,),
),
doc='section title with checkbox',
),
StructFieldDecl(
name='secttitlecheck2',
type=ArrayType(
inner_type=ValueType(name='float'),
extents=(3,),
),
doc='section title with checkbox: bottom color',
),
StructFieldDecl( StructFieldDecl(
name='sectfont', name='sectfont',
type=ArrayType( type=ArrayType(
@@ -11440,6 +11348,22 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='section pane', doc='section pane',
), ),
StructFieldDecl(
name='separator',
type=ArrayType(
inner_type=ValueType(name='float'),
extents=(3,),
),
doc='separator title',
),
StructFieldDecl(
name='separator2',
type=ArrayType(
inner_type=ValueType(name='float'),
extents=(3,),
),
doc='separator title: bottom color',
),
StructFieldDecl( StructFieldDecl(
name='shortcut', name='shortcut',
type=ArrayType( type=ArrayType(
@@ -11602,6 +11526,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='int'), type=ValueType(name='int'),
doc='id of item within section', doc='id of item within section',
), ),
StructFieldDecl(
name='userid',
type=ValueType(name='int'),
doc='user-supplied id (for event handling)',
),
AnonymousUnionDecl( AnonymousUnionDecl(
fields=( fields=(
StructFieldDecl( StructFieldDecl(
@@ -11631,6 +11560,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='mjrRect'), type=ValueType(name='mjrRect'),
doc='rectangle occupied by item', doc='rectangle occupied by item',
), ),
StructFieldDecl(
name='skip',
type=ValueType(name='int'),
doc='item skipped due to closed separator',
),
), ),
)), )),
('mjuiSection', ('mjuiSection',
@@ -11649,7 +11583,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([
StructFieldDecl( StructFieldDecl(
name='state', name='state',
type=ValueType(name='int'), type=ValueType(name='int'),
doc='0: closed, 1: open', doc='section state (mjtSection)',
), ),
StructFieldDecl( StructFieldDecl(
name='modifier', name='modifier',
@@ -11661,6 +11595,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='int'), type=ValueType(name='int'),
doc='shortcut key; 0: undefined', doc='shortcut key; 0: undefined',
), ),
StructFieldDecl(
name='checkbox',
type=ValueType(name='int'),
doc='0: none, 1: hidden, 2: unchecked, 2: checked',
),
StructFieldDecl( StructFieldDecl(
name='nitem', name='nitem',
type=ValueType(name='int'), type=ValueType(name='int'),
@@ -11684,6 +11623,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='mjrRect'), type=ValueType(name='mjrRect'),
doc='rectangle occupied by content', doc='rectangle occupied by content',
), ),
StructFieldDecl(
name='lastclick',
type=ValueType(name='int'),
doc='last mouse click over this section',
),
), ),
)), )),
('mjUI', ('mjUI',
@@ -11763,6 +11707,16 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='int'), type=ValueType(name='int'),
doc='help button down: print shortcuts', doc='help button down: print shortcuts',
), ),
StructFieldDecl(
name='mouseclicks',
type=ValueType(name='int'),
doc='number of mouse clicks over UI',
),
StructFieldDecl(
name='mousesectcheck',
type=ValueType(name='int'),
doc='0: none, otherwise 1+section',
),
StructFieldDecl( StructFieldDecl(
name='editsect', name='editsect',
type=ValueType(name='int'), type=ValueType(name='int'),
@@ -11851,6 +11805,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
), ),
doc='string with type-specific properties', doc='string with type-specific properties',
), ),
StructFieldDecl(
name='otherint',
type=ValueType(name='int'),
doc='int with type-specific properties',
),
), ),
)), )),
]) ])
+1 -3
View File
@@ -32,9 +32,7 @@ jaxlib==0.4.18; python_version >= '3.9' \
--hash=sha256:f7787a5531d226d6cc9ec2baa7141260bb713435e1cfc053cb9f5cefa9756ac3 \ --hash=sha256:f7787a5531d226d6cc9ec2baa7141260bb713435e1cfc053cb9f5cefa9756ac3 \
--hash=sha256:6cb20bbbdafd90e71ad0deb9295519a0175c108c8c557b84fb9fe94f751daee4 \ --hash=sha256:6cb20bbbdafd90e71ad0deb9295519a0175c108c8c557b84fb9fe94f751daee4 \
--hash=sha256:116a0d6aedd3e856b52493d7e392fb1b40952b84fb72448fde1c1ab5687db667 \ --hash=sha256:116a0d6aedd3e856b52493d7e392fb1b40952b84fb72448fde1c1ab5687db667 \
--hash=sha256:9593ff69f424947567e206f3e356b2a2df55ca68e6d815d5adc6cae308e8f652 \ --hash=sha256:9593ff69f424947567e206f3e356b2a2df55ca68e6d815d5adc6cae308e8f652
--hash=sha256:2b17b3f05b3bbf8e0ddb85fba339525ac03bac21c9f26d0f83dcea1b1654353e \
--hash=sha256:b35ec08984e2aa5e96ba3f3f8b88e90dee0283649e037f213dec8e85638fa17d
pip==23.3.1 \ pip==23.3.1 \
--hash=sha256:55eb67bb6171d37447e82213be585b75fe2b12b359e993773aca4de9247a052b --hash=sha256:55eb67bb6171d37447e82213be585b75fe2b12b359e993773aca4de9247a052b
pytest==7.4.2 \ pytest==7.4.2 \
+118 -33
View File
@@ -1,39 +1,39 @@
{ {
"cells": [ "cells": [
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {
"id": "MpkYHwCqk7W-" "id": "MpkYHwCqk7W-"
},
"source": [
"![MuJoCo banner](https://raw.githubusercontent.com/google-deepmind/mujoco/main/banner.png)\n",
"\n",
"# <h1><center>Tutorial <a href=\"https://colab.research.google.com/github/google-deepmind/mujoco/blob/main/mjx/training_apg.ipynb\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" width=\"140\" align=\"center\"/></a></center></h1>\n",
"\n",
"This notebook provides a tutorial for differentiable physics for policy learning in [**MuJoCo XLA (MJX)**](https://github.com/google-deepmind/mujoco/blob/main/mjx), a JAX-based implementation of MuJoCo.\n",
"\n",
"**A Colab runtime with GPU acceleration is required.** If you're using a CPU-only runtime, you can switch using the menu \"Runtime > Change runtime type\".\n",
"\n",
"\n",
"This notebook was written by [Jing Yuan Luo](https://github.com/Andrew-Luo1).\n",
"\n",
"\u003c!-- Copyright 2021 DeepMind Technologies Limited\n",
"\n",
" Licensed under the Apache License, Version 2.0 (the \"License\");\n",
" you may not use this file except in compliance with the License.\n",
" You may obtain a copy of the License at\n",
"\n",
" http://www.apache.org/licenses/LICENSE-2.0\n",
"\n",
" Unless required by applicable law or agreed to in writing, software\n",
" distributed under the License is distributed on an \"AS IS\" BASIS,\n",
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
" See the License for the specific language governing permissions and\n",
" limitations under the License.\n",
"--\u003e"
]
}, },
{ "source": [
"![MuJoCo banner](https://raw.githubusercontent.com/google-deepmind/mujoco/main/banner.png)\n",
"\n",
"# <h1><center>Tutorial <a href=\"https://colab.research.google.com/github/google-deepmind/mujoco/blob/main/mjx/training_apg.ipynb\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" width=\"140\" align=\"center\"/></a></center></h1>\n",
"\n",
"This notebook provides a tutorial for differentiable physics for policy learning in [**MuJoCo XLA (MJX)**](https://github.com/google-deepmind/mujoco/blob/main/mjx), a JAX-based implementation of MuJoCo.\n",
"\n",
"**A Colab runtime with GPU acceleration is required.** If you're using a CPU-only runtime, you can switch using the menu \"Runtime > Change runtime type\".\n",
"\n",
"\n",
"This notebook was written by [Jing Yuan Luo](https://github.com/Andrew-Luo1).\n",
"\n",
"<!-- Copyright 2021 DeepMind Technologies Limited\n",
"\n",
" Licensed under the Apache License, Version 2.0 (the \"License\");\n",
" you may not use this file except in compliance with the License.\n",
" You may obtain a copy of the License at\n",
"\n",
" http://www.apache.org/licenses/LICENSE-2.0\n",
"\n",
" Unless required by applicable law or agreed to in writing, software\n",
" distributed under the License is distributed on an \"AS IS\" BASIS,\n",
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
" See the License for the specific language governing permissions and\n",
" limitations under the License.\n",
"-->"
]
},
{
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
@@ -106,12 +106,97 @@
"## Setup: Imports and installations" "## Setup: Imports and installations"
] ]
}, },
{
"cell_type": "code",
"execution_count": 0,
"metadata": {},
"outputs": [],
"source": [
"# Install MuJoCo, MJX, and Brax\n",
"!pip install mujoco\n",
"!pip install mujoco_mjx\n",
"!pip install brax"
]
},
{
"cell_type": "code",
"execution_count": 0,
"metadata": {},
"outputs": [],
"source": [
"#@title Check if MuJoCo installation was successful\n",
"\n",
"# Set up GPU rendering.\n",
"from google.colab import files\n",
"import distutils.util\n",
"import os\n",
"import subprocess\n",
"if subprocess.run('nvidia-smi').returncode:\n",
" raise RuntimeError(\n",
" 'Cannot communicate with GPU. '\n",
" 'Make sure you are using a GPU Colab runtime. '\n",
" 'Go to the Runtime menu and select Choose runtime type.')\n",
"\n",
"# Add an ICD config so that glvnd can pick up the Nvidia EGL driver.\n",
"# This is usually installed as part of an Nvidia driver package, but the Colab\n",
"# kernel doesn't install its driver via APT, and as a result the ICD is missing.\n",
"# (https://github.com/NVIDIA/libglvnd/blob/master/src/EGL/icd_enumeration.md)\n",
"NVIDIA_ICD_CONFIG_PATH = '/usr/share/glvnd/egl_vendor.d/10_nvidia.json'\n",
"if not os.path.exists(NVIDIA_ICD_CONFIG_PATH):\n",
" with open(NVIDIA_ICD_CONFIG_PATH, 'w') as f:\n",
" f.write(\"\"\"{\n",
" \"file_format_version\" : \"1.0.0\",\n",
" \"ICD\" : {\n",
" \"library_path\" : \"libEGL_nvidia.so.0\"\n",
" }\n",
"}\n",
"\"\"\")\n",
"\n",
"# Configure MuJoCo to use the EGL rendering backend (requires GPU)\n",
"print('Setting environment variable to use GPU rendering:')\n",
"%env MUJOCO_GL=egl\n",
"\n",
"# Check if installation was succesful.\n",
"try:\n",
" print('Checking that the installation succeeded:')\n",
" import mujoco\n",
" mujoco.MjModel.from_xml_string('<mujoco/>')\n",
"except Exception as e:\n",
" raise e from RuntimeError(\n",
" 'Something went wrong during installation. Check the shell output above '\n",
" 'for more information.\\n'\n",
" 'If using a hosted Colab runtime, make sure you enable GPU acceleration '\n",
" 'by going to the Runtime menu and selecting \"Choose runtime type\".')\n",
"\n",
"print('Installation successful.')\n",
"\n",
"# Other imports and helper functions\n",
"import time\n",
"import itertools\n",
"import numpy as np\n",
"\n",
"# Graphics and plotting.\n",
"print('Installing mediapy:')\n",
"!command -v ffmpeg >/dev/null || (apt update && apt install -y ffmpeg)\n",
"!pip install -q mediapy\n",
"import mediapy as media\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# More legible printing from numpy.\n",
"np.set_printoptions(precision=3, suppress=True, linewidth=100)\n",
"\n",
"from IPython.display import clear_output\n",
"clear_output()"
]
},
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 1,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"#@title Import MuJoCo, MJX, and Brax\n",
"\n",
"import os\n", "import os\n",
"os.environ[\"XLA_PYTHON_CLIENT_MEM_FRACTION\"] = \"0.8\" # 0.9 causes too much lag. \n", "os.environ[\"XLA_PYTHON_CLIENT_MEM_FRACTION\"] = \"0.8\" # 0.9 causes too much lag. \n",
"from datetime import datetime\n", "from datetime import datetime\n",
@@ -162,7 +247,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 0,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
+1 -1
View File
@@ -25,7 +25,7 @@
<asset> <asset>
<texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="512" height="512"/> <texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="512" height="512"/>
<texture name="body" type="cube" builtin="flat" mark="cross" width="128" height="128" <texture name="body" type="cube" builtin="flat" mark="cross" width="128" height="128"
rgb1="0.8 0.6 0.4" rgb2="0.8 0.6 0.4" markrgb="1 1 1" random="0.01"/> rgb1="0.8 0.6 0.4" rgb2="0.8 0.6 0.4" markrgb="1 1 1"/>
<material name="body" texture="body" texuniform="true" rgba="0.8 0.6 .4 1"/> <material name="body" texture="body" texuniform="true" rgba="0.8 0.6 .4 1"/>
<texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/> <texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/>
<material name="grid" texture="grid" texrepeat="1 1" texuniform="true" reflectance=".2"/> <material name="grid" texture="grid" texrepeat="1 1" texuniform="true" reflectance=".2"/>
+1 -1
View File
@@ -21,7 +21,7 @@
<asset> <asset>
<texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="512" height="512"/> <texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="512" height="512"/>
<texture name="body" type="cube" builtin="flat" mark="cross" width="128" height="128" <texture name="body" type="cube" builtin="flat" mark="cross" width="128" height="128"
rgb1="0.8 0.6 0.4" rgb2="0.8 0.6 0.4" markrgb="1 1 1" random="0.01"/> rgb1="0.8 0.6 0.4" rgb2="0.8 0.6 0.4" markrgb="1 1 1"/>
<material name="body" texture="body" texuniform="true" rgba="0.8 0.6 .4 1"/> <material name="body" texture="body" texuniform="true" rgba="0.8 0.6 .4 1"/>
<texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/> <texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/>
<material name="grid" texture="grid" texrepeat="1 1" texuniform="true" reflectance=".2"/> <material name="grid" texture="grid" texrepeat="1 1" texuniform="true" reflectance=".2"/>
+1 -1
View File
@@ -26,7 +26,7 @@
<asset> <asset>
<texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="32" height="512"/> <texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="32" height="512"/>
<texture name="body" type="cube" builtin="flat" mark="cross" width="128" height="128" rgb1="0.8 0.6 0.4" rgb2="0.8 0.6 0.4" markrgb="1 1 1" random="0.01"/> <texture name="body" type="cube" builtin="flat" mark="cross" width="128" height="128" rgb1="0.8 0.6 0.4" rgb2="0.8 0.6 0.4" markrgb="1 1 1"/>
<material name="body" texture="body" texuniform="true" rgba="0.8 0.6 .4 1"/> <material name="body" texture="body" texuniform="true" rgba="0.8 0.6 .4 1"/>
<texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/> <texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/>
<material name="grid" texture="grid" texrepeat="1 1" texuniform="true" reflectance=".2"/> <material name="grid" texture="grid" texrepeat="1 1" texuniform="true" reflectance=".2"/>
+1 -1
View File
@@ -25,7 +25,7 @@
<asset> <asset>
<texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="512" height="512"/> <texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="512" height="512"/>
<texture name="body" type="cube" builtin="flat" mark="cross" width="128" height="128" <texture name="body" type="cube" builtin="flat" mark="cross" width="128" height="128"
rgb1="0.8 0.6 0.4" rgb2="0.8 0.6 0.4" markrgb="1 1 1" random="0.01"/> rgb1="0.8 0.6 0.4" rgb2="0.8 0.6 0.4" markrgb="1 1 1"/>
<material name="body" texture="body" texuniform="true" rgba="0.8 0.6 .4 1"/> <material name="body" texture="body" texuniform="true" rgba="0.8 0.6 .4 1"/>
<texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/> <texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/>
<material name="grid" texture="grid" texrepeat="1 1" texuniform="true" reflectance=".2"/> <material name="grid" texture="grid" texrepeat="1 1" texuniform="true" reflectance=".2"/>
+1 -1
View File
@@ -148,7 +148,7 @@ void Bolt::RegisterPlugin() {
delete reinterpret_cast<Bolt*>(d->plugin_data[instance]); delete reinterpret_cast<Bolt*>(d->plugin_data[instance]);
d->plugin_data[instance] = 0; d->plugin_data[instance] = 0;
}; };
plugin.reset = +[](const mjModel* m, double* plugin_state, void* plugin_data, plugin.reset = +[](const mjModel* m, mjtNum* plugin_state, void* plugin_data,
int instance) { int instance) {
auto sdf = reinterpret_cast<Bolt*>(plugin_data); auto sdf = reinterpret_cast<Bolt*>(plugin_data);
sdf->Reset(); sdf->Reset();
+1 -1
View File
@@ -146,7 +146,7 @@ void Bowl::RegisterPlugin() {
delete reinterpret_cast<Bowl*>(d->plugin_data[instance]); delete reinterpret_cast<Bowl*>(d->plugin_data[instance]);
d->plugin_data[instance] = 0; d->plugin_data[instance] = 0;
}; };
plugin.reset = +[](const mjModel* m, double* plugin_state, void* plugin_data, plugin.reset = +[](const mjModel* m, mjtNum* plugin_state, void* plugin_data,
int instance) { int instance) {
auto sdf = reinterpret_cast<Bowl*>(plugin_data); auto sdf = reinterpret_cast<Bowl*>(plugin_data);
sdf->Reset(); sdf->Reset();
+1 -1
View File
@@ -232,7 +232,7 @@ void Gear::RegisterPlugin() {
delete reinterpret_cast<Gear*>(d->plugin_data[instance]); delete reinterpret_cast<Gear*>(d->plugin_data[instance]);
d->plugin_data[instance] = 0; d->plugin_data[instance] = 0;
}; };
plugin.reset = +[](const mjModel* m, double* plugin_state, void* plugin_data, plugin.reset = +[](const mjModel* m, mjtNum* plugin_state, void* plugin_data,
int instance) { int instance) {
auto sdf = reinterpret_cast<Gear*>(plugin_data); auto sdf = reinterpret_cast<Gear*>(plugin_data);
sdf->Reset(); sdf->Reset();
+1 -1
View File
@@ -148,7 +148,7 @@ void Nut::RegisterPlugin() {
delete reinterpret_cast<Nut*>(d->plugin_data[instance]); delete reinterpret_cast<Nut*>(d->plugin_data[instance]);
d->plugin_data[instance] = 0; d->plugin_data[instance] = 0;
}; };
plugin.reset = +[](const mjModel* m, double* plugin_state, void* plugin_data, plugin.reset = +[](const mjModel* m, mjtNum* plugin_state, void* plugin_data,
int instance) { int instance) {
auto sdf = reinterpret_cast<Nut*>(plugin_data); auto sdf = reinterpret_cast<Nut*>(plugin_data);
sdf->Reset(); sdf->Reset();
+1 -1
View File
@@ -180,7 +180,7 @@ void SdfLib::RegisterPlugin() {
delete reinterpret_cast<SdfLib*>(d->plugin_data[instance]); delete reinterpret_cast<SdfLib*>(d->plugin_data[instance]);
d->plugin_data[instance] = 0; d->plugin_data[instance] = 0;
}; };
plugin.reset = +[](const mjModel* m, double* plugin_state, void* plugin_data, plugin.reset = +[](const mjModel* m, mjtNum* plugin_state, void* plugin_data,
int instance) { int instance) {
auto sdf = reinterpret_cast<SdfLib*>(plugin_data); auto sdf = reinterpret_cast<SdfLib*>(plugin_data);
sdf->Reset(); sdf->Reset();
+1 -1
View File
@@ -95,7 +95,7 @@ void Torus::RegisterPlugin() {
delete reinterpret_cast<Torus*>(d->plugin_data[instance]); delete reinterpret_cast<Torus*>(d->plugin_data[instance]);
d->plugin_data[instance] = 0; d->plugin_data[instance] = 0;
}; };
plugin.reset = +[](const mjModel* m, double* plugin_state, void* plugin_data, plugin.reset = +[](const mjModel* m, mjtNum* plugin_state, void* plugin_data,
int instance) { int instance) {
// do nothing // do nothing
}; };
+1 -1
View File
@@ -1,3 +1,3 @@
include LICENSE *.md include LICENSE *.md
recursive-include mujoco *.h *.cc *.mm CMakeLists.txt *.cmake recursive-include mujoco *.h *.cc *.cc.inc *.mm CMakeLists.txt *.cmake
recursive-include mujoco/mjpython mjpython.* Info.plist recursive-include mujoco/mjpython mjpython.* Info.plist
+2
View File
@@ -44,6 +44,8 @@ python "${package_dir}"/mujoco/codegen/generate_enum_traits.py > \
mujoco/enum_traits.h mujoco/enum_traits.h
python "${package_dir}"/mujoco/codegen/generate_function_traits.py > \ python "${package_dir}"/mujoco/codegen/generate_function_traits.py > \
mujoco/function_traits.h mujoco/function_traits.h
python "${package_dir}"/mujoco/codegen/generate_spec_bindings.py > \
mujoco/specs.cc.inc
export PYTHONPATH="${old_pythonpath}" export PYTHONPATH="${old_pythonpath}"
# Copy over the LICENSE file. # Copy over the LICENSE file.
+25
View File
@@ -405,6 +405,29 @@ target_link_libraries(
structs_header structs_header
) )
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/specs.cc.inc)
add_custom_command(
OUTPUT specs.cc.inc
COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${mujoco_SOURCE_DIR}/mujoco ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/codegen/generate_spec_bindings.py > specs.cc.inc
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/codegen/generate_spec_bindings.py
)
endif()
mujoco_pybind11_module(
_specs
specs.cc
specs.cc.inc
)
target_link_libraries(
_specs
PRIVATE mujoco
Eigen3::Eigen
errors_header
raw
structs_header
)
mujoco_pybind11_module(_simulate simulate.cc) mujoco_pybind11_module(_simulate simulate.cc)
target_link_libraries( target_link_libraries(
_simulate _simulate
@@ -424,6 +447,7 @@ set(LIBRARIES_FOR_WHEEL
"$<TARGET_FILE:_render>" "$<TARGET_FILE:_render>"
"$<TARGET_FILE:_rollout>" "$<TARGET_FILE:_rollout>"
"$<TARGET_FILE:_simulate>" "$<TARGET_FILE:_simulate>"
"$<TARGET_FILE:_specs>"
"$<TARGET_FILE:_structs>" "$<TARGET_FILE:_structs>"
"$<TARGET_FILE:mujoco>" "$<TARGET_FILE:mujoco>"
) )
@@ -459,6 +483,7 @@ if(MUJOCO_PYTHON_MAKE_WHEEL)
_render _render
_rollout _rollout
_simulate _simulate
_specs
_structs _structs
mujoco mujoco
) )
+1
View File
@@ -43,6 +43,7 @@ from mujoco._enums import *
from mujoco._errors import * from mujoco._errors import *
from mujoco._functions import * from mujoco._functions import *
from mujoco._render import * from mujoco._render import *
from mujoco._specs import *
from mujoco._structs import * from mujoco._structs import *
from mujoco.gl_context import * from mujoco.gl_context import *
from mujoco.renderer import Renderer from mujoco.renderer import Renderer
-16
View File
@@ -409,19 +409,6 @@ class MuJoCoBindingsTest(parameterized.TestCase):
np.testing.assert_array_equal(self.model.geom_size[1], [0.5, 0.5, 0.5]) np.testing.assert_array_equal(self.model.geom_size[1], [0.5, 0.5, 0.5])
np.testing.assert_array_equal(model_copy.geom_size[1], [0.1, 0.1, 0.1]) np.testing.assert_array_equal(model_copy.geom_size[1], [0.1, 0.1, 0.1])
def test_assets_array_filename_too_long(self):
# Longest allowed filename (excluding null byte)
limit = mujoco.mjMAXVFSNAME - 1
contents = b'<mujoco/>'
valid_filename = 'a' * limit
mujoco.MjModel.from_xml_path(valid_filename, {valid_filename: contents})
invalid_filename = 'a' * (limit + 1)
expected_message = (
f'Filename length 1000 exceeds 999 character limit: {invalid_filename}')
with self.assertRaisesWithLiteralMatch(ValueError, expected_message):
mujoco.MjModel.from_xml_path(invalid_filename,
{invalid_filename: contents})
def test_mjdata_can_copy(self): def test_mjdata_can_copy(self):
self.data.qpos = [0, 0, 0.1*np.sqrt(2) - 0.001, self.data.qpos = [0, 0, 0.1*np.sqrt(2) - 0.001,
np.cos(np.pi/8), np.sin(np.pi/8), 0, 0, 0, np.cos(np.pi/8), np.sin(np.pi/8), 0, 0, 0,
@@ -856,9 +843,6 @@ Return the current version of MuJoCo as a null-terminated string.
Euler integrator, semi-implicit in velocity. Euler integrator, semi-implicit in velocity.
""") """)
def test_int_constant(self):
self.assertEqual(mujoco.mjMAXVFSNAME, 1000)
def test_float_constant(self): def test_float_constant(self):
self.assertEqual(mujoco.mjMAXVAL, 1e10) self.assertEqual(mujoco.mjMAXVAL, 1e10)
self.assertEqual(mujoco.mjMINVAL, 1e-15) self.assertEqual(mujoco.mjMINVAL, 1e-15)
@@ -0,0 +1,221 @@
# Copyright 2024 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
#
# http://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.
# ==============================================================================
"""Generates the bindings for the MuJoCo specs."""
from collections.abc import Sequence
from absl import app
from introspect import ast_nodes
from introspect import structs
SCALAR_TYPES = {'int', 'double', 'float', 'mjtByte', 'mjtNum'}
def _value_binding_code(
field: ast_nodes.ValueType, classname: str = '', varname: str = ''
) -> str:
"""Creates a string that defines Python bindings for a value type."""
fulltype = field.name
if field.name not in SCALAR_TYPES:
fulltype += '&'
fullvarname = varname
rawclassname = classname.replace('mjs', 'raw::Mjs')
if classname == 'mjSpec': # raw mjSpec has a wrapper
rawclassname = classname.replace('mjS', 'MjS')
fullvarname = 'ptr->' + varname
if field.name.startswith('mjs'): # all other mjs are raw structs
fulltype = field.name.replace('mjs', 'raw::Mjs')
if field.name != 'mjsPlugin' and field.name != 'mjsOrientation':
fulltype = fulltype + '*' # plugin and orientation are pointers
def_property_args = (
f'"{varname}"',
f"""[]({rawclassname}& self) -> {fulltype} {{
return self.{fullvarname};
}}""",
f"""[]({rawclassname}& self, {fulltype} {varname}) {{
self.{fullvarname} = {varname};
}}""",
)
if field.name not in SCALAR_TYPES:
def_property_args += ('py::return_value_policy::reference_internal',)
return f'{classname}.def_property({",".join(def_property_args)});'
def _array_binding_code(
field: ast_nodes.ArrayType, classname: str = '', varname: str = ''
) -> str:
"""Creates a string that declares Python bindings for an array type."""
if len(field.extents) > 1:
raise NotImplementedError()
innertype = field.inner_type.decl()
rawclassname = classname.replace('mjs', 'raw::Mjs')
fullvarname = varname
if classname == 'mjSpec': # raw mjSpec has a wrapper
rawclassname = classname.replace('mjS', 'MjS')
fullvarname = 'ptr->' + varname
if innertype == 'double' or innertype == 'mjtNum':
innertype = 'MjDouble' # custom Eigen type
elif innertype == 'float':
innertype = 'MjFloat' # custom Eigen type
elif innertype == 'int':
innertype = 'MjInt' # custom Eigen type
elif innertype == 'char':
# char array special case
return f"""\
{classname}.def_property(
"{varname}",
[]({rawclassname}& self) -> py::array_t<char> {{
return py::array_t<char>({field.extents[0]}, self.{fullvarname});
}},
[]({rawclassname}& self, py::object rhs) {{
int i = 0;
for (auto val : rhs) {{
self.{fullvarname}[i++] = py::cast<char>(val);
}}
}}, py::return_value_policy::reference_internal);"""
# all other array types
return f"""\
{classname}.def_property(
"{varname}",
[]({rawclassname}& self) -> {innertype}{field.extents[0]} {{
return {innertype}{field.extents[0]}(self.{fullvarname});
}},
[]({rawclassname}& self, {innertype}Ref{field.extents[0]} {varname}) {{
{innertype}{field.extents[0]}(self.{fullvarname}) = {varname};
}}, py::return_value_policy::reference_internal);"""
def _ptr_binding_code(
field: ast_nodes.PointerType, classname: str = '', varname: str = ''
) -> str:
"""Creates a string that declares Python bindings for a pointer type."""
vartype = field.inner_type.decl()
rawclassname = classname.replace('mjs', 'raw::Mjs')
fullvarname = varname
if classname == 'mjSpec': # raw mjSpec has a wrapper
rawclassname = classname.replace('mjS', 'MjS')
fullvarname = 'ptr->' + varname
if vartype == 'mjsElement': # this is ignored by the caller
return 'mjsElement'
if vartype.startswith('mjs'): # for structs, use the value case
return _value_binding_code(field.inner_type, classname, varname)
elif vartype == 'mjString': # C++ string -> Python string
return f"""\
{classname}.def_property(
"{varname}",
[]({rawclassname}& self) -> std::string_view {{
return *self.{fullvarname};
}},
[]({rawclassname}& self, std::string_view {varname}) {{
*(self.{fullvarname}) = {varname};
}});"""
elif ( # C++ vectors of values -> Python array
vartype == 'mjDoubleVec'
or vartype == 'mjFloatVec'
or vartype == 'mjIntVec'
):
vartype = vartype.replace('mj', '').replace('Vec', '').lower()
return f"""\
{classname}.def_property(
"{varname}",
[]({rawclassname}& self) -> py::array_t<{vartype}> {{
return py::array_t<{vartype}>(self.{fullvarname}->size(),
self.{fullvarname}->data());
}},
[]({rawclassname}& self, py::object rhs) {{
self.{fullvarname}->clear();
self.{fullvarname}->reserve(py::len(rhs));
for (auto val : rhs) {{
self.{fullvarname}->push_back(py::cast<{vartype}>(val));
}}
}}, py::return_value_policy::reference_internal);"""
elif vartype == 'mjStringVec': # C++ vector of strings -> Python list
return f"""\
{classname}.def_property(
"{varname}",
[]({rawclassname}& self) -> py::list {{
py::list list;
for (auto val : *self.{fullvarname}) {{
list.append(val);
}}
return list;
}},
[]({rawclassname}& self, py::object rhs) {{
self.{fullvarname}->clear();
self.{fullvarname}->reserve(py::len(rhs));
for (auto val : rhs) {{
self.{fullvarname}->push_back(py::cast<std::string>(val));
}}
}}, py::return_value_policy::reference_internal);"""
elif 'VecVec' in vartype: # C++ vector of vectors -> Python list of lists
vartype = vartype.replace('mj', '').replace('VecVec', '').lower()
return f"""\
{classname}.def_property(
"{varname}",
[]({rawclassname}& self) -> py::list {{
py::list list;
for (auto inner_vec : *self.{fullvarname}) {{
py::list inner_list;
for (auto val : inner_vec) {{
inner_list.append(val);
}}
list.append(inner_list);
}}
return list;
}},
[]({rawclassname}& self, py::object rhs) {{
self.{fullvarname}->clear();
self.{fullvarname}->reserve(py::len(rhs));
for (auto inner_list : rhs) {{
auto inner_vec = py::cast<std::vector<{vartype}>>(inner_list);
self.{fullvarname}->push_back(inner_vec);
}}
}}, py::return_value_policy::reference_internal);"""
raise NotImplementedError()
def _binding_code(field: ast_nodes.StructFieldDecl, key: str) -> str:
if isinstance(field.type, ast_nodes.ValueType):
return _value_binding_code(field.type, key, field.name)
elif isinstance(field.type, ast_nodes.PointerType):
return _ptr_binding_code(field.type, key, field.name)
elif isinstance(field.type, ast_nodes.ArrayType):
return _array_binding_code(field.type, key, field.name)
return ''
def generate() -> None:
for key in structs.STRUCTS.keys():
if (key.startswith('mjs') or key == 'mjSpec') and key != 'mjsElement':
print('\n // ' + key)
for field in structs.STRUCTS[key].fields:
code = _binding_code(field, key)
if code != 'mjsElement':
print(code)
def main(argv: Sequence[str]) -> None:
if len(argv) > 1:
raise app.UsageError('Too many command-line arguments.')
generate()
if __name__ == '__main__':
app.run(main)
-2
View File
@@ -57,8 +57,6 @@ PYBIND11_MODULE(_constants, pymodule) {
X(mjMINIMP); X(mjMINIMP);
X(mjMAXIMP); X(mjMAXIMP);
X(mjMAXCONPAIR); X(mjMAXCONPAIR);
X(mjMAXVFS);
X(mjMAXVFSNAME);
X(mjNEQDATA); X(mjNEQDATA);
X(mjNDYN); X(mjNDYN);
X(mjNGAIN); X(mjNGAIN);
+8 -8
View File
@@ -17,7 +17,6 @@
#include <array> #include <array>
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include <sstream>
#include <string> #include <string>
#include <optional> #include <optional>
@@ -29,6 +28,7 @@
#include "functions.h" #include "functions.h"
#include "private.h" #include "private.h"
#include "raw.h" #include "raw.h"
#include "structs.h"
#include <pybind11/eigen.h> #include <pybind11/eigen.h>
#include <pybind11/pybind11.h> #include <pybind11/pybind11.h>
#include <pybind11/stl.h> #include <pybind11/stl.h>
@@ -108,9 +108,10 @@ PYBIND11_MODULE(_functions, pymodule) {
// Skipped: mj_copyModel (have MjModel.__copy__, memory managed by MjModel) // Skipped: mj_copyModel (have MjModel.__copy__, memory managed by MjModel)
pymodule.def( pymodule.def(
"mj_saveModel", "mj_saveModel",
[](const MjModelWrapper& m, const std::optional<std::string>& filename = std::nullopt, [](const MjModelWrapper& m,
std::optional< const std::optional<std::string>& filename = std::nullopt,
Eigen::Ref<Eigen::Vector<std::uint8_t, Eigen::Dynamic>>> buffer = std::nullopt) { std::optional<Eigen::Ref<Eigen::Vector<std::uint8_t, Eigen::Dynamic>>>
buffer = std::nullopt) {
void* buffer_ptr = nullptr; void* buffer_ptr = nullptr;
int buffer_sz = 0; int buffer_sz = 0;
if (buffer.has_value()) { if (buffer.has_value()) {
@@ -122,8 +123,7 @@ PYBIND11_MODULE(_functions, pymodule) {
buffer_ptr, buffer_sz); buffer_ptr, buffer_sz);
}, },
py::arg("m"), py::arg_v("filename", std::nullopt), py::arg("m"), py::arg_v("filename", std::nullopt),
py::arg_v("buffer", std::nullopt), py::arg_v("buffer", std::nullopt), py::doc(traits::mj_saveModel::doc),
py::doc(traits::mj_saveModel::doc),
py::call_guard<py::gil_scoped_release>()); py::call_guard<py::gil_scoped_release>());
// Skipped: mj_loadModel (have MjModel.from_binary_path) // Skipped: mj_loadModel (have MjModel.from_binary_path)
// Skipped: mj_deleteModel (have MjModel.__del__) // Skipped: mj_deleteModel (have MjModel.__del__)
@@ -700,8 +700,8 @@ PYBIND11_MODULE(_functions, pymodule) {
Def<traits::mju_dist3>(pymodule); Def<traits::mju_dist3>(pymodule);
Def<traits::mju_mulMatVec3>(pymodule); Def<traits::mju_mulMatVec3>(pymodule);
Def<traits::mju_mulMatTVec3>(pymodule); Def<traits::mju_mulMatTVec3>(pymodule);
Def<traits::mju_rotVecMat>(pymodule); // skipped: mju_rotVecMat
Def<traits::mju_rotVecMatT>(pymodule); // skipped: mju_rotVecMatT
Def<traits::mju_cross>(pymodule); Def<traits::mju_cross>(pymodule);
Def<traits::mju_zero4>(pymodule); Def<traits::mju_zero4>(pymodule);
Def<traits::mju_unit4>(pymodule); Def<traits::mju_unit4>(pymodule);
+1 -1
View File
@@ -168,7 +168,7 @@
X( float, light_, specular, nlight, 3 ) X( float, light_, specular, nlight, 3 )
#define MJMODEL_MATERIAL \ #define MJMODEL_MATERIAL \
X( int, mat_, texid, nmat, 1 ) \ X( int, mat_, texid, nmat, mjNTEXMAT ) \
X( mjtByte, mat_, texuniform, nmat, 1 ) \ X( mjtByte, mat_, texuniform, nmat, 1 ) \
X( float, mat_, texrepeat, nmat, 2 ) \ X( float, mat_, texrepeat, nmat, 2 ) \
X( float, mat_, emission, nmat, 1 ) \ X( float, mat_, emission, nmat, 1 ) \
+69
View File
@@ -0,0 +1,69 @@
# Copyright 2024 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
#
# http://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.
# ==============================================================================
"""Test that copying mujoco.MjData multiple times doesn't leak memory."""
import copy
import textwrap
from absl.testing import absltest
import mujoco
class MemoryLeakTest(absltest.TestCase):
# Regression test for https://github.com/google-deepmind/mujoco/issues/1572
def test_deepcopy_mjdata_leak(self):
# MuJoCo model with textures that take up significant memory.
model_xml = textwrap.dedent("""
<mujoco>
<asset>
<material name="body"/>
<texture name="grid" type="2d" builtin="checker"
width="1024" height="1024" rgb1="0 0 0" rgb2="1 1 1"/>
<material name="grid" texture="grid" texrepeat="1 1"
texuniform="true" reflectance=".2"/>
</asset>
<worldbody>
<geom size="0 0 .05" type="plane" material="grid"/>
</worldbody>
</mujoco>
""")
limit = self._memory_limit(4 * 2**30)
try:
model = mujoco.MjModel.from_xml_string(model_xml)
data = mujoco.MjData(model)
total = 0
for _ in range(1000):
mujoco.mj_step(model, data)
last_data = copy.deepcopy(data)
total += last_data.time
finally:
self._memory_limit(limit)
def _memory_limit(self, limit_in_bytes: int) -> int:
"""Limits max memory usage, and returns previous limit."""
soft = -1
try:
import resource # pylint: disable=g-import-not-at-top
soft, hard = resource.getrlimit(resource.RLIMIT_AS)
resource.setrlimit(resource.RLIMIT_AS, (limit_in_bytes, hard))
except (ImportError, ValueError):
# On Windows or systems where setting resource limits fails, do nothing.
pass
return soft
if __name__ == '__main__':
absltest.main()
+30
View File
@@ -18,6 +18,7 @@
#include <mujoco/mjdata.h> #include <mujoco/mjdata.h>
#include <mujoco/mjmodel.h> #include <mujoco/mjmodel.h>
#include <mujoco/mjrender.h> #include <mujoco/mjrender.h>
#include <mujoco/mjspec.h>
#include <mujoco/mjvisualize.h> #include <mujoco/mjvisualize.h>
// Type aliases for MuJoCo C structs to allow us refer to consistently refer // Type aliases for MuJoCo C structs to allow us refer to consistently refer
@@ -28,6 +29,35 @@ using MjContact = ::mjContact;
using MjData = ::mjData; using MjData = ::mjData;
using MjLROpt = ::mjLROpt; using MjLROpt = ::mjLROpt;
using MjModel = ::mjModel; using MjModel = ::mjModel;
using MjSpec = ::mjSpec;
using MjsElement = ::mjsElement;
using MjsOrientation = ::mjsOrientation;
using MjsPlugin = ::mjsPlugin;
using MjsBody = ::mjsBody;
using MjsFrame = ::mjsFrame;
using MjsJoint = ::mjsJoint;
using MjsGeom = ::mjsGeom;
using MjsSite = ::mjsSite;
using MjsCamera = ::mjsCamera;
using MjsLight = ::mjsLight;
using MjsFlex = ::mjsFlex;
using MjsMesh = ::mjsMesh;
using MjsHField = ::mjsHField;
using MjsSkin = ::mjsSkin;
using MjsTexture = ::mjsTexture;
using MjsMaterial = ::mjsMaterial;
using MjsPair = ::mjsPair;
using MjsExclude = ::mjsExclude;
using MjsEquality = ::mjsEquality;
using MjsTendon = ::mjsTendon;
using MjsWrap = ::mjsWrap;
using MjsActuator = ::mjsActuator;
using MjsSensor = ::mjsSensor;
using MjsNumeric = ::mjsNumeric;
using MjsText = ::mjsText;
using MjsTuple = ::mjsTuple;
using MjsKey = ::mjsKey;
using MjsDefault = ::mjsDefault;
using MjOption = ::mjOption; using MjOption = ::mjOption;
using MjSolverStat = ::mjSolverStat; using MjSolverStat = ::mjSolverStat;
using MjStatistic = ::mjStatistic; using MjStatistic = ::mjStatistic;
+12
View File
@@ -54,6 +54,9 @@ class MjWrapper<raw::MjrContext> : public WrapperBase<raw::MjrContext> {
X(auxFBO_r); X(auxFBO_r);
X(auxColor); X(auxColor);
X(auxColor_r); X(auxColor_r);
X(mat_texid);
X(mat_texuniform);
X(mat_texrepeat);
X(textureType); X(textureType);
X(texture); X(texture);
X(skinvertVBO); X(skinvertVBO);
@@ -95,6 +98,9 @@ MjrContextWrapper::MjWrapper()
X(auxFBO_r), X(auxFBO_r),
X(auxColor), X(auxColor),
X(auxColor_r), X(auxColor_r),
X(mat_texid),
X(mat_texuniform),
X(mat_texrepeat),
X(textureType), X(textureType),
X(texture), X(texture),
X_SKIN(skinvertVBO), X_SKIN(skinvertVBO),
@@ -119,6 +125,9 @@ MjrContextWrapper::MjWrapper(const MjModelWrapper& model, int fontscale)
X(auxFBO_r), X(auxFBO_r),
X(auxColor), X(auxColor),
X(auxColor_r), X(auxColor_r),
X(mat_texid),
X(mat_texuniform),
X(mat_texrepeat),
X(textureType), X(textureType),
X(texture), X(texture),
X_SKIN(skinvertVBO), X_SKIN(skinvertVBO),
@@ -238,6 +247,9 @@ PYBIND11_MODULE(_render, pymodule) {
X(auxFBO_r); X(auxFBO_r);
X(auxColor); X(auxColor);
X(auxColor_r); X(auxColor_r);
X(mat_texid);
X(mat_texuniform);
X(mat_texrepeat);
X(textureType); X(textureType);
X(texture); X(texture);
X(skinvertVBO); X(skinvertVBO);
+5
View File
@@ -123,6 +123,9 @@ class SimulateWrapper {
mujoco::Simulate* simulate() { return simulate_; } mujoco::Simulate* simulate() { return simulate_; }
py::object GetModel() const { return m_; }
py::object GetData() const { return d_; }
private: private:
mujoco::Simulate* simulate_; mujoco::Simulate* simulate_;
std::atomic_int destroyed_ = 0; std::atomic_int destroyed_ = 0;
@@ -222,6 +225,8 @@ PYBIND11_MODULE(_simulate, pymodule) {
.def("lock", GetIfNotNull(&mujoco::Simulate::mtx), .def("lock", GetIfNotNull(&mujoco::Simulate::mtx),
py::call_guard<py::gil_scoped_release>(), py::call_guard<py::gil_scoped_release>(),
py::return_value_policy::reference_internal) py::return_value_policy::reference_internal)
.def_property_readonly("m", &SimulateWrapper::GetModel)
.def_property_readonly("d", &SimulateWrapper::GetData)
.def_property_readonly("ctrl_noise_std", .def_property_readonly("ctrl_noise_std",
GetIfNotNull(&mujoco::Simulate::ctrl_noise_std), GetIfNotNull(&mujoco::Simulate::ctrl_noise_std),
py::call_guard<py::gil_scoped_release>()) py::call_guard<py::gil_scoped_release>())
+954
View File
@@ -0,0 +1,954 @@
// Copyright 2024 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
//
// http://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.
#include <array>
#include <cstddef> // IWYU pragma: keep
#include <cstdint>
#include <memory>
#include <string>
#include <string_view> // IWYU pragma: keep
#include <vector> // IWYU pragma: keep
#include <Eigen/Core>
#include <Eigen/Eigen>
#include <mujoco/mjspec.h> // IWYU pragma: keep
#include <mujoco/mujoco.h>
#include "errors.h"
#include "indexers.h" // IWYU pragma: keep
#include "raw.h"
#include "structs.h" // IWYU pragma: keep
#include <pybind11/cast.h>
#include <pybind11/eigen.h>
#include <pybind11/eigen/matrix.h>
#include <pybind11/pybind11.h>
#include <pybind11/pytypes.h>
#include <pybind11/stl.h>
namespace py = ::pybind11;
namespace mujoco::python {
using MjInt2 = Eigen::Map<Eigen::Vector2i>;
using MjInt3 = Eigen::Map<Eigen::Vector3i>;
using MjFloat2 = Eigen::Map<Eigen::Vector2f>;
using MjFloat3 = Eigen::Map<Eigen::Vector3f>;
using MjFloat4 = Eigen::Map<Eigen::Vector4f>;
using MjDouble2 = Eigen::Map<Eigen::Vector2d>;
using MjDouble3 = Eigen::Map<Eigen::Vector3d>;
using MjDouble4 = Eigen::Map<Eigen::Vector4d>;
using MjDouble5 = Eigen::Map<Eigen::Matrix<double, 5, 1>>;
using MjDouble6 = Eigen::Map<Eigen::Matrix<double, 6, 1>>;
using MjDouble10 = Eigen::Map<Eigen::Matrix<double, 10, 1>>;
using MjDouble11 = Eigen::Map<Eigen::Matrix<double, 11, 1>>;
using MjDoubleVec = Eigen::Map<Eigen::VectorXd>;
using MjIntRef2 = Eigen::Ref<const Eigen::Vector2i>;
using MjIntRef3 = Eigen::Ref<const Eigen::Vector3i>;
using MjFloatRef2 = Eigen::Ref<const Eigen::Vector2f>;
using MjFloatRef3 = Eigen::Ref<const Eigen::Vector3f>;
using MjFloatRef4 = Eigen::Ref<const Eigen::Vector4f>;
using MjDoubleRef2 = Eigen::Ref<const Eigen::Vector2d>;
using MjDoubleRef3 = Eigen::Ref<const Eigen::Vector3d>;
using MjDoubleRef4 = Eigen::Ref<const Eigen::Vector4d>;
using MjDoubleRef5 = Eigen::Ref<const Eigen::Matrix<double, 5, 1>>;
using MjDoubleRef6 = Eigen::Ref<const Eigen::Matrix<double, 6, 1>>;
using MjDoubleRef10 = Eigen::Ref<const Eigen::Matrix<double, 10, 1>>;
using MjDoubleRef11 = Eigen::Ref<const Eigen::Matrix<double, 11, 1>>;
using MjDoubleRefVec = Eigen::Ref<const Eigen::VectorXd>;
struct MjSpec {
MjSpec() : ptr(mj_makeSpec()) {}
~MjSpec() { mj_deleteSpec(ptr); }
raw::MjSpec* ptr;
};
PYBIND11_MODULE(_specs, m) {
auto structs_m = py::module::import("mujoco._structs");
py::function mjmodel_from_spec_ptr =
structs_m.attr("MjModel").attr("_from_spec_ptr");
py::function mjmodel_mjdata_from_spec_ptr =
structs_m.attr("_recompile_spec_addr");
py::class_<MjSpec> mjSpec(m, "MjSpec");
py::class_<raw::MjsElement> mjsElement(m, "MjsElement");
py::class_<raw::MjsDefault> mjsDefault(m, "MjsDefault");
py::class_<raw::MjsBody> mjsBody(m, "MjsBody");
py::class_<raw::MjsFrame> mjsFrame(m, "MjsFrame");
py::class_<raw::MjsGeom> mjsGeom(m, "MjsGeom");
py::class_<raw::MjsJoint> mjsJoint(m, "MjsJoint");
py::class_<raw::MjsLight> mjsLight(m, "MjsLight");
py::class_<raw::MjsMaterial> mjsMaterial(m, "MjsMaterial");
py::class_<raw::MjsSite> mjsSite(m, "MjsSite");
py::class_<raw::MjsMesh> mjsMesh(m, "MjsMesh");
py::class_<raw::MjsSkin> mjsSkin(m, "MjsSkin");
py::class_<raw::MjsTexture> mjsTexture(m, "MjsTexture");
py::class_<raw::MjsText> mjsText(m, "MjsText");
py::class_<raw::MjsTuple> mjsTuple(m, "MjsTuple");
py::class_<raw::MjsCamera> mjsCamera(m, "MjsCamera");
py::class_<raw::MjsFlex> mjsFlex(m, "MjsFlex");
py::class_<raw::MjsHField> mjsHField(m, "MjsHField");
py::class_<raw::MjsKey> mjsKey(m, "MjsKey");
py::class_<raw::MjsNumeric> mjsNumeric(m, "MjsNumeric");
py::class_<raw::MjsPair> mjsPair(m, "MjsPair");
py::class_<raw::MjsExclude> mjsExclude(m, "MjsExclude");
py::class_<raw::MjsEquality> mjsEquality(m, "MjsEquality");
py::class_<raw::MjsTendon> mjsTendon(m, "MjsTendon");
py::class_<raw::MjsSensor> mjsSensor(m, "MjsSensor");
py::class_<raw::MjsActuator> mjsActuator(m, "MjsActuator");
py::class_<raw::MjsPlugin> mjsPlugin(m, "MjsPlugin");
py::class_<raw::MjsOrientation> mjsOrientation(m, "MjsOrientation");
py::class_<raw::MjsWrap> mjsWrap(m, "MjsWrap");
// ============================= MJSPEC =====================================
mjSpec.def(py::init<>());
mjSpec.def("recompile", [mjmodel_mjdata_from_spec_ptr](
const MjSpec& self, py::object m, py::object d) {
return mjmodel_mjdata_from_spec_ptr(reinterpret_cast<uintptr_t>(self.ptr),
m, d);
});
mjSpec.def(
"copy",
[](const MjSpec& self) -> raw::MjSpec* { return mj_copySpec(self.ptr); },
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"worldbody",
[](MjSpec& self) -> raw::MjsBody* {
return mjs_findBody(self.ptr, "world");
},
py::return_value_policy::reference_internal);
mjSpec.def(
"find_body",
[](MjSpec& self, std::string& name) -> raw::MjsBody* {
return mjs_findBody(self.ptr, name.c_str());
},
py::return_value_policy::reference_internal);
mjSpec.def(
"find_mesh",
[](MjSpec& self, std::string& name) -> raw::MjsMesh* {
return mjs_findMesh(self.ptr, name.c_str());
},
py::return_value_policy::reference_internal);
mjSpec.def(
"find_frame",
[](MjSpec& self, std::string& name) -> raw::MjsFrame* {
return mjs_findFrame(self.ptr, name.c_str());
},
py::return_value_policy::reference_internal);
mjSpec.def(
"find_keyframe",
[](MjSpec& self, std::string& name) -> raw::MjsKey* {
return mjs_findKeyframe(self.ptr, name.c_str());
},
py::return_value_policy::reference_internal);
mjSpec.def(
"find_default",
[](MjSpec& self, std::string& classname) -> raw::MjsDefault* {
return mjs_findDefault(self.ptr, classname.c_str());
},
py::return_value_policy::reference_internal);
mjSpec.def("compile", [mjmodel_from_spec_ptr](MjSpec& self) {
return mjmodel_from_spec_ptr(reinterpret_cast<uintptr_t>(self.ptr));
});
mjSpec.def(
"copy_back",
[](MjSpec& self, raw::MjModel& model) {
return mj_copyBack(self.ptr, &model);
},
py::return_value_policy::reference_internal);
mjSpec.def("to_xml", [](MjSpec& self) -> std::string {
int size = mj_saveXMLString(self.ptr, nullptr, 0, nullptr, 0);
std::unique_ptr<char[]> buf(new char[size + 1]);
std::array<char, 1024> err;
buf[0] = '\0';
err[0] = '\0';
mj_saveXMLString(self.ptr, buf.get(), size + 1, err.data(), err.size());
if (err[0] != '\0') {
throw FatalError(std::string(err.data()));
}
return std::string(buf.get());
});
mjSpec.def("from_file", [](MjSpec& self, std::string& filename) -> void {
std::array<char, 1024> err;
err[0] = '\0';
mj_deleteSpec(self.ptr);
self.ptr = mj_parseXML(filename.c_str(), 0, err.data(), err.size());
if (!self.ptr) {
throw FatalError(std::string(err.data()));
}
});
mjSpec.def("from_string", [](MjSpec& self, std::string& xml) -> void {
std::array<char, 1024> err;
err[0] = '\0';
mj_deleteSpec(self.ptr);
self.ptr = mj_parseXMLString(xml.c_str(), 0, err.data(), err.size());
if (!self.ptr) {
throw FatalError(std::string(err.data()));
}
});
mjSpec.def(
"add_default",
[](MjSpec* spec, std::string& classname,
raw::MjsDefault* parent) -> raw::MjsDefault* {
return mjs_addDefault(spec->ptr, classname.c_str(), parent);
},
py::return_value_policy::reference_internal);
mjSpec.def(
"default",
[](MjSpec& self) -> raw::MjsDefault* {
return mjs_getSpecDefault(self.ptr);
},
py::return_value_policy::reference_internal);
mjSpec.def(
"add_material",
[](MjSpec& self, raw::MjsDefault* default_) -> raw::MjsMaterial* {
return mjs_addMaterial(self.ptr, default_);
},
py::arg_v("default", nullptr),
py::return_value_policy::reference_internal);
mjSpec.def(
"add_mesh",
[](MjSpec& self, raw::MjsDefault* default_) -> raw::MjsMesh* {
return mjs_addMesh(self.ptr, default_);
},
py::arg_v("default", nullptr),
py::return_value_policy::reference_internal);
mjSpec.def(
"add_skin",
[](MjSpec& self) -> raw::MjsSkin* { return mjs_addSkin(self.ptr); },
py::return_value_policy::reference_internal);
mjSpec.def(
"add_texture",
[](MjSpec& self) -> raw::MjsTexture* { return mjs_addTexture(self.ptr); },
py::return_value_policy::reference_internal);
mjSpec.def(
"add_text",
[](MjSpec& self) -> raw::MjsText* { return mjs_addText(self.ptr); },
py::return_value_policy::reference_internal);
mjSpec.def(
"add_tuple",
[](MjSpec& self) -> raw::MjsTuple* { return mjs_addTuple(self.ptr); },
py::return_value_policy::reference_internal);
mjSpec.def(
"add_flex",
[](MjSpec& self) -> raw::MjsFlex* { return mjs_addFlex(self.ptr); },
py::return_value_policy::reference_internal);
mjSpec.def(
"add_hfield",
[](MjSpec& self) -> raw::MjsHField* { return mjs_addHField(self.ptr); },
py::return_value_policy::reference_internal);
mjSpec.def(
"add_key",
[](MjSpec& self) -> raw::MjsKey* { return mjs_addKey(self.ptr); },
py::return_value_policy::reference_internal);
mjSpec.def(
"add_numeric",
[](MjSpec& self) -> raw::MjsNumeric* { return mjs_addNumeric(self.ptr); },
py::return_value_policy::reference_internal);
mjSpec.def(
"add_pair",
[](MjSpec& self, raw::MjsDefault* default_) -> raw::MjsPair* {
return mjs_addPair(self.ptr, default_);
},
py::arg_v("default", nullptr),
py::return_value_policy::reference_internal);
mjSpec.def(
"add_exclude",
[](MjSpec& self) -> raw::MjsExclude* { return mjs_addExclude(self.ptr); },
py::return_value_policy::reference_internal);
mjSpec.def(
"add_equality",
[](MjSpec& self, raw::MjsDefault* default_) -> raw::MjsEquality* {
return mjs_addEquality(self.ptr, default_);
},
py::arg_v("default", nullptr),
py::return_value_policy::reference_internal);
mjSpec.def(
"add_tendon",
[](MjSpec& self, raw::MjsDefault* default_) -> raw::MjsTendon* {
return mjs_addTendon(self.ptr, default_);
},
py::arg_v("default", nullptr),
py::return_value_policy::reference_internal);
mjSpec.def(
"add_sensor",
[](MjSpec& self) -> raw::MjsSensor* { return mjs_addSensor(self.ptr); },
py::return_value_policy::reference_internal);
mjSpec.def(
"add_actuator",
[](MjSpec& self, raw::MjsDefault* default_) -> raw::MjsActuator* {
return mjs_addActuator(self.ptr, default_);
},
py::arg_v("default", nullptr),
py::return_value_policy::reference_internal);
mjSpec.def(
"add_plugin",
[](MjSpec& self) -> raw::MjsPlugin* { return mjs_addPlugin(self.ptr); },
py::return_value_policy::reference_internal);
mjSpec.def("detach_body", [](MjSpec& self, raw::MjsBody& body) {
mjs_detachBody(self.ptr, &body);
});
mjSpec.def_property_readonly(
"actuators",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_ACTUATOR);
while (el) {
list.append(mjs_asActuator(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"sensors",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_SENSOR);
while (el) {
list.append(mjs_asSensor(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"flexes",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_FLEX);
while (el) {
list.append(mjs_asFlex(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"pairs",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_PAIR);
while (el) {
list.append(mjs_asPair(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"equality",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_EQUALITY);
while (el) {
list.append(mjs_asEquality(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"excludes",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_EXCLUDE);
while (el) {
list.append(mjs_asExclude(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"tendons",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_TENDON);
while (el) {
list.append(mjs_asTendon(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"numeric",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_NUMERIC);
while (el) {
list.append(mjs_asNumeric(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"text",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_TEXT);
while (el) {
list.append(mjs_asText(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"tuple",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_TUPLE);
while (el) {
list.append(mjs_asTuple(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"key",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_KEY);
while (el) {
list.append(mjs_asKey(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"mesh",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_MESH);
while (el) {
list.append(mjs_asMesh(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"hfield",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_HFIELD);
while (el) {
list.append(mjs_asHField(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"skin",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_SKIN);
while (el) {
list.append(mjs_asSkin(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"texture",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_TEXTURE);
while (el) {
list.append(mjs_asTexture(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
mjSpec.def_property_readonly(
"material",
[](MjSpec& self) -> py::list {
py::list list;
raw::MjsElement* el = mjs_firstElement(self.ptr, mjOBJ_MATERIAL);
while (el) {
list.append(mjs_asMaterial(el));
el = mjs_nextElement(self.ptr, el);
}
return list;
},
py::return_value_policy::reference_internal);
// ============================= MJSBODY =====================================
mjsBody.def_property_readonly(
"id", [](raw::MjsBody& self) -> int { return mjs_getId(self.element); });
mjsBody.def("delete", [](raw::MjsBody& self) { mjs_delete(self.element); });
mjsBody.def(
"add_body",
[](raw::MjsBody& self, raw::MjsDefault* default_) -> raw::MjsBody* {
return mjs_addBody(&self, default_);
},
py::arg_v("default", nullptr),
py::return_value_policy::reference_internal);
mjsBody.def(
"add_frame",
[](raw::MjsBody& self, raw::MjsFrame* parentframe_) -> raw::MjsFrame* {
return mjs_addFrame(&self, parentframe_);
},
py::arg_v("default", nullptr),
py::return_value_policy::reference_internal);
mjsBody.def(
"add_geom",
[](raw::MjsBody& self, raw::MjsDefault* default_) -> raw::MjsGeom* {
return mjs_addGeom(&self, default_);
},
py::arg_v("default", nullptr),
py::return_value_policy::reference_internal);
mjsBody.def(
"add_joint",
[](raw::MjsBody& self, raw::MjsDefault* default_) -> raw::MjsJoint* {
return mjs_addJoint(&self, default_);
},
py::arg_v("default", nullptr),
py::return_value_policy::reference_internal);
mjsBody.def(
"add_freejoint",
[](raw::MjsBody& self) -> raw::MjsJoint* {
return mjs_addFreeJoint(&self);
},
py::return_value_policy::reference_internal);
mjsBody.def(
"add_light",
[](raw::MjsBody& self, raw::MjsDefault* default_) -> raw::MjsLight* {
return mjs_addLight(&self, default_);
},
py::arg_v("default", nullptr),
py::return_value_policy::reference_internal);
mjsBody.def(
"add_site",
[](raw::MjsBody& self, raw::MjsDefault* default_) -> raw::MjsSite* {
return mjs_addSite(&self, default_);
},
py::arg_v("default", nullptr),
py::return_value_policy::reference_internal);
mjsBody.def(
"add_camera",
[](raw::MjsBody& self, raw::MjsDefault* default_) -> raw::MjsCamera* {
return mjs_addCamera(&self, default_);
},
py::arg_v("default", nullptr),
py::return_value_policy::reference_internal);
mjsBody.def("set_frame",
[](raw::MjsBody& self, raw::MjsFrame& frame) -> void {
mjs_setFrame(self.element, &frame);
});
mjsBody.def("set_default",
[](raw::MjsBody& self, raw::MjsDefault& default_) -> void {
mjs_setDefault(self.element, &default_);
});
mjsBody.def(
"default",
[](raw::MjsBody& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element);
},
py::return_value_policy::reference_internal);
mjsBody.def(
"find_child",
[](raw::MjsBody& self, std::string& name) -> raw::MjsBody* {
return mjs_findChild(&self, name.c_str());
},
py::return_value_policy::reference_internal);
mjsBody.def(
"first_body",
[](raw::MjsBody& self) -> raw::MjsBody* {
return mjs_asBody(mjs_firstChild(&self, mjOBJ_BODY));
},
py::return_value_policy::reference_internal);
mjsBody.def(
"next_body",
[](raw::MjsBody& self, raw::MjsBody& child) -> raw::MjsBody* {
return mjs_asBody(mjs_nextChild(&self, child.element));
},
py::return_value_policy::reference_internal);
mjsBody.def(
"first_camera",
[](raw::MjsBody& self) -> raw::MjsCamera* {
return mjs_asCamera(mjs_firstChild(&self, mjOBJ_CAMERA));
},
py::return_value_policy::reference_internal);
mjsBody.def(
"next_camera",
[](raw::MjsBody& self, raw::MjsCamera& child) -> raw::MjsCamera* {
return mjs_asCamera(mjs_nextChild(&self, child.element));
},
py::return_value_policy::reference_internal);
mjsBody.def(
"first_light",
[](raw::MjsBody& self) -> raw::MjsLight* {
return mjs_asLight(mjs_firstChild(&self, mjOBJ_LIGHT));
},
py::return_value_policy::reference_internal);
mjsBody.def(
"next_light",
[](raw::MjsBody& self, raw::MjsLight& child) -> raw::MjsLight* {
return mjs_asLight(mjs_nextChild(&self, child.element));
},
py::return_value_policy::reference_internal);
mjsBody.def(
"first_joint",
[](raw::MjsBody& self) -> raw::MjsJoint* {
return mjs_asJoint(mjs_firstChild(&self, mjOBJ_JOINT));
},
py::return_value_policy::reference_internal);
mjsBody.def(
"next_joint",
[](raw::MjsBody& self, raw::MjsJoint& child) -> raw::MjsJoint* {
return mjs_asJoint(mjs_nextChild(&self, child.element));
},
py::return_value_policy::reference_internal);
mjsBody.def(
"first_geom",
[](raw::MjsBody& self) -> raw::MjsGeom* {
return mjs_asGeom(mjs_firstChild(&self, mjOBJ_GEOM));
},
py::return_value_policy::reference_internal);
mjsBody.def(
"next_geom",
[](raw::MjsBody& self, raw::MjsGeom& child) -> raw::MjsGeom* {
return mjs_asGeom(mjs_nextChild(&self, child.element));
},
py::return_value_policy::reference_internal);
mjsBody.def(
"first_site",
[](raw::MjsBody& self) -> raw::MjsSite* {
return mjs_asSite(mjs_firstChild(&self, mjOBJ_SITE));
},
py::return_value_policy::reference_internal);
mjsBody.def(
"next_site",
[](raw::MjsBody& self, raw::MjsSite& child) -> raw::MjsSite* {
return mjs_asSite(mjs_nextChild(&self, child.element));
},
py::return_value_policy::reference_internal);
mjsBody.def(
"first_frame",
[](raw::MjsBody& self) -> raw::MjsFrame* {
return mjs_asFrame(mjs_firstChild(&self, mjOBJ_FRAME));
},
py::return_value_policy::reference_internal);
mjsBody.def(
"next_frame",
[](raw::MjsBody& self, raw::MjsFrame& child) -> raw::MjsFrame* {
return mjs_asFrame(mjs_nextChild(&self, child.element));
},
py::return_value_policy::reference_internal);
mjsBody.def(
"spec",
[](raw::MjsBody& self) -> raw::MjSpec* { return mjs_getSpec(&self); },
py::return_value_policy::reference_internal);
mjsBody.def("attach_frame",
[](raw::MjsBody& self, raw::MjsFrame& frame, std::string& prefix,
std::string& suffix) -> void {
mjs_attachFrame(&self, &frame, prefix.c_str(), suffix.c_str());
});
// ============================= MJSFRAME ====================================
mjsFrame.def_property_readonly(
"id", [](raw::MjsFrame& self) -> int { return mjs_getId(self.element); });
mjsFrame.def("delete", [](raw::MjsFrame& self) { mjs_delete(self.element); });
mjsFrame.def("set_frame", [](raw::MjsFrame& self, raw::MjsFrame& frame) {
mjs_setFrame(self.element, &frame);
});
mjsFrame.def("attach_body", [](raw::MjsFrame& self, raw::MjsBody& body,
std::string& prefix, std::string& suffix) {
mjs_attachBody(&self, &body, prefix.c_str(), suffix.c_str());
});
// ============================= MJSGEOM =====================================
mjsGeom.def_property_readonly(
"id", [](raw::MjsGeom& self) -> int { return mjs_getId(self.element); });
mjsGeom.def("delete", [](raw::MjsGeom& self) { mjs_delete(self.element); });
mjsGeom.def("set_frame", [](raw::MjsGeom& self, raw::MjsFrame& frame) {
mjs_setFrame(self.element, &frame);
});
mjsGeom.def("set_default", [](raw::MjsGeom& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsGeom.def(
"default",
[](raw::MjsGeom& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element);
},
py::return_value_policy::reference_internal);
// ============================= MJSJOINT ====================================
mjsJoint.def_property_readonly(
"id", [](raw::MjsJoint& self) -> int { return mjs_getId(self.element); });
mjsJoint.def("delete", [](raw::MjsJoint& self) { mjs_delete(self.element); });
mjsJoint.def("set_frame", [](raw::MjsJoint& self, raw::MjsFrame& frame) {
mjs_setFrame(self.element, &frame);
});
mjsJoint.def("set_default", [](raw::MjsJoint& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsJoint.def(
"default",
[](raw::MjsJoint& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element);
},
py::return_value_policy::reference_internal);
// ============================= MJSSITE =====================================
mjsSite.def_property_readonly(
"id", [](raw::MjsSite& self) -> int { return mjs_getId(self.element); });
mjsSite.def("delete", [](raw::MjsSite& self) { mjs_delete(self.element); });
mjsSite.def("set_frame", [](raw::MjsSite& self, raw::MjsFrame& frame) {
mjs_setFrame(self.element, &frame);
});
mjsSite.def("set_default", [](raw::MjsSite& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsSite.def(
"default",
[](raw::MjsSite& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element);
},
py::return_value_policy::reference_internal);
// ============================= MJSCAMERA ===================================
mjsCamera.def_property_readonly("id", [](raw::MjsCamera& self) -> int {
return mjs_getId(self.element);
});
mjsCamera.def("delete",
[](raw::MjsCamera& self) { mjs_delete(self.element); });
mjsCamera.def("set_frame", [](raw::MjsCamera& self, raw::MjsFrame& frame) {
mjs_setFrame(self.element, &frame);
});
mjsCamera.def("set_default", [](raw::MjsCamera& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsCamera.def(
"default",
[](raw::MjsCamera& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element);
},
py::return_value_policy::reference_internal);
// ============================= MJSLIGHT ====================================
mjsLight.def_property_readonly(
"id", [](raw::MjsLight& self) -> int { return mjs_getId(self.element); });
mjsLight.def("delete", [](raw::MjsLight& self) { mjs_delete(self.element); });
mjsLight.def("set_frame", [](raw::MjsLight& self, raw::MjsFrame& frame) {
mjs_setFrame(self.element, &frame);
});
mjsLight.def("set_default", [](raw::MjsLight& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsLight.def(
"default",
[](raw::MjsLight& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element);
},
py::return_value_policy::reference_internal);
// ============================= MJSMATERIAL =================================
mjsMaterial.def_property_readonly("id", [](raw::MjsMaterial& self) -> int {
return mjs_getId(self.element);
});
mjsMaterial.def("delete",
[](raw::MjsMaterial& self) { mjs_delete(self.element); });
mjsMaterial.def("set_default",
[](raw::MjsMaterial& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsMaterial.def(
"default",
[](raw::MjsMaterial& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element);
},
py::return_value_policy::reference_internal);
// ============================= MJSMESH =====================================
mjsMesh.def_property_readonly(
"id", [](raw::MjsMesh& self) -> int { return mjs_getId(self.element); });
mjsMesh.def("delete", [](raw::MjsMesh& self) { mjs_delete(self.element); });
mjsMesh.def("set_default", [](raw::MjsMesh& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsMesh.def(
"default",
[](raw::MjsMesh& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element);
},
py::return_value_policy::reference_internal);
// ============================= MJSPAIR =====================================
mjsPair.def_property_readonly(
"id", [](raw::MjsPair& self) -> int { return mjs_getId(self.element); });
mjsPair.def("delete", [](raw::MjsPair& self) { mjs_delete(self.element); });
mjsPair.def("set_default", [](raw::MjsPair& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsPair.def(
"default",
[](raw::MjsPair& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element);
},
py::return_value_policy::reference_internal);
// ============================= MJSEQUAL ====================================
mjsEquality.def_property_readonly("id", [](raw::MjsEquality& self) -> int {
return mjs_getId(self.element);
});
mjsEquality.def("delete",
[](raw::MjsEquality& self) { mjs_delete(self.element); });
mjsEquality.def("set_default",
[](raw::MjsEquality& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsEquality.def(
"default",
[](raw::MjsEquality& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element);
},
py::return_value_policy::reference_internal);
// ============================= MJSACTUATOR =================================
mjsActuator.def_property_readonly("id", [](raw::MjsActuator& self) -> int {
return mjs_getId(self.element);
});
mjsActuator.def("delete",
[](raw::MjsActuator& self) { mjs_delete(self.element); });
mjsActuator.def("set_default",
[](raw::MjsActuator& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsActuator.def(
"default",
[](raw::MjsActuator& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element);
},
py::return_value_policy::reference_internal);
// ============================= MJSTENDON ===================================
mjsTendon.def_property_readonly("id", [](raw::MjsTendon& self) -> int {
return mjs_getId(self.element);
});
mjsTendon.def("delete",
[](raw::MjsTendon& self) { mjs_delete(self.element); });
mjsTendon.def("set_default", [](raw::MjsTendon& self, raw::MjsDefault& def) {
mjs_setDefault(self.element, &def);
});
mjsTendon.def(
"default",
[](raw::MjsTendon& self) -> raw::MjsDefault* {
return mjs_getDefault(self.element);
},
py::return_value_policy::reference_internal);
mjsTendon.def(
"wrap_site",
[](raw::MjsTendon& self, std::string& name) {
return mjs_wrapSite(&self, name.c_str());
},
py::return_value_policy::reference_internal);
mjsTendon.def(
"wrap_geom",
[](raw::MjsTendon& self, std::string& name, std::string& sidesite) {
return mjs_wrapGeom(&self, name.c_str(), sidesite.c_str());
},
py::return_value_policy::reference_internal);
mjsTendon.def(
"wrap_joint",
[](raw::MjsTendon& self, std::string& name, double coef) {
return mjs_wrapJoint(&self, name.c_str(), coef);
},
py::return_value_policy::reference_internal);
mjsTendon.def(
"wrap_pulley",
[](raw::MjsTendon& self, double divisor) {
return mjs_wrapPulley(&self, divisor);
},
py::return_value_policy::reference_internal);
// ============================= MJSSENSOR ===================================
mjsSensor.def_property_readonly("id", [](raw::MjsSensor& self) -> int {
return mjs_getId(self.element);
});
mjsSensor.def("delete",
[](raw::MjsSensor& self) { mjs_delete(self.element); });
// ============================= MJSFLEX =====================================
mjsFlex.def_property_readonly(
"id", [](raw::MjsFlex& self) -> int { return mjs_getId(self.element); });
mjsFlex.def("delete", [](raw::MjsFlex& self) { mjs_delete(self.element); });
// ============================= MJSHFIELD ===================================
mjsHField.def_property_readonly("id", [](raw::MjsHField& self) -> int {
return mjs_getId(self.element);
});
mjsHField.def("delete",
[](raw::MjsHField& self) { mjs_delete(self.element); });
// ============================= MJSSKIN =====================================
mjsSkin.def_property_readonly(
"id", [](raw::MjsSkin& self) -> int { return mjs_getId(self.element); },
py::return_value_policy::reference_internal);
mjsSkin.def("delete", [](raw::MjsSkin& self) { mjs_delete(self.element); });
// ============================= MJSTEXTURE ==================================
mjsTexture.def_property_readonly("id", [](raw::MjsTexture& self) -> int {
return mjs_getId(self.element);
});
mjsTexture.def("delete",
[](raw::MjsTexture& self) { mjs_delete(self.element); });
// ============================= MJSKEY ======================================
mjsKey.def_property_readonly(
"id", [](raw::MjsKey& self) -> int { return mjs_getId(self.element); });
mjsKey.def("delete", [](raw::MjsKey& self) { mjs_delete(self.element); });
// ============================= MJSTEXT =====================================
mjsText.def_property_readonly(
"id", [](raw::MjsText& self) -> int { return mjs_getId(self.element); });
mjsText.def("delete", [](raw::MjsText& self) { mjs_delete(self.element); });
// ============================= MJSNUMERIC ==================================
mjsNumeric.def_property_readonly("id", [](raw::MjsNumeric& self) -> int {
return mjs_getId(self.element);
});
mjsNumeric.def("delete",
[](raw::MjsNumeric& self) { mjs_delete(self.element); });
// ============================= MJSEXCLUDE ==================================
mjsExclude.def_property_readonly("id", [](raw::MjsExclude& self) -> int {
return mjs_getId(self.element);
});
mjsExclude.def("delete",
[](raw::MjsExclude& self) { mjs_delete(self.element); });
// ============================= MJSTUPLE ====================================
mjsTuple.def_property_readonly(
"id", [](raw::MjsTuple& self) -> int { return mjs_getId(self.element); });
mjsTuple.def("delete", [](raw::MjsTuple& self) { mjs_delete(self.element); });
// ============================= MJSPLUGIN ===================================
mjsPlugin.def_property_readonly("id", [](raw::MjsPlugin& self) -> int {
return mjs_getId(self.instance);
});
mjsPlugin.def("delete",
[](raw::MjsPlugin& self) { mjs_delete(self.instance); });
#include "specs.cc.inc"
} // PYBIND11_MODULE // NOLINT
} // namespace mujoco::python
+237
View File
@@ -0,0 +1,237 @@
# Copyright 2024 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
#
# http://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.
# ==============================================================================
"""Tests for mjSpec bindings."""
import inspect
import textwrap
from absl.testing import absltest
import mujoco
import numpy as np
def get_linenumber():
cf = inspect.currentframe()
return cf.f_back.f_lineno
class SpecsTest(absltest.TestCase):
def test_basic(self):
# Create a spec.
spec = mujoco.MjSpec()
# Check that euler sequence order is set correctly.
self.assertEqual(spec.eulerseq[0], ord('x'))
spec.eulerseq = ['z', 'y', 'x']
self.assertEqual(spec.eulerseq[0], ord('z'))
# Add a body, check that it has default orientation.
body = spec.worldbody.add_body()
self.assertEqual(body.name, '')
np.testing.assert_array_equal(body.quat, [1, 0, 0, 0])
# Change the name of the body and read it back twice.
body.name = 'foobar'
self.assertEqual(body.name, 'foobar')
body.name = 'baz'
self.assertEqual(body.name, 'baz')
# Change the position of the body and read it back.
body.pos = [1, 2, 3]
np.testing.assert_array_equal(body.pos, [1, 2, 3])
self.assertEqual(body.pos.shape, (3,))
# Change the orientation of the body and read it back.
body.quat = [0, 1, 0, 0]
np.testing.assert_array_equal(body.quat, [0, 1, 0, 0])
self.assertEqual(body.quat.shape, (4,))
# Add a site to the body with user data and read it back.
site = body.add_site()
site.name = 'sitename'
site.userdata = [1, 2, 3, 4, 5, 6]
self.assertEqual(site.name, 'sitename')
np.testing.assert_array_equal(site.userdata, [1, 2, 3, 4, 5, 6])
# Check that the site and body have no id before compilation.
self.assertEqual(body.id, -1)
self.assertEqual(site.id, -1)
# Compile the spec and check for expected values in the model.
model = spec.compile()
self.assertEqual(spec.worldbody.id, 0)
self.assertEqual(body.id, 1)
self.assertEqual(site.id, 0)
self.assertEqual(model.nbody, 2) # 2 bodies, including the world body
np.testing.assert_array_equal(model.body_pos[1], [1, 2, 3])
np.testing.assert_array_equal(model.body_quat[1], [0, 1, 0, 0])
self.assertEqual(model.nsite, 1)
self.assertEqual(model.nuser_site, 6)
np.testing.assert_array_equal(model.site_user[0], [1, 2, 3, 4, 5, 6])
self.assertEqual(spec.to_xml(), textwrap.dedent("""\
<mujoco model="MuJoCo Model">
<compiler angle="radian"/>
<size nuser_site="6"/>
<worldbody>
<body name="baz" pos="1 2 3" quat="0 1 0 0">
<site name="sitename" pos="0 0 0" user="1 2 3 4 5 6"/>
</body>
</worldbody>
</mujoco>
"""),)
def test_compile_errors_with_line_info(self):
spec = mujoco.MjSpec()
added_on_line = get_linenumber() + 1
geom = spec.worldbody.add_geom()
geom.name = 'MyGeom'
geom.info = f'geom added on line {added_on_line}'
# Try to compile, get error.
expected_error = (
'Error: size 0 must be positive in geom\n'
+ f'Element name \'MyGeom\', id 0, geom added on line {added_on_line}'
)
with self.assertRaisesRegex(ValueError, expected_error):
spec.compile()
def test_recompile(self):
# Create a spec.
spec = mujoco.MjSpec()
# Add movable body1.
body1 = spec.worldbody.add_body()
geom = body1.add_geom()
geom.size[0] = 1
geom.pos = [1, 1, 0]
joint = body1.add_joint()
joint.type = mujoco.mjtJoint.mjJNT_BALL
# Compile model, make data.
model = spec.compile()
data = mujoco.MjData(model)
# Simulate for 1 second.
while data.time < 1:
mujoco.mj_step(model, data)
# Add movable body2.
body2 = spec.worldbody.add_body()
body2.pos[1] = 3
geom = body2.add_geom()
geom.size[0] = 1
geom.pos = [0, 1, 0]
joint = body2.add_joint()
joint.type = mujoco.mjtJoint.mjJNT_BALL
# Recompile model and data while maintaining the state.
model_new, data_new = spec.recompile(model, data)
# Check that the state is preserved.
np.testing.assert_array_equal(model_new.body_pos[1], model.body_pos[1])
np.testing.assert_array_equal(data_new.qpos[:4], data.qpos)
np.testing.assert_array_equal(data_new.qvel[:3], data.qvel)
def test_uncompiled_spec_cannot_be_written(self):
spec = mujoco.MjSpec()
# Cannot write XML of an uncompiled spec.
expected_error = 'XML Write error: Only compiled model can be written'
with self.assertRaisesWithLiteralMatch(mujoco.FatalError, expected_error):
spec.to_xml()
def test_modelname_default_class(self):
spec = mujoco.MjSpec()
spec.modelname = 'test'
main = spec.default()
main.geom.size[0] = 2
def1 = spec.add_default('def1', main)
def1.geom.size[0] = 3
spec.worldbody.add_geom(def1)
spec.worldbody.add_geom(main)
spec.compile()
self.assertEqual(spec.to_xml(), textwrap.dedent("""\
<mujoco model="test">
<compiler angle="radian"/>
<default>
<geom size="2 0 0"/>
<default class="def1">
<geom size="3 0 0"/>
</default>
</default>
<worldbody>
<geom class="def1"/>
<geom/>
</worldbody>
</mujoco>
"""))
spec = mujoco.MjSpec()
spec.modelname = 'test'
main = spec.default()
main.geom.size[0] = 2
def1 = spec.add_default('def1', main)
def1.geom.size[0] = 3
spec.worldbody.add_geom(def1)
spec.worldbody.add_geom(main)
spec.compile()
self.assertEqual(spec.to_xml(), textwrap.dedent("""\
<mujoco model="test">
<compiler angle="radian"/>
<default>
<geom size="2 0 0"/>
<default class="def1">
<geom size="3 0 0"/>
</default>
</default>
<worldbody>
<geom class="def1"/>
<geom/>
</worldbody>
</mujoco>
"""))
def test_element_list(self):
spec = mujoco.MjSpec()
sensor1 = spec.add_sensor()
sensor2 = spec.add_sensor()
sensor3 = spec.add_sensor()
sensor1.name = 'sensor1'
sensor2.name = 'sensor2'
sensor3.name = 'sensor3'
self.assertLen(spec.sensors, 3)
self.assertEqual(spec.sensors[0].name, 'sensor1')
self.assertEqual(spec.sensors[1].name, 'sensor2')
self.assertEqual(spec.sensors[2].name, 'sensor3')
if __name__ == '__main__':
absltest.main()
+47 -23
View File
@@ -28,6 +28,7 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <tuple>
#include <type_traits> #include <type_traits>
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
@@ -316,24 +317,22 @@ static raw::MjModel* LoadModelFileImpl(
const std::string& filename, const std::string& filename,
const std::vector<VfsAsset>& assets, const std::vector<VfsAsset>& assets,
LoadFunc&& loadfunc) { LoadFunc&& loadfunc) {
std::unique_ptr<mjVFS, void(*)(mjVFS*)> vfs(nullptr, [](mjVFS*){}); mjVFS vfs;
mjVFS* vfs_ptr = nullptr;
if (!assets.empty()) { if (!assets.empty()) {
// mjVFS should be allocated on the heap, because it's ~2MB mj_defaultVFS(&vfs);
vfs = decltype(vfs)(new mjVFS, [](mjVFS* vfs) { vfs_ptr = &vfs;
mj_deleteVFS(vfs);
delete vfs;
});
mj_defaultVFS(vfs.get());
for (const auto& asset : assets) { for (const auto& asset : assets) {
const int vfs_error = InterceptMjErrors(mj_addBufferVFS)( const int vfs_error = InterceptMjErrors(mj_addBufferVFS)(
vfs.get(), asset.name, asset.content, asset.content_size); vfs_ptr, asset.name, asset.content, asset.content_size);
if (vfs_error) { if (vfs_error) {
throw py::value_error("assets dict is too big"); throw py::value_error("assets dict is too big");
} }
} }
} }
raw::MjModel* model = loadfunc(filename.c_str(), vfs.get()); raw::MjModel* model = loadfunc(filename.c_str(), vfs_ptr);
mj_deleteVFS(vfs_ptr);
if (model && !model->buffer) { if (model && !model->buffer) {
mj_deleteModel(model); mj_deleteModel(model);
model = nullptr; model = nullptr;
@@ -350,12 +349,6 @@ ConvertAssetsDict(
std::vector<VfsAsset> out; std::vector<VfsAsset> out;
if (assets.has_value()) { if (assets.has_value()) {
for (const auto& [name, content] : *assets) { for (const auto& [name, content] : *assets) {
if (name.length() >= mjMAXVFSNAME) {
std::ostringstream error;
error << "Filename length " << name.length() << " exceeds "
<< mjMAXVFSNAME - 1 << " character limit: " << name;
throw py::value_error(error.str());
}
out.emplace_back(name.c_str(), PYBIND11_BYTES_AS_STRING(content.ptr()), out.emplace_back(name.c_str(), PYBIND11_BYTES_AS_STRING(content.ptr()),
py::len(content)); py::len(content));
} }
@@ -430,6 +423,27 @@ MjModelWrapper MjModelWrapper::LoadXML(
return MjModelWrapper(model); return MjModelWrapper(model);
} }
MjModelWrapper MjModelWrapper::CompileSpec(raw::MjSpec* spec) {
auto m = mj_compile(spec, nullptr);
if (!m || mjs_isWarning(spec)) {
throw py::value_error(mjs_getError(spec));
}
return MjModelWrapper(m);
}
py::tuple RecompileSpec(raw::MjSpec* spec, const MjModelWrapper& old_m,
const MjDataWrapper& old_d) {
raw::MjModel* m = static_cast<raw::MjModel*>(mju_malloc(sizeof(mjModel)));
m->buffer = nullptr;
raw::MjData* d = mj_copyData(nullptr, old_m.get(), old_d.get());
mj_recompile(spec, nullptr, m, d);
py::object m_pyobj = py::cast((MjModelWrapper(m)));
py::object d_pyobj =
py::cast((MjDataWrapper(py::cast<MjModelWrapper*>(m_pyobj), d)));
return py::make_tuple(m_pyobj, d_pyobj);
}
namespace { namespace {
// A byte at the start of serialized mjModel structs, which can be incremented // A byte at the start of serialized mjModel structs, which can be incremented
// when we change the serialization logic to reject pickles from an unsupported // when we change the serialization logic to reject pickles from an unsupported
@@ -1056,7 +1070,6 @@ MjvGLCameraWrapper::MjWrapper(const MjvGLCameraWrapper& other)
#define X(var) var(InitPyArray(ptr_->var, owner_)) #define X(var) var(InitPyArray(ptr_->var, owner_))
MjvGeomWrapper::MjWrapper() MjvGeomWrapper::MjWrapper()
: WrapperBase(new raw::MjvGeom{}), : WrapperBase(new raw::MjvGeom{}),
X(texrepeat),
X(size), X(size),
X(pos), X(pos),
mat([this]() { mat([this]() {
@@ -1069,7 +1082,6 @@ MjvGeomWrapper::MjWrapper()
MjvGeomWrapper::MjWrapper(raw::MjvGeom* ptr, py::handle owner) MjvGeomWrapper::MjWrapper(raw::MjvGeom* ptr, py::handle owner)
: WrapperBase(ptr, owner), : WrapperBase(ptr, owner),
X(texrepeat),
X(size), X(size),
X(pos), X(pos),
mat([this]() { mat([this]() {
@@ -1557,6 +1569,11 @@ PYBIND11_MODULE(_structs, m) {
py::arg("xml"), py::arg_v("assets", py::none()), py::arg("xml"), py::arg_v("assets", py::none()),
py::doc( py::doc(
R"(Loads an MjModel from an XML string and an optional assets dictionary.)")); R"(Loads an MjModel from an XML string and an optional assets dictionary.)"));
mjModel.def_static(
"_from_spec_ptr", [](uintptr_t addr) {
return MjModelWrapper::CompileSpec(
reinterpret_cast<raw::MjSpec*>(addr));
});
mjModel.def_static( mjModel.def_static(
"from_xml_path", &MjModelWrapper::LoadXMLFile, "from_xml_path", &MjModelWrapper::LoadXMLFile,
py::arg("filename"), py::arg_v("assets", py::none()), py::arg("filename"), py::arg_v("assets", py::none()),
@@ -1907,9 +1924,11 @@ This is useful for example when the MJB is not available as a file on disk.)"));
mjData.def("__copy__", [](const MjDataWrapper& other) { mjData.def("__copy__", [](const MjDataWrapper& other) {
return MjDataWrapper(other); return MjDataWrapper(other);
}); });
mjData.def("__deepcopy__", [](const MjDataWrapper& other, py::dict) { mjData.def("__deepcopy__", [](const MjDataWrapper& other, py::dict memo) {
MjModelWrapper* model_copy = new MjModelWrapper(other.model()); // Use copy.deepcopy(model) to make a model that Python is aware of.
return MjDataWrapper(other, model_copy); py::object new_model_py =
py::cast(other.model()).attr("__deepcopy__")(memo);
return MjDataWrapper(other, new_model_py.cast<MjModelWrapper*>());
}); });
mjData.def(py::pickle( mjData.def(py::pickle(
[](const MjDataWrapper& d) { // __getstate__ [](const MjDataWrapper& d) { // __getstate__
@@ -2185,8 +2204,7 @@ This is useful for example when the MJB is not available as a file on disk.)"));
X(objtype); X(objtype);
X(objid); X(objid);
X(category); X(category);
X(texid); X(matid);
X(texuniform);
X(texcoord); X(texcoord);
X(segid); X(segid);
X(emission); X(emission);
@@ -2199,7 +2217,6 @@ This is useful for example when the MJB is not available as a file on disk.)"));
#undef X #undef X
#define X(var) DefinePyArray(mjvGeom, #var, &MjvGeomWrapper::var) #define X(var) DefinePyArray(mjvGeom, #var, &MjvGeomWrapper::var)
X(texrepeat);
X(size); X(size);
X(pos); X(pos);
X(mat); X(mat);
@@ -2404,5 +2421,12 @@ This is useful for example when the MJB is not available as a file on disk.)"));
}, },
py::arg("cam1"), py::arg("cam2"), py::arg("cam1"), py::arg("cam2"),
py::doc(python_traits::mjv_averageCamera::doc)); py::doc(python_traits::mjv_averageCamera::doc));
m.def(
"_recompile_spec_addr",
[](uintptr_t spec_addr, const MjModelWrapper& m, const MjDataWrapper& d) {
return RecompileSpec(reinterpret_cast<raw::MjSpec*>(spec_addr), m, d);
}
);
} // PYBIND11_MODULE NOLINT(readability/fn_size) } // PYBIND11_MODULE NOLINT(readability/fn_size)
} // namespace mujoco::python::_impl } // namespace mujoco::python::_impl
+13 -6
View File
@@ -462,6 +462,10 @@ class MjWrapper<raw::MjModel> : public WrapperBase<raw::MjModel> {
public: public:
MjWrapper(const MjWrapper&); MjWrapper(const MjWrapper&);
MjWrapper(MjWrapper&&); MjWrapper(MjWrapper&&);
// Takes ownership of the raw mjModel pointer.
explicit MjWrapper(raw::MjModel* ptr);
~MjWrapper(); ~MjWrapper();
MjModelIndexer& indexer() { return indexer_; } MjModelIndexer& indexer() { return indexer_; }
@@ -485,6 +489,8 @@ class MjWrapper<raw::MjModel> : public WrapperBase<raw::MjModel> {
const std::optional< const std::optional<
std::unordered_map<std::string, pybind11::bytes>>& assets); std::unordered_map<std::string, pybind11::bytes>>& assets);
static MjWrapper CompileSpec(raw::MjSpec* spec);
static constexpr char kFromRawPointer[] = static constexpr char kFromRawPointer[] =
"__MUJOCO_STRUCTS_MJMODELWRAPPER_LOOKUP"; "__MUJOCO_STRUCTS_MJMODELWRAPPER_LOOKUP";
static MjWrapper* FromRawPointer(raw::MjModel* m) noexcept; static MjWrapper* FromRawPointer(raw::MjModel* m) noexcept;
@@ -502,8 +508,6 @@ class MjWrapper<raw::MjModel> : public WrapperBase<raw::MjModel> {
pybind11::bytes paths_bytes; pybind11::bytes paths_bytes;
protected: protected:
explicit MjWrapper(raw::MjModel* ptr);
MjModelIndexer indexer_; MjModelIndexer indexer_;
}; };
@@ -591,8 +595,14 @@ class MjWrapper<raw::MjData>: public WrapperBase<raw::MjData> {
explicit MjWrapper(MjModelWrapper* model); explicit MjWrapper(MjModelWrapper* model);
MjWrapper(const MjWrapper& other); MjWrapper(const MjWrapper& other);
MjWrapper(MjWrapper&&); MjWrapper(MjWrapper&&);
// Used for deepcopy // Used for deepcopy
MjWrapper(const MjWrapper& other, MjModelWrapper* model); MjWrapper(const MjWrapper& other, MjModelWrapper* model);
// Internal constructor which takes ownership of given mjData pointer.
// Used for deserialization and recompile.
explicit MjWrapper(MjModelWrapper* model, raw::MjData* d);
~MjWrapper(); ~MjWrapper();
const MjModelWrapper& model() const { return *model_; } const MjModelWrapper& model() const { return *model_; }
@@ -622,9 +632,6 @@ class MjWrapper<raw::MjData>: public WrapperBase<raw::MjData> {
py_array_or_tuple_t<mjtNum> energy; py_array_or_tuple_t<mjtNum> energy;
protected: protected:
// Internal constructor which takes ownership of given mjData pointer.
// Used for deserialization.
explicit MjWrapper(MjModelWrapper* model, raw::MjData* d);
raw::MjData* Copy() const; raw::MjData* Copy() const;
// A reference to the model that was used to create this mjData. // A reference to the model that was used to create this mjData.
@@ -727,7 +734,7 @@ class MjWrapper<raw::MjvGeom> : public WrapperBase<raw::MjvGeom> {
py_array_or_tuple_t< \ py_array_or_tuple_t< \
std::remove_all_extents_t<decltype(raw::MjvGeom::var)>> \ std::remove_all_extents_t<decltype(raw::MjvGeom::var)>> \
var var
X(texrepeat); X(matid);
X(size); X(size);
X(pos); X(pos);
X(mat); X(mat);
+5 -1
View File
@@ -247,7 +247,11 @@ class USDExporter:
assert geom_name not in self.geom_names assert geom_name not in self.geom_names
texture_file = self.texture_files[geom.texid] if geom.texid != -1 else None texture_file = (
self.texture_files[self.model.mat_texid[mujoco.mjNTEXMAT*geom.matid]]
if geom.matid != -1
else None
)
# handling meshes in our scene # handling meshes in our scene
if geom.type == mujoco.mjtGeom.mjGEOM_MESH: if geom.type == mujoco.mjtGeom.mjGEOM_MESH:
+14
View File
@@ -94,6 +94,20 @@ class Handle:
def user_scn(self): def user_scn(self):
return self._user_scn return self._user_scn
@property
def m(self):
sim = self._sim()
if sim is not None:
return sim.m
return None
@property
def d(self):
sim = self._sim()
if sim is not None:
return sim.d
return None
def close(self): def close(self):
sim = self._sim() sim = self._sim()
if sim is not None: if sim is not None:
+1
View File
@@ -347,6 +347,7 @@ setuptools.setup(
CMakeExtension('mujoco._render'), CMakeExtension('mujoco._render'),
CMakeExtension('mujoco._rollout'), CMakeExtension('mujoco._rollout'),
CMakeExtension('mujoco._simulate'), CMakeExtension('mujoco._simulate'),
CMakeExtension('mujoco._specs'),
CMakeExtension('mujoco._structs'), CMakeExtension('mujoco._structs'),
], ],
scripts=[ scripts=[
+197 -176
View File
@@ -420,8 +420,8 @@
"data = mujoco.MjData(model)\n", "data = mujoco.MjData(model)\n",
"\n", "\n",
"# Make renderer, render and show the pixels\n", "# Make renderer, render and show the pixels\n",
"renderer = mujoco.Renderer(model)\n", "with mujoco.Renderer(model) as renderer:\n",
"media.show_image(renderer.render())" " media.show_image(renderer.render())"
] ]
}, },
{ {
@@ -445,10 +445,11 @@
}, },
"outputs": [], "outputs": [],
"source": [ "source": [
"mujoco.mj_forward(model, data)\n", "with mujoco.Renderer(model) as renderer:\n",
"renderer.update_scene(data)\n", " mujoco.mj_forward(model, data)\n",
" renderer.update_scene(data)\n",
"\n", "\n",
"media.show_image(renderer.render())" " media.show_image(renderer.render())"
] ]
}, },
{ {
@@ -480,11 +481,11 @@
"model = mujoco.MjModel.from_xml_string(xml)\n", "model = mujoco.MjModel.from_xml_string(xml)\n",
"data = mujoco.MjData(model)\n", "data = mujoco.MjData(model)\n",
"\n", "\n",
"renderer = mujoco.Renderer(model)\n", "with mujoco.Renderer(model) as renderer:\n",
"mujoco.mj_forward(model, data)\n", " mujoco.mj_forward(model, data)\n",
"renderer.update_scene(data)\n", " renderer.update_scene(data)\n",
"\n", "\n",
"media.show_image(renderer.render())" " media.show_image(renderer.render())"
] ]
}, },
{ {
@@ -508,9 +509,10 @@
"source": [ "source": [
"# Run this cell multiple times for different colors\n", "# Run this cell multiple times for different colors\n",
"model.geom('red_box').rgba[:3] = np.random.rand(3)\n", "model.geom('red_box').rgba[:3] = np.random.rand(3)\n",
"renderer.update_scene(data)\n", "with mujoco.Renderer(model) as renderer:\n",
" renderer.update_scene(data)\n",
"\n", "\n",
"media.show_image(renderer.render())" " media.show_image(renderer.render())"
] ]
}, },
{ {
@@ -540,12 +542,13 @@
"# Simulate and display video.\n", "# Simulate and display video.\n",
"frames = []\n", "frames = []\n",
"mujoco.mj_resetData(model, data) # Reset state and time.\n", "mujoco.mj_resetData(model, data) # Reset state and time.\n",
"while data.time < duration:\n", "with mujoco.Renderer(model) as renderer:\n",
" mujoco.mj_step(model, data)\n", " while data.time < duration:\n",
" if len(frames) < data.time * framerate:\n", " mujoco.mj_step(model, data)\n",
" renderer.update_scene(data)\n", " if len(frames) < data.time * framerate:\n",
" pixels = renderer.render()\n", " renderer.update_scene(data)\n",
" frames.append(pixels)\n", " pixels = renderer.render()\n",
" frames.append(pixels)\n",
"\n", "\n",
"media.show_video(frames, fps=framerate)" "media.show_video(frames, fps=framerate)"
] ]
@@ -583,7 +586,6 @@
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(xml)\n", "model = mujoco.MjModel.from_xml_string(xml)\n",
"data = mujoco.MjData(model)\n", "data = mujoco.MjData(model)\n",
"renderer = mujoco.Renderer(model)\n",
"\n", "\n",
"# enable joint visualization option:\n", "# enable joint visualization option:\n",
"scene_option = mujoco.MjvOption()\n", "scene_option = mujoco.MjvOption()\n",
@@ -595,12 +597,13 @@
"# Simulate and display video.\n", "# Simulate and display video.\n",
"frames = []\n", "frames = []\n",
"mujoco.mj_resetData(model, data)\n", "mujoco.mj_resetData(model, data)\n",
"while data.time < duration:\n", "with mujoco.Renderer(model) as renderer:\n",
" mujoco.mj_step(model, data)\n", " while data.time < duration:\n",
" if len(frames) < data.time * framerate:\n", " mujoco.mj_step(model, data)\n",
" renderer.update_scene(data, scene_option=scene_option)\n", " if len(frames) < data.time * framerate:\n",
" pixels = renderer.render()\n", " renderer.update_scene(data, scene_option=scene_option)\n",
" frames.append(pixels)\n", " pixels = renderer.render()\n",
" frames.append(pixels)\n",
"\n", "\n",
"media.show_video(frames, fps=framerate)" "media.show_video(frames, fps=framerate)"
] ]
@@ -651,12 +654,13 @@
"# Simulate and display video.\n", "# Simulate and display video.\n",
"frames = []\n", "frames = []\n",
"mujoco.mj_resetData(model, data)\n", "mujoco.mj_resetData(model, data)\n",
"while data.time < duration:\n", "with mujoco.Renderer(model) as renderer:\n",
" mujoco.mj_step(model, data)\n", " while data.time < duration:\n",
" if len(frames) < data.time * framerate:\n", " mujoco.mj_step(model, data)\n",
" renderer.update_scene(data, scene_option=scene_option)\n", " if len(frames) < data.time * framerate:\n",
" pixels = renderer.render()\n", " renderer.update_scene(data, scene_option=scene_option)\n",
" frames.append(pixels)\n", " pixels = renderer.render()\n",
" frames.append(pixels)\n",
"\n", "\n",
"media.show_video(frames, fps=60)" "media.show_video(frames, fps=60)"
] ]
@@ -760,12 +764,12 @@
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(tippe_top)\n", "model = mujoco.MjModel.from_xml_string(tippe_top)\n",
"data = mujoco.MjData(model)\n", "data = mujoco.MjData(model)\n",
"renderer = mujoco.Renderer(model)\n",
"\n", "\n",
"mujoco.mj_forward(model, data)\n", "mujoco.mj_forward(model, data)\n",
"renderer.update_scene(data, camera=\"closeup\")\n", "with mujoco.Renderer(model) as renderer:\n",
" renderer.update_scene(data, camera=\"closeup\")\n",
"\n", "\n",
"media.show_image(renderer.render())" " media.show_image(renderer.render())"
] ]
}, },
{ {
@@ -821,12 +825,13 @@
"# Simulate and display video.\n", "# Simulate and display video.\n",
"frames = []\n", "frames = []\n",
"mujoco.mj_resetDataKeyframe(model, data, 0) # Reset the state to keyframe 0\n", "mujoco.mj_resetDataKeyframe(model, data, 0) # Reset the state to keyframe 0\n",
"while data.time < duration:\n", "with mujoco.Renderer(model) as renderer:\n",
" mujoco.mj_step(model, data)\n", " while data.time < duration:\n",
" if len(frames) < data.time * framerate:\n", " mujoco.mj_step(model, data)\n",
" renderer.update_scene(data, \"closeup\")\n", " if len(frames) < data.time * framerate:\n",
" pixels = renderer.render()\n", " renderer.update_scene(data, \"closeup\")\n",
" frames.append(pixels)\n", " pixels = renderer.render()\n",
" frames.append(pixels)\n",
"\n", "\n",
"media.show_video(frames, fps=framerate)" "media.show_video(frames, fps=framerate)"
] ]
@@ -939,12 +944,14 @@
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(chaotic_pendulum)\n", "model = mujoco.MjModel.from_xml_string(chaotic_pendulum)\n",
"data = mujoco.MjData(model)\n", "data = mujoco.MjData(model)\n",
"renderer = mujoco.Renderer(model, 480, 640)\n", "height = 480\n",
"width = 640\n",
"\n", "\n",
"mujoco.mj_forward(model, data)\n", "with mujoco.Renderer(model, height, width) as renderer:\n",
"renderer.update_scene(data, camera=\"fixed\")\n", " mujoco.mj_forward(model, data)\n",
" renderer.update_scene(data, camera=\"fixed\")\n",
"\n", "\n",
"media.show_image(renderer.render())" " media.show_image(renderer.render())"
] ]
}, },
{ {
@@ -970,7 +977,8 @@
"framerate = 30 # Hz\n", "framerate = 30 # Hz\n",
"n_frames = int(n_seconds * framerate)\n", "n_frames = int(n_seconds * framerate)\n",
"frames = []\n", "frames = []\n",
"renderer = mujoco.Renderer(model, 240, 320)\n", "height = 240\n",
"width = 320\n",
"\n", "\n",
"# set initial state\n", "# set initial state\n",
"mujoco.mj_resetData(model, data)\n", "mujoco.mj_resetData(model, data)\n",
@@ -981,17 +989,18 @@
"sim_time = 0\n", "sim_time = 0\n",
"render_time = 0\n", "render_time = 0\n",
"n_steps = 0\n", "n_steps = 0\n",
"for i in range(n_frames):\n", "with mujoco.Renderer(model, height, width) as renderer:\n",
" while data.time * framerate < i:\n", " for i in range(n_frames):\n",
" while data.time * framerate < i:\n",
" tic = time.time()\n",
" mujoco.mj_step(model, data)\n",
" sim_time += time.time() - tic\n",
" n_steps += 1\n",
" tic = time.time()\n", " tic = time.time()\n",
" mujoco.mj_step(model, data)\n", " renderer.update_scene(data, \"fixed\")\n",
" sim_time += time.time() - tic\n", " frame = renderer.render()\n",
" n_steps += 1\n", " render_time += time.time() - tic\n",
" tic = time.time()\n", " frames.append(frame)\n",
" renderer.update_scene(data, \"fixed\")\n",
" frame = renderer.render()\n",
" render_time += time.time() - tic\n",
" frames.append(frame)\n",
"\n", "\n",
"# print timing and play video\n", "# print timing and play video\n",
"step_time = 1e6*sim_time/n_steps\n", "step_time = 1e6*sim_time/n_steps\n",
@@ -1233,12 +1242,14 @@
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(free_body_MJCF)\n", "model = mujoco.MjModel.from_xml_string(free_body_MJCF)\n",
"data = mujoco.MjData(model)\n", "data = mujoco.MjData(model)\n",
"renderer = mujoco.Renderer(model, 400, 600)\n", "height = 400\n",
"width = 600\n",
"\n", "\n",
"mujoco.mj_forward(model, data)\n", "with mujoco.Renderer(model, height, width) as renderer:\n",
"renderer.update_scene(data, \"fixed\")\n", " mujoco.mj_forward(model, data)\n",
" renderer.update_scene(data, \"fixed\")\n",
"\n", "\n",
"media.show_image(renderer.render())" " media.show_image(renderer.render())"
] ]
}, },
{ {
@@ -1262,7 +1273,6 @@
"height = 240\n", "height = 240\n",
"width = 320\n", "width = 320\n",
"frames = []\n", "frames = []\n",
"renderer = mujoco.Renderer(model, height, width)\n",
"\n", "\n",
"# visualize contact frames and forces, make body transparent\n", "# visualize contact frames and forces, make body transparent\n",
"options = mujoco.MjvOption()\n", "options = mujoco.MjvOption()\n",
@@ -1282,12 +1292,13 @@
"data.qvel[3:6] = 5*np.random.randn(3)\n", "data.qvel[3:6] = 5*np.random.randn(3)\n",
"\n", "\n",
"# Simulate and display video.\n", "# Simulate and display video.\n",
"for i in range(n_frames):\n", "with mujoco.Renderer(model, height, width) as renderer:\n",
" while data.time < i/120.0: #1/4x real time\n", " for i in range(n_frames):\n",
" mujoco.mj_step(model, data)\n", " while data.time < i/120.0: #1/4x real time\n",
" renderer.update_scene(data, \"track\", options)\n", " mujoco.mj_step(model, data)\n",
" frame = renderer.render()\n", " renderer.update_scene(data, \"track\", options)\n",
" frames.append(frame)\n", " frame = renderer.render()\n",
" frames.append(frame)\n",
"\n", "\n",
"media.show_video(frames, fps=30)" "media.show_video(frames, fps=30)"
] ]
@@ -1440,16 +1451,16 @@
"# load\n", "# load\n",
"model = mujoco.MjModel.from_xml_string(MJCF)\n", "model = mujoco.MjModel.from_xml_string(MJCF)\n",
"data = mujoco.MjData(model)\n", "data = mujoco.MjData(model)\n",
"renderer = mujoco.Renderer(model, height, width)\n",
"\n", "\n",
"# Simulate and display video.\n", "# Simulate and display video.\n",
"mujoco.mj_resetData(model, data)\n", "with mujoco.Renderer(model, height, width) as renderer:\n",
"for i in range(n_frames):\n", " mujoco.mj_resetData(model, data)\n",
" while data.time < i/30.0:\n", " for i in range(n_frames):\n",
" mujoco.mj_step(model, data)\n", " while data.time < i/30.0:\n",
" renderer.update_scene(data, \"y\")\n", " mujoco.mj_step(model, data)\n",
" frame = renderer.render()\n", " renderer.update_scene(data, \"y\")\n",
" frames.append(frame)\n", " frame = renderer.render()\n",
" frames.append(frame)\n",
"\n", "\n",
"media.show_video(frames, fps=30)" "media.show_video(frames, fps=30)"
] ]
@@ -1520,12 +1531,14 @@
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(MJCF)\n", "model = mujoco.MjModel.from_xml_string(MJCF)\n",
"data = mujoco.MjData(model)\n", "data = mujoco.MjData(model)\n",
"renderer = mujoco.Renderer(model, 480, 480)\n", "height = 480\n",
"width = 480\n",
"\n", "\n",
"mujoco.mj_forward(model, data)\n", "with mujoco.Renderer(model, height, width) as renderer:\n",
"renderer.update_scene(data, \"fixed\")\n", " mujoco.mj_forward(model, data)\n",
" renderer.update_scene(data, \"fixed\")\n",
"\n", "\n",
"media.show_image(renderer.render())\n" " media.show_image(renderer.render())"
] ]
}, },
{ {
@@ -1553,21 +1566,20 @@
"times = []\n", "times = []\n",
"sensordata = []\n", "sensordata = []\n",
"\n", "\n",
"renderer = mujoco.Renderer(model, height, width)\n",
"\n",
"# constant actuator signal\n", "# constant actuator signal\n",
"mujoco.mj_resetData(model, data)\n", "mujoco.mj_resetData(model, data)\n",
"data.ctrl = 20\n", "data.ctrl = 20\n",
"\n", "\n",
"# Simulate and display video.\n", "# Simulate and display video.\n",
"for i in range(n_frames):\n", "with mujoco.Renderer(model, height, width) as renderer:\n",
" while data.time < i/fps:\n", " for i in range(n_frames):\n",
" mujoco.mj_step(model, data)\n", " while data.time < i/fps:\n",
" times.append(data.time)\n", " mujoco.mj_step(model, data)\n",
" sensordata.append(data.sensor('accelerometer').data.copy())\n", " times.append(data.time)\n",
" renderer.update_scene(data, \"fixed\")\n", " sensordata.append(data.sensor('accelerometer').data.copy())\n",
" frame = renderer.render()\n", " renderer.update_scene(data, \"fixed\")\n",
" frames.append(frame)\n", " frame = renderer.render()\n",
" frames.append(frame)\n",
"\n", "\n",
"media.show_video(frames, fps=fps)" "media.show_video(frames, fps=fps)"
] ]
@@ -1644,12 +1656,12 @@
"</mujoco>\n", "</mujoco>\n",
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(xml)\n", "model = mujoco.MjModel.from_xml_string(xml)\n",
"renderer = mujoco.Renderer(model)\n",
"data = mujoco.MjData(model)\n", "data = mujoco.MjData(model)\n",
"\n", "\n",
"mujoco.mj_forward(model, data)\n", "with mujoco.Renderer(model) as renderer:\n",
"renderer.update_scene(data)\n", " mujoco.mj_forward(model, data)\n",
"media.show_image(renderer.render())" " renderer.update_scene(data)\n",
" media.show_image(renderer.render())"
] ]
}, },
{ {
@@ -1664,9 +1676,10 @@
"\n", "\n",
"scene_option.frame = mujoco.mjtFrame.mjFRAME_GEOM\n", "scene_option.frame = mujoco.mjtFrame.mjFRAME_GEOM\n",
"scene_option.flags[mujoco.mjtVisFlag.mjVIS_TRANSPARENT] = True\n", "scene_option.flags[mujoco.mjtVisFlag.mjVIS_TRANSPARENT] = True\n",
"renderer.update_scene(data, scene_option=scene_option)\n", "with mujoco.Renderer(model) as renderer:\n",
"frame = renderer.render()\n", " renderer.update_scene(data, scene_option=scene_option)\n",
"media.show_image(frame)" " frame = renderer.render()\n",
" media.show_image(frame)"
] ]
}, },
{ {
@@ -1679,25 +1692,24 @@
"source": [ "source": [
"#@title Depth rendering {vertical-output: true}\n", "#@title Depth rendering {vertical-output: true}\n",
"\n", "\n",
"# update renderer to render depth\n", "with mujoco.Renderer(model) as renderer:\n",
"renderer.enable_depth_rendering()\n", " # update renderer to render depth\n",
" renderer.enable_depth_rendering()\n",
"\n", "\n",
"# reset the scene\n", " # reset the scene\n",
"renderer.update_scene(data)\n", " renderer.update_scene(data)\n",
"\n", "\n",
"# depth is a float array, in meters.\n", " # depth is a float array, in meters.\n",
"depth = renderer.render()\n", " depth = renderer.render()\n",
"\n", "\n",
"# Shift nearest values to the origin.\n", " # Shift nearest values to the origin.\n",
"depth -= depth.min()\n", " depth -= depth.min()\n",
"# Scale by 2 mean distances of near rays.\n", " # Scale by 2 mean distances of near rays.\n",
"depth /= 2*depth[depth <= 1].mean()\n", " depth /= 2*depth[depth <= 1].mean()\n",
"# Scale to [0, 255]\n", " # Scale to [0, 255]\n",
"pixels = 255*np.clip(depth, 0, 1)\n", " pixels = 255*np.clip(depth, 0, 1)\n",
"\n", "\n",
"media.show_image(pixels.astype(np.uint8))\n", " media.show_image(pixels.astype(np.uint8))"
"\n",
"renderer.disable_depth_rendering()"
] ]
}, },
{ {
@@ -1710,25 +1722,26 @@
"source": [ "source": [
"#@title Segmentation rendering {vertical-output: true}\n", "#@title Segmentation rendering {vertical-output: true}\n",
"\n", "\n",
"# update renderer to render segmentation\n", "with mujoco.Renderer(model) as renderer:\n",
"renderer.enable_segmentation_rendering()\n", " renderer.disable_depth_rendering()\n",
"\n", "\n",
"# reset the scene\n", " # update renderer to render segmentation\n",
"renderer.update_scene(data)\n", " renderer.enable_segmentation_rendering()\n",
"\n", "\n",
"seg = renderer.render()\n", " # reset the scene\n",
" renderer.update_scene(data)\n",
"\n", "\n",
"# Display the contents of the first channel, which contains object\n", " seg = renderer.render()\n",
"# IDs. The second channel, seg[:, :, 1], contains object types.\n",
"geom_ids = seg[:, :, 0]\n",
"# Infinity is mapped to -1\n",
"geom_ids = geom_ids.astype(np.float64) + 1\n",
"# Scale to [0, 1]\n",
"geom_ids = geom_ids / geom_ids.max()\n",
"pixels = 255*geom_ids\n",
"media.show_image(pixels.astype(np.uint8))\n",
"\n", "\n",
"renderer.disable_segmentation_rendering()" " # Display the contents of the first channel, which contains object\n",
" # IDs. The second channel, seg[:, :, 1], contains object types.\n",
" geom_ids = seg[:, :, 0]\n",
" # Infinity is mapped to -1\n",
" geom_ids = geom_ids.astype(np.float64) + 1\n",
" # Scale to [0, 1]\n",
" geom_ids = geom_ids / geom_ids.max()\n",
" pixels = 255*geom_ids\n",
" media.show_image(pixels.astype(np.uint8))"
] ]
}, },
{ {
@@ -1792,37 +1805,39 @@
"source": [ "source": [
"#@title Project from world to camera coordinates {vertical-output: true}\n", "#@title Project from world to camera coordinates {vertical-output: true}\n",
"\n", "\n",
"# reset the scene\n", "with mujoco.Renderer(model) as renderer:\n",
"renderer.update_scene(data)\n", " renderer.disable_segmentation_rendering()\n",
" # reset the scene\n",
" renderer.update_scene(data)\n",
"\n", "\n",
"# Get the world coordinates of the box corners\n", " # Get the world coordinates of the box corners\n",
"box_pos = data.geom_xpos[model.geom('red_box').id]\n", " box_pos = data.geom_xpos[model.geom('red_box').id]\n",
"box_mat = data.geom_xmat[model.geom('red_box').id].reshape(3, 3)\n", " box_mat = data.geom_xmat[model.geom('red_box').id].reshape(3, 3)\n",
"box_size = model.geom_size[model.geom('red_box').id]\n", " box_size = model.geom_size[model.geom('red_box').id]\n",
"offsets = np.array([-1, 1]) * box_size[:, None]\n", " offsets = np.array([-1, 1]) * box_size[:, None]\n",
"xyz_local = np.stack(list(itertools.product(*offsets))).T\n", " xyz_local = np.stack(list(itertools.product(*offsets))).T\n",
"xyz_global = box_pos[:, None] + box_mat @ xyz_local\n", " xyz_global = box_pos[:, None] + box_mat @ xyz_local\n",
"\n", "\n",
"# Camera matrices multiply homogenous [x, y, z, 1] vectors.\n", " # Camera matrices multiply homogenous [x, y, z, 1] vectors.\n",
"corners_homogeneous = np.ones((4, xyz_global.shape[1]), dtype=float)\n", " corners_homogeneous = np.ones((4, xyz_global.shape[1]), dtype=float)\n",
"corners_homogeneous[:3, :] = xyz_global\n", " corners_homogeneous[:3, :] = xyz_global\n",
"\n", "\n",
"# Get the camera matrix.\n", " # Get the camera matrix.\n",
"m = compute_camera_matrix(renderer, data)\n", " m = compute_camera_matrix(renderer, data)\n",
"\n", "\n",
"# Project world coordinates into pixel space. See:\n", " # Project world coordinates into pixel space. See:\n",
"# https://en.wikipedia.org/wiki/3D_projection#Mathematical_formula\n", " # https://en.wikipedia.org/wiki/3D_projection#Mathematical_formula\n",
"xs, ys, s = m @ corners_homogeneous\n", " xs, ys, s = m @ corners_homogeneous\n",
"# x and y are in the pixel coordinate system.\n", " # x and y are in the pixel coordinate system.\n",
"x = xs / s\n", " x = xs / s\n",
"y = ys / s\n", " y = ys / s\n",
"\n", "\n",
"# Render the camera view and overlay the projected corner coordinates.\n", " # Render the camera view and overlay the projected corner coordinates.\n",
"pixels = renderer.render()\n", " pixels = renderer.render()\n",
"fig, ax = plt.subplots(1, 1)\n", " fig, ax = plt.subplots(1, 1)\n",
"ax.imshow(pixels)\n", " ax.imshow(pixels)\n",
"ax.plot(x, y, '+', c='w')\n", " ax.plot(x, y, '+', c='w')\n",
"ax.set_axis_off()" " ax.set_axis_off()"
] ]
}, },
{ {
@@ -1894,17 +1909,18 @@
"mujoco.mj_resetData(model, data)\n", "mujoco.mj_resetData(model, data)\n",
"mujoco.mj_forward(model, data)\n", "mujoco.mj_forward(model, data)\n",
"\n", "\n",
"while data.time < duration:\n", "with mujoco.Renderer(model) as renderer:\n",
" # append data to the traces\n", " while data.time < duration:\n",
" positions.append(data.geom_xpos[data.geom(\"green_sphere\").id].copy())\n", " # append data to the traces\n",
" times.append(data.time)\n", " positions.append(data.geom_xpos[data.geom(\"green_sphere\").id].copy())\n",
" speeds.append(get_geom_speed(model, data, \"green_sphere\"))\n", " times.append(data.time)\n",
" mujoco.mj_step(model, data)\n", " speeds.append(get_geom_speed(model, data, \"green_sphere\"))\n",
" if len(frames) < data.time * framerate:\n", " mujoco.mj_step(model, data)\n",
" renderer.update_scene(data)\n", " if len(frames) < data.time * framerate:\n",
" modify_scene(renderer.scene)\n", " renderer.update_scene(data)\n",
" pixels = renderer.render()\n", " modify_scene(renderer.scene)\n",
" frames.append(pixels)\n", " pixels = renderer.render()\n",
" frames.append(pixels)\n",
"\n", "\n",
"media.show_video(frames, fps=framerate)" "media.show_video(frames, fps=framerate)"
] ]
@@ -2018,8 +2034,7 @@
"</mujoco>\n", "</mujoco>\n",
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(dominos_xml)\n", "model = mujoco.MjModel.from_xml_string(dominos_xml)\n",
"data = mujoco.MjData(model)\n", "data = mujoco.MjData(model)\n"
"renderer = mujoco.Renderer(model, height=1024, width=1440)"
] ]
}, },
{ {
@@ -2035,16 +2050,19 @@
"\n", "\n",
"duration = 2.5 # (seconds)\n", "duration = 2.5 # (seconds)\n",
"framerate = 60 # (Hz)\n", "framerate = 60 # (Hz)\n",
"height = 1024\n",
"width = 1440\n",
"\n", "\n",
"# Simulate and display video.\n", "# Simulate and display video.\n",
"frames = []\n", "frames = []\n",
"mujoco.mj_resetData(model, data) # Reset state and time.\n", "mujoco.mj_resetData(model, data) # Reset state and time.\n",
"while data.time < duration:\n", "with mujoco.Renderer(model, height, width) as renderer:\n",
" mujoco.mj_step(model, data)\n", " while data.time < duration:\n",
" if len(frames) < data.time * framerate:\n", " mujoco.mj_step(model, data)\n",
" renderer.update_scene(data, camera='top')\n", " if len(frames) < data.time * framerate:\n",
" pixels = renderer.render()\n", " renderer.update_scene(data, camera='top')\n",
" frames.append(pixels)\n", " pixels = renderer.render()\n",
" frames.append(pixels)\n",
"\n", "\n",
"media.show_video(frames, fps=framerate)" "media.show_video(frames, fps=framerate)"
] ]
@@ -2061,6 +2079,8 @@
"#@title Render from moving camera\n", "#@title Render from moving camera\n",
"\n", "\n",
"duration = 3 # (seconds)\n", "duration = 3 # (seconds)\n",
"height = 1024\n",
"width = 1440\n",
"\n", "\n",
"# find time when box is thrown (speed > 2cm/s)\n", "# find time when box is thrown (speed > 2cm/s)\n",
"throw_time = 0.0\n", "throw_time = 0.0\n",
@@ -2115,13 +2135,14 @@
"slowdown = 4 # 4x slow-down\n", "slowdown = 4 # 4x slow-down\n",
"mujoco.mj_resetData(model, data)\n", "mujoco.mj_resetData(model, data)\n",
"frames = []\n", "frames = []\n",
"while data.time < duration:\n", "with mujoco.Renderer(model, height, width) as renderer:\n",
" mujoco.mj_step(model, data)\n", " while data.time < duration:\n",
" if len(frames) < data.time * framerate * slowdown:\n", " mujoco.mj_step(model, data)\n",
" cam.distance, cam.azimuth, cam.elevation, cam.lookat = cam_motion()\n", " if len(frames) < data.time * framerate * slowdown:\n",
" renderer.update_scene(data, cam)\n", " cam.distance, cam.azimuth, cam.elevation, cam.lookat = cam_motion()\n",
" pixels = renderer.render()\n", " renderer.update_scene(data, cam)\n",
" frames.append(pixels)\n", " pixels = renderer.render()\n",
" frames.append(pixels)\n",
"\n", "\n",
"media.show_video(frames, fps=framerate)" "media.show_video(frames, fps=framerate)"
] ]
-12
View File
@@ -1,12 +0,0 @@
# This Makefile assumes that you have GLFW libraries and headers installed on,
# which is commonly available through your distro's package manager.
# On Debian and Ubuntu, GLFW can be installed via `apt install libglfw3-dev`.
COMMON=-O2 -I../include -L../lib -std=c++17 -pthread -Wl,-no-as-needed -Wl,-rpath,'$$ORIGIN'/../lib
.PHONY: all
all:
$(CXX) $(COMMON) testspeed.cc -lmujoco -o ../bin/testspeed
$(CXX) $(COMMON) compile.cc -lmujoco -o ../bin/compile
$(CXX) $(COMMON) basic.cc -lmujoco -lglfw -o ../bin/basic
$(CXX) $(COMMON) record.cc -lmujoco -lglfw -o ../bin/record
-18
View File
@@ -1,18 +0,0 @@
# This Makefile assumes that GLFW is installed via Homebrew.
# If your setup is different, you will need to set GLFWROOT manually.
# This Makefile also assumes that MuJoCo.app is present in /Applications.
GLFWROOT?=$(shell brew --prefix)
MUJOCOPATH?=/Applications/MuJoCo.app/Contents/Frameworks
CFLAGS=-O2 -F$(MUJOCOPATH) -I$(GLFWROOT)/include -pthread
CXXFLAGS=$(CFLAGS) -std=c++17 -stdlib=libc++
ALLFLAGS=$(CXXFLAGS) -L$(GLFWROOT)/lib -Wl,-rpath,$(MUJOCOPATH)
.PHONY: all
all:
clang++ $(ALLFLAGS) testspeed.cc -framework mujoco -o testspeed
clang++ $(ALLFLAGS) compile.cc -framework mujoco -o compile
clang++ $(ALLFLAGS) basic.cc -framework mujoco -lglfw -o basic
clang++ $(ALLFLAGS) record.cc -framework mujoco -lglfw -o record
-17
View File
@@ -1,17 +0,0 @@
# A copy of the GLFW library is required to build some sample programs.
# If this is not already installed on your system, download the WIN64 archive
# from https://github.com/glfw/glfw/releases, and copy files as follows:
# - Copy the entire `include/GLFW` subdirectory to `mujoco/include/GLFW`.
# - Copy glfw3dll.lib from the subdirectory corresponding into your compiler
# choice to `mujoco/lib/glfw3dll.lib`.
# - Copy glfw3.dll from the same subdirectory into `mujoco/bin/glfw3.dll`.
COMMON=/O2 /MT /EHsc /arch:AVX /I../include /Fe../bin/
.PHONY: all
all:
cl $(COMMON) testspeed.cc ../lib/mujoco.lib
cl $(COMMON) compile.cc ../lib/mujoco.lib
cl $(COMMON) basic.cc ../lib/glfw3dll.lib ../lib/mujoco.lib
cl $(COMMON) record.cc ../lib/glfw3dll.lib ../lib/mujoco.lib
del *.obj
+4
View File
@@ -104,6 +104,10 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang
endif() endif()
endif() endif()
if(NOT CMAKE_INTERPROCEDURAL_OPTIMIZATION AND (CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug"))
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
endif()
include(MujocoHarden) include(MujocoHarden)
set(EXTRA_COMPILE_OPTIONS ${EXTRA_COMPILE_OPTIONS} ${MUJOCO_HARDEN_COMPILE_OPTIONS}) set(EXTRA_COMPILE_OPTIONS ${EXTRA_COMPILE_OPTIONS} ${MUJOCO_HARDEN_COMPILE_OPTIONS})
set(EXTRA_LINK_OPTIONS ${EXTRA_LINK_OPTIONS} ${MUJOCO_HARDEN_LINK_OPTIONS}) set(EXTRA_LINK_OPTIONS ${EXTRA_LINK_OPTIONS} ${MUJOCO_HARDEN_LINK_OPTIONS})
+12 -10
View File
@@ -34,18 +34,17 @@ mjData* d[maxthread];
// per-thread statistics // per-thread statistics
int contacts[maxthread]; int contacts[maxthread];
int constraints[maxthread]; int constraints[maxthread];
double simtime[maxthread]; mjtNum simtime[maxthread];
// timer // timer
std::chrono::steady_clock::time_point tm_start;
mjtNum gettm(void) { mjtNum gettm(void) {
std::chrono::duration<double, std::micro> elapsed; using std::chrono::steady_clock;
elapsed = std::chrono::steady_clock::now() - tm_start; using Microseconds = std::chrono::duration<double, std::micro>;
static steady_clock::time_point tm_start = steady_clock::now();
auto elapsed = Microseconds(steady_clock::now() - tm_start);
return elapsed.count(); return elapsed.count();
} }
// deallocate and print message // deallocate and print message
int finish(const char* msg = NULL, mjModel* m = NULL) { int finish(const char* msg = NULL, mjModel* m = NULL) {
// deallocate model // deallocate model
@@ -87,7 +86,7 @@ void simulate(int id, int nstep, mjtNum* ctrl) {
constraints[id] = 0; constraints[id] = 0;
// run and time // run and time
double start = gettm(); mjtNum start = gettm();
for (int i=0; i < nstep; i++) { for (int i=0; i < nstep; i++) {
// inject pseudo-random control noise // inject pseudo-random control noise
mju_copy(d[id]->ctrl, ctrl + i*m->nu, m->nu); mju_copy(d[id]->ctrl, ctrl + i*m->nu, m->nu);
@@ -126,7 +125,7 @@ int main(int argc, char** argv) {
// read arguments // read arguments
int nstep = 10000, nthread = 0, npoolthread = 0; int nstep = 10000, nthread = 0, npoolthread = 0;
// inject small noise by default, to avoid fixed contact state // inject small noise by default, to avoid fixed contact state
mjtNum ctrlnoise = 0.01; double ctrlnoise = 0.01;
if (argc > 2 && (std::sscanf(argv[2], "%d", &nstep) != 1 || nstep <= 0)) { if (argc > 2 && (std::sscanf(argv[2], "%d", &nstep) != 1 || nstep <= 0)) {
return finish("Invalid nstep argument"); return finish("Invalid nstep argument");
} }
@@ -149,7 +148,7 @@ int main(int argc, char** argv) {
// get filename, determine file type // get filename, determine file type
std::string filename(argv[1]); std::string filename(argv[1]);
bool binary = (filename.find(".mjb") != std::string::npos); bool binary = (filename.find(".mjb") != std::string::npos); // NOLINT
// load model // load model
char error[1000] = "Could not load binary model"; char error[1000] = "Could not load binary model";
@@ -191,8 +190,11 @@ int main(int argc, char** argv) {
nstep, nstep,
nthread > 1 ? " per thread" : "", nthread > 1 ? " per thread" : "",
m->opt.timestep); m->opt.timestep);
if (sizeof(mjtNum) == 4) {
std::printf(", using single-precision");
}
if (npoolthread > 1) { if (npoolthread > 1) {
std::printf(", using %d threads for engine-internal threadpool", npoolthread); std::printf(", using %d threads", npoolthread);
} }
std::printf("...\n\n"); std::printf("...\n\n");
-11
View File
@@ -1,11 +0,0 @@
# This Makefile assumes that you have GLFW libraries and headers installed on,
# which is commonly available through your distro's package manager.
# On Debian and Ubuntu, GLFW can be installed via `apt install libglfw3-dev`.
COMMON=-O2 -I../include -L../lib -pthread -Wl,-no-as-needed -Wl,-rpath,'$$ORIGIN'/../lib
all:
$(CXX) $(COMMON) -std=c++17 -c simulate.cc
$(CC) $(COMMON) -std=c11 -c uitools.c
$(CXX) $(COMMON) -std=c++17 main.cc simulate.o uitools.o -lmujoco -lglfw -o ../bin/simulate
rm uitools.o simulate.o
-18
View File
@@ -1,18 +0,0 @@
# This Makefile assumes that GLFW is installed via Homebrew.
# If your setup is different, you will need to set GLFWROOT manually.
# This Makefile also assumes that MuJoCo.app is present in /Applications.
GLFWROOT?=$(shell brew --prefix)
MUJOCOPATH?=/Applications/MuJoCo.app/Contents/Frameworks
CFLAGS=-O2 -F$(MUJOCOPATH) -I$(GLFWROOT)/include -pthread
CXXFLAGS=$(CFLAGS) -std=c++17 -stdlib=libc++
ALLFLAGS=$(CXXFLAGS) -L$(GLFWROOT)/lib -Wl,-rpath,$(MUJOCOPATH)
all:
clang++ $(CXXFLAGS) -c macos_gui.mm
clang++ $(CXXFLAGS) -c simulate.cc
clang $(CFLAGS) -std=c11 -c uitools.c
clang++ $(CXXFLAGS) main.cc macos_gui.o simulate.o uitools.o -framework mujoco -framework Cocoa -lglfw -o simulate
rm *.o
-13
View File
@@ -1,13 +0,0 @@
# A copy of the GLFW library is required to build some sample programs.
# If this is not already installed on your system, download the WIN64 archive
# from https://github.com/glfw/glfw/releases, and copy files as follows:
# - Copy the entire `include/GLFW` subdirectory to `mujoco/include/GLFW`.
# - Copy glfw3dll.lib from the subdirectory corresponding into your compiler
# choice to `mujoco/lib/glfw3dll.lib`.
# - Copy glfw3.dll from the same subdirectory into `mujoco/bin/glfw3.dll`.
COMMON=/O2 /MT /EHsc /arch:AVX /I../include /Fe../bin/
all:
cl $(COMMON) main.cc simulate.cc uitools.c ../lib/glfw3dll.lib ../lib/mujoco.lib
del *.obj
+4
View File
@@ -104,6 +104,10 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang
endif() endif()
endif() endif()
if(NOT CMAKE_INTERPROCEDURAL_OPTIMIZATION AND (CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug"))
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
endif()
include(MujocoHarden) include(MujocoHarden)
set(EXTRA_COMPILE_OPTIONS ${EXTRA_COMPILE_OPTIONS} ${MUJOCO_HARDEN_COMPILE_OPTIONS}) set(EXTRA_COMPILE_OPTIONS ${EXTRA_COMPILE_OPTIONS} ${MUJOCO_HARDEN_COMPILE_OPTIONS})
set(EXTRA_LINK_OPTIONS ${EXTRA_LINK_OPTIONS} ${MUJOCO_HARDEN_LINK_OPTIONS}) set(EXTRA_LINK_OPTIONS ${EXTRA_LINK_OPTIONS} ${MUJOCO_HARDEN_LINK_OPTIONS})
+2 -1
View File
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <cerrno>
#include <chrono> #include <chrono>
#include <cstdint> #include <cstdint>
#include <cstdio> #include <cstdio>
@@ -334,7 +335,7 @@ void PhysicsLoop(mj::Simulate& sim) {
// misalignment condition: distance from target sim time is bigger than syncmisalign // misalignment condition: distance from target sim time is bigger than syncmisalign
bool misaligned = bool misaligned =
mju_abs(Seconds(elapsedCPU).count()/slowdown - elapsedSim) > syncMisalign; std::abs(Seconds(elapsedCPU).count()/slowdown - elapsedSim) > syncMisalign;
// out-of-sync (for any reason): reset sync times, step // out-of-sync (for any reason): reset sync times, step
if (elapsedSim < 0 || elapsedCPU.count() < 0 || syncCPU.time_since_epoch().count() == 0 || if (elapsedSim < 0 || elapsedCPU.count() < 0 || syncCPU.time_since_epoch().count() == 0 ||
+105 -97
View File
@@ -117,13 +117,13 @@ enum {
// file section of UI // file section of UI
const mjuiDef defFile[] = { const mjuiDef defFile[] = {
{mjITEM_SECTION, "File", 1, nullptr, "AF"}, {mjITEM_SECTION, "File", mjPRESERVE, nullptr, "AF"},
{mjITEM_BUTTON, "Save xml", 2, nullptr, ""}, {mjITEM_BUTTON, "Save xml", 2, nullptr, ""},
{mjITEM_BUTTON, "Save mjb", 2, nullptr, ""}, {mjITEM_BUTTON, "Save mjb", 2, nullptr, ""},
{mjITEM_BUTTON, "Print model", 2, nullptr, "CM"}, {mjITEM_BUTTON, "Print model", 2, nullptr, "CM"},
{mjITEM_BUTTON, "Print data", 2, nullptr, "CD"}, {mjITEM_BUTTON, "Print data", 2, nullptr, "CD"},
{mjITEM_BUTTON, "Quit", 1, nullptr, "CQ"}, {mjITEM_BUTTON, "Quit", 1, nullptr, "CQ"},
{mjITEM_BUTTON, "Screenshot", 2, nullptr, "CP"}, {mjITEM_BUTTON, "Screenshot", 2, nullptr, "CP"},
{mjITEM_END} {mjITEM_END}
}; };
@@ -674,15 +674,15 @@ void UpdateWatch(mj::Simulate* sim, const mjModel* m, const mjData* d) {
//---------------------------------- UI construction ----------------------------------------------- //---------------------------------- UI construction -----------------------------------------------
// make physics section of UI // make physics section of UI
void MakePhysicsSection(mj::Simulate* sim, int oldstate) { void MakePhysicsSection(mj::Simulate* sim) {
mjOption* opt = sim->is_passive_ ? &sim->scnstate_.model.opt : &sim->m_->opt; mjOption* opt = sim->is_passive_ ? &sim->scnstate_.model.opt : &sim->m_->opt;
mjuiDef defPhysics[] = { mjuiDef defPhysics[] = {
{mjITEM_SECTION, "Physics", oldstate, nullptr, "AP"}, {mjITEM_SECTION, "Physics", mjPRESERVE, nullptr, "AP"},
{mjITEM_SELECT, "Integrator", 2, &(opt->integrator), "Euler\nRK4\nimplicit\nimplicitfast"}, {mjITEM_SELECT, "Integrator", 2, &(opt->integrator), "Euler\nRK4\nimplicit\nimplicitfast"},
{mjITEM_SELECT, "Cone", 2, &(opt->cone), "Pyramidal\nElliptic"}, {mjITEM_SELECT, "Cone", 2, &(opt->cone), "Pyramidal\nElliptic"},
{mjITEM_SELECT, "Jacobian", 2, &(opt->jacobian), "Dense\nSparse\nAuto"}, {mjITEM_SELECT, "Jacobian", 2, &(opt->jacobian), "Dense\nSparse\nAuto"},
{mjITEM_SELECT, "Solver", 2, &(opt->solver), "PGS\nCG\nNewton"}, {mjITEM_SELECT, "Solver", 2, &(opt->solver), "PGS\nCG\nNewton"},
{mjITEM_SEPARATOR, "Algorithmic Parameters", 1}, {mjITEM_SEPARATOR, "Algorithmic Parameters", mjPRESERVE},
{mjITEM_EDITNUM, "Timestep", 2, &(opt->timestep), "1 0 1"}, {mjITEM_EDITNUM, "Timestep", 2, &(opt->timestep), "1 0 1"},
{mjITEM_EDITINT, "Iterations", 2, &(opt->iterations), "1 0 1000"}, {mjITEM_EDITINT, "Iterations", 2, &(opt->iterations), "1 0 1000"},
{mjITEM_EDITNUM, "Tolerance", 2, &(opt->tolerance), "1 0 1"}, {mjITEM_EDITNUM, "Tolerance", 2, &(opt->tolerance), "1 0 1"},
@@ -695,22 +695,22 @@ void MakePhysicsSection(mj::Simulate* sim, int oldstate) {
{mjITEM_EDITNUM, "API Rate", 2, &(opt->apirate), "1 0 1000"}, {mjITEM_EDITNUM, "API Rate", 2, &(opt->apirate), "1 0 1000"},
{mjITEM_EDITINT, "SDF Iter", 2, &(opt->sdf_iterations), "1 1 20"}, {mjITEM_EDITINT, "SDF Iter", 2, &(opt->sdf_iterations), "1 1 20"},
{mjITEM_EDITINT, "SDF Init", 2, &(opt->sdf_initpoints), "1 1 100"}, {mjITEM_EDITINT, "SDF Init", 2, &(opt->sdf_initpoints), "1 1 100"},
{mjITEM_SEPARATOR, "Physical Parameters", 1}, {mjITEM_SEPARATOR, "Physical Parameters", mjPRESERVE},
{mjITEM_EDITNUM, "Gravity", 2, opt->gravity, "3"}, {mjITEM_EDITNUM, "Gravity", 2, opt->gravity, "3"},
{mjITEM_EDITNUM, "Wind", 2, opt->wind, "3"}, {mjITEM_EDITNUM, "Wind", 2, opt->wind, "3"},
{mjITEM_EDITNUM, "Magnetic", 2, opt->magnetic, "3"}, {mjITEM_EDITNUM, "Magnetic", 2, opt->magnetic, "3"},
{mjITEM_EDITNUM, "Density", 2, &(opt->density), "1"}, {mjITEM_EDITNUM, "Density", 2, &(opt->density), "1"},
{mjITEM_EDITNUM, "Viscosity", 2, &(opt->viscosity), "1"}, {mjITEM_EDITNUM, "Viscosity", 2, &(opt->viscosity), "1"},
{mjITEM_EDITNUM, "Imp Ratio", 2, &(opt->impratio), "1"}, {mjITEM_EDITNUM, "Imp Ratio", 2, &(opt->impratio), "1"},
{mjITEM_SEPARATOR, "Disable Flags", 1}, {mjITEM_SEPARATOR, "Disable Flags", mjPRESERVE},
{mjITEM_END} {mjITEM_END}
}; };
mjuiDef defEnableFlags[] = { mjuiDef defEnableFlags[] = {
{mjITEM_SEPARATOR, "Enable Flags", 1}, {mjITEM_SEPARATOR, "Enable Flags", mjPRESERVE},
{mjITEM_END} {mjITEM_END}
}; };
mjuiDef defOverride[] = { mjuiDef defOverride[] = {
{mjITEM_SEPARATOR, "Contact Override", 1}, {mjITEM_SEPARATOR, "Contact Override", mjPRESERVE},
{mjITEM_EDITNUM, "Margin", 2, &(opt->o_margin), "1"}, {mjITEM_EDITNUM, "Margin", 2, &(opt->o_margin), "1"},
{mjITEM_EDITNUM, "Sol Imp", 2, &(opt->o_solimp), "5"}, {mjITEM_EDITNUM, "Sol Imp", 2, &(opt->o_solimp), "5"},
{mjITEM_EDITNUM, "Sol Ref", 2, &(opt->o_solref), "2"}, {mjITEM_EDITNUM, "Sol Ref", 2, &(opt->o_solref), "2"},
@@ -718,7 +718,7 @@ void MakePhysicsSection(mj::Simulate* sim, int oldstate) {
{mjITEM_END} {mjITEM_END}
}; };
mjuiDef defDisableActuator[] = { mjuiDef defDisableActuator[] = {
{mjITEM_SEPARATOR, "Actuator Group Enable", 1}, {mjITEM_SEPARATOR, "Actuator Group Enable", mjPRESERVE},
{mjITEM_CHECKBYTE, "Act Group 0", 2, sim->enableactuator+0, ""}, {mjITEM_CHECKBYTE, "Act Group 0", 2, sim->enableactuator+0, ""},
{mjITEM_CHECKBYTE, "Act Group 1", 2, sim->enableactuator+1, ""}, {mjITEM_CHECKBYTE, "Act Group 1", 2, sim->enableactuator+1, ""},
{mjITEM_CHECKBYTE, "Act Group 2", 2, sim->enableactuator+2, ""}, {mjITEM_CHECKBYTE, "Act Group 2", 2, sim->enableactuator+2, ""},
@@ -752,57 +752,39 @@ void MakePhysicsSection(mj::Simulate* sim, int oldstate) {
// add actuator group enable/disable // add actuator group enable/disable
mjui_add(&sim->ui0, defDisableActuator); mjui_add(&sim->ui0, defDisableActuator);
// make some subsections closed by default
for (int i=0; i < sim->ui0.sect[SECT_PHYSICS].nitem; i++) {
mjuiItem* it = sim->ui0.sect[SECT_PHYSICS].item + i;
// close less useful subsections
if (it->type == mjITEM_SEPARATOR) {
if (mju::strcmp_arr(it->name, "Actuator Group Enable") &&
mju::strcmp_arr(it->name, "Contact Override") &&
mju::strcmp_arr(it->name, "Physical Parameters")) {
it->state = mjSEPCLOSED+1;
}
}
}
} }
// make rendering section of UI // make rendering section of UI
void MakeRenderingSection(mj::Simulate* sim, const mjModel* m, int oldstate) { void MakeRenderingSection(mj::Simulate* sim, const mjModel* m) {
mjuiDef defRendering[] = { mjuiDef defRendering[] = {
{ {mjITEM_SECTION, "Rendering", mjPRESERVE, nullptr, "AR"},
mjITEM_SECTION, {mjITEM_SELECT, "Camera", 2, &(sim->camera), "Free\nTracking"},
"Rendering", {mjITEM_SELECT, "Label", 2, &(sim->opt.label),
oldstate,
nullptr,
"AR"
},
{
mjITEM_SELECT,
"Camera",
2,
&(sim->camera),
"Free\nTracking"
},
{
mjITEM_SELECT,
"Label",
2,
&(sim->opt.label),
"None\nBody\nJoint\nGeom\nSite\nCamera\nLight\nTendon\n" "None\nBody\nJoint\nGeom\nSite\nCamera\nLight\nTendon\n"
"Actuator\nConstraint\nFlex\nSkin\nSelection\nSel Pnt\nContact\nForce\nIsland" "Actuator\nConstraint\nFlex\nSkin\nSelection\nSel Pnt\nContact\nForce\nIsland"
}, },
{ {mjITEM_SELECT, "Frame", 2, &(sim->opt.frame),
mjITEM_SELECT,
"Frame",
2,
&(sim->opt.frame),
"None\nBody\nGeom\nSite\nCamera\nLight\nContact\nWorld" "None\nBody\nGeom\nSite\nCamera\nLight\nContact\nWorld"
}, },
{ {mjITEM_BUTTON, "Copy camera", 2, nullptr, ""},
mjITEM_BUTTON, {mjITEM_SEPARATOR, "Model Elements", 1},
"Copy camera", {mjITEM_END}
2,
nullptr,
""
},
{
mjITEM_SEPARATOR,
"Model Elements",
1
},
{
mjITEM_END
}
}; };
mjuiDef defOpenGL[] = { mjuiDef defOpenGL[] = {
{mjITEM_SEPARATOR, "OpenGL Effects", 1}, {mjITEM_SEPARATOR, "OpenGL Effects", 1},
@@ -876,18 +858,18 @@ void MakeRenderingSection(mj::Simulate* sim, const mjModel* m, int oldstate) {
} }
// make visualization section of UI // make visualization section of UI
void MakeVisualizationSection(mj::Simulate* sim, const mjModel* m, int oldstate) { void MakeVisualizationSection(mj::Simulate* sim, const mjModel* m) {
mjStatistic* stat = sim->is_passive_ ? &sim->scnstate_.model.stat : &sim->m_->stat; mjStatistic* stat = sim->is_passive_ ? &sim->scnstate_.model.stat : &sim->m_->stat;
mjVisual* vis = sim->is_passive_ ? &sim->scnstate_.model.vis : &sim->m_->vis; mjVisual* vis = sim->is_passive_ ? &sim->scnstate_.model.vis : &sim->m_->vis;
mjuiDef defVisualization[] = { mjuiDef defVisualization[] = {
{mjITEM_SECTION, "Visualization", oldstate, nullptr, "AV"}, {mjITEM_SECTION, "Visualization", mjPRESERVE, nullptr, "AV"},
{mjITEM_SEPARATOR, "Headlight", 1}, {mjITEM_SEPARATOR, "Headlight", 1},
{mjITEM_RADIO, "Active", 5, &(vis->headlight.active), "Off\nOn"}, {mjITEM_RADIO, "Active", 5, &(vis->headlight.active), "Off\nOn"},
{mjITEM_EDITFLOAT, "Ambient", 2, &(vis->headlight.ambient), "3"}, {mjITEM_EDITFLOAT, "Ambient", 2, &(vis->headlight.ambient), "3"},
{mjITEM_EDITFLOAT, "Diffuse", 2, &(vis->headlight.diffuse), "3"}, {mjITEM_EDITFLOAT, "Diffuse", 2, &(vis->headlight.diffuse), "3"},
{mjITEM_EDITFLOAT, "Specular", 2, &(vis->headlight.specular), "3"}, {mjITEM_EDITFLOAT, "Specular", 2, &(vis->headlight.specular), "3"},
{mjITEM_SEPARATOR, "Free Camera", 1}, {mjITEM_SEPARATOR, "Free Camera", 1},
{mjITEM_RADIO, "Orthographic", 2, &(vis->global.orthographic), "No\nYes"}, {mjITEM_RADIO, "Orthographic", 2, &(vis->global.orthographic), "No\nYes"},
{mjITEM_EDITFLOAT, "Field of view", 2, &(vis->global.fovy), "1"}, {mjITEM_EDITFLOAT, "Field of view", 2, &(vis->global.fovy), "1"},
{mjITEM_EDITNUM, "Center", 2, &(stat->center), "3"}, {mjITEM_EDITNUM, "Center", 2, &(stat->center), "3"},
@@ -911,8 +893,8 @@ void MakeVisualizationSection(mj::Simulate* sim, const mjModel* m, int oldstate)
{mjITEM_EDITFLOAT, "Haze", 2, &(vis->map.haze), "1"}, {mjITEM_EDITFLOAT, "Haze", 2, &(vis->map.haze), "1"},
{mjITEM_EDITFLOAT, "Shadow clip", 2, &(vis->map.shadowclip), "1"}, {mjITEM_EDITFLOAT, "Shadow clip", 2, &(vis->map.shadowclip), "1"},
{mjITEM_EDITFLOAT, "Shadow scale", 2, &(vis->map.shadowscale), "1"}, {mjITEM_EDITFLOAT, "Shadow scale", 2, &(vis->map.shadowscale), "1"},
{mjITEM_SEPARATOR, "Scale", 1}, {mjITEM_SEPARATOR, "Scale", mjPRESERVE},
{mjITEM_EDITNUM, "All [meansize]", 2, &(stat->meansize), "1"}, {mjITEM_EDITNUM, "All (meansize)", 2, &(stat->meansize), "1"},
{mjITEM_EDITFLOAT, "Force width", 2, &(vis->scale.forcewidth), "1"}, {mjITEM_EDITFLOAT, "Force width", 2, &(vis->scale.forcewidth), "1"},
{mjITEM_EDITFLOAT, "Contact width", 2, &(vis->scale.contactwidth), "1"}, {mjITEM_EDITFLOAT, "Contact width", 2, &(vis->scale.contactwidth), "1"},
{mjITEM_EDITFLOAT, "Contact height", 2, &(vis->scale.contactheight), "1"}, {mjITEM_EDITFLOAT, "Contact height", 2, &(vis->scale.contactheight), "1"},
@@ -929,17 +911,43 @@ void MakeVisualizationSection(mj::Simulate* sim, const mjModel* m, int oldstate)
{mjITEM_EDITFLOAT, "Frame width", 2, &(vis->scale.framewidth), "1"}, {mjITEM_EDITFLOAT, "Frame width", 2, &(vis->scale.framewidth), "1"},
{mjITEM_EDITFLOAT, "Constraint", 2, &(vis->scale.constraint), "1"}, {mjITEM_EDITFLOAT, "Constraint", 2, &(vis->scale.constraint), "1"},
{mjITEM_EDITFLOAT, "Slider-crank", 2, &(vis->scale.slidercrank), "1"}, {mjITEM_EDITFLOAT, "Slider-crank", 2, &(vis->scale.slidercrank), "1"},
{mjITEM_SEPARATOR, "RGBA", mjPRESERVE},
{mjITEM_EDITFLOAT, "fog", 2, &(vis->rgba.fog), "4"},
{mjITEM_EDITFLOAT, "haze", 2, &(vis->rgba.haze), "4"},
{mjITEM_EDITFLOAT, "force", 2, &(vis->rgba.force), "4"},
{mjITEM_EDITFLOAT, "inertia", 2, &(vis->rgba.inertia), "4"},
{mjITEM_EDITFLOAT, "joint", 2, &(vis->rgba.joint), "4"},
{mjITEM_EDITFLOAT, "actuator", 2, &(vis->rgba.actuator), "4"},
{mjITEM_EDITFLOAT, "actnegative", 2, &(vis->rgba.actuatornegative), "4"},
{mjITEM_EDITFLOAT, "actpositive", 2, &(vis->rgba.actuatorpositive), "4"},
{mjITEM_EDITFLOAT, "com", 2, &(vis->rgba.com), "4"},
{mjITEM_EDITFLOAT, "camera", 2, &(vis->rgba.camera), "4"},
{mjITEM_EDITFLOAT, "light", 2, &(vis->rgba.light), "4"},
{mjITEM_EDITFLOAT, "selectpoint", 2, &(vis->rgba.selectpoint), "4"},
{mjITEM_EDITFLOAT, "connect", 2, &(vis->rgba.connect), "4"},
{mjITEM_EDITFLOAT, "contactpoint", 2, &(vis->rgba.contactpoint), "4"},
{mjITEM_EDITFLOAT, "contactforce", 2, &(vis->rgba.contactforce), "4"},
{mjITEM_EDITFLOAT, "contactfriction", 2, &(vis->rgba.contactfriction), "4"},
{mjITEM_EDITFLOAT, "contacttorque", 2, &(vis->rgba.contacttorque), "4"},
{mjITEM_EDITFLOAT, "contactgap", 2, &(vis->rgba.contactgap), "4"},
{mjITEM_EDITFLOAT, "rangefinder", 2, &(vis->rgba.rangefinder), "4"},
{mjITEM_EDITFLOAT, "constraint", 2, &(vis->rgba.constraint), "4"},
{mjITEM_EDITFLOAT, "slidercrank", 2, &(vis->rgba.slidercrank), "4"},
{mjITEM_EDITFLOAT, "crankbroken", 2, &(vis->rgba.crankbroken), "4"},
{mjITEM_EDITFLOAT, "frustum", 2, &(vis->rgba.frustum), "4"},
{mjITEM_EDITFLOAT, "bv", 2, &(vis->rgba.bv), "4"},
{mjITEM_EDITFLOAT, "bvactive", 2, &(vis->rgba.bvactive), "4"},
{mjITEM_END} {mjITEM_END}
}; };
// add rendering standard // add visualization section
mjui_add(&sim->ui0, defVisualization); mjui_add(&sim->ui0, defVisualization);
} }
// make group section of UI // make group section of UI
void MakeGroupSection(mj::Simulate* sim, int oldstate) { void MakeGroupSection(mj::Simulate* sim) {
mjuiDef defGroup[] = { mjuiDef defGroup[] = {
{mjITEM_SECTION, "Group enable", oldstate, nullptr, "AG"}, {mjITEM_SECTION, "Group enable", mjPRESERVE, nullptr, "AG"},
{mjITEM_SEPARATOR, "Geom groups", 1}, {mjITEM_SEPARATOR, "Geom groups", 1},
{mjITEM_CHECKBYTE, "Geom 0", 2, sim->opt.geomgroup, " 0"}, {mjITEM_CHECKBYTE, "Geom 0", 2, sim->opt.geomgroup, " 0"},
{mjITEM_CHECKBYTE, "Geom 1", 2, sim->opt.geomgroup+1, " 1"}, {mjITEM_CHECKBYTE, "Geom 1", 2, sim->opt.geomgroup+1, " 1"},
@@ -997,9 +1005,9 @@ void MakeGroupSection(mj::Simulate* sim, int oldstate) {
} }
// make joint section of UI // make joint section of UI
void MakeJointSection(mj::Simulate* sim, int oldstate) { void MakeJointSection(mj::Simulate* sim) {
mjuiDef defJoint[] = { mjuiDef defJoint[] = {
{mjITEM_SECTION, "Joint", oldstate, nullptr, "AJ"}, {mjITEM_SECTION, "Joint", mjPRESERVE, nullptr, "AJ"},
{mjITEM_END} {mjITEM_END}
}; };
mjuiDef defSlider[] = { mjuiDef defSlider[] = {
@@ -1050,9 +1058,9 @@ void MakeJointSection(mj::Simulate* sim, int oldstate) {
} }
// make control section of UI // make control section of UI
void MakeControlSection(mj::Simulate* sim, int oldstate) { void MakeControlSection(mj::Simulate* sim) {
mjuiDef defControl[] = { mjuiDef defControl[] = {
{mjITEM_SECTION, "Control", oldstate, nullptr, "AC"}, {mjITEM_SECTION, "Control", mjPRESERVE, nullptr, "AC"},
{mjITEM_BUTTON, "Clear all", 2}, {mjITEM_BUTTON, "Clear all", 2},
{mjITEM_END} {mjITEM_END}
}; };
@@ -1107,35 +1115,17 @@ void MakeControlSection(mj::Simulate* sim, int oldstate) {
// make model-dependent UI sections // make model-dependent UI sections
void MakeUiSections(mj::Simulate* sim, const mjModel* m, const mjData* d) { void MakeUiSections(mj::Simulate* sim, const mjModel* m, const mjData* d) {
// get section open-close state, UI 0
int oldstate0[NSECT0];
for (int i=0; i<NSECT0; i++) {
oldstate0[i] = 0;
if (sim->ui0.nsect>i) {
oldstate0[i] = sim->ui0.sect[i].state;
}
}
// get section open-close state, UI 1
int oldstate1[NSECT1];
for (int i=0; i<NSECT1; i++) {
oldstate1[i] = 0;
if (sim->ui1.nsect>i) {
oldstate1[i] = sim->ui1.sect[i].state;
}
}
// clear model-dependent sections of UI // clear model-dependent sections of UI
sim->ui0.nsect = SECT_PHYSICS; sim->ui0.nsect = SECT_PHYSICS;
sim->ui1.nsect = 0; sim->ui1.nsect = 0;
// make // make
MakePhysicsSection(sim, oldstate0[SECT_PHYSICS]); MakePhysicsSection(sim);
MakeRenderingSection(sim, m, oldstate0[SECT_RENDERING]); MakeRenderingSection(sim, m);
MakeVisualizationSection(sim, m, oldstate0[SECT_VISUALIZATION]); MakeVisualizationSection(sim, m);
MakeGroupSection(sim, oldstate0[SECT_GROUP]); MakeGroupSection(sim);
MakeJointSection(sim, oldstate1[SECT_JOINT]); MakeJointSection(sim);
MakeControlSection(sim, oldstate1[SECT_CONTROL]); MakeControlSection(sim);
} }
//---------------------------------- utility functions --------------------------------------------- //---------------------------------- utility functions ---------------------------------------------
@@ -1165,7 +1155,9 @@ void CopyPose(mj::Simulate* sim, const mjModel* m, const mjData* d) {
// millisecond timer, for MuJoCo built-in profiler // millisecond timer, for MuJoCo built-in profiler
mjtNum Timer() { mjtNum Timer() {
return Milliseconds(mj::Simulate::Clock::now().time_since_epoch()).count(); static auto start = mj::Simulate::Clock::now();
auto elapsed = Milliseconds(mj::Simulate::Clock::now() - start);
return elapsed.count();
} }
// clear all times // clear all times
@@ -1263,7 +1255,7 @@ int ComputeFontScale(const mj::PlatformUIAdapter& platform_ui) {
fs = 150; fs = 150;
} }
fs = mju_round(fs * 0.02) * 50; fs = mju_round(fs * 0.02) * 50;
fs = mjMIN(250, mjMAX(100, fs)); fs = mjMIN(300, mjMAX(100, fs));
return fs; return fs;
} }
@@ -1320,9 +1312,22 @@ void UiLayout(mjuiState* state) {
rect[3].height = rect[0].height; rect[3].height = rect[0].height;
} }
// modify UI
void UiModify(mjUI* ui, mjuiState* state, mjrContext* con) { void UiModify(mjUI* ui, mjuiState* state, mjrContext* con) {
mjui_resize(ui, con); mjui_resize(ui, con);
mjr_addAux(ui->auxid, ui->width, ui->maxheight, ui->spacing.samples, con);
// remake aux buffer only if missing or different
int id = ui->auxid;
if (con->auxFBO[id] == 0 ||
con->auxFBO_r[id] == 0 ||
con->auxColor[id] == 0 ||
con->auxColor_r[id] == 0 ||
con->auxWidth[id] != ui->width ||
con->auxHeight[id] != ui->maxheight ||
con->auxSamples[id] != ui->spacing.samples) {
mjr_addAux(id, ui->width, ui->maxheight, ui->spacing.samples, con);
}
UiLayout(state); UiLayout(state);
mjui_update(-1, -1, ui, state, con); mjui_update(-1, -1, ui, state, con);
} }
@@ -1502,7 +1507,7 @@ void UiEvent(mjuiState* state) {
// remake joint section if joint group changed // remake joint section if joint group changed
if (it->name[0]=='J' && it->name[1]=='o') { if (it->name[0]=='J' && it->name[1]=='o') {
sim->ui1.nsect = SECT_JOINT; sim->ui1.nsect = SECT_JOINT;
MakeJointSection(sim, sim->ui1.sect[SECT_JOINT].state); MakeJointSection(sim);
sim->ui1.nsect = NSECT1; sim->ui1.nsect = NSECT1;
UiModify(&sim->ui1, state, &sim->platform_ui->mjr_context()); UiModify(&sim->ui1, state, &sim->platform_ui->mjr_context());
} }
@@ -2455,7 +2460,7 @@ void Simulate::Render() {
if (pending_.ui_remake_ctrl) { if (pending_.ui_remake_ctrl) {
if (this->ui1_enable && this->ui1.sect[SECT_CONTROL].state) { if (this->ui1_enable && this->ui1.sect[SECT_CONTROL].state) {
this->ui1.nsect = SECT_CONTROL; this->ui1.nsect = SECT_CONTROL;
MakeControlSection(this, this->ui1.sect[SECT_CONTROL].state); MakeControlSection(this);
this->ui1.nsect = NSECT1; this->ui1.nsect = NSECT1;
UiModify(&this->ui1, &this->uistate, &this->platform_ui->mjr_context()); UiModify(&this->ui1, &this->uistate, &this->platform_ui->mjr_context());
} }
@@ -2643,12 +2648,15 @@ void Simulate::RenderLoop() {
this->platform_ui->SetEventCallback(UiEvent); this->platform_ui->SetEventCallback(UiEvent);
this->platform_ui->SetLayoutCallback(UiLayout); this->platform_ui->SetLayoutCallback(UiLayout);
// populate uis with standard sections // populate uis with standard sections, open some sections initially
this->ui0.userdata = this; this->ui0.userdata = this;
this->ui1.userdata = this; this->ui1.userdata = this;
mjui_add(&this->ui0, defFile); mjui_add(&this->ui0, defFile);
mjui_add(&this->ui0, this->def_option); mjui_add(&this->ui0, this->def_option);
mjui_add(&this->ui0, this->def_simulation); mjui_add(&this->ui0, this->def_simulation);
this->ui0.sect[0].state = 1;
this->ui0.sect[1].state = 1;
this->ui0.sect[2].state = 1;
mjui_add(&this->ui0, this->def_watch); mjui_add(&this->ui0, this->def_watch);
UiModify(&this->ui0, &this->uistate, &this->platform_ui->mjr_context()); UiModify(&this->ui0, &this->uistate, &this->platform_ui->mjr_context());
UiModify(&this->ui1, &this->uistate, &this->platform_ui->mjr_context()); UiModify(&this->ui1, &this->uistate, &this->platform_ui->mjr_context());
+3 -3
View File
@@ -265,7 +265,7 @@ class Simulate {
// Constant arrays needed for the option section of UI and the UI interface // Constant arrays needed for the option section of UI and the UI interface
// TODO setting the size here is not ideal // TODO setting the size here is not ideal
const mjuiDef def_option[13] = { const mjuiDef def_option[13] = {
{mjITEM_SECTION, "Option", 1, nullptr, "AO"}, {mjITEM_SECTION, "Option", mjPRESERVE, nullptr, "AO"},
{mjITEM_CHECKINT, "Help", 2, &this->help, " #290"}, {mjITEM_CHECKINT, "Help", 2, &this->help, " #290"},
{mjITEM_CHECKINT, "Info", 2, &this->info, " #291"}, {mjITEM_CHECKINT, "Info", 2, &this->info, " #291"},
{mjITEM_CHECKINT, "Profiler", 2, &this->profiler, " #292"}, {mjITEM_CHECKINT, "Profiler", 2, &this->profiler, " #292"},
@@ -287,7 +287,7 @@ class Simulate {
// simulation section of UI // simulation section of UI
const mjuiDef def_simulation[14] = { const mjuiDef def_simulation[14] = {
{mjITEM_SECTION, "Simulation", 1, nullptr, "AS"}, {mjITEM_SECTION, "Simulation", mjPRESERVE, nullptr, "AS"},
{mjITEM_RADIO, "", 5, &this->run, "Pause\nRun"}, {mjITEM_RADIO, "", 5, &this->run, "Pause\nRun"},
{mjITEM_BUTTON, "Reset", 2, nullptr, " #259"}, {mjITEM_BUTTON, "Reset", 2, nullptr, " #259"},
{mjITEM_BUTTON, "Reload", 5, nullptr, "CL"}, {mjITEM_BUTTON, "Reload", 5, nullptr, "CL"},
@@ -306,7 +306,7 @@ class Simulate {
// watch section of UI // watch section of UI
const mjuiDef def_watch[5] = { const mjuiDef def_watch[5] = {
{mjITEM_SECTION, "Watch", 0, nullptr, "AW"}, {mjITEM_SECTION, "Watch", mjPRESERVE, nullptr, "AW"},
{mjITEM_EDITTXT, "Field", 2, this->field, "qpos"}, {mjITEM_EDITTXT, "Field", 2, this->field, "qpos"},
{mjITEM_EDITINT, "Index", 2, &this->index, "1"}, {mjITEM_EDITINT, "Index", 2, &this->index, "1"},
{mjITEM_STATIC, "Value", 2, nullptr, " "}, {mjITEM_STATIC, "Value", 2, nullptr, " "},
+4
View File
@@ -21,6 +21,8 @@ set(MUJOCO_ENGINE_SRCS
engine_collision_convex.h engine_collision_convex.h
engine_collision_driver.c engine_collision_driver.c
engine_collision_driver.h engine_collision_driver.h
engine_collision_gjk.c
engine_collision_gjk.h
engine_collision_primitive.c engine_collision_primitive.c
engine_collision_primitive.h engine_collision_primitive.h
engine_collision_sdf.c engine_collision_sdf.c
@@ -45,6 +47,8 @@ set(MUJOCO_ENGINE_SRCS
engine_io.c engine_io.c
engine_io.h engine_io.h
engine_macro.h engine_macro.h
engine_name.c
engine_name.h
engine_passive.c engine_passive.c
engine_passive.h engine_passive.h
engine_plugin.cc engine_plugin.cc
+6 -6
View File
@@ -806,8 +806,8 @@ int mjc_BoxBox(const mjModel* M, const mjData* D, mjContact* con, int g1, int g2
if (q2) { if (q2) {
mju_mulMatMatT3(r, rotmore, rot); mju_mulMatMatT3(r, rotmore, rot);
// mju_rotVecMat(p,pos12,rotmore); // mju_mulMatVec3(p,rotmore,pos12);
// mju_rotVecMat(tmp1,size2,rotmore); // mju_mulMatVec3(tmp1,rotmore,size2);
rotaxis(p, pos12); rotaxis(p, pos12);
rotaxis(tmp1, size2); rotaxis(tmp1, size2);
@@ -818,8 +818,8 @@ int mjc_BoxBox(const mjModel* M, const mjData* D, mjContact* con, int g1, int g2
rotmatx(r, rot); rotmatx(r, rot);
// mju_rotVecMat(p,pos21,rotmore); // mju_mulMatVec3(p,rotmore,pos21);
// mju_rotVecMat(tmp1,size1,rotmore); // mju_mulMatVec3(tmp1,rotmore,size1);
rotaxis(p, pos21); rotaxis(p, pos21);
rotaxis(tmp1, size1); rotaxis(tmp1, size1);
@@ -1074,8 +1074,8 @@ edgeedge:
f2 = -1; f2 = -1;
} }
// mju_rotVecMat(p,pos21,rotmore); // mju_mulMatVec3(p,rotmore,pos21);
// mju_rotVecMat(rnorm,clnorm,rotmore); // mju_mulMatVec3(rnorm,rotmore,clnorm);
rotaxis(p, pos21); rotaxis(p, pos21);
rotaxis(rnorm, clnorm); rotaxis(rnorm, clnorm);
+65 -56
View File
@@ -34,25 +34,31 @@
// ccd center function // ccd center function
void mjccd_center(const void *obj, ccd_vec3_t *center) { void mjccd_center(const void *obj, ccd_vec3_t *center) {
const mjtCCD* ccd = (const mjtCCD*)obj; mjc_center(center->v, (const mjCCDObj*) obj);
int g = ccd->geom; }
int f = ccd->flex;
int e = ccd->elem;
int v = ccd->vert;
// center function for convex collision algorithms
void mjc_center(mjtNum res[3], const mjCCDObj *obj) {
int g = obj->geom;
int f = obj->flex;
int e = obj->elem;
int v = obj->vert;
// return geom position // return geom position
if (g >= 0) { if (g >= 0) {
mju_copy3(center->v, ccd->data->geom_xpos + 3*g); mju_copy3(res, obj->data->geom_xpos + 3*g);
} }
// return flex element position // return flex element position
else if (e >= 0) { else if (e >= 0) {
mju_copy3(center->v, ccd->data->flexelem_aabb + 6*(ccd->model->flex_elemadr[f]+e)); mju_copy3(res, obj->data->flexelem_aabb + 6*(obj->model->flex_elemadr[f]+e));
} }
// return flex vertex position // return flex vertex position
else { else {
mju_copy3(center->v, ccd->data->flexvert_xpos + 3*(ccd->model->flex_vertadr[f]+v)); mju_copy3(res, obj->data->flexvert_xpos + 3*(obj->model->flex_vertadr[f]+v));
} }
} }
@@ -60,21 +66,25 @@ void mjccd_center(const void *obj, ccd_vec3_t *center) {
// ccd support function // ccd support function
void mjccd_support(const void *obj, const ccd_vec3_t *_dir, ccd_vec3_t *vec) { void mjccd_support(const void *obj, const ccd_vec3_t *_dir, ccd_vec3_t *vec) {
const mjtCCD* ccd = (const mjtCCD*)obj; mjc_support(vec->v, (mjCCDObj*) obj, _dir->v);
const mjModel* m = ccd->model; }
const mjData* d = ccd->data;
int g = ccd->geom;
// support function for convex collision algorithms
void mjc_support(mjtNum res[3], mjCCDObj* obj, const mjtNum dir[3]) {
const mjModel* m = obj->model;
const mjData* d = obj->data;
int g = obj->geom;
//-------------------------- flex element or vertex ----------------------------- //-------------------------- flex element or vertex -----------------------------
if (g < 0) { if (g < 0) {
int f = ccd->flex; int f = obj->flex;
int dim = m->flex_dim[f]; int dim = m->flex_dim[f];
mjtNum *res = vec->v;
const mjtNum *dir = _dir->v;
// flex element // flex element
if (ccd->elem >= 0) { if (obj->elem >= 0) {
int e = ccd->elem; int e = obj->elem;
const int* edata = m->flex_elem + m->flex_elemdataadr[f] + e*(dim+1); const int* edata = m->flex_elem + m->flex_elemdataadr[f] + e*(dim+1);
const mjtNum* vert = d->flexvert_xpos + 3*m->flex_vertadr[f]; const mjtNum* vert = d->flexvert_xpos + 3*m->flex_vertadr[f];
@@ -92,14 +102,14 @@ void mjccd_support(const void *obj, const ccd_vec3_t *_dir, ccd_vec3_t *vec) {
} }
// add radius and margin/2 // add radius and margin/2
mju_addToScl3(res, dir, m->flex_radius[f] + 0.5*ccd->margin); mju_addToScl3(res, dir, m->flex_radius[f] + 0.5*obj->margin);
return; return;
} }
// flex vertex // flex vertex
else { else {
const mjtNum* vert = d->flexvert_xpos + 3*(m->flex_vertadr[f] + ccd->vert); const mjtNum* vert = d->flexvert_xpos + 3*(m->flex_vertadr[f] + obj->vert);
mju_addScl3(res, vert, dir, m->flex_radius[f] + 0.5*ccd->margin); mju_addScl3(res, vert, dir, m->flex_radius[f] + 0.5*obj->margin);
return; return;
} }
} }
@@ -111,30 +121,29 @@ void mjccd_support(const void *obj, const ccd_vec3_t *_dir, ccd_vec3_t *vec) {
mjtNum tmp, vdot; mjtNum tmp, vdot;
const mjtNum* size = m->geom_size+3*g; // geom sizes const mjtNum* size = m->geom_size+3*g; // geom sizes
mjtNum dir[3]; // direction in geom local frame mjtNum local_dir[3]; // direction in geom local frame
mjtNum res[3]; // result in geom local frame
// rotate dir to geom local frame // rotate dir to geom local frame
mju_mulMatTVec3(dir, d->geom_xmat+9*g, _dir->v); mju_mulMatTVec3(local_dir, d->geom_xmat+9*g, dir);
// compute result according to geom type // compute result according to geom type
switch ((mjtGeom) m->geom_type[g]) { switch ((mjtGeom) m->geom_type[g]) {
case mjGEOM_SPHERE: case mjGEOM_SPHERE:
mju_scl3(res, dir, size[0]); mju_scl3(res, local_dir, size[0]);
break; break;
case mjGEOM_CAPSULE: case mjGEOM_CAPSULE:
// start with sphere // start with sphere
mju_scl3(res, dir, size[0]); mju_scl3(res, local_dir, size[0]);
// add cylinder contribution // add cylinder contribution
res[2] += mju_sign(dir[2]) * size[1]; res[2] += mju_sign(local_dir[2]) * size[1];
break; break;
case mjGEOM_ELLIPSOID: case mjGEOM_ELLIPSOID:
// find support point on unit sphere: scale dir by ellipsoid sizes and renormalize // find support point on unit sphere: scale dir by ellipsoid sizes and renormalize
for (int i=0; i < 3; i++) { for (int i=0; i < 3; i++) {
res[i] = dir[i] * size[i]; res[i] = local_dir[i] * size[i];
} }
mju_normalize3(res); mju_normalize3(res);
@@ -146,21 +155,21 @@ void mjccd_support(const void *obj, const ccd_vec3_t *_dir, ccd_vec3_t *vec) {
case mjGEOM_CYLINDER: case mjGEOM_CYLINDER:
// set result in XY plane: support on circle // set result in XY plane: support on circle
tmp = mju_sqrt(dir[0]*dir[0] + dir[1]*dir[1]); tmp = mju_sqrt(local_dir[0]*local_dir[0] + local_dir[1]*local_dir[1]);
if (tmp > mjMINVAL) { if (tmp > mjMINVAL) {
res[0] = dir[0]/tmp*size[0]; res[0] = local_dir[0]/tmp*size[0];
res[1] = dir[1]/tmp*size[0]; res[1] = local_dir[1]/tmp*size[0];
} else { } else {
res[0] = res[1] = 0; res[0] = res[1] = 0;
} }
// set result in Z direction // set result in Z direction
res[2] = mju_sign(dir[2]) * size[1]; res[2] = mju_sign(local_dir[2]) * size[1];
break; break;
case mjGEOM_BOX: case mjGEOM_BOX:
for (int i=0; i < 3; i++) { for (int i=0; i < 3; i++) {
res[i] = mju_sign(dir[i]) * size[i]; res[i] = mju_sign(local_dir[i]) * size[i];
} }
break; break;
@@ -176,9 +185,9 @@ void mjccd_support(const void *obj, const ccd_vec3_t *_dir, ccd_vec3_t *vec) {
// search all vertices, find best // search all vertices, find best
for (int i=0; i < m->mesh_vertnum[m->geom_dataid[g]]; i++) { for (int i=0; i < m->mesh_vertnum[m->geom_dataid[g]]; i++) {
// vdot = dot(vertex, dir) // vdot = dot(vertex, dir)
vdot = dir[0] * (mjtNum)vertdata[3*i] + vdot = local_dir[0] * (mjtNum)vertdata[3*i] +
dir[1] * (mjtNum)vertdata[3*i+1] + local_dir[1] * (mjtNum)vertdata[3*i+1] +
dir[2] * (mjtNum)vertdata[3*i+2]; local_dir[2] * (mjtNum)vertdata[3*i+2];
// update best // update best
if (vdot > tmp) { if (vdot > tmp) {
@@ -188,7 +197,7 @@ void mjccd_support(const void *obj, const ccd_vec3_t *_dir, ccd_vec3_t *vec) {
} }
// record best vertex index, in globalid format // record best vertex index, in globalid format
((mjtCCD*)ccd)->meshindex = ibest; obj->meshindex = ibest;
} }
// hill-climb using graph data // hill-climb using graph data
@@ -202,9 +211,9 @@ void mjccd_support(const void *obj, const ccd_vec3_t *_dir, ccd_vec3_t *vec) {
// init with first vertex in convex hull // init with first vertex in convex hull
ibest = 0; ibest = 0;
tmp = dir[0] * (mjtNum)vertdata[3*vert_globalid[0]] + tmp = local_dir[0] * (mjtNum)vertdata[3*vert_globalid[0]] +
dir[1] * (mjtNum)vertdata[3*vert_globalid[0]+1] + local_dir[1] * (mjtNum)vertdata[3*vert_globalid[0]+1] +
dir[2] * (mjtNum)vertdata[3*vert_globalid[0]+2]; local_dir[2] * (mjtNum)vertdata[3*vert_globalid[0]+2];
// hill-climb until no change // hill-climb until no change
change = 1; change = 1;
@@ -213,10 +222,10 @@ void mjccd_support(const void *obj, const ccd_vec3_t *_dir, ccd_vec3_t *vec) {
change = 0; change = 0;
int i = vert_edgeadr[ibest]; int i = vert_edgeadr[ibest];
while ((locid=edge_localid[i]) >= 0) { while ((locid=edge_localid[i]) >= 0) {
// vdot = dot(vertex, dir) // vdot = dot(vertex, local_dir)
vdot = dir[0] * (mjtNum)vertdata[3*vert_globalid[locid]] + vdot = local_dir[0] * (mjtNum)vertdata[3*vert_globalid[locid]] +
dir[1] * (mjtNum)vertdata[3*vert_globalid[locid]+1] + local_dir[1] * (mjtNum)vertdata[3*vert_globalid[locid]+1] +
dir[2] * (mjtNum)vertdata[3*vert_globalid[locid]+2]; local_dir[2] * (mjtNum)vertdata[3*vert_globalid[locid]+2];
// update best // update best
if (vdot > tmp) { if (vdot > tmp) {
@@ -231,7 +240,7 @@ void mjccd_support(const void *obj, const ccd_vec3_t *_dir, ccd_vec3_t *vec) {
} }
// record best vertex index, in locid format // record best vertex index, in locid format
((mjtCCD*)ccd)->meshindex = ibest; obj->meshindex = ibest;
// map best index to globalid // map best index to globalid
ibest = vert_globalid[ibest]; ibest = vert_globalid[ibest];
@@ -255,16 +264,16 @@ void mjccd_support(const void *obj, const ccd_vec3_t *_dir, ccd_vec3_t *vec) {
mjERROR("ccd support function is undefined for geom type %d", m->geom_type[g]); mjERROR("ccd support function is undefined for geom type %d", m->geom_type[g]);
} }
// add dir*margin/2 to result // add local_dir*margin/2 to result
for (int i=0; i < 3; i++) { for (int i=0; i < 3; i++) {
res[i] += dir[i] * ccd->margin/2; res[i] += local_dir[i] * obj->margin/2;
} }
// rotate result to global frame // rotate result to global frame
mju_mulMatVec3(vec->v, d->geom_xmat+9*g, res); mju_mulMatVec3(res, d->geom_xmat+9*g, res);
// add geom position // add geom position
mju_addTo3(vec->v, d->geom_xpos+3*g); mju_addTo3(res, d->geom_xpos+3*g);
} }
@@ -280,7 +289,7 @@ static void mjc_initCCD(ccd_t* ccd, const mjModel* m) {
// find single convex-convex collision, using libccd // find single convex-convex collision, using libccd
static int mjc_MPRIteration(mjtCCD* obj1, mjtCCD* obj2, const ccd_t* ccd, static int mjc_MPRIteration(mjCCDObj* obj1, mjCCDObj* obj2, const ccd_t* ccd,
const mjModel* m, const mjData* d, const mjModel* m, const mjData* d,
mjContact* con, mjtNum margin) { mjContact* con, mjtNum margin) {
ccd_vec3_t dir, pos; ccd_vec3_t dir, pos;
@@ -351,8 +360,8 @@ static void mju_rotateFrame(const mjtNum origin[3], const mjtNum rot[9],
int mjc_Convex(const mjModel* m, const mjData* d, int mjc_Convex(const mjModel* m, const mjData* d,
mjContact* con, int g1, int g2, mjtNum margin) { mjContact* con, int g1, int g2, mjtNum margin) {
ccd_t ccd; ccd_t ccd;
mjtCCD obj1 = {m, d, g1, -1, -1, -1, -1, margin, {1, 0, 0, 0}}; mjCCDObj obj1 = {m, d, g1, -1, -1, -1, -1, margin, {1, 0, 0, 0}, {0, 0, 0}};
mjtCCD obj2 = {m, d, g2, -1, -1, -1, -1, margin, {1, 0, 0, 0}}; mjCCDObj obj2 = {m, d, g2, -1, -1, -1, -1, margin, {1, 0, 0, 0}, {0, 0, 0}};
// init ccd structure // init ccd structure
mjc_initCCD(&ccd, m); mjc_initCCD(&ccd, m);
@@ -480,7 +489,7 @@ int mjc_PlaneConvex(const mjModel* m, const mjData* d,
mjGETINFO mjGETINFO
mjtNum dist, dif[3], normal[3] = {mat1[2], mat1[5], mat1[8]}; mjtNum dist, dif[3], normal[3] = {mat1[2], mat1[5], mat1[8]};
ccd_vec3_t dir, vec; ccd_vec3_t dir, vec;
mjtCCD obj = {m, d, g2, -1, -1, -1, -1, 0, {1, 0, 0, 0}}; mjCCDObj obj = {m, d, g2, -1, -1, -1, -1, 0, {1, 0, 0, 0}, {0, 0, 0}};
// get support point in -normal direction // get support point in -normal direction
ccdVec3Set(&dir, -mat1[2], -mat1[5], -mat1[8]); ccdVec3Set(&dir, -mat1[2], -mat1[5], -mat1[8]);
@@ -661,7 +670,7 @@ int mjc_ConvexHField(const mjModel* m, const mjData* d,
// ccd-related // ccd-related
ccd_vec3_t dirccd, vecccd; ccd_vec3_t dirccd, vecccd;
ccd_real_t depth; ccd_real_t depth;
mjtCCD obj = {m, d, g2, -1, -1, -1, -1, 0, {1, 0, 0, 0}}; mjCCDObj obj = {m, d, g2, -1, -1, -1, -1, 0, {1, 0, 0, 0}, {0, 0, 0}};
ccd_t ccd; ccd_t ccd;
// point size1 to hfield size instead of geom1 size // point size1 to hfield size instead of geom1 size
@@ -1094,8 +1103,8 @@ void mjc_fixNormal(const mjModel* m, const mjData* d, mjContact* con, int g1, in
int mjc_ConvexElem(const mjModel* m, const mjData* d, mjContact* con, int mjc_ConvexElem(const mjModel* m, const mjData* d, mjContact* con,
int g1, int f1, int e1, int v1, int f2, int e2, mjtNum margin) { int g1, int f1, int e1, int v1, int f2, int e2, mjtNum margin) {
ccd_t ccd; ccd_t ccd;
mjtCCD obj1 = {m, d, g1, -1, f1, e1, v1, margin, {1, 0, 0, 0}}; mjCCDObj obj1 = {m, d, g1, -1, f1, e1, v1, margin, {1, 0, 0, 0}, {0, 0, 0}};
mjtCCD obj2 = {m, d, -1, -1, f2, e2, -1, margin, {1, 0, 0, 0}}; mjCCDObj obj2 = {m, d, -1, -1, f2, e2, -1, margin, {1, 0, 0, 0}, {0, 0, 0}};
// init ccd structure // init ccd structure
mjc_initCCD(&ccd, m); mjc_initCCD(&ccd, m);
@@ -1142,7 +1151,7 @@ int mjc_HFieldElem(const mjModel* m, const mjData* d, mjContact* con,
// ccd-related // ccd-related
ccd_vec3_t dirccd, vecccd; ccd_vec3_t dirccd, vecccd;
ccd_real_t depth; ccd_real_t depth;
mjtCCD obj = {m, d, -1, -1, f, e, -1, margin, {1, 0, 0, 0}}; mjCCDObj obj = {m, d, -1, -1, f, e, -1, margin, {1, 0, 0, 0}, {0, 0, 0}};
ccd_t ccd; ccd_t ccd;
//------------------------------------- AABB computation, box-box test //------------------------------------- AABB computation, box-box test
+11 -4
View File
@@ -23,8 +23,10 @@
#include <ccd/vec3.h> #include <ccd/vec3.h>
#include <mujoco/mjexport.h>
#include <mujoco/mjdata.h> #include <mujoco/mjdata.h>
#include <mujoco/mjmodel.h> #include <mujoco/mjmodel.h>
#include <mujoco/mjtnum.h>
#define mjGETINFO_HFIELD \ #define mjGETINFO_HFIELD \
const mjtNum* pos1 = d->geom_xpos + 3*g1; \ const mjtNum* pos1 = d->geom_xpos + 3*g1; \
@@ -38,8 +40,8 @@
extern "C" { extern "C" {
#endif #endif
// ccd general object type // internal object type for convex collision detection
struct _mjtCCD { struct _mjCCDObj {
const mjModel* model; const mjModel* model;
const mjData* data; const mjData* data;
int geom; int geom;
@@ -49,14 +51,19 @@ struct _mjtCCD {
int vert; int vert;
mjtNum margin; mjtNum margin;
mjtNum rotate[4]; mjtNum rotate[4];
mjtNum x0[3]; // initial guess of the witness point
}; };
typedef struct _mjtCCD mjtCCD; typedef struct _mjCCDObj mjCCDObj;
// support function for convex collision algorithms
MJAPI void mjc_support(mjtNum res[3], mjCCDObj* obj, const mjtNum dir[3]);
// center function for convex collision algorithms
MJAPI void mjc_center(mjtNum res[3], const mjCCDObj *obj);
// ccd support function // ccd support function
void mjccd_support(const void *obj, const ccd_vec3_t *dir, ccd_vec3_t *vec); void mjccd_support(const void *obj, const ccd_vec3_t *dir, ccd_vec3_t *vec);
// pairwise geom collision functions using ccd // pairwise geom collision functions using ccd
int mjc_PlaneConvex (const mjModel* m, const mjData* d, int mjc_PlaneConvex (const mjModel* m, const mjData* d,
mjContact* con, int g1, int g2, mjtNum margin); mjContact* con, int g1, int g2, mjtNum margin);
+475
View File
@@ -0,0 +1,475 @@
// Copyright 2024 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
//
// http://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.
#include "engine/engine_collision_gjk.h"
#include <stddef.h>
#include <mujoco/mjtnum.h>
#include <mujoco/mjmodel.h>
#include "engine/engine_util_blas.h"
#include "engine/engine_util_spatial.h"
#include "engine/engine_collision_convex.h"
// Computes the shortest distance between the origin and an n-simplex (n <= 3) and returns the
// barycentric coordinates of the closest point in the simplex. This is the so called distance
// sub-algorithm of the original 1988 GJK algorithm.
//
// We have adapted the Signed Volume method for our approach from the paper:
// Improving the GJK Algorithm for Faster and More Reliable Distance Queries Between Two
// Convex Objects, Montanari et al, ToG 2017.
static void signedVolume(mjtNum lambda[4], const mjtNum simplex[12], int n);
// these internal functions compute the barycentric coordinates of the closest point
// to the origin in the n-simplex, where n = 3, 2, 1 respectively
static void S3D(mjtNum lambda[4], const mjtNum simplex[12]);
static void S2D(mjtNum lambda[3], const mjtNum simplex[9]);
static void S1D(mjtNum lambda[2], const mjtNum simplex[6]);
// helper function to compute the support point in the Minkowski difference
static void support(mjtNum s1[3], mjtNum s2[3], mjCCDObj* obj1, mjCCDObj* obj2,
const mjtNum x_k[3]);
// linear algebra utility functions
static mjtNum det3(const mjtNum v1[3], const mjtNum v2[3], const mjtNum v3[3]);
static void lincomb(mjtNum res[3], const mjtNum* coef, const mjtNum* v, int n);
// returns the distance between the two objects. The witness points are
// recoverable from x_0 in obj1 and obj2.
mjtNum mj_gjk(const mjCCDConfig* config, mjCCDObj* obj1, mjCCDObj* obj2) {
mjtNum simplex[12]; // our current simplex with max 4 vertices due to only 3 dimensions
int n = 0; // number of vertices in the simplex
mjtNum x_k[3]; // the kth approximation point with initial value x_0
// segregated simplices and points for the two objects to recover witness points
mjtNum simplex1[12], simplex2[12];
mjtNum* x1_k = obj1->x0;
mjtNum* x2_k = obj2->x0;
mju_sub3(x_k, x1_k, x2_k);
int N = config->max_iterations;
for (size_t k = 0; k < N; k++) {
mjtNum s1[3], s2[3]; // the support points in obj1 and obj2
mjtNum s_k[3]; // the kth support point of Minkowski difference
mjtNum lambda[4]; // barycentric coordinates for x_k
// compute the kth support point
support(s1, s2, obj1, obj2, x_k);
mju_sub3(s_k, s1, s2);
// the stopping criteria relies on the Frank-Wolfe duality gap given by
// f(x_k) - f(x_min) <= < grad f(x_k), (x_k - s_k) >
mjtNum diff[3];
mju_sub3(diff, x_k, s_k);
if (2*mju_dot3(x_k, diff) < config->tolerance) {
return mju_norm3(x_k);
}
// TODO(kylebayes): signedVolume has been written to assume the first vertex is the latest
// support to be added. Once the logic has been updated, then this hack should be removed.
for (int i = n; i > 0; i--) {
// shift the simplex vertices to the right
mju_copy3(simplex + 3*i, simplex + 3*(i-1));
mju_copy3(simplex1 + 3*i, simplex1 + 3*(i-1));
mju_copy3(simplex2 + 3*i, simplex2 + 3*(i-1));
}
// copy new support point into the simplex
mju_copy3(simplex, s_k);
// copy new support point into the individual simplexes
mju_copy3(simplex1, s1);
mju_copy3(simplex2, s2);
// run the distance subalgorithm to compute the barycentric coordinates
// of the closest point to the origin in the simplex
signedVolume(lambda, simplex, ++n);
lincomb(x_k, lambda, simplex, 4);
// compute the approximate witness points
lincomb(x1_k, lambda, simplex1, 4);
lincomb(x2_k, lambda, simplex2, 4);
// for lambda[i] == 0, remove the ith vertex from the simplex
n = 0;
for (int i = 0; i < 4; i++) {
if (lambda[i] == 0) continue;
// recover simplex for the two objects
mju_copy3(simplex1 + 3*n, simplex1 + 3*i);
mju_copy3(simplex2 + 3*n, simplex2 + 3*i);
// simplex in Minkowski difference
mju_copy3(simplex + 3*n++, simplex + 3*i);
}
}
return mju_norm3(x_k);
}
// computes the support points in obj1 and obj2 for the kth approximation point
static void support(mjtNum s1[3], mjtNum s2[3], mjCCDObj* obj1, mjCCDObj* obj2,
const mjtNum x_k[3]) {
mjtNum dir[3], dir_neg[3];
mju_copy3(dir_neg, x_k);
mju_normalize3(dir_neg); // mjc_support assumes a normalized direction
mju_scl3(dir, dir_neg, -1);
// compute S_{A-B}(dir) = S_A(dir) - S_B(-dir)
mjc_support(s1, obj1, dir);
mjc_support(s2, obj2, dir_neg);
}
// linear combination of n 3D vectors:
// res = coef[0]*v[0] + ... + coef[n-1]*v[3*(n-1)]
static void lincomb(mjtNum res[3], const mjtNum* coef, const mjtNum* v, int n) {
mju_zero3(res);
for (int i = 0; i < n; i++) {
if (coef[i] == 0) continue;
res[0] += coef[i] * v[3*i + 0];
res[1] += coef[i] * v[3*i + 1];
res[2] += coef[i] * v[3*i + 2];
}
}
// returns determinant of the 3x3 matrix with columns v1, v2, v3
static mjtNum det3(const mjtNum v1[3], const mjtNum v2[3], const mjtNum v3[3]) {
mjtNum temp[3];
mju_cross(temp, v2, v3);
return mju_dot3(v1, temp);
}
// returns true only when a and b are both strictly positive or both strictly negative
static int compareSigns(mjtNum a, mjtNum b) {
if (a > 0 && b > 0) return 1;
if (a < 0 && b < 0) return 1;
return 0;
}
// computes the barycentric coordinates of the closest point to the origin in the n-simplex
void signedVolume(mjtNum lambda[4], const mjtNum simplex[12], int n) {
int r = n - 1; // spatial dimension of the simplex
mju_zero4(lambda);
if (r == 3) {
S3D(lambda, simplex);
} else if (r == 2) {
S2D(lambda, simplex);
} else if (r == 1) {
S1D(lambda, simplex);
} else {
lambda[0] = 1;
}
}
static void S3D(mjtNum lambda[4], const mjtNum simplex[12]) {
// the four vertices of the 3-simplex that correspond to 4 support points
const mjtNum* s1 = simplex;
const mjtNum* s2 = simplex + 3;
const mjtNum* s3 = simplex + 6;
const mjtNum* s4 = simplex + 9;
// the matrix M is given by
// [[ s1_x, s2_x, s3_x, s4_x ],
// [ s1_y, s2_y, s3_y, s4_y ],
// [ s1_z, s2_z, s3_z, s4_z ],
// [ 1, 1, 1, 1 ]]
// we want to solve M*lambda = P, where P = [p_x, p_y, p_z, 1] with [p_x, p_y, p_z] is the
// origin projected onto the simplex
// compute cofactors to find det(M)
mjtNum C41 = -det3(s2, s3, s4);
mjtNum C42 = det3(s1, s3, s4);
mjtNum C43 = -det3(s1, s2, s4);
mjtNum C44 = det3(s1, s2, s3);
// note that m_det = 6*SignVol(simplex) with C4i corresponding to the volume of the 3-simplex
// with vertices {s1, s2, s3, 0} - si
mjtNum m_det = C41 + C42 + C43 + C44;
int comp1 = compareSigns(m_det, C41),
comp2 = compareSigns(m_det, C42),
comp3 = compareSigns(m_det, C43),
comp4 = compareSigns(m_det, C44);
// if all signs are the same then the origin is inside the simplex
if (comp1 && comp2 && comp3 && comp4) {
lambda[0] = C41 / m_det;
lambda[1] = C42 / m_det;
lambda[2] = C43 / m_det;
lambda[3] = C44 / m_det;
return;
}
// find the smallest distance, and use the corresponding barycentric coordinates
mjtNum dist = mjMAXVAL;
if (!comp2) {
mjtNum lambda_2d[3], verts[9], x[3];
mju_copy3(verts, s1);
mju_copy3(verts + 3, s3);
mju_copy3(verts + 6, s4);
S2D(lambda_2d, verts);
lincomb(x, lambda_2d, verts, 3);
mjtNum d = mju_norm3(x);
lambda[0] = lambda_2d[0];
lambda[1] = 0;
lambda[2] = lambda_2d[1];
lambda[3] = lambda_2d[2];
dist = d;
}
if (!comp3) {
mjtNum lambda_2d[3], verts[9], x[3];
mju_copy3(verts, s1);
mju_copy3(verts + 3, s2);
mju_copy3(verts + 6, s4);
S2D(lambda_2d, verts);
lincomb(x, lambda_2d, verts, 3);
mjtNum d = mju_norm3(x);
if (d < dist) {
lambda[0] = lambda_2d[0];
lambda[1] = lambda_2d[1];
lambda[2] = 0;
lambda[3] = lambda_2d[2];
dist = d;
}
}
if (!comp4) {
mjtNum lambda_2d[3], verts[9], x[3];
mju_copy3(verts, s1);
mju_copy3(verts + 3, s2);
mju_copy3(verts + 6, s3);
S2D(lambda_2d, verts);
lincomb(x, lambda_2d, verts, 3);
mjtNum d = mju_norm3(x);
if (d < dist) {
lambda[0] = lambda_2d[0];
lambda[1] = lambda_2d[1];
lambda[2] = lambda_2d[2];
lambda[3] = 0;
dist = d;
}
}
if (!comp1) {
mjtNum lambda_2d[3], verts[9], x[3];
mju_copy3(verts, s2);
mju_copy3(verts + 3, s3);
mju_copy3(verts + 6, s4);
S2D(lambda_2d, verts);
lincomb(x, lambda_2d, verts, 3);
mjtNum d = mju_norm3(x);
if (d < dist) {
lambda[0] = 0;
lambda[1] = lambda_2d[0];
lambda[2] = lambda_2d[1];
lambda[3] = lambda_2d[2];
dist = d;
}
}
}
static void S2D(mjtNum lambda[3], const mjtNum simplex[9]) {
// the three vertices of the 2-simplex that correspond to 3 support points
const mjtNum* s1 = simplex;
const mjtNum* s2 = simplex + 3;
const mjtNum* s3 = simplex + 6;
// compute normal
mjtNum diff1[3], diff2[3], n[3];
mju_sub3(diff1, s2, s1);
mju_sub3(diff2, s3, s1);
mju_cross(n, diff1, diff2);
// project origin
mjtNum p_o[3];
mju_scl3(p_o, n, mju_dot3(n, s1) / mju_dot3(n, n));
mjtNum mu_max = 0;
// Below are the minors M_i4 of the matrix M given by
// [[ s1_x, s2_x, s3_x, s4_x ],
// [ s1_y, s2_y, s3_y, s4_y ],
// [ s1_z, s2_z, s3_z, s4_z ],
// [ 1, 1, 1, 1 ]]
mjtNum M_14 = s2[1]*s3[2] - s2[2]*s3[1] - s1[1]*s3[2] + s1[2]*s3[1] + s1[1]*s2[2] - s1[2]*s2[1];
mjtNum M_24 = s2[0]*s3[2] - s2[2]*s3[0] - s1[0]*s3[2] + s1[2]*s3[0] + s1[0]*s2[2] - s1[2]*s2[0];
mjtNum M_34 = s2[0]*s3[1] - s2[1]*s3[0] - s1[0]*s3[1] + s1[1]*s3[0] + s1[0]*s2[1] - s1[1]*s2[0];
// exclude one of the axes with the largest projection of the simplex using the computed minors
mjtNum s1_2D[2], s2_2D[2], s3_2D[2], p_o_2D[2];
mjtNum mu1 = mju_abs(M_14), mu2 = mju_abs(M_24), mu3 = mju_abs(M_34);
if (mu1 >= mu2 && mu1 >= mu3) {
mu_max = mu1;
s1_2D[0] = s1[1];
s1_2D[1] = s1[2];
s2_2D[0] = s2[1];
s2_2D[1] = s2[2];
s3_2D[0] = s3[1];
s3_2D[1] = s3[2];
p_o_2D[0] = p_o[1];
p_o_2D[1] = p_o[2];
} else if (mu2 >= mu3) {
mu_max = mu2;
s1_2D[0] = s1[0];
s1_2D[1] = s1[2];
s2_2D[0] = s2[0];
s2_2D[1] = s2[2];
s3_2D[0] = s3[0];
s3_2D[1] = s3[2];
p_o_2D[0] = p_o[0];
p_o_2D[1] = p_o[2];
} else {
mu_max = mu3;
s1_2D[0] = s1[0];
s1_2D[1] = s1[1];
s2_2D[0] = s2[0];
s2_2D[1] = s2[1];
s3_2D[0] = s3[0];
s3_2D[1] = s3[1];
p_o_2D[0] = p_o[0];
p_o_2D[1] = p_o[1];
}
// substitute p_o as a vertex in simplex
mjtNum C1 = p_o_2D[0]*s2_2D[1] + p_o_2D[1]*s3_2D[0] + s2_2D[0]*s3_2D[1]
- p_o_2D[0]*s3_2D[1] - p_o_2D[1]*s2_2D[0] - s3_2D[0]*s2_2D[1];
mjtNum C2 = p_o_2D[0]*s3_2D[1] + p_o_2D[1]*s1_2D[0] + s3_2D[0]*s1_2D[1]
- p_o_2D[0]*s1_2D[1] - p_o_2D[1]*s3_2D[0] - s1_2D[0]*s3_2D[1];
mjtNum C3 = p_o_2D[0]*s1_2D[1] + p_o_2D[1]*s2_2D[0] + s1_2D[0]*s2_2D[1]
- p_o_2D[0]*s2_2D[1] - p_o_2D[1]*s1_2D[0] - s2_2D[0]*s1_2D[1];
int comp1 = compareSigns(mu_max, C1),
comp2 = compareSigns(mu_max, C2),
comp3 = compareSigns(mu_max, C3);
// inside the simplex
if (comp1 && comp2 && comp3) {
lambda[0] = C1 / mu_max;
lambda[1] = C2 / mu_max;
lambda[2] = C3 / mu_max;
return;
}
// find the smallest distance, and use the corresponding barycentric coordinates
mjtNum dist = mjMAXVAL;
if (!comp2) {
mjtNum lambda_1d[2], verts[6], x[3];
mju_copy3(verts, s1);
mju_copy3(verts + 3, s3);
S1D(lambda_1d, verts);
lincomb(x, lambda_1d, verts, 2);
mjtNum d = mju_norm3(x);
lambda[0] = lambda_1d[0];
lambda[1] = 0;
lambda[2] = lambda_1d[1];
dist = d;
}
if (!comp3) {
mjtNum lambda_1d[2], verts[6], x[3];
mju_copy3(verts, s1);
mju_copy3(verts + 3, s2);
S1D(lambda_1d, verts);
lincomb(x, lambda_1d, verts, 2);
mjtNum d = mju_norm3(x);
if (d < dist) {
lambda[0] = lambda_1d[0];
lambda[1] = lambda_1d[1];
lambda[2] = 0;
dist = d;
}
}
if (!comp1) {
mjtNum lambda_1d[2], verts[6], x[3];
mju_copy3(verts, s2);
mju_copy3(verts + 3, s3);
S1D(lambda_1d, verts);
lincomb(x, lambda_1d, verts, 2);
mjtNum d = mju_norm3(x);
if (d < dist) {
lambda[1] = lambda_1d[0];
lambda[2] = lambda_1d[1];
lambda[0] = 0;
dist = d;
}
}
}
static void S1D(mjtNum lambda[2], const mjtNum simplex[6]) {
// the two vertices of the 1-simplex correspond to 2 support points
const mjtNum* s1 = simplex;
const mjtNum* s2 = simplex + 3;
// find projection of origin onto the 1-simplex:
// p_o = s2 - <s2, s2 - s1> / <s2 - s1, s2 - s1> * (s2 - s1)
mjtNum p_o[3];
mjtNum diff[3];
mju_sub3(diff, s2, s1);
mjtNum temp1 = mju_dot3(s2, diff);
mjtNum temp2 = mju_dot3(diff, diff);
mju_addScl3(p_o, s2, diff, - temp1 / temp2);
// find the axis with the largest projection "shadow" of the simplex
mjtNum mu_max = 0;
int index;
for (int i = 0; i < 3; i++) {
mjtNum mu = s1[i] - s2[i];
if (mju_abs(mu) >= mju_abs(mu_max)) {
mu_max = mu;
index = i;
}
}
mjtNum C1 = p_o[index] - s2[index];
mjtNum C2 = s1[index] - p_o[index];
// inside the simplex
if (compareSigns(mu_max, C1) && compareSigns(mu_max, C2)) {
lambda[0] = C1 / mu_max;
lambda[1] = C2 / mu_max;
} else {
lambda[0] = 1;
lambda[1] = 0;
}
}
+41
View File
@@ -0,0 +1,41 @@
// Copyright 2024 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
//
// http://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.
#ifndef MUJOCO_SRC_ENGINE_ENGINE_COLLISION_GJK_H_
#define MUJOCO_SRC_ENGINE_ENGINE_COLLISION_GJK_H_
#include <mujoco/mjexport.h>
#include <mujoco/mjtnum.h>
#include "engine/engine_collision_convex.h"
#ifdef __cplusplus
extern "C" {
#endif
// internal configuration for convex collision detection
struct _mjCCDConfig {
int max_iterations;
mjtNum tolerance;
};
typedef struct _mjCCDConfig mjCCDConfig;
// Returns the distance between the two objects. The witness points are
// recoverable from x_0 in obj1 and obj2.
MJAPI mjtNum mj_gjk(const mjCCDConfig* config, mjCCDObj* obj1, mjCCDObj* obj2);
#ifdef __cplusplus
}
#endif
#endif // MUJOCO_SRC_ENGINE_ENGINE_COLLISION_GJK_H_
+10 -4
View File
@@ -35,9 +35,9 @@
#endif #endif
#ifdef mjUSEPLATFORMSIMD #ifdef mjUSEPLATFORMSIMD
#if defined(__AVX__) && defined(mjUSEDOUBLE) #if defined(__AVX__) && !defined(mjUSESINGLE)
#define mjUSEAVX #define mjUSEAVX
#endif // defined(__AVX__) && defined(mjUSEDOUBLE) #endif // defined(__AVX__) && !defined(mjUSESINGLE)
#endif // mjUSEPLATFORMSIMD #endif // mjUSEPLATFORMSIMD
@@ -818,7 +818,10 @@ void mj_instantiateLimit(const mjModel* m, mjData* d) {
// BALL joint // BALL joint
else if (m->jnt_type[i] == mjJNT_BALL) { else if (m->jnt_type[i] == mjJNT_BALL) {
// convert joint quaternion to axis-angle // convert joint quaternion to axis-angle
mju_quat2Vel(angleAxis, d->qpos+m->jnt_qposadr[i], 1); int adr = m->jnt_qposadr[i];
mjtNum quat[4] = {d->qpos[adr], d->qpos[adr+1], d->qpos[adr+2], d->qpos[adr+3]};
mju_normalize4(quat);
mju_quat2Vel(angleAxis, quat, 1);
// get rotation angle, normalize // get rotation angle, normalize
value = mju_normalize3(angleAxis); value = mju_normalize3(angleAxis);
@@ -1767,7 +1770,10 @@ static int mj_nl(const mjModel* m, const mjData* d, int *nnz) {
} }
else if (m->jnt_type[i] == mjJNT_BALL) { else if (m->jnt_type[i] == mjJNT_BALL) {
mjtNum angleAxis[3]; mjtNum angleAxis[3];
mju_quat2Vel(angleAxis, d->qpos+m->jnt_qposadr[i], 1); int adr = m->jnt_qposadr[i];
mjtNum quat[4] = {d->qpos[adr], d->qpos[adr+1], d->qpos[adr+2], d->qpos[adr+3]};
mju_normalize4(quat);
mju_quat2Vel(angleAxis, quat, 1);
value = mju_normalize3(angleAxis); value = mju_normalize3(angleAxis);
dist = mju_max(m->jnt_range[2*i], m->jnt_range[2*i+1]) - value; dist = mju_max(m->jnt_range[2*i], m->jnt_range[2*i+1]) - value;
if (dist < margin) { if (dist < margin) {
+14 -13
View File
@@ -44,14 +44,6 @@ void mj_kinematics(const mjModel* m, mjData* d) {
d->xmat[0] = d->xmat[4] = d->xmat[8] = 1; d->xmat[0] = d->xmat[4] = d->xmat[8] = 1;
d->ximat[0] = d->ximat[4] = d->ximat[8] = 1; d->ximat[0] = d->ximat[4] = d->ximat[8] = 1;
// normalize all quaternions in qpos
mj_normalizeQuat(m, d->qpos);
// normalize mocap quaternions
for (int i=0; i < m->nmocap; i++) {
mju_normalize4(d->mocap_quat+4*i);
}
// compute global cartesian positions and orientations of all bodies // compute global cartesian positions and orientations of all bodies
for (int i=1; i < m->nbody; i++) { for (int i=1; i < m->nbody; i++) {
mjtNum xpos[3], xquat[4]; mjtNum xpos[3], xquat[4];
@@ -66,6 +58,7 @@ void mj_kinematics(const mjModel* m, mjData* d) {
// copy pos and quat from qpos // copy pos and quat from qpos
mju_copy3(xpos, d->qpos+qadr); mju_copy3(xpos, d->qpos+qadr);
mju_copy4(xquat, d->qpos+qadr+3); mju_copy4(xquat, d->qpos+qadr+3);
mju_normalize4(xquat);
// assign xanchor and xaxis // assign xanchor and xaxis
mju_copy3(d->xanchor+3*jntadr, xpos); mju_copy3(d->xanchor+3*jntadr, xpos);
@@ -77,10 +70,12 @@ void mj_kinematics(const mjModel* m, mjData* d) {
int pid = m->body_parentid[i]; int pid = m->body_parentid[i];
// get body pos and quat: from model or mocap // get body pos and quat: from model or mocap
mjtNum *bodypos, *bodyquat; mjtNum *bodypos, *bodyquat, quat[4];
if (m->body_mocapid[i] >= 0) { if (m->body_mocapid[i] >= 0) {
bodypos = d->mocap_pos + 3*m->body_mocapid[i]; bodypos = d->mocap_pos + 3*m->body_mocapid[i];
bodyquat = d->mocap_quat + 4*m->body_mocapid[i]; mju_copy4(quat, d->mocap_quat + 4*m->body_mocapid[i]);
mju_normalize4(quat);
bodyquat = quat;
} else { } else {
bodypos = m->body_pos+3*i; bodypos = m->body_pos+3*i;
bodyquat = m->body_quat+4*i; bodyquat = m->body_quat+4*i;
@@ -125,6 +120,7 @@ void mj_kinematics(const mjModel* m, mjData* d) {
mjtNum qloc[4]; mjtNum qloc[4];
if (jtype == mjJNT_BALL) { if (jtype == mjJNT_BALL) {
mju_copy4(qloc, d->qpos+qadr); mju_copy4(qloc, d->qpos+qadr);
mju_normalize4(qloc);
} else { } else {
mju_axisAngle2Quat(qloc, m->jnt_axis+3*jid, d->qpos[qadr] - m->qpos0[qadr]); mju_axisAngle2Quat(qloc, m->jnt_axis+3*jid, d->qpos[qadr] - m->qpos0[qadr]);
} }
@@ -890,13 +886,15 @@ void mj_transmission(const mjModel* m, mjData* d) {
int j = m->jnt_qposadr[id]; int j = m->jnt_qposadr[id];
// axis: expmap representation of quaternion // axis: expmap representation of quaternion
mju_quat2Vel(axis, d->qpos+j, 1); mju_copy4(quat, d->qpos+j);
mju_normalize4(quat);
mju_quat2Vel(axis, quat, 1);
// gearAxis: rotate to parent frame if necessary // gearAxis: rotate to parent frame if necessary
if (m->actuator_trntype[i] == mjTRN_JOINT) { if (m->actuator_trntype[i] == mjTRN_JOINT) {
mju_copy3(gearAxis, gear); mju_copy3(gearAxis, gear);
} else { } else {
mju_negQuat(quat, d->qpos+j); mju_negQuat(quat, quat);
mju_rotVecQuat(gearAxis, gear, quat); mju_rotVecQuat(gearAxis, gear, quat);
} }
@@ -923,12 +921,15 @@ void mj_transmission(const mjModel* m, mjData* d) {
// axis: expmap representation of quaternion // axis: expmap representation of quaternion
mju_quat2Vel(axis, d->qpos+j+3, 1); mju_quat2Vel(axis, d->qpos+j+3, 1);
mju_copy4(quat, d->qpos+j+3);
mju_normalize4(quat);
mju_quat2Vel(axis, quat, 1);
// gearAxis: rotate to world frame if necessary // gearAxis: rotate to world frame if necessary
if (m->actuator_trntype[i] == mjTRN_JOINT) { if (m->actuator_trntype[i] == mjTRN_JOINT) {
mju_copy3(gearAxis, gear+3); mju_copy3(gearAxis, gear+3);
} else { } else {
mju_negQuat(quat, d->qpos+j+3); mju_negQuat(quat, quat);
mju_rotVecQuat(gearAxis, gear+3, quat); mju_rotVecQuat(gearAxis, gear+3, quat);
} }
+284
View File
@@ -0,0 +1,284 @@
// 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
//
// http://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.
#include "engine/engine_name.h"
#include <stdint.h>
#include <string.h>
#include <mujoco/mjmodel.h>
#include "engine/engine_crossplatform.h"
#include "engine/engine_io.h"
//-------------------------- name functions --------------------------------------------------------
// get number of objects and name addresses for given object type
static int _getnumadr(const mjModel* m, mjtObj type, int** padr, int* mapadr) {
int num = -1;
// map address starts at the end, subtract with explicit switch fallthrough below
*mapadr = m->nnames_map;
// get address list and size for object type
switch (type) {
case mjOBJ_BODY:
case mjOBJ_XBODY:
*mapadr -= mjLOAD_MULTIPLE*m->nbody;
*padr = m->name_bodyadr;
num = m->nbody;
mjFALLTHROUGH;
case mjOBJ_JOINT:
*mapadr -= mjLOAD_MULTIPLE*m->njnt;
if (num < 0) {
*padr = m->name_jntadr;
num = m->njnt;
}
mjFALLTHROUGH;
case mjOBJ_GEOM:
*mapadr -= mjLOAD_MULTIPLE*m->ngeom;
if (num < 0) {
*padr = m->name_geomadr;
num = m->ngeom;
}
mjFALLTHROUGH;
case mjOBJ_SITE:
*mapadr -= mjLOAD_MULTIPLE*m->nsite;
if (num < 0) {
*padr = m->name_siteadr;
num = m->nsite;
}
mjFALLTHROUGH;
case mjOBJ_CAMERA:
*mapadr -= mjLOAD_MULTIPLE*m->ncam;
if (num < 0) {
*padr = m->name_camadr;
num = m->ncam;
}
mjFALLTHROUGH;
case mjOBJ_LIGHT:
*mapadr -= mjLOAD_MULTIPLE*m->nlight;
if (num < 0) {
*padr = m->name_lightadr;
num = m->nlight;
}
mjFALLTHROUGH;
case mjOBJ_FLEX:
*mapadr -= mjLOAD_MULTIPLE*m->nflex;
if (num < 0) {
*padr = m->name_flexadr;
num = m->nflex;
}
mjFALLTHROUGH;
case mjOBJ_MESH:
*mapadr -= mjLOAD_MULTIPLE*m->nmesh;
if (num < 0) {
*padr = m->name_meshadr;
num = m->nmesh;
}
mjFALLTHROUGH;
case mjOBJ_SKIN:
*mapadr -= mjLOAD_MULTIPLE*m->nskin;
if (num < 0) {
*padr = m->name_skinadr;
num = m->nskin;
}
mjFALLTHROUGH;
case mjOBJ_HFIELD:
*mapadr -= mjLOAD_MULTIPLE*m->nhfield;
if (num < 0) {
*padr = m->name_hfieldadr;
num = m->nhfield;
}
mjFALLTHROUGH;
case mjOBJ_TEXTURE:
*mapadr -= mjLOAD_MULTIPLE*m->ntex;
if (num < 0) {
*padr = m->name_texadr;
num = m->ntex;
}
mjFALLTHROUGH;
case mjOBJ_MATERIAL:
*mapadr -= mjLOAD_MULTIPLE*m->nmat;
if (num < 0) {
*padr = m->name_matadr;
num = m->nmat;
}
mjFALLTHROUGH;
case mjOBJ_PAIR:
*mapadr -= mjLOAD_MULTIPLE*m->npair;
if (num < 0) {
*padr = m->name_pairadr;
num = m->npair;
}
mjFALLTHROUGH;
case mjOBJ_EXCLUDE:
*mapadr -= mjLOAD_MULTIPLE*m->nexclude;
if (num < 0) {
*padr = m->name_excludeadr;
num = m->nexclude;
}
mjFALLTHROUGH;
case mjOBJ_EQUALITY:
*mapadr -= mjLOAD_MULTIPLE*m->neq;
if (num < 0) {
*padr = m->name_eqadr;
num = m->neq;
}
mjFALLTHROUGH;
case mjOBJ_TENDON:
*mapadr -= mjLOAD_MULTIPLE*m->ntendon;
if (num < 0) {
*padr = m->name_tendonadr;
num = m->ntendon;
}
mjFALLTHROUGH;
case mjOBJ_ACTUATOR:
*mapadr -= mjLOAD_MULTIPLE*m->nu;
if (num < 0) {
*padr = m->name_actuatoradr;
num = m->nu;
}
mjFALLTHROUGH;
case mjOBJ_SENSOR:
*mapadr -= mjLOAD_MULTIPLE*m->nsensor;
if (num < 0) {
*padr = m->name_sensoradr;
num = m->nsensor;
}
mjFALLTHROUGH;
case mjOBJ_NUMERIC:
*mapadr -= mjLOAD_MULTIPLE*m->nnumeric;
if (num < 0) {
*padr = m->name_numericadr;
num = m->nnumeric;
}
mjFALLTHROUGH;
case mjOBJ_TEXT:
*mapadr -= mjLOAD_MULTIPLE*m->ntext;
if (num < 0) {
*padr = m->name_textadr;
num = m->ntext;
}
mjFALLTHROUGH;
case mjOBJ_TUPLE:
*mapadr -= mjLOAD_MULTIPLE*m->ntuple;
if (num < 0) {
*padr = m->name_tupleadr;
num = m->ntuple;
}
mjFALLTHROUGH;
case mjOBJ_KEY:
*mapadr -= mjLOAD_MULTIPLE*m->nkey;
if (num < 0) {
*padr = m->name_keyadr;
num = m->nkey;
}
mjFALLTHROUGH;
case mjOBJ_PLUGIN:
*mapadr -= mjLOAD_MULTIPLE*m->nplugin;
if (num < 0) {
*padr = m->name_pluginadr;
num = m->nplugin;
}
mjFALLTHROUGH;
default:
if (num < 0) {
*padr = 0;
num = 0;
}
}
return num;
}
// get string hash, see http://www.cse.yorku.ca/~oz/hash.html
uint64_t mj_hashString(const char* s, uint64_t n) {
uint64_t h = 5381;
int c;
while ((c = *s++)) {
h = ((h << 5) + h) ^ c;
}
return h % n;
}
// get id of object with the specified mjtObj type and name,
// returns -1 if id not found
int mj_name2id(const mjModel* m, int type, const char* name) {
int mapadr;
int* adr = 0;
// get number of objects and name addresses
int num = mjLOAD_MULTIPLE*_getnumadr(m, type, &adr, &mapadr);
// search
if (num) { // look up at hash address
uint64_t hash = mj_hashString(name, num);
uint64_t i = hash;
do {
int j = m->names_map[mapadr + i];
if (j < 0) {
return -1;
}
if (!strncmp(name, m->names+adr[j], m->nnames-adr[j])) {
return j;
}
if ((++i) == num)i = 0;
} while (i != hash);
}
return -1;
}
// get name of object with the specified mjtObj type and id,
// returns NULL if name not found
const char* mj_id2name(const mjModel* m, int type, int id) {
int mapadr;
int* adr = 0;
// get number of objects and name addresses
int num = _getnumadr(m, type, &adr, &mapadr);
// id is in [0, num) and the found name is not the empty string "\0"
if (id >= 0 && id < num && m->names[adr[id]]) {
return m->names+adr[id];
}
return NULL;
}
+41
View File
@@ -0,0 +1,41 @@
// 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
//
// http://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.
#ifndef MUJOCO_SRC_ENGINE_ENGINE_NAME_H_
#define MUJOCO_SRC_ENGINE_ENGINE_NAME_H_
#include <stdint.h>
#include <mujoco/mjexport.h>
#include <mujoco/mjmodel.h>
#ifdef __cplusplus
extern "C" {
#endif
//-------------------------- name functions --------------------------------------------------------
// get string hash, see http://www.cse.yorku.ca/~oz/hash.html
uint64_t mj_hashString(const char* s, uint64_t n);
// get id of object with the specified mjtObj type and name, returns -1 if id not found
MJAPI int mj_name2id(const mjModel* m, int type, const char* name);
// get name of object with the specified mjtObj type and id, returns NULL if name not found
MJAPI const char* mj_id2name(const mjModel* m, int type, int id);
#ifdef __cplusplus
}
#endif
#endif // MUJOCO_SRC_ENGINE_ENGINE_NAME_H_
+4 -2
View File
@@ -64,9 +64,11 @@ static void mj_springdamper(const mjModel* m, mjData* d) {
case mjJNT_BALL: case mjJNT_BALL:
{ {
mjtNum dif[3];
// convert quatertion difference into angular "velocity" // convert quatertion difference into angular "velocity"
mju_subQuat(dif, d->qpos + padr, m->qpos_spring + padr); mjtNum dif[3], quat[4];
mju_copy4(quat, d->qpos+padr);
mju_normalize4(quat);
mju_subQuat(dif, quat, m->qpos_spring + padr);
// apply torque // apply torque
d->qfrc_spring[dadr+0] = -stiffness*dif[0]; d->qfrc_spring[dadr+0] = -stiffness*dif[0];
+1
View File
@@ -25,6 +25,7 @@
#include <mujoco/mjxmacro.h> #include <mujoco/mjxmacro.h>
#include "engine/engine_core_constraint.h" #include "engine/engine_core_constraint.h"
#include "engine/engine_io.h" #include "engine/engine_io.h"
#include "engine/engine_name.h"
#include "engine/engine_support.h" #include "engine/engine_support.h"
#include "engine/engine_util_errmem.h" #include "engine/engine_util_errmem.h"
#include "engine/engine_util_misc.h" #include "engine/engine_util_misc.h"
+8 -17
View File
@@ -14,6 +14,7 @@
#include "engine/engine_resource.h" #include "engine/engine_resource.h"
#include <errno.h>
#include <limits.h> #include <limits.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@@ -41,7 +42,6 @@ static void* _fileToMemory(FILE* fp, const char* filename, size_t* filesize);
// file buffer used internally for the OS filesystem // file buffer used internally for the OS filesystem
typedef struct { typedef struct {
FILE* fp; // file handle
int is_read; // set to nonzero if buffer was read into int is_read; // set to nonzero if buffer was read into
uint8_t* buffer; // raw bytes from file uint8_t* buffer; // raw bytes from file
size_t nbuffer; // size of buffer in bytes size_t nbuffer; // size of buffer in bytes
@@ -100,20 +100,16 @@ mjResource* mju_openResource(const char* name, char* error, size_t error_sz) {
spec->is_read = 0; spec->is_read = 0;
spec->buffer = NULL; spec->buffer = NULL;
spec->nbuffer = 0; spec->nbuffer = 0;
spec->fp = fopen(name, "rb");
if (!spec->fp) {
if (error) {
snprintf(error, error_sz,
"resource not found via provider or OS filesystem: '%s'", name);
}
mju_closeResource(resource);
return NULL;
}
struct stat file_stat; struct stat file_stat;
errno = 0;
if (stat(name, &file_stat) == 0) { if (stat(name, &file_stat) == 0) {
memcpy(&spec->mtime, &file_stat.st_mtime, sizeof(time_t)); memcpy(&spec->mtime, &file_stat.st_mtime, sizeof(time_t));
} else { } else {
memset(&spec->mtime, 0, sizeof(time_t)); if (error) {
snprintf(error, error_sz, "Error opening file '%s': %s", name, strerror(errno));
}
mju_closeResource(resource);
return NULL;
} }
mju_encodeBase64(resource->timestamp, (uint8_t*) &spec->mtime, sizeof(time_t)); mju_encodeBase64(resource->timestamp, (uint8_t*) &spec->mtime, sizeof(time_t));
return resource; return resource;
@@ -157,17 +153,12 @@ int mju_readResource(mjResource* resource, const void** buffer) {
return resource->provider->read(resource, buffer); return resource->provider->read(resource, buffer);
} }
// if provider is NULL, then OS filesystem is used // if provider is NULL, then OS filesystem is used
file_spec* spec = (file_spec*) resource->data; file_spec* spec = (file_spec*) resource->data;
if (!spec->fp && !spec->is_read) {
mjERROR("internal error FILE pointer undefined"); // should not occur
}
// only read once from file // only read once from file
if (!spec->is_read) { if (!spec->is_read) {
spec->buffer = _fileToMemory(spec->fp, resource->name, &(spec->nbuffer)); spec->buffer = mju_fileToMemory(resource->name, &(spec->nbuffer));
spec->fp = NULL; // closed by _fileToMemory
spec->is_read = 1; spec->is_read = 1;
} }
*buffer = spec->buffer; *buffer = spec->buffer;
+7 -2
View File
@@ -281,6 +281,7 @@ void mj_sensorPos(const mjModel* m, mjData* d) {
case mjSENS_BALLQUAT: // ballquat case mjSENS_BALLQUAT: // ballquat
mju_copy4(d->sensordata+adr, d->qpos+m->jnt_qposadr[objid]); mju_copy4(d->sensordata+adr, d->qpos+m->jnt_qposadr[objid]);
mju_normalize4(d->sensordata+adr);
break; break;
case mjSENS_JOINTLIMITPOS: // jointlimitpos case mjSENS_JOINTLIMITPOS: // jointlimitpos
@@ -899,7 +900,7 @@ void mj_sensorAcc(const mjModel* m, mjData* d) {
// position-dependent energy (potential) // position-dependent energy (potential)
void mj_energyPos(const mjModel* m, mjData* d) { void mj_energyPos(const mjModel* m, mjData* d) {
int padr; int padr;
mjtNum dif[3], stiffness; mjtNum dif[3], quat[4], stiffness;
// disabled: clear and return // disabled: clear and return
if (!mjENABLED(mjENBL_ENERGY)) { if (!mjENABLED(mjENBL_ENERGY)) {
@@ -923,7 +924,9 @@ void mj_energyPos(const mjModel* m, mjData* d) {
switch ((mjtJoint) m->jnt_type[i]) { switch ((mjtJoint) m->jnt_type[i]) {
case mjJNT_FREE: case mjJNT_FREE:
mju_sub3(dif, d->qpos+padr, m->qpos_spring+padr); mju_copy4(quat, d->qpos+padr);
mju_normalize4(quat);
mju_sub3(dif, quat, m->qpos_spring+padr);
d->energy[0] += 0.5*stiffness*mju_dot3(dif, dif); d->energy[0] += 0.5*stiffness*mju_dot3(dif, dif);
// continue with rotations // continue with rotations
@@ -932,6 +935,8 @@ void mj_energyPos(const mjModel* m, mjData* d) {
case mjJNT_BALL: case mjJNT_BALL:
// covert quatertion difference into angular "velocity" // covert quatertion difference into angular "velocity"
mju_copy4(quat, d->qpos+padr);
mju_normalize4(quat);
mju_subQuat(dif, d->qpos + padr, m->qpos_spring + padr); mju_subQuat(dif, d->qpos + padr, m->qpos_spring + padr);
d->energy[0] += 0.5*stiffness*mju_dot3(dif, dif); d->energy[0] += 0.5*stiffness*mju_dot3(dif, dif);
break; break;
+1 -265
View File
@@ -15,7 +15,6 @@
#include "engine/engine_support.h" #include "engine/engine_support.h"
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
#include <string.h> #include <string.h>
#include <mujoco/mjdata.h> #include <mujoco/mjdata.h>
@@ -31,7 +30,7 @@
#include "engine/engine_util_spatial.h" #include "engine/engine_util_spatial.h"
#ifdef mjUSEPLATFORMSIMD #ifdef mjUSEPLATFORMSIMD
#if defined(__AVX__) && defined(mjUSEDOUBLE) #if defined(__AVX__) && !defined(mjUSESINGLE)
#define mjUSEAVX #define mjUSEAVX
#include "immintrin.h" #include "immintrin.h"
#endif #endif
@@ -868,269 +867,6 @@ void mj_angmomMat(const mjModel* m, mjData* d, mjtNum* mat, int body) {
//-------------------------- name functions --------------------------------------------------------
// get number of objects and name addresses for given object type
static int _getnumadr(const mjModel* m, mjtObj type, int** padr, int* mapadr) {
int num = -1;
// map address starts at the end, subtract with explicit switch fallthrough below
*mapadr = m->nnames_map;
// get address list and size for object type
switch (type) {
case mjOBJ_BODY:
case mjOBJ_XBODY:
*mapadr -= mjLOAD_MULTIPLE*m->nbody;
*padr = m->name_bodyadr;
num = m->nbody;
mjFALLTHROUGH;
case mjOBJ_JOINT:
*mapadr -= mjLOAD_MULTIPLE*m->njnt;
if (num < 0) {
*padr = m->name_jntadr;
num = m->njnt;
}
mjFALLTHROUGH;
case mjOBJ_GEOM:
*mapadr -= mjLOAD_MULTIPLE*m->ngeom;
if (num < 0) {
*padr = m->name_geomadr;
num = m->ngeom;
}
mjFALLTHROUGH;
case mjOBJ_SITE:
*mapadr -= mjLOAD_MULTIPLE*m->nsite;
if (num < 0) {
*padr = m->name_siteadr;
num = m->nsite;
}
mjFALLTHROUGH;
case mjOBJ_CAMERA:
*mapadr -= mjLOAD_MULTIPLE*m->ncam;
if (num < 0) {
*padr = m->name_camadr;
num = m->ncam;
}
mjFALLTHROUGH;
case mjOBJ_LIGHT:
*mapadr -= mjLOAD_MULTIPLE*m->nlight;
if (num < 0) {
*padr = m->name_lightadr;
num = m->nlight;
}
mjFALLTHROUGH;
case mjOBJ_FLEX:
*mapadr -= mjLOAD_MULTIPLE*m->nflex;
if (num < 0) {
*padr = m->name_flexadr;
num = m->nflex;
}
mjFALLTHROUGH;
case mjOBJ_MESH:
*mapadr -= mjLOAD_MULTIPLE*m->nmesh;
if (num < 0) {
*padr = m->name_meshadr;
num = m->nmesh;
}
mjFALLTHROUGH;
case mjOBJ_SKIN:
*mapadr -= mjLOAD_MULTIPLE*m->nskin;
if (num < 0) {
*padr = m->name_skinadr;
num = m->nskin;
}
mjFALLTHROUGH;
case mjOBJ_HFIELD:
*mapadr -= mjLOAD_MULTIPLE*m->nhfield;
if (num < 0) {
*padr = m->name_hfieldadr;
num = m->nhfield;
}
mjFALLTHROUGH;
case mjOBJ_TEXTURE:
*mapadr -= mjLOAD_MULTIPLE*m->ntex;
if (num < 0) {
*padr = m->name_texadr;
num = m->ntex;
}
mjFALLTHROUGH;
case mjOBJ_MATERIAL:
*mapadr -= mjLOAD_MULTIPLE*m->nmat;
if (num < 0) {
*padr = m->name_matadr;
num = m->nmat;
}
mjFALLTHROUGH;
case mjOBJ_PAIR:
*mapadr -= mjLOAD_MULTIPLE*m->npair;
if (num < 0) {
*padr = m->name_pairadr;
num = m->npair;
}
mjFALLTHROUGH;
case mjOBJ_EXCLUDE:
*mapadr -= mjLOAD_MULTIPLE*m->nexclude;
if (num < 0) {
*padr = m->name_excludeadr;
num = m->nexclude;
}
mjFALLTHROUGH;
case mjOBJ_EQUALITY:
*mapadr -= mjLOAD_MULTIPLE*m->neq;
if (num < 0) {
*padr = m->name_eqadr;
num = m->neq;
}
mjFALLTHROUGH;
case mjOBJ_TENDON:
*mapadr -= mjLOAD_MULTIPLE*m->ntendon;
if (num < 0) {
*padr = m->name_tendonadr;
num = m->ntendon;
}
mjFALLTHROUGH;
case mjOBJ_ACTUATOR:
*mapadr -= mjLOAD_MULTIPLE*m->nu;
if (num < 0) {
*padr = m->name_actuatoradr;
num = m->nu;
}
mjFALLTHROUGH;
case mjOBJ_SENSOR:
*mapadr -= mjLOAD_MULTIPLE*m->nsensor;
if (num < 0) {
*padr = m->name_sensoradr;
num = m->nsensor;
}
mjFALLTHROUGH;
case mjOBJ_NUMERIC:
*mapadr -= mjLOAD_MULTIPLE*m->nnumeric;
if (num < 0) {
*padr = m->name_numericadr;
num = m->nnumeric;
}
mjFALLTHROUGH;
case mjOBJ_TEXT:
*mapadr -= mjLOAD_MULTIPLE*m->ntext;
if (num < 0) {
*padr = m->name_textadr;
num = m->ntext;
}
mjFALLTHROUGH;
case mjOBJ_TUPLE:
*mapadr -= mjLOAD_MULTIPLE*m->ntuple;
if (num < 0) {
*padr = m->name_tupleadr;
num = m->ntuple;
}
mjFALLTHROUGH;
case mjOBJ_KEY:
*mapadr -= mjLOAD_MULTIPLE*m->nkey;
if (num < 0) {
*padr = m->name_keyadr;
num = m->nkey;
}
mjFALLTHROUGH;
case mjOBJ_PLUGIN:
*mapadr -= mjLOAD_MULTIPLE*m->nplugin;
if (num < 0) {
*padr = m->name_pluginadr;
num = m->nplugin;
}
mjFALLTHROUGH;
default:
if (num < 0) {
*padr = 0;
num = 0;
}
}
return num;
}
// get string hash, see http://www.cse.yorku.ca/~oz/hash.html
uint64_t mj_hashString(const char* s, uint64_t n) {
uint64_t h = 5381;
int c;
while ((c = *s++)) {
h = ((h << 5) + h) ^ c;
}
return h % n;
}
// get id of object with the specified mjtObj type and name,
// returns -1 if id not found
int mj_name2id(const mjModel* m, int type, const char* name) {
int mapadr;
int* adr = 0;
// get number of objects and name addresses
int num = mjLOAD_MULTIPLE*_getnumadr(m, type, &adr, &mapadr);
// search
if (num) { // look up at hash address
uint64_t hash = mj_hashString(name, num);
uint64_t i = hash;
do {
int j = m->names_map[mapadr + i];
if (j < 0) {
return -1;
}
if (!strncmp(name, m->names+adr[j], m->nnames-adr[j])) {
return j;
}
if ((++i) == num)i = 0;
} while (i != hash);
}
return -1;
}
// get name of object with the specified mjtObj type and id,
// returns NULL if name not found
const char* mj_id2name(const mjModel* m, int type, int id) {
int mapadr;
int* adr = 0;
// get number of objects and name addresses
int num = _getnumadr(m, type, &adr, &mapadr);
// id is in [0, num) and the found name is not the empty string "\0"
if (id >= 0 && id < num && m->names[adr[id]]) {
return m->names+adr[id];
}
return NULL;
}
//-------------------------- inertia functions ----------------------------------------------------- //-------------------------- inertia functions -----------------------------------------------------
// convert sparse inertia matrix M into full matrix // convert sparse inertia matrix M into full matrix
-14
View File
@@ -15,8 +15,6 @@
#ifndef MUJOCO_SRC_ENGINE_ENGINE_SUPPORT_H_ #ifndef MUJOCO_SRC_ENGINE_ENGINE_SUPPORT_H_
#define MUJOCO_SRC_ENGINE_ENGINE_SUPPORT_H_ #define MUJOCO_SRC_ENGINE_ENGINE_SUPPORT_H_
#include <stdint.h>
#include <mujoco/mjdata.h> #include <mujoco/mjdata.h>
#include <mujoco/mjexport.h> #include <mujoco/mjexport.h>
#include <mujoco/mjmodel.h> #include <mujoco/mjmodel.h>
@@ -113,18 +111,6 @@ int mj_jacSum(const mjModel* m, mjData* d, int* chain,
MJAPI void mj_angmomMat(const mjModel* m, mjData* d, mjtNum* mat, int body); MJAPI void mj_angmomMat(const mjModel* m, mjData* d, mjtNum* mat, int body);
//-------------------------- name functions --------------------------------------------------------
// get string hash, see http://www.cse.yorku.ca/~oz/hash.html
uint64_t mj_hashString(const char* s, uint64_t n);
// get id of object with the specified mjtObj type and name, returns -1 if id not found
MJAPI int mj_name2id(const mjModel* m, int type, const char* name);
// get name of object with the specified mjtObj type and id, returns NULL if name not found
MJAPI const char* mj_id2name(const mjModel* m, int type, int id);
//-------------------------- inertia functions ----------------------------------------------------- //-------------------------- inertia functions -----------------------------------------------------
// convert sparse inertia matrix M into full matrix // convert sparse inertia matrix M into full matrix
+2 -2
View File
@@ -19,7 +19,7 @@
#include <mujoco/mjtnum.h> #include <mujoco/mjtnum.h>
#ifdef mjUSEPLATFORMSIMD #ifdef mjUSEPLATFORMSIMD
#if defined(__AVX__) && defined(mjUSEDOUBLE) #if defined(__AVX__) && !defined(mjUSESINGLE)
#define mjUSEAVX #define mjUSEAVX
#include "immintrin.h" #include "immintrin.h"
#endif #endif
@@ -609,7 +609,7 @@ void mju_addToScl(mjtNum* res, const mjtNum* vec, mjtNum scl, int n) {
void mju_addScl(mjtNum* res, const mjtNum* vec1, const mjtNum* vec2, mjtNum scl, int n) { void mju_addScl(mjtNum* res, const mjtNum* vec1, const mjtNum* vec2, mjtNum scl, int n) {
int i = 0; int i = 0;
#if defined(__AVX__) && defined(mjUSEAVX) && defined(mjUSEDOUBLE) #if defined(__AVX__) && defined(mjUSEAVX) && !defined(mjUSESINGLE)
int n_4 = n - 4; int n_4 = n - 4;
// vector part // vector part
+2 -2
View File
@@ -26,7 +26,7 @@ extern "C" {
//------------------------------ standard library functions ---------------------------------------- //------------------------------ standard library functions ----------------------------------------
#ifdef mjUSEDOUBLE #if !defined(mjUSESINGLE)
#define mju_sqrt sqrt #define mju_sqrt sqrt
#define mju_exp exp #define mju_exp exp
#define mju_sin sin #define mju_sin sin
@@ -59,7 +59,7 @@ extern "C" {
#define mju_log10 log10f #define mju_log10 log10f
#define mju_floor floorf #define mju_floor floorf
#define mju_ceil ceilf #define mju_ceil ceilf
#endif #endif // !defined(mjUSESINGLE)
//------------------------------ 3D vector and matrix-vector operations ---------------------------- //------------------------------ 3D vector and matrix-vector operations ----------------------------
-45
View File
@@ -1407,51 +1407,6 @@ char* mju_strncpy(char *dst, const char *src, int n) {
// assemble full filename from directory and filename, return 0 on success
int mju_makefullname(char* full, size_t nfull, const char* dir, const char* file) {
int dirlen = (!dir) ? 0 : strlen(dir);
int filelen = (!file) ? 0 : strlen(file);
char* filepos = full + dirlen;
// missing filename
if (!filelen) {
return -1;
}
// no directory then just copy filename over
if (!dirlen) {
// make sure full has space
if (filelen >= nfull) {
return -1;
}
strcpy(full, file);
return 0;
}
// make sure full has space
if (dirlen + filelen >= nfull) {
return -1;
}
// dir doesn't end with a slash
if (dir[dirlen - 1] != '\\' && dir[dirlen - 1] != '/') {
// need extra space for forward slash
if ((dirlen + filelen + 1) >= nfull) {
return -1;
}
// add forward slash
*filepos++ = '/';
}
// copy directory and file over
memcpy(full, dir, sizeof(char) * dirlen);
strcpy(filepos, file);
return 0;
}
// sigmoid function over 0<=x<=1 using quintic polynomial // sigmoid function over 0<=x<=1 using quintic polynomial
mjtNum mju_sigmoid(mjtNum x) { mjtNum mju_sigmoid(mjtNum x) {
// fast return // fast return
-4
View File
@@ -164,10 +164,6 @@ MJAPI mjtNum mju_Halton(int index, int base);
// call strncpy, then set dst[n-1] = 0 // call strncpy, then set dst[n-1] = 0
MJAPI char* mju_strncpy(char *dst, const char *src, int n); MJAPI char* mju_strncpy(char *dst, const char *src, int n);
// assemble full filename from directory and filename, return 0 on success
MJAPI int mju_makefullname(char* full, size_t nfull,
const char* dir, const char* file);
// sigmoid function over 0<=x<=1 using quintic polynomial // sigmoid function over 0<=x<=1 using quintic polynomial
MJAPI mjtNum mju_sigmoid(mjtNum x); MJAPI mjtNum mju_sigmoid(mjtNum x);
+2 -2
View File
@@ -16,7 +16,7 @@
#define MUJOCO_SRC_ENGINE_ENGINE_UTIL_SPARSE_AVX_H_ #define MUJOCO_SRC_ENGINE_ENGINE_UTIL_SPARSE_AVX_H_
#ifdef mjUSEPLATFORMSIMD #ifdef mjUSEPLATFORMSIMD
#if defined(__AVX__) && defined(mjUSEDOUBLE) #if defined(__AVX__) && !defined(mjUSESINGLE)
#define mjUSEAVX #define mjUSEAVX
@@ -315,7 +315,7 @@ int mju_compare_avx(const int* vec1, const int* vec2, int n) {
return !memcmp(vec1+i, vec2+i, (n-i)*sizeof(int)); return !memcmp(vec1+i, vec2+i, (n-i)*sizeof(int));
} }
#endif // defined(__AVX__) && defined(mjUSEDOUBLE) #endif // defined(__AVX__) && !defined(mjUSESINGLE)
#endif // mjUSEPLATFORMSIMD #endif // mjUSEPLATFORMSIMD
+1 -1
View File
@@ -247,8 +247,8 @@ void mju_quatIntegrate(mjtNum quat[4], const mjtNum vel[3], mjtNum scale) {
mju_copy3(tmp, vel); mju_copy3(tmp, vel);
angle = scale * mju_normalize3(tmp); angle = scale * mju_normalize3(tmp);
mju_axisAngle2Quat(qrot, tmp, angle); mju_axisAngle2Quat(qrot, tmp, angle);
mju_mulQuat(quat, quat, qrot);
mju_normalize4(quat); mju_normalize4(quat);
mju_mulQuat(quat, quat, qrot);
} }
+4 -14
View File
@@ -23,6 +23,7 @@
#include <mujoco/mjvisualize.h> #include <mujoco/mjvisualize.h>
#include "engine/engine_array_safety.h" #include "engine/engine_array_safety.h"
#include "engine/engine_io.h" #include "engine/engine_io.h"
#include "engine/engine_name.h"
#include "engine/engine_plugin.h" #include "engine/engine_plugin.h"
#include "engine/engine_support.h" #include "engine/engine_support.h"
#include "engine/engine_util_blas.h" #include "engine/engine_util_blas.h"
@@ -301,21 +302,13 @@ static void setMaterial(const mjModel* m, mjvGeom* geom, int matid, const float*
const mjtByte* flags) { const mjtByte* flags) {
// set material properties if given // set material properties if given
if (matid >= 0) { if (matid >= 0) {
f2f(geom->texrepeat, m->mat_texrepeat + 2*matid, 2);
f2f(geom->rgba, m->mat_rgba + 4*matid, 4); f2f(geom->rgba, m->mat_rgba + 4*matid, 4);
geom->texuniform = m->mat_texuniform[matid];
geom->emission = m->mat_emission[matid]; geom->emission = m->mat_emission[matid];
geom->specular = m->mat_specular[matid]; geom->specular = m->mat_specular[matid];
geom->shininess = m->mat_shininess[matid]; geom->shininess = m->mat_shininess[matid];
geom->reflectance = m->mat_reflectance[matid]; geom->reflectance = m->mat_reflectance[matid];
} }
// otherwise clear texrepeat
else {
geom->texrepeat[0] = 0;
geom->texrepeat[1] = 0;
}
// use rgba if different from default, or no material given // use rgba if different from default, or no material given
if (rgba[0] != 0.5f || rgba[1] != 0.5f || rgba[2] != 0.5f || rgba[3] != 1.0f || matid < 0) { if (rgba[0] != 0.5f || rgba[1] != 0.5f || rgba[2] != 0.5f || rgba[3] != 1.0f || matid < 0) {
f2f(geom->rgba, rgba, 4); f2f(geom->rgba, rgba, 4);
@@ -323,7 +316,7 @@ static void setMaterial(const mjModel* m, mjvGeom* geom, int matid, const float*
// set texture // set texture
if (flags[mjVIS_TEXTURE] && matid >= 0) { if (flags[mjVIS_TEXTURE] && matid >= 0) {
geom->texid = m->mat_texid[matid]; geom->matid = matid;
} }
// scale alpha for dynamic geoms only // scale alpha for dynamic geoms only
@@ -457,11 +450,8 @@ void mjv_initGeom(mjvGeom* geom, int type, const mjtNum* size,
// set defaults that cannot be assigned via this function // set defaults that cannot be assigned via this function
geom->dataid = -1; geom->dataid = -1;
geom->texid = -1; geom->matid = -1;
geom->texuniform = 0;
geom->texcoord = 0; geom->texcoord = 0;
geom->texrepeat[0] = 1;
geom->texrepeat[1] = 1;
geom->emission = 0; geom->emission = 0;
geom->specular = 0.5; geom->specular = 0.5;
geom->shininess = 0.5; geom->shininess = 0.5;
@@ -570,7 +560,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
thisgeom->texcoord = 1; thisgeom->texcoord = 1;
} }
else { else {
thisgeom->texid = -1; thisgeom->matid = -1;
} }
// glow flex if selected // glow flex if selected
+38
View File
@@ -1294,6 +1294,43 @@ static void makeFont(mjrContext* con, int fontscale) {
} }
} }
// make materials, just for those that have textures
static void makeMaterial(const mjModel* m, mjrContext* con) {
memset(con->mat_texid, -1, sizeof(con->mat_texid));
memset(con->mat_texuniform, 0, sizeof(con->mat_texuniform));
memset(con->mat_texrepeat, 0, sizeof(con->mat_texrepeat));
if (!m->nmat || !m->ntex) {
return;
}
if (m->nmat >= mjMAXMATERIAL-1) {
mju_error("Maximum number of materials is %d", mjMAXMATERIAL);
}
for (int i=0; i < m->nmat; i++) {
if (m->mat_texid[i*mjNTEXMAT] >= 0) {
for (int j=0; j < mjNTEXMAT; j++) {
con->mat_texid[i*mjNTEXMAT + j] = m->mat_texid[i*mjNTEXMAT + j];
}
con->mat_texuniform[i] = m->mat_texuniform[i];
con->mat_texrepeat[2*i] = m->mat_texrepeat[2*i];
con->mat_texrepeat[2*i+1] = m->mat_texrepeat[2*i+1];
}
}
// find skybox texture
for (int i=0; i < m->ntex; i++) {
if (m->tex_type[i] == mjTEXTURE_SKYBOX) {
if (m->nmat >= mjMAXMATERIAL-2) {
mju_error("With skybox, maximum number of materials is %d", mjMAXMATERIAL);
}
con->mat_texid[mjNTEXMAT * (mjMAXMATERIAL-1)] = i;
for (int j=1; j < mjNTEXMAT; j++) {
con->mat_texid[mjNTEXMAT * (mjMAXMATERIAL-1) + j] = -1;
}
break;
}
}
}
// make textures // make textures
@@ -1585,6 +1622,7 @@ void mjr_makeContext_offSize(const mjModel* m, mjrContext* con, int fontscale,
// make everything // make everything
makeOff(con); makeOff(con);
makeShadow(m, con); makeShadow(m, con);
makeMaterial(m, con);
makeTexture(m, con); makeTexture(m, con);
makePlane(m, con); makePlane(m, con);
makeMesh(m, con); makeMesh(m, con);
+19 -15
View File
@@ -61,6 +61,10 @@ enum {
// enable/disable texture mapping // enable/disable texture mapping
static void settexture(int type, int state, const mjrContext* con, const mjvGeom* geom) { static void settexture(int type, int state, const mjrContext* con, const mjvGeom* geom) {
float plane[4], scl[2]; float plane[4], scl[2];
int texid = -1;
if (geom) {
texid = (geom->matid == -1) ? -1 : con->mat_texid[mjNTEXMAT * geom->matid];
}
// shadow // shadow
if (type == mjtexSHADOW) { if (type == mjtexSHADOW) {
@@ -92,7 +96,7 @@ static void settexture(int type, int state, const mjrContext* con, const mjvGeom
if (state) { if (state) {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, con->texture[geom->texid]); glBindTexture(GL_TEXTURE_2D, con->texture[texid]);
} }
// disable // disable
@@ -103,18 +107,18 @@ static void settexture(int type, int state, const mjrContext* con, const mjvGeom
} }
// 2D // 2D
else if (type == mjtexREGULAR && con->textureType[geom->texid] == mjTEXTURE_2D) { else if (type == mjtexREGULAR && con->textureType[texid] == mjTEXTURE_2D) {
// enable // enable
if (state) { if (state) {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_GEN_T);
glBindTexture(GL_TEXTURE_2D, con->texture[geom->texid]); glBindTexture(GL_TEXTURE_2D, con->texture[texid]);
// determine scaling, adjust for pre-scaled geoms // determine scaling, adjust for pre-scaled geoms
scl[0] = geom->texrepeat[0]; scl[0] = con->mat_texrepeat[geom->matid*2];
scl[1] = geom->texrepeat[1]; scl[1] = con->mat_texrepeat[geom->matid*2+1];
if (geom->dataid >= 0) { if (geom->dataid >= 0) {
if (geom->size[0] > 0) { if (geom->size[0] > 0) {
scl[0] = scl[0] / mju_max(mjMINVAL, geom->size[0]); scl[0] = scl[0] / mju_max(mjMINVAL, geom->size[0]);
@@ -126,7 +130,7 @@ static void settexture(int type, int state, const mjrContext* con, const mjvGeom
} }
// uniform: repeat relative to spatial units rather than object // uniform: repeat relative to spatial units rather than object
if (geom->texuniform) { if (con->mat_texuniform[geom->matid]) {
if (geom->size[0] > 0) { if (geom->size[0] > 0) {
scl[0] = scl[0] * geom->size[0]; scl[0] = scl[0] * geom->size[0];
} }
@@ -161,15 +165,15 @@ static void settexture(int type, int state, const mjrContext* con, const mjvGeom
glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R); glEnable(GL_TEXTURE_GEN_R);
glBindTexture(GL_TEXTURE_CUBE_MAP, con->texture[geom->texid]); glBindTexture(GL_TEXTURE_CUBE_MAP, con->texture[texid]);
// set mapping : cube // set mapping : cube
if (type == mjtexREGULAR) { if (type == mjtexREGULAR) {
mjr_setf4(plane, geom->texuniform ? geom->size[0] : 1, 0, 0, 0); mjr_setf4(plane, con->mat_texuniform[geom->matid] ? geom->size[0] : 1, 0, 0, 0);
glTexGenfv(GL_S, GL_OBJECT_PLANE, plane); glTexGenfv(GL_S, GL_OBJECT_PLANE, plane);
mjr_setf4(plane, 0, geom->texuniform ? geom->size[1] : 1, 0, 0); mjr_setf4(plane, 0, con->mat_texuniform[geom->matid] ? geom->size[1] : 1, 0, 0);
glTexGenfv(GL_T, GL_OBJECT_PLANE, plane); glTexGenfv(GL_T, GL_OBJECT_PLANE, plane);
mjr_setf4(plane, 0, 0, geom->texuniform ? geom->size[2] : 1, 0); mjr_setf4(plane, 0, 0, con->mat_texuniform[geom->matid] ? geom->size[2] : 1, 0);
glTexGenfv(GL_R, GL_OBJECT_PLANE, plane); glTexGenfv(GL_R, GL_OBJECT_PLANE, plane);
} }
@@ -232,7 +236,7 @@ static void renderGeom(const mjvGeom* geom, int mode, const float* headpos,
behind = isBehind(headpos, geom->pos, geom->mat); behind = isBehind(headpos, geom->pos, geom->mat);
// enable texture in normal and shadowmap mode // enable texture in normal and shadowmap mode
if (geom->texid >= 0 && con->ntexture > 0 && if (geom->matid >= 0 &&
(mode == mjrRND_NORMAL || mode == mjrRND_SHADOWMAP)) { (mode == mjrRND_NORMAL || mode == mjrRND_SHADOWMAP)) {
settexture(mjtexREGULAR, 1, con, geom); settexture(mjtexREGULAR, 1, con, geom);
} }
@@ -515,14 +519,14 @@ static void renderGeom(const mjvGeom* geom, int mode, const float* headpos,
glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, scn->flexface + 9*scn->flexfaceadr[geom->objid]); glVertexPointer(3, GL_FLOAT, 0, scn->flexface + 9*scn->flexfaceadr[geom->objid]);
glNormalPointer(GL_FLOAT, 0, scn->flexnormal + 9*scn->flexfaceadr[geom->objid]); glNormalPointer(GL_FLOAT, 0, scn->flexnormal + 9*scn->flexfaceadr[geom->objid]);
if (geom->texcoord && geom->texid>=0) { if (geom->texcoord && geom->matid>=0) {
glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, scn->flextexcoord + 6*scn->flexfaceadr[geom->objid]); glTexCoordPointer(2, GL_FLOAT, 0, scn->flextexcoord + 6*scn->flexfaceadr[geom->objid]);
} }
glDrawArrays(GL_TRIANGLES, 0, 3*scn->flexfaceused[geom->objid]); glDrawArrays(GL_TRIANGLES, 0, 3*scn->flexfaceused[geom->objid]);
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_NORMAL_ARRAY);
if (geom->texcoord && geom->texid>=0) { if (geom->texcoord && geom->matid>=0) {
glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY);
} }
} }
@@ -568,7 +572,7 @@ static void renderGeom(const mjvGeom* geom, int mode, const float* headpos,
glPopMatrix(); glPopMatrix();
// disable texture if enabled // disable texture if enabled
if (geom->texid >= 0 && con->ntexture > 0 && if (geom->matid >= 0 &&
(mode == mjrRND_NORMAL || mode == mjrRND_SHADOWMAP)) { (mode == mjrRND_NORMAL || mode == mjrRND_SHADOWMAP)) {
settexture(mjtexREGULAR, 0, con, geom); settexture(mjtexREGULAR, 0, con, geom);
} }
@@ -1268,7 +1272,7 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) {
if (con->textureType[i] == mjTEXTURE_SKYBOX) { if (con->textureType[i] == mjTEXTURE_SKYBOX) {
// save first skybox texture id in tempgeom // save first skybox texture id in tempgeom
memset(&tempgeom, 0, sizeof(mjvGeom)); memset(&tempgeom, 0, sizeof(mjvGeom));
tempgeom.texid = i; tempgeom.matid = mjMAXMATERIAL - 1;
// modify settings // modify settings
glDisable(GL_LIGHTING); glDisable(GL_LIGHTING);
+717 -371
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -29,7 +29,7 @@ set(MUJOCO_USER_SRCS
user_objects.h user_objects.h
user_util.cc user_util.cc
user_util.h user_util.h
user_vfs.c user_vfs.cc
user_vfs.h user_vfs.h
) )
+190 -10
View File
@@ -437,10 +437,11 @@ mjsPlugin* mjs_addPlugin(mjSpec* s) {
// add default to model // add default to model
mjsDefault* mjs_addDefault(mjSpec* s, const char* classname, int parentid, int* id) { mjsDefault* mjs_addDefault(mjSpec* s, const char* classname, const mjsDefault* parent) {
mjCModel* modelC = static_cast<mjCModel*>(s->element); mjCModel* modelC = static_cast<mjCModel*>(s->element);
*id = (int)modelC->NumDefaults(); mjCDef* parentC = parent ? static_cast<mjCDef*>(parent->element) :
mjCDef* def = modelC->AddDefault(classname, parentid); static_cast<mjCModel*>(s->element)->Defaults(0);
mjCDef* def = modelC->AddDefault(classname, parentC);
if (def) { if (def) {
return &def->spec; return &def->spec;
} else { } else {
@@ -529,6 +530,15 @@ mjsFrame* mjs_findFrame(mjSpec* s, const char* name) {
// find keyframe by name
mjsKey* mjs_findKeyframe(mjSpec* s, const char* name) {
mjCModel* model = static_cast<mjCModel*>(s->element);
mjCKey* key = (mjCKey*)model->FindObject(mjOBJ_KEY, std::string(name));
return key ? &(static_cast<mjCKey*>(key)->spec) : nullptr;
}
// set frame // set frame
void mjs_setFrame(mjsElement* dest, mjsFrame* frame) { void mjs_setFrame(mjsElement* dest, mjsFrame* frame) {
if (!frame) { if (!frame) {
@@ -580,6 +590,183 @@ mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child) {
// return spec's first element of selected type
mjsElement* mjs_firstElement(mjSpec* s, mjtObj type) {
mjCModel* modelC = static_cast<mjCModel*>(s->element);
return modelC->NextObject(NULL, type);
}
// return spec's next element; return NULL if element is last
mjsElement* mjs_nextElement(mjSpec* s, mjsElement* element) {
mjCModel* modelC = static_cast<mjCModel*>(s->element);
return modelC->NextObject(element);
}
// return body given mjsElement
mjsBody* mjs_asBody(mjsElement* element) {
return element->elemtype == mjOBJ_BODY ? &(static_cast<mjCBody*>(element)->spec) : nullptr;
}
// return geom given mjsElement
mjsGeom* mjs_asGeom(mjsElement* element) {
return element->elemtype == mjOBJ_GEOM ? &(static_cast<mjCGeom*>(element)->spec) : nullptr;
}
// return joint given mjsElement
mjsJoint* mjs_asJoint(mjsElement* element) {
return element->elemtype == mjOBJ_JOINT ? &(static_cast<mjCJoint*>(element)->spec) : nullptr;
}
// Return site given mjsElement
mjsSite* mjs_asSite(mjsElement* element) {
return element->elemtype == mjOBJ_SITE ? &(static_cast<mjCSite*>(element)->spec) : nullptr;
}
// return camera given mjsElement
mjsCamera* mjs_asCamera(mjsElement* element) {
return element->elemtype == mjOBJ_CAMERA ? &(static_cast<mjCCamera*>(element)->spec) : nullptr;
}
// return light given mjsElement
mjsLight* mjs_asLight(mjsElement* element) {
return element->elemtype == mjOBJ_LIGHT ? &(static_cast<mjCLight*>(element)->spec) : nullptr;
}
// return frame given mjsElement
mjsFrame* mjs_asFrame(mjsElement* element) {
return element->elemtype == mjOBJ_FRAME ? &(static_cast<mjCFrame*>(element)->spec) : nullptr;
}
// return actuator given mjsElement
mjsActuator* mjs_asActuator(mjsElement* element) {
return element->elemtype == mjOBJ_ACTUATOR ? &(static_cast<mjCActuator*>(element)->spec) : nullptr;
}
// return sensor given mjsElement
mjsSensor* mjs_asSensor(mjsElement* element) {
return element->elemtype == mjOBJ_SENSOR ? &(static_cast<mjCSensor*>(element)->spec) : nullptr;
}
// return flex given mjsElement
mjsFlex* mjs_asFlex(mjsElement* element) {
return element->elemtype == mjOBJ_FLEX ? &(static_cast<mjCFlex*>(element)->spec) : nullptr;
}
// return pair given mjsElement
mjsPair* mjs_asPair(mjsElement* element) {
return element->elemtype == mjOBJ_PAIR ? &(static_cast<mjCPair*>(element)->spec) : nullptr;
}
// return equality given mjsElement
mjsEquality* mjs_asEquality(mjsElement* element) {
return element->elemtype == mjOBJ_EQUALITY ? &(static_cast<mjCEquality*>(element)->spec) : nullptr;
}
// return exclude given mjsElement
mjsExclude* mjs_asExclude(mjsElement* element) {
return element->elemtype == mjOBJ_EXCLUDE ? &(static_cast<mjCBodyPair*>(element)->spec) : nullptr;
}
// return tendon given mjsElement
mjsTendon* mjs_asTendon(mjsElement* element) {
return element->elemtype == mjOBJ_TENDON ? &(static_cast<mjCTendon*>(element)->spec) : nullptr;
}
// return numeric given mjsElement
mjsNumeric* mjs_asNumeric(mjsElement* element) {
return element->elemtype == mjOBJ_NUMERIC ? &(static_cast<mjCNumeric*>(element)->spec) : nullptr;
}
// return text given mjsElement
mjsText* mjs_asText(mjsElement* element) {
return element->elemtype == mjOBJ_TEXT ? &(static_cast<mjCText*>(element)->spec) : nullptr;
}
// return tuple given mjsElement
mjsTuple* mjs_asTuple(mjsElement* element) {
return element->elemtype == mjOBJ_TUPLE ? &(static_cast<mjCTuple*>(element)->spec) : nullptr;
}
// return key given mjsElement
mjsKey* mjs_asKey(mjsElement* element) {
return element->elemtype == mjOBJ_KEY ? &(static_cast<mjCKey*>(element)->spec) : nullptr;
}
// return mesh given mjsElement
mjsMesh* mjs_asMesh(mjsElement* element) {
return element->elemtype == mjOBJ_MESH ? &(static_cast<mjCMesh*>(element)->spec) : nullptr;
}
// return hfield given mjsElement
mjsHField* mjs_asHField(mjsElement* element) {
return element->elemtype == mjOBJ_HFIELD ? &(static_cast<mjCHField*>(element)->spec) : nullptr;
}
// return skin given mjsElement
mjsSkin* mjs_asSkin(mjsElement* element) {
return element->elemtype == mjOBJ_SKIN ? &(static_cast<mjCSkin*>(element)->spec) : nullptr;
}
// return texture given mjsElement
mjsTexture* mjs_asTexture(mjsElement* element) {
return element->elemtype == mjOBJ_TEXTURE ? &(static_cast<mjCTexture*>(element)->spec) : nullptr;
}
// return material given mjsElement
mjsMaterial* mjs_asMaterial(mjsElement* element) {
return element->elemtype == mjOBJ_MATERIAL ? &(static_cast<mjCMaterial*>(element)->spec) : nullptr;
}
// set string // set string
void mjs_setString(mjString* dest, const char* text) { void mjs_setString(mjString* dest, const char* text) {
std::string* str = static_cast<std::string*>(dest); std::string* str = static_cast<std::string*>(dest);
@@ -696,13 +883,6 @@ void mjs_setActivePlugins(mjSpec* s, void* activeplugins) {
// compute full inertia
const char* mjs_fullInertia(double quat[4], double inertia[3], const double fullinertia[6]) {
return FullInertia(quat, inertia, fullinertia);
}
// -------------------------- GLOBAL ASSET CACHE ------------------------------- // -------------------------- GLOBAL ASSET CACHE -------------------------------
void mj_setCacheSize(mjCache cache, std::size_t size) { void mj_setCacheSize(mjCache cache, std::size_t size) {
+79 -4
View File
@@ -156,7 +156,7 @@ MJAPI mjsKey* mjs_addKey(mjSpec* s);
MJAPI mjsPlugin* mjs_addPlugin(mjSpec* s); MJAPI mjsPlugin* mjs_addPlugin(mjSpec* s);
// Add default. // Add default.
MJAPI mjsDefault* mjs_addDefault(mjSpec* s, const char* classname, int parentid, int* id); MJAPI mjsDefault* mjs_addDefault(mjSpec* s, const char* classname, const mjsDefault* parent);
//---------------------------------- Add assets ---------------------------------------------------- //---------------------------------- Add assets ----------------------------------------------------
@@ -194,6 +194,9 @@ MJAPI mjsMesh* mjs_findMesh(mjSpec* s, const char* name);
// Find frame by name. // Find frame by name.
MJAPI mjsFrame* mjs_findFrame(mjSpec* s, const char* name); MJAPI mjsFrame* mjs_findFrame(mjSpec* s, const char* name);
// Find keyframe by name.
MJAPI mjsKey* mjs_findKeyframe(mjSpec* s, const char* name);
// Get default corresponding to an element. // Get default corresponding to an element.
MJAPI mjsDefault* mjs_getDefault(mjsElement* element); MJAPI mjsDefault* mjs_getDefault(mjsElement* element);
@@ -215,6 +218,81 @@ MJAPI mjsElement* mjs_firstChild(mjsBody* body, mjtObj type);
// Return body's next child of the same type; return NULL if child is last. // Return body's next child of the same type; return NULL if child is last.
MJAPI mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child); MJAPI mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child);
// Return spec's first element of selected type.
MJAPI mjsElement* mjs_firstElement(mjSpec* s, mjtObj type);
// Return spec's next element; return NULL if element is last.
MJAPI mjsElement* mjs_nextElement(mjSpec* s, mjsElement* element);
// Safely cast an element as mjsBody, or return NULL if the element is not an mjsBody.
MJAPI mjsBody* mjs_asBody(mjsElement* element);
// Safely cast an element as mjsGeom, or return NULL if the element is not an mjsGeom.
MJAPI mjsGeom* mjs_asGeom(mjsElement* element);
// Safely cast an element as mjsJoint, or return NULL if the element is not an mjsJoint.
MJAPI mjsJoint* mjs_asJoint(mjsElement* element);
// Safely cast an element as mjsSite, or return NULL if the element is not an mjsSite.
MJAPI mjsSite* mjs_asSite(mjsElement* element);
// Safely cast an element as mjsCamera, or return NULL if the element is not an mjsCamera.
MJAPI mjsCamera* mjs_asCamera(mjsElement* element);
// Safely cast an element as mjsLight, or return NULL if the element is not an mjsLight.
MJAPI mjsLight* mjs_asLight(mjsElement* element);
// Safely cast an element as mjsFrame, or return NULL if the element is not an mjsFrame.
MJAPI mjsFrame* mjs_asFrame(mjsElement* element);
// Safely cast an element as mjsActuator, or return NULL if the element is not an mjsActuator.
MJAPI mjsActuator* mjs_asActuator(mjsElement* element);
// Safely cast an element as mjsSensor, or return NULL if the element is not an mjsSensor.
MJAPI mjsSensor* mjs_asSensor(mjsElement* element);
// Safely cast an element as mjsFlex, or return NULL if the element is not an mjsFlex.
MJAPI mjsFlex* mjs_asFlex(mjsElement* element);
// Safely cast an element as mjsPair, or return NULL if the element is not an mjsPair.
MJAPI mjsPair* mjs_asPair(mjsElement* element);
// Safely cast an element as mjsEquality, or return NULL if the element is not an mjsEquality.
MJAPI mjsEquality* mjs_asEquality(mjsElement* element);
// Safely cast an element as mjsExclude, or return NULL if the element is not an mjsExclude.
MJAPI mjsExclude* mjs_asExclude(mjsElement* element);
// Safely cast an element as mjsTendon, or return NULL if the element is not an mjsTendon.
MJAPI mjsTendon* mjs_asTendon(mjsElement* element);
// Safely cast an element as mjsNumeric, or return NULL if the element is not an mjsNumeric.
MJAPI mjsNumeric* mjs_asNumeric(mjsElement* element);
// Safely cast an element as mjsText, or return NULL if the element is not an mjsText.
MJAPI mjsText* mjs_asText(mjsElement* element);
// Safely cast an element as mjsTuple, or return NULL if the element is not an mjsTuple.
MJAPI mjsTuple* mjs_asTuple(mjsElement* element);
// Safely cast an element as mjsKey, or return NULL if the element is not an mjsKey.
MJAPI mjsKey* mjs_asKey(mjsElement* element);
// Safely cast an element as mjsMesh, or return NULL if the element is not an mjsMesh.
MJAPI mjsMesh* mjs_asMesh(mjsElement* element);
// Safely cast an element as mjsHField, or return NULL if the element is not an mjsHField.
MJAPI mjsHField* mjs_asHField(mjsElement* element);
// Safely cast an element as mjsSkin, or return NULL if the element is not an mjsSkin.
MJAPI mjsSkin* mjs_asSkin(mjsElement* element);
// Safely cast an element as mjsTexture, or return NULL if the element is not an mjsTexture.
MJAPI mjsTexture* mjs_asTexture(mjsElement* element);
// Safely cast an element as mjsMaterial, or return NULL if the element is not an mjsMaterial.
MJAPI mjsMaterial* mjs_asMaterial(mjsElement* element);
//---------------------------------- Attribute setters --------------------------------------------- //---------------------------------- Attribute setters ---------------------------------------------
@@ -273,9 +351,6 @@ MJAPI void mjs_setFrame(mjsElement* dest, mjsFrame* frame);
MJAPI const char* mjs_resolveOrientation(double quat[4], mjtByte degree, const char* sequence, MJAPI const char* mjs_resolveOrientation(double quat[4], mjtByte degree, const char* sequence,
const mjsOrientation* orientation); const mjsOrientation* orientation);
// Compute quat and diag inertia from full inertia matrix, return error if any.
MJAPI const char* mjs_fullInertia(double quat[4], double inertia[3], const double fullinertia[6]);
//---------------------------------- Initialization ----------------------------------------------- //---------------------------------- Initialization -----------------------------------------------
+17 -16
View File
@@ -31,7 +31,6 @@
#include <mujoco/mujoco.h> #include <mujoco/mujoco.h>
#include "cc/array_safety.h" #include "cc/array_safety.h"
#include "engine/engine_io.h" #include "engine/engine_io.h"
#include "engine/engine_util_blas.h"
#include "engine/engine_util_errmem.h" #include "engine/engine_util_errmem.h"
#include "engine/engine_util_misc.h" #include "engine/engine_util_misc.h"
#include "user/user_model.h" #include "user/user_model.h"
@@ -428,12 +427,12 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjsBody* body, char* error, int
} }
// compute volume // compute volume
std::vector<mjtNum> volume(uservert.size()/3); std::vector<double> volume(uservert.size()/3);
mjtNum t = 1; double thickness = 1;
if (dim == 2 && plugin.active) { if (dim == 2 && plugin.active) {
try { try {
mjCPlugin* pplugin = static_cast<mjCPlugin*>(plugin.instance); mjCPlugin* pplugin = static_cast<mjCPlugin*>(plugin.instance);
t = std::stod(pplugin->config_attribs["thickness"], nullptr); thickness = std::stod(pplugin->config_attribs["thickness"], nullptr);
} catch (const std::invalid_argument& e) { } catch (const std::invalid_argument& e) {
return comperr(error, "Invalid thickness attribute", error_sz); return comperr(error, "Invalid thickness attribute", error_sz);
} }
@@ -441,9 +440,9 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjsBody* body, char* error, int
if (!userface.empty()) { if (!userface.empty()) {
face = mjXUtil::String2Vector<int>(userface); face = mjXUtil::String2Vector<int>(userface);
for (int j=0; j<face.size()/3; j++) { for (int j=0; j<face.size()/3; j++) {
mjtNum area[3]; double area[3];
mjtNum edge1[3]; double edge1[3];
mjtNum edge2[3]; double edge2[3];
for (int i=0; i<3; i++) { for (int i=0; i<3; i++) {
edge1[i] = uservert[3*face[3*j+1]+i] - uservert[3*face[3*j]+i]; edge1[i] = uservert[3*face[3*j+1]+i] - uservert[3*face[3*j]+i];
@@ -452,12 +451,12 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjsBody* body, char* error, int
mjuu_crossvec(area, edge1, edge2); mjuu_crossvec(area, edge1, edge2);
for (int i=0; i<3; i++) { for (int i=0; i<3; i++) {
volume[face[3*j+i]] += sqrt(mjuu_dot3(area, area)) / 2 * t; volume[face[3*j+i]] += sqrt(mjuu_dot3(area, area)) / 2 * thickness;
} }
} }
} else { } else {
for (int i=0; i<uservert.size()/3; i++) { for (int i=0; i<uservert.size()/3; i++) {
volume[i] = 6 * spacing * spacing / 2 * t; volume[i] = 6 * spacing * spacing / 2 * thickness;
} }
} }
@@ -754,7 +753,7 @@ bool mjCComposite::MakeCable(mjCModel* model, mjsBody* body, char* error, int er
} }
// create frame // create frame
mjtNum normal[3], prev_quat[4]; double normal[3], prev_quat[4];
mjuu_setvec(normal, 0, 1, 0); mjuu_setvec(normal, 0, 1, 0);
mjuu_setvec(prev_quat, 1, 0, 0, 0); mjuu_setvec(prev_quat, 1, 0, 0, 0);
@@ -780,10 +779,11 @@ bool mjCComposite::MakeCable(mjCModel* model, mjsBody* body, char* error, int er
mjsBody* mjCComposite::AddCableBody(mjCModel* model, mjsBody* body, int ix, mjtNum normal[3], mjtNum prev_quat[4]) { mjsBody* mjCComposite::AddCableBody(mjCModel* model, mjsBody* body, int ix,
double normal[3], double prev_quat[4]) {
char txt_geom[100], txt_site[100], txt_slide[100]; char txt_geom[100], txt_site[100], txt_slide[100];
char this_body[100], next_body[100], this_joint[100]; char this_body[100], next_body[100], this_joint[100];
mjtNum dquat[4], this_quat[4]; double dquat[4], this_quat[4];
// set flags // set flags
int lastidx = count[0]-2; int lastidx = count[0]-2;
@@ -792,7 +792,7 @@ mjsBody* mjCComposite::AddCableBody(mjCModel* model, mjsBody* body, int ix, mjtN
bool secondlast = ix==lastidx-1; bool secondlast = ix==lastidx-1;
// compute edge and tangent vectors // compute edge and tangent vectors
mjtNum edge[3], tprev[3], tnext[3], length_prev = 0; double edge[3], tprev[3], tnext[3], length_prev = 0;
mjuu_setvec(edge, uservert[3*(ix+1)+0]-uservert[3*ix+0], mjuu_setvec(edge, uservert[3*(ix+1)+0]-uservert[3*ix+0],
uservert[3*(ix+1)+1]-uservert[3*ix+1], uservert[3*(ix+1)+1]-uservert[3*ix+1],
uservert[3*(ix+1)+2]-uservert[3*ix+2]); uservert[3*(ix+1)+2]-uservert[3*ix+2]);
@@ -810,7 +810,7 @@ mjsBody* mjCComposite::AddCableBody(mjCModel* model, mjsBody* body, int ix, mjtN
} }
// update moving frame // update moving frame
mjtNum length = mju_updateFrame(this_quat, normal, edge, tprev, tnext, first); double length = mjuu_updateFrame(this_quat, normal, edge, tprev, tnext, first);
// create body, joint, and geom names // create body, joint, and geom names
if (first) { if (first) {
@@ -845,7 +845,7 @@ mjsBody* mjCComposite::AddCableBody(mjCModel* model, mjsBody* body, int ix, mjtN
mjuu_copyvec(body->quat, this_quat, 4); mjuu_copyvec(body->quat, this_quat, 4);
} else { } else {
mjuu_setvec(body->pos, length_prev, 0, 0); mjuu_setvec(body->pos, length_prev, 0, 0);
mjtNum negquat[4] = {prev_quat[0], -prev_quat[1], -prev_quat[2], -prev_quat[3]}; double negquat[4] = {prev_quat[0], -prev_quat[1], -prev_quat[2], -prev_quat[3]};
mjuu_mulquat(dquat, negquat, this_quat); mjuu_mulquat(dquat, negquat, this_quat);
mjuu_copyvec(body->quat, dquat, 4); mjuu_copyvec(body->quat, dquat, 4);
} }
@@ -1091,7 +1091,7 @@ void mjCComposite::BoxProject(double* pos) {
// cylinder // cylinder
else if (type==mjCOMPTYPE_CYLINDER) { else if (type==mjCOMPTYPE_CYLINDER) {
double L0 = mju_max(mju_abs(pos[0]), mju_abs(pos[1])); double L0 = std::max(std::abs(pos[0]), std::abs(pos[1]));
mjuu_normvec(pos, 2); mjuu_normvec(pos, 2);
pos[0] *= size[0]*L0; pos[0] *= size[0]*L0;
pos[1] *= size[1]*L0; pos[1] *= size[1]*L0;
@@ -1156,6 +1156,7 @@ bool mjCComposite::MakeBox(mjCModel* model, mjsBody* body, char* error, int erro
BoxProject(b->pos); BoxProject(b->pos);
// reorient body // reorient body
b->alt.type = mjORIENTATION_ZAXIS;
mjuu_copyvec(b->alt.zaxis, b->pos, 3); mjuu_copyvec(b->alt.zaxis, b->pos, 3);
mjuu_normvec(b->alt.zaxis, 3); mjuu_normvec(b->alt.zaxis, 3);
+2 -2
View File
@@ -107,7 +107,7 @@ class mjCComposite {
std::string initial; // root boundary type std::string initial; // root boundary type
std::vector<float> uservert; // user-specified vertex positions std::vector<float> uservert; // user-specified vertex positions
std::string userface; // connectivity std::string userface; // connectivity
mjtNum size[3]; // rope size (meaning depends on the shape) double size[3]; // rope size (meaning depends on the shape)
mjtCompShape curve[3]; // geometric shape mjtCompShape curve[3]; // geometric shape
// body names used in the skin // body names used in the skin
@@ -137,7 +137,7 @@ class mjCComposite {
private: private:
mjsBody* AddRopeBody(mjCModel* model, mjsBody* body, int ix, int ix1); mjsBody* AddRopeBody(mjCModel* model, mjsBody* body, int ix, int ix1);
mjsBody* AddCableBody(mjCModel* model, mjsBody* body, int ix, mjtNum normal[3], mjtNum prev_quat[4]); mjsBody* AddCableBody(mjCModel* model, mjsBody* body, int ix, double normal[3], double prev_quat[4]);
// temporary skin vectors // temporary skin vectors
void CopyIntoSkin(mjsSkin* skin); void CopyIntoSkin(mjsSkin* skin);
+16 -20
View File
@@ -14,6 +14,7 @@
#include <algorithm> #include <algorithm>
#include <climits> #include <climits>
#include <cmath>
#include <cstddef> #include <cstddef>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
@@ -26,13 +27,11 @@
#include <mujoco/mjmodel.h> #include <mujoco/mjmodel.h>
#include <mujoco/mjtnum.h> #include <mujoco/mjtnum.h>
#include <mujoco/mjplugin.h> #include <mujoco/mjplugin.h>
#include <mujoco/mujoco.h>
#include "cc/array_safety.h" #include "cc/array_safety.h"
#include "engine/engine_crossplatform.h" #include "engine/engine_crossplatform.h"
#include "engine/engine_resource.h" #include "engine/engine_resource.h"
#include "engine/engine_util_blas.h"
#include "engine/engine_util_errmem.h" #include "engine/engine_util_errmem.h"
#include "engine/engine_util_misc.h"
#include "engine/engine_util_spatial.h"
#include "user/user_flexcomp.h" #include "user/user_flexcomp.h"
#include <mujoco/mjspec.h> #include <mujoco/mjspec.h>
#include "user/user_model.h" #include "user/user_model.h"
@@ -147,7 +146,7 @@ bool mjCFlexcomp::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz) {
} }
// compute orientation // compute orientation
const char* alterr = mjs_resolveOrientation(quat, model->spec.degree, model->spec.euler, &alt); const char* alterr = mjs_resolveOrientation(quat, model->spec.degree, model->spec.eulerseq, &alt);
if (alterr) { if (alterr) {
return comperr(error, alterr, error_sz); return comperr(error, alterr, error_sz);
} }
@@ -250,12 +249,9 @@ bool mjCFlexcomp::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz) {
} }
// apply pose transform to points // apply pose transform to points
mjtNum posn[3], quatn[4];
mju_d2n(posn, pos, 3);
mju_d2n(quatn, quat, 4);
for (int i=0; i < npnt; i++) { for (int i=0; i < npnt; i++) {
mjtNum newp[3], oldp[3] = {point[3*i], point[3*i+1], point[3*i+2]}; double newp[3], oldp[3] = {point[3*i], point[3*i+1], point[3*i+2]};
mju_trnVecPose(newp, posn, quatn, oldp); mjuu_trnVecPose(newp, pos, quat, oldp);
point[3*i] = newp[0]; point[3*i] = newp[0];
point[3*i+1] = newp[1]; point[3*i+1] = newp[1];
point[3*i+2] = newp[2]; point[3*i+2] = newp[2];
@@ -570,7 +566,7 @@ bool mjCFlexcomp::MakeGrid(char* error, int error_sz) {
int quad2tri[2][3] = {{0, 1, 2}, {0, 2, 3}}; int quad2tri[2][3] = {{0, 1, 2}, {0, 2, 3}};
// add point // add point
mjtNum pos[2] = {spacing[0]*(ix - 0.5*(count[0]-1)), double pos[2] = {spacing[0]*(ix - 0.5*(count[0]-1)),
spacing[1]*(iy - 0.5*(count[1]-1))}; spacing[1]*(iy - 0.5*(count[1]-1))};
point.push_back(pos[0]); point.push_back(pos[0]);
point.push_back(pos[1]); point.push_back(pos[1]);
@@ -578,8 +574,8 @@ bool mjCFlexcomp::MakeGrid(char* error, int error_sz) {
// add texture coordinates, if not specified explicitly // add texture coordinates, if not specified explicitly
if (!hastex) { if (!hastex) {
texcoord.push_back(ix/(mjtNum)mjMAX(count[0]-1, 1)); texcoord.push_back(ix/(double)std::max(count[0]-1, 1));
texcoord.push_back(iy/(mjtNum)mjMAX(count[1]-1, 1)); texcoord.push_back(iy/(double)std::max(count[1]-1, 1));
} }
// flip triangles if radial projection is requested // flip triangles if radial projection is requested
@@ -713,7 +709,7 @@ void mjCFlexcomp::BoxProject(double* pos, int ix, int iy, int iz) {
// cylinder // cylinder
else if (type==mjFCOMPTYPE_CYLINDER) { else if (type==mjFCOMPTYPE_CYLINDER) {
double L0 = mjMAX(mju_abs(pos[0]), mju_abs(pos[1])); double L0 = std::max(std::abs(pos[0]), std::abs(pos[1]));
mjuu_normvec(pos, 2); mjuu_normvec(pos, 2);
pos[0] *= size[0]*L0; pos[0] *= size[0]*L0;
pos[1] *= size[1]*L0; pos[1] *= size[1]*L0;
@@ -749,8 +745,8 @@ bool mjCFlexcomp::MakeSquare(char* error, int error_sz) {
}; };
for (int i=0; i < point.size()/3; i++) { for (int i=0; i < point.size()/3; i++) {
mjtNum* pos = point.data() + i*3; double* pos = point.data() + i*3;
double L0 = mjMAX(mju_abs(pos[0]), mju_abs(pos[1])); double L0 = std::max(std::abs(pos[0]), std::abs(pos[1]));
mjuu_normvec(pos, 2); mjuu_normvec(pos, 2);
pos[0] *= size[0]*L0; pos[0] *= size[0]*L0;
pos[1] *= size[1]*L0; pos[1] *= size[1]*L0;
@@ -904,7 +900,7 @@ bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) {
} }
// load resource // load resource
std::string filename = mjuu_makefullname(mjs_getString(model->spec.modelfiledir), std::string filename = mjuu_combinePaths(mjs_getString(model->spec.modelfiledir),
mjs_getString(model->spec.meshdir), file); mjs_getString(model->spec.meshdir), file);
mjResource* resource = nullptr; mjResource* resource = nullptr;
@@ -952,10 +948,10 @@ bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) {
// copy faces // copy faces
element = mesh.face_; element = mesh.face_;
// copy vertices, convert from float to mjtNum // copy vertices, convert from float to double
point = vector<mjtNum> (mesh.nvert()*3); point = vector<double> (mesh.nvert()*3);
for (int i=0; i < mesh.nvert()*3; i++) { for (int i=0; i < mesh.nvert()*3; i++) {
point[i] = (mjtNum) mesh.vert_[i]; point[i] = (double) mesh.vert_[i];
} }
return true; return true;
@@ -1003,7 +999,7 @@ bool mjCFlexcomp::MakeGMSH(mjCModel* model, char* error, int error_sz) {
} }
// open resource // open resource
std::string filename = mjuu_makefullname(mjs_getString(model->spec.modelfiledir), std::string filename = mjuu_combinePaths(mjs_getString(model->spec.modelfiledir),
mjs_getString(model->spec.meshdir), file); mjs_getString(model->spec.meshdir), file);
mjResource* resource = nullptr; mjResource* resource = nullptr;

Some files were not shown because too many files have changed in this diff Show More