Skip to content

Commit

Permalink
Introduce trilinear flex parametrization.
Browse files Browse the repository at this point in the history
These flexes use only 24 DOFs (3 per vertex of the bounding box), while colliding with the full high resolution mesh.

On an 8x8x8 cube, the performance using DOFs at all vertices is

```
 Simulation time      : 18.74 s
 Steps per second     : 533
 Realtime factor      : 0.53 x
 Time per step        : 1874.4 µs

 Contacts per step    : 114.88
 Constraints per step : 3322.51
 Degrees of freedom   : 1536
```

With the new implementation, it is the following:

```
 Simulation time      : 1.82 s
 Steps per second     : 5507
 Realtime factor      : 5.51 x
 Time per step        : 181.6 µs

 Contacts per step    : 38.84
 Constraints per step : 155.36
 Degrees of freedom   : 24
```

PiperOrigin-RevId: 721008829
Change-Id: I833df027527db578d86667cc4b24295bcf6f7d22
quagla authored and copybara-github committed Jan 29, 2025
1 parent 1a4b821 commit 7cdf180
Showing 47 changed files with 8,967 additions and 96 deletions.
4 changes: 2 additions & 2 deletions doc/APIreference/functions.rst
Original file line number Diff line number Diff line change
@@ -3572,8 +3572,8 @@ Construct quaternion performing rotation from z-axis to given vector.

.. mujoco-include:: mju_mat2Rot

extract 3D rotation from an arbitrary 3x3 matrix by refining the input quaternion
returns the number of iterations required to converge
Extract 3D rotation from an arbitrary 3x3 matrix by refining the input quaternion.
Returns the number of iterations required to converge

.. _mju_euler2Quat:

45 changes: 45 additions & 0 deletions doc/XMLreference.rst
Original file line number Diff line number Diff line change
@@ -3487,6 +3487,45 @@ saving the XML:
radius in 2D, and tetrahedra with radius in 3D. Certain flexcomp types imply a dimensionality, in which case the
value specified here is ignored.

.. youtube:: uNt3i8hrJu4
:align: right
:width: 240px

.. _body-flexcomp-dof:

:at:`dof`: :at-val:`[full, radial, trilinear], "full"`
The parametrization of the flex's degrees of freedom (dofs). See the video on the right illustrating the
different parametrizations with deformable spheres. The three models in the video are respectively
`sphere_full <https://github.com/google-deepmind/mujoco/blob/main/model/flex/sphere_full.xml>`__,
`sphere_radial <https://github.com/google-deepmind/mujoco/blob/main/model/flex/sphere_radial.xml>`__
and `sphere_trilinear <https://github.com/google-deepmind/mujoco/blob/main/model/flex/sphere_trilinear.xml>`__.

**full**
Three translational dofs per vertex. This is the most expressive but also the most expensive option.

**radial**
A single radial translational dof per vertex. Note that unlike in the "full" case, the radial parametrization
requires a free joint at the flex's parent in order for free body motion to be possible. This type of
parametrization is appropriate for shapes that are relatively spherical.

**trilinear**
Three translational dofs at each corner of the bounding box of the flex, for a total of 24 dofs for the entire
flex, independent of the number of vertices. The positions of the vertices are updated using trilinear
interpolation over the bounding box.

.. youtube:: qJFbx-FR7Bc
:align: right
:width: 240px

Trilinear flexes are much faster than the previous two options, and are the preferred choice if the expected
deformations can be captured by the reduced parametriation. For example, see the video on the right comparing `full
<https://github.com/google-deepmind/mujoco/blob/main/model/flex/gripper.xml>`__ and `trilinear
<https://github.com/google-deepmind/mujoco/blob/main/model/flex/gripper_trilinear.xml>`__ flexes for modeling
deformable gripper pads.

Note that the choice of dof parametrization affects the deformation modes of the flex but has no effect on the
accuracy of the collision geometry, which always takes into account the high-resolution mesh of the flex.

.. _body-flexcomp-type:

:at:`type`: :at-val:`[grid, box, cylinder, ellipsoid, disc, circle, mesh, gmsh, direct], "grid"`
@@ -4081,6 +4120,12 @@ cases, the user will specify a :el:`flexcomp` which will then automatically cons
Integer group to which the flex belongs. This attribute can be used for custom tags. It is also used by the
visualizer to enable and disable the rendering of entire groups of flexes.

.. _deformable-flex-node:

:at:`node`: :at-val:`string(nnode), optional`
The degrees-of-freedom of the flex.
An array of MuJoCo body names (separated by white space) to which each node belongs. The number of body names
should equal the number of nodes (nnode). See the flexcomp :ref:`dof<body-flexcomp-dof>` attribute for more details.

.. _flex-edge:

14 changes: 7 additions & 7 deletions doc/XMLschema.rst
Original file line number Diff line number Diff line change
@@ -435,17 +435,17 @@
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`name<body-flexcomp-name>` | :ref:`type<body-flexcomp-type>` | :ref:`group<body-flexcomp-group>` | :ref:`dim<body-flexcomp-dim>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`count<body-flexcomp-count>` | :ref:`spacing<body-flexcomp-spacing>` | :ref:`radius<body-flexcomp-radius>` | :ref:`rigid<body-flexcomp-rigid>` | |
| | | | :ref:`dof<body-flexcomp-dof>` | :ref:`count<body-flexcomp-count>` | :ref:`spacing<body-flexcomp-spacing>` | :ref:`radius<body-flexcomp-radius>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`mass<body-flexcomp-mass>` | :ref:`inertiabox<body-flexcomp-inertiabox>` | :ref:`scale<body-flexcomp-scale>` | :ref:`file<body-flexcomp-file>` | |
| | | | :ref:`rigid<body-flexcomp-rigid>` | :ref:`mass<body-flexcomp-mass>` | :ref:`inertiabox<body-flexcomp-inertiabox>` | :ref:`scale<body-flexcomp-scale>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`point<body-flexcomp-point>` | :ref:`element<body-flexcomp-element>` | :ref:`texcoord<body-flexcomp-texcoord>` | :ref:`material<body-flexcomp-material>` | |
| | | | :ref:`file<body-flexcomp-file>` | :ref:`point<body-flexcomp-point>` | :ref:`element<body-flexcomp-element>` | :ref:`texcoord<body-flexcomp-texcoord>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`rgba<body-flexcomp-rgba>` | :ref:`flatskin<body-flexcomp-flatskin>` | :ref:`pos<body-flexcomp-pos>` | :ref:`quat<body-flexcomp-quat>` | |
| | | | :ref:`material<body-flexcomp-material>` | :ref:`rgba<body-flexcomp-rgba>` | :ref:`flatskin<body-flexcomp-flatskin>` | :ref:`pos<body-flexcomp-pos>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`axisangle<body-flexcomp-axisangle>` | :ref:`xyaxes<body-flexcomp-xyaxes>` | :ref:`zaxis<body-flexcomp-zaxis>` | :ref:`euler<body-flexcomp-euler>` | |
| | | | :ref:`quat<body-flexcomp-quat>` | :ref:`axisangle<body-flexcomp-axisangle>` | :ref:`xyaxes<body-flexcomp-xyaxes>` | :ref:`zaxis<body-flexcomp-zaxis>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`origin<body-flexcomp-origin>` | | | | |
| | | | :ref:`euler<body-flexcomp-euler>` | :ref:`origin<body-flexcomp-origin>` | | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_2| flexcomp |br| |_2| |L| | | .. table:: |
@@ -509,7 +509,7 @@
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`material<deformable-flex-material>` | :ref:`rgba<deformable-flex-rgba>` | :ref:`flatskin<deformable-flex-flatskin>` | :ref:`body<deformable-flex-body>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`vertex<deformable-flex-vertex>` | :ref:`element<deformable-flex-element>` | :ref:`texcoord<deformable-flex-texcoord>` | | |
| | | | :ref:`vertex<deformable-flex-vertex>` | :ref:`element<deformable-flex-element>` | :ref:`texcoord<deformable-flex-texcoord>` | :ref:`node<deformable-flex-node>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_2| flex |br| |_2| |L| | | .. table:: |
19 changes: 19 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
@@ -5,8 +5,27 @@ Changelog
Upcoming version (not yet released)
-----------------------------------


Feature promotion
^^^^^^^^^^^^^^^^^
.. youtube:: qJFbx-FR7Bc
:align: right
:width: 240px

- Introduced a new kind of **fast deformable body**, activated by setting :ref:`flexcomp/dof<body-flexcomp-dof>` to
"trilinear". This type of :ref:`deformable<CDeformable>` flex object has the same collision geometry as a regular
flex, but has far fewer degrees of freedom. Instead of 3 dofs per vertex, only the corners of the bounding box are
free to move, with the positions of the interior vertices computed with trilinear interpolation of the 8 corners, for
a total of 24 dofs for the entire flex object (or less, if some of the corners are pinned). This limits the types of
deformation achievable by the flex, but allows for much faster simulation. For example, see the video on the right
comparing `full <https://github.com/google-deepmind/mujoco/blob/main/model/flex/gripper.xml>`__ and `trilinear
<https://github.com/google-deepmind/mujoco/blob/main/model/flex/gripper_trilinear.xml>`__ flexes for modeling
deformable gripper pads.

General
^^^^^^^
- Separate collision and deformation meshes for :ref:`flex<deformable-flex>`. This enables a fixed cost for the soft
body computations, while preserving the fidelity of high-resolution collisions.
- Added :ref:`mjs_setDeepCopy` API function. When the deep copy flag is 0, attaching a model will not copy it to the
parent, so the original references to the child can be used to modify the parent after attachment. The default
behavior is to perform such a shallow copy. The old behavior of creating a deep copy of the child model while
15 changes: 15 additions & 0 deletions doc/includes/references.h
Original file line number Diff line number Diff line change
@@ -901,6 +901,7 @@ struct mjModel_ {
int ncam; // number of cameras
int nlight; // number of lights
int nflex; // number of flexes
int nflexnode; // number of dofs in all flexes
int nflexvert; // number of vertices in all flexes
int nflexedge; // number of edges in all flexes
int nflexelem; // number of elements in all flexes
@@ -1153,6 +1154,9 @@ struct mjModel_ {
int* flex_dim; // 1: lines, 2: triangles, 3: tetrahedra (nflex x 1)
int* flex_matid; // material id for rendering (nflex x 1)
int* flex_group; // group for visibility (nflex x 1)
int* flex_interp; // interpolation (0: vertex, 1: nodes) (nflex x 1)
int* flex_nodeadr; // first node address (nflex x 1)
int* flex_nodenum; // number of nodes (nflex x 1)
int* flex_vertadr; // first vertex address (nflex x 1)
int* flex_vertnum; // number of vertices (nflex x 1)
int* flex_edgeadr; // first edge address (nflex x 1)
@@ -1166,6 +1170,7 @@ struct mjModel_ {
int* flex_evpairadr; // first evpair address (nflex x 1)
int* flex_evpairnum; // number of evpairs (nflex x 1)
int* flex_texcoordadr; // address in flex_texcoord; -1: none (nflex x 1)
int* flex_nodebodyid; // node body ids (nflexnode x 1)
int* flex_vertbodyid; // vertex body ids (nflexvert x 1)
int* flex_edge; // edge vertex ids (2 per edge) (nflexedge x 2)
int* flex_elem; // element vertex ids (dim+1 per elem) (nflexelemdata x 1)
@@ -1175,6 +1180,8 @@ struct mjModel_ {
int* flex_evpair; // (element, vertex) collision pairs (nflexevpair x 2)
mjtNum* flex_vert; // vertex positions in local body frames (nflexvert x 3)
mjtNum* flex_vert0; // vertex positions in qpos0 on [0, 1]^d (nflexvert x 3)
mjtNum* flex_node; // node positions in local body frames (nflexnode x 3)
mjtNum* flex_node0; // Cartesian node positions in qpos0 (nflexnode x 3)
mjtNum* flexedge_length0; // edge lengths in qpos0 (nflexedge x 1)
mjtNum* flexedge_invweight0; // edge inv. weight in qpos0 (nflexedge x 1)
mjtNum* flex_radius; // radius around primitive element (nflex x 1)
@@ -1983,7 +1990,9 @@ typedef struct mjsFlex_ { // flex specification
double thickness; // thickness (2D only)

// mesh properties
mjStringVec* nodebody; // node body names
mjStringVec* vertbody; // vertex body names
mjDoubleVec* node; // node positions
mjDoubleVec* vert; // vertex positions
mjIntVec* elem; // element vertex ids
mjFloatVec* texcoord; // vertex texture coordinates
@@ -2968,6 +2977,10 @@ struct mjvSceneState_ {
int* flex_dim;
int* flex_matid;
int* flex_group;
int* flex_interp;
int* flex_nodeadr;
int* flex_nodenum;
int* flex_nodebodyid;
int* flex_vertadr;
int* flex_vertnum;
int* flex_elem;
@@ -2981,6 +2994,8 @@ struct mjvSceneState_ {
int* flex_texcoordadr;
int* flex_bvhadr;
int* flex_bvhnum;
mjtByte* flex_centered;
mjtNum* flex_node;
mjtNum* flex_radius;
float* flex_rgba;

Loading

0 comments on commit 7cdf180

Please sign in to comment.