Improve composite docs and changelog.

PiperOrigin-RevId: 730394496
Change-Id: Ie993214deb82b526a96510e02f6ecff103c58607
This commit is contained in:
Alessio Quaglino
2025-02-24 04:25:38 -08:00
committed by Copybara-Service
parent 81b1948b46
commit b3aa5df68a
7 changed files with 78 additions and 131 deletions
+17 -48
View File
@@ -2964,14 +2964,14 @@ the direction specified by the dir attribute. It does not have a full spatial fr
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is not a model element, but rather a macro which expands into multiple model elements representing a composite This is not a model element, but rather a macro which expands into multiple model elements representing a composite
object. These elements are bodies (with their own joints, geoms and sites) that become children of the parent body object. These elements are bodies (with their own joints and geoms) that become children of the parent body containing
containing the macro, as well as tendons and equality constraints added to the corresponding model sections. The the macro. The macro expansion is done by the model compiler. If the resulting model is then saved, the macro will be
automatically-generated bodies are laid out in a regular grid in 1D, 2D or 3D depending on the object type and count
attributes. The macro expansion is done by the model compiler. If the resulting model is then saved, the macro will be
replaced with the actual model elements. The defaults mechanism used in the rest of MJCF does not apply here, even if replaced with the actual model elements. The defaults mechanism used in the rest of MJCF does not apply here, even if
the parent body has a childclass attribute defined. Instead there are internal defaults adjusted automatically for each the parent body has a childclass attribute defined. Instead there are internal defaults adjusted automatically for each
composite object type. Composite objects can only be defined if the model is in local coordinates. Using them in global composite object type. See :ref:`CComposite` in the modeling guide for more detailed explanation. Note that there used
coordinates results in compiler error. See :ref:`CComposite` in the modeling guide for more detailed explanation. to be several composite types, but they have incrementally replaced by :ref:`replicate<replicate>` (for repeated
objects) and :ref:`flexcomp<body-flexcomp>` (for soft objects). Therefore, the only supported composite type is now
cable, which produces an inextensible chain of bodies connected with ball joints.
.. _body-composite-prefix: .. _body-composite-prefix:
@@ -2982,16 +2982,8 @@ coordinates results in compiler error. See :ref:`CComposite` in the modeling gui
.. _body-composite-type: .. _body-composite-type:
:at:`type`: :at-val:`[particle, cable], required` :at:`type`: :at-val:`[cable], required`
This attribute determines the type of composite object. The remaining attributes and sub-elements are then This attribute determines the type of composite object. The only supported type is cable.
interpreted according to the type. Default settings are also adjusted depending on the type.
The **particle** type creates a 1D, 2D or 3D grid of equally-spaced bodies. By default, each body has a single sphere
geom and 3 orthogonal sliding joints, allowing translation but not rotation. The geom condim and priority attributes
are set to 1 by default. This makes the spheres have frictionless contacts with all other geoms (unless the priority
of some frictional geom is higher). The user can replace the default sliders with multiple joints of kind="particle"
and replace the default sphere with a custom geom. Note that the particle composite type is deprecated and might be
removed in a future version. Instead of particle, it is recommended to use :ref:`replicate`.
The **cable** type creates a 1D chain of bodies connected with ball joints, each having a geom with user-defined type The **cable** type creates a 1D chain of bodies connected with ball joints, each having a geom with user-defined type
(cylinder, capsule or box). The geometry can either be defined with an array of 3D vertex coordinates :at:`vertex` (cylinder, capsule or box). The geometry can either be defined with an array of 3D vertex coordinates :at:`vertex`
@@ -3013,41 +3005,30 @@ coordinates results in compiler error. See :ref:`CComposite` in the modeling gui
.. _body-composite-offset: .. _body-composite-offset:
:at:`offset`: :at-val:`real(3), "0 0 0"` :at:`offset`: :at-val:`real(3), "0 0 0"`
This attribute affects particle and grid types, and is ignored for all other types. It specifies a 3D offset from the It specifies a 3D offset from the center of the parent body to the center of the grid of elements. The offset is
center of the parent body to the center of the grid of elements. The offset is expressed in the local coordinate expressed in the local coordinate frame of the parent body.
frame of the parent body.
.. _body-composite-flatinertia:
:at:`flatinertia`: :at-val:`real, "0"`
This attribute affects the cloth type and is ignored for all other types. The default value 0 disables this
mechanism. When the value is positive, it specifies the ratio of the small-to-large axes of the modified diagonal
inertia. The idea is to set it to a small value, say 0.01, in which case the inertias of the body elements will
corresponds to flat boxes aligned with the cloth (which can then be used for lift forces). This will not change the
geom shapes, but instead will set the body inertias directly and disable the automatic computation of inertia from
geom shape for the composite body only.
.. _body-composite-vertex: .. _body-composite-vertex:
:at:`vertex`: :at-val:`real(3*nvert), optional` :at:`vertex`: :at-val:`real(3*nvert), optional`
Vertex 3D positions in global coordinates (cable only). Vertex 3D positions in global coordinates.
.. _body-composite-initial: .. _body-composite-initial:
:at:`initial`: :at-val:`[free, ball, none], "0"` :at:`initial`: :at-val:`[free, ball, none], "0"`
Behavior of the first point (cable only). Free: free joint. Ball: ball joint. None: no dof. Behavior of the first point. Free: free joint. Ball: ball joint. None: no dof.
.. _body-composite-curve: .. _body-composite-curve:
:at:`curve`: :at-val:`string(3), optional` :at:`curve`: :at-val:`string(3), optional`
Functions specifying the vertex positions (cable only). Available functions are `s`, `cos(s)`, and `sin(s)`, where Functions specifying the vertex positions. Available functions are `s`, `cos(s)`, and `sin(s)`, where `s` is the arc
`s` is the arc length parameter. length parameter.
.. _body-composite-size: .. _body-composite-size:
:at:`size`: :at-val:`int(3), optional` :at:`size`: :at-val:`int(3), optional`
Scaling of the curve functions (cable only). `size[0]` is the scaling of `s`, `size[1]` is the radius of `\cos(s)` Scaling of the curve functions. `size[0]` is the scaling of `s`, `size[1]` is the radius of `\cos(s)` and `\sin(s)`,
and `\sin(s)`, and `size[2]` is the speed of the argument (i.e. `\cos(2*\pi*size[2]*s)`). and `size[2]` is the speed of the argument (i.e. `\cos(2*\pi*size[2]*s)`).
.. _composite-joint: .. _composite-joint:
@@ -3061,7 +3042,7 @@ joints should be created, as well as to adjust the attributes of both automatic
.. _composite-joint-kind: .. _composite-joint-kind:
:at:`kind`: :at-val:`[main, twist, stretch, particle], required` :at:`kind`: :at-val:`[main], required`
The joint kind here is orthogonal to the joint type in the rest of MJCF. The joint kind refers to the function of the The joint kind here is orthogonal to the joint type in the rest of MJCF. The joint kind refers to the function of the
joint within the mechanism comprising the composite body, while the joint type (hinge or slide) is implied by the joint within the mechanism comprising the composite body, while the joint type (hinge or slide) is implied by the
joint kind and composite body type. joint kind and composite body type.
@@ -3071,18 +3052,6 @@ joints should be created, as well as to adjust the attributes of both automatic
sliders for box, cylinder and rope; universal joints for cloth, rope and loop. Even though the main joints are sliders for box, cylinder and rope; universal joints for cloth, rope and loop. Even though the main joints are
included automatically, this sub-element is still useful for adjusting their attributes. included automatically, this sub-element is still useful for adjusting their attributes.
The **twist** kind corresponds to hinge joints enabling rope, loop and cloth objects to twist. These are optional
joints and are only created if this sub-element is present. This sub-element is also used to adjust the attributes of
the optional twist joints. For other composite object types this sub-element has no effect.
The **stretch** kind corresponds to slide joints enabling rope, loop and cloth objects to stretch. These are optional
joints and are only created if this sub-element is present. This sub-element is also used to adjust the attributes of
the optional stretch joints. For other composite object types this sub-element has no effect.
The **particle** kind can only be used with the particle composite type. As opposed to all previous kinds, this kind
*replaces* the default 3 sliders with user-defined joints. User-defined joints can be repeated, for example
to create planar particles with two sliders and a hinge.
.. _composite-joint-solreffix: .. _composite-joint-solreffix:
.. _composite-joint-solimpfix: .. _composite-joint-solimpfix:
+1 -3
View File
@@ -342,9 +342,7 @@
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`prefix<body-composite-prefix>` | :ref:`type<body-composite-type>` | :ref:`count<body-composite-count>` | :ref:`offset<body-composite-offset>` | | | | | | :ref:`prefix<body-composite-prefix>` | :ref:`type<body-composite-type>` | :ref:`count<body-composite-count>` | :ref:`offset<body-composite-offset>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`flatinertia<body-composite-flatinertia>` | :ref:`vertex<body-composite-vertex>` | :ref:`initial<body-composite-initial>` | :ref:`curve<body-composite-curve>` | | | | | | :ref:`vertex<body-composite-vertex>` | :ref:`initial<body-composite-initial>` | :ref:`curve<body-composite-curve>` | :ref:`size<body-composite-size>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`size<body-composite-size>` | | | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_2| composite |br| |_2| |L| | | .. table:: | | |_2| composite |br| |_2| |L| | | .. table:: |
+7 -7
View File
@@ -29,20 +29,17 @@ General
and a ``clear_figures`` method. and a ``clear_figures`` method.
- Separate collision and deformation meshes for :ref:`flex<deformable-flex>`. This enables a fixed cost for the soft - 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. 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
attaching can be restored by setting the deep copy flag to 1.
- Added :ref:`potential<sensor-e_potential>` and :ref:`kinetic<sensor-e_kinetic>` energy sensors. - Added :ref:`potential<sensor-e_potential>` and :ref:`kinetic<sensor-e_kinetic>` energy sensors.
- Improved shadow rendering in the native renderer. - Improved shadow rendering in the native renderer.
- Moved ``introspect`` to ``python/introspect``. - Moved ``introspect`` to ``python/introspect``.
- Removed the ``particle`` composite type. It is recommended to use the more generic :ref:`replicate<replicate>`
instead, for example `this model
<https://github.com/google-deepmind/mujoco/blob/main/model/replicate/particle.xml>`__.
.. admonition:: Breaking API changes .. admonition:: Breaking API changes
:class: attention :class: attention
- 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
attaching can be restored by setting the deep copy flag to 1.
- Changes to inertia inference from meshes: - Changes to inertia inference from meshes:
Previously, in order to specify that the mass lies on the surface, :ref:`geom/shellinertia<body-geom-shellinertia>` Previously, in order to specify that the mass lies on the surface, :ref:`geom/shellinertia<body-geom-shellinertia>`
@@ -52,6 +49,9 @@ General
Previously, if the volumetric inertia computation failed (for example due to a very flat mesh), the compiler Previously, if the volumetric inertia computation failed (for example due to a very flat mesh), the compiler
would silently fall back to surface inertia computation. Now, the compiler will throw an informative error. would silently fall back to surface inertia computation. Now, the compiler will throw an informative error.
- Removed the composite type ``grid``. Users should instead use :ref:`flexcomp<body-flexcomp>`. - Removed the composite type ``grid``. Users should instead use :ref:`flexcomp<body-flexcomp>`.
- Removed the ``particle`` composite type. It is recommended to use the more generic :ref:`replicate<replicate>`
instead, see for example `this
model<https://github.com/google-deepmind/mujoco/blob/main/model/replicate/particle.xml>`__.
MJX MJX
^^^ ^^^
+48 -57
View File
@@ -1121,59 +1121,40 @@ Intrinsics
Composite objects Composite objects
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
Composite objects are not new model elements. Instead, they are (large) collections of existing elements designed to Composite objects are not new model elements. Instead, they are collections of existing element originally designed to
simulate particle systems, ropes, cloth, and soft bodies. These collections are generated by the model compiler simulate particle systems, ropes, cloth, and soft bodies. Over time, most of these types have been replaced by
automatically. The user configures the automatic generator on a high level, using the new XML element :ref:`replicate<replicate>` (for repeated objects) and :ref:`flexcomp<body-flexcomp>` (for soft objects). Therefore, the
:ref:`composite <body-composite>` and its attributes and sub-elements, as described in the XML reference only supported composite type is now ``cable``, which produces an inextensible chain of bodies connected with ball
chapter. If the compiled model is then saved, :el:`composite` is no longer present and is replaced with the collection joints.
of regular model elements that were automatically generated. So think of it as a macro that gets expanded by the model
compiler.
Composite objects are made up of regular MuJoCo bodies, which we call "element bodies" in this context. The element Composite objects are made up of regular MuJoCo bodies, which we call "element bodies" in this context. The collection
bodies are created as children of the body within which :el:`composite` appears; thus a composite object appears in the of element bodies is generated by the model compiler automatically. The user configures the automatic generator on a
same place in the XML where a regular child body may have been defined. Each automatically-generated element body has a high level, using the new XML element :ref:`composite <body-composite>` and its attributes and sub-elements, as
single geom attached to it, usually a sphere but could also be a capsule or an ellipsoid. Thus the composite object is described in the XML reference chapter. If the compiled model is then saved, :el:`composite` is no longer present and is
essentially a particle system, however the particles can be constrained to move together in ways that simulate various replaced with the collection of regular model elements that were automatically generated. So think of it as a macro that
flexible objects. The initial positions of the element bodies form a regular grid in 1D, 2D or 3D. They could all be gets expanded by the model compiler. The element bodies are created as children of the body within which :el:`composite`
children of the parent body (which can be the world or another regular body; composite objects cannot be nested) and appears; thus a composite object appears in the same place in the XML where a regular child body may have been defined.
have joints allowing motion relative to the parent, or they could form a kinematic tree with joints between the element Each automatically-generated element body has a single geom attached to it. We have designed the composite object
bodies. They can also be connected with tendons with soft equality constraints on the tendon length, creating the generator to have intuitive high-level controls as much as possible, but at the same time it exposes a large number of
necessary coupling. Joint equality constraints are also used in some cases. The :at:`solref` and :at:`solimp` attributes options that interact with each other and can profoundly affect the resulting physics. So at some point users should
of these equality constraints can be adjusted by the user, thereby adjusting the softness and flexibility of the read the :ref:`reference documentation <body-composite>` carefully.
composite objects.
In addition to setting up the physics, the composite object generator creates suitable rendering. 2D and 3D objects In addition to setting up the physics, the composite object generator creates suitable rendering. Objects can be
can be rendered as :ref:`skins <asset-skin>`. The skin is generated rendered as :ref:`skins <asset-skin>`. The skin is generated automatically, and can be textured as well as subdivided
automatically, and can be textured as well as subdivided using bi-cubic interpolation. The actual physics and in using bi-cubic interpolation. The actual physics and in particular the collision detection are based on the element
particular the collision detection are based on the element bodies and their geoms, while the skin is purely a bodies and their geoms, while the skin is purely a visualization object. Yet in some situations we prefer to look at the
visualization object. Yet in most situations we prefer to look at the skin representation. To facilitate this, the skin representation, as in `this model
generator places all geoms, sites and tendons in group 3 whose visualization is disabled by default. So when you load <https://github.com/google-deepmind/mujoco/blob/main/model/plugin/elasticity/belt.xml>`__, whose skin is a continuous
a 2D grid for example, you will see a continuous flexible surface and not a collection of spheres connected with flexible surface and not a collection of discontinuous thin boxes. However when fine-tuning the model and trying to
tendons. However when fine-tuning the model and trying to understand the physics behind it, it is useful to be able to understand the physics behind it, it is useful to be able to render the geoms. To switch the rendering style, disable
render the spheres and tendons. To switch the rendering style, disable the rendering of skins and enable group 3 for the rendering of skins and enable group 3 for geoms and tendons.
geoms and tendons.
We have designed the composite object generator to have intuitive high-level controls as much as possible, but at the
same time it exposes a large number of options that interact with each other and can profoundly affect the resulting
physics. So at some point users should read the :ref:`reference documentation <body-composite>` carefully.
As a quick start though, MuJoCo comes with an example of each composite object type. Below we go over these
examples and explain the less obvious aspects. In all examples we have a static scene which is included in the model,
followed by a single composite object. The static scene has a mocap body (large capsule) that can be moved around with
the mouse to probe the behavior of the system. The XML snippets below are just the definition of the composite object;
see the XML model files in the distribution for the complete examples.
**Particle**.
The particle type is deprecated. It is recommended to use the more generic :ref:`replicate<replicate>` instead, for
example `this model <https://github.com/google-deepmind/mujoco/blob/main/model/replicate/particle.xml>`__.
**Grid**.
The grid composite type has been removed. It is recommended to use 2D flex :ref:`deformable objects <CDeformable>` for
simulating thin elastic structures.
**Cable**. **Cable**.
As a quick start, MuJoCo comes with an example of composite cables. In all examples we have a static scene which is
included in the model, followed by a single composite object. The XML snippets below are just the definition of the
composite object; see the XML model files in the distribution for the complete examples.
|coil| |coil|
.. code-block:: xml .. code-block:: xml
@@ -1207,6 +1188,16 @@ stiffnesses can be set independently. Moreover, it is possible to specify if the
curve, such as in the case of coil springs. The cable requires using a first-party :ref:`engine plugin<exPlugin>`, which curve, such as in the case of coil springs. The cable requires using a first-party :ref:`engine plugin<exPlugin>`, which
may be integrated directly into the engine in the future. may be integrated directly into the engine in the future.
**Particle**.
The particle type is deprecated. It is recommended to use the more generic :ref:`replicate<replicate>` instead, for
example `this model <https://github.com/google-deepmind/mujoco/blob/main/model/replicate/particle.xml>`__.
**Grid**.
The grid composite type has been removed. It is recommended to use 2D flex :ref:`deformable objects <CDeformable>` for
simulating thin elastic structures.
**Rope and loop**. **Rope and loop**.
The rope and loop are deprecated. It is recommended to use the cable for simulating inextensible elastic rods that are The rope and loop are deprecated. It is recommended to use the cable for simulating inextensible elastic rods that are
@@ -1431,15 +1422,15 @@ mocap bodies around:
|particle| |particle|
The key thing to understand about mocap bodies is that the simulator treats them as being fixed. We are causing them The key thing to understand about mocap bodies is that the simulator treats them as being fixed. We are causing them to
to move from one simulation time step to the next by updating their position and orientation directly, but as far as move from one simulation time step to the next by updating their position and orientation directly, but as far as the
the physics model is concerned their position and orientation are constant. So what happens if we make contact with a physics model is concerned their position and orientation are constant. So what happens if we make contact with a
regular dynamic body, as in the composite object examples provided with the MuJoCo distribution (recall that in regular dynamic body, as in the particle examples provided with the MuJoCo distribution (recall that in those example we
those example we have a capsule probe which is a mocap body that we move with the mouse). A contact between two have a capsule probe which is a mocap body that we move with the mouse). A contact between two regular bodies will
regular bodies will experience penetration as well as relative velocity, while contact with a mocap body is missing experience penetration as well as relative velocity, while contact with a mocap body is missing the relative velocity
the relative velocity component because the simulator does not know that the mocap body itself is moving. So the component because the simulator does not know that the mocap body itself is moving. So the resulting contact force is
resulting contact force is smaller and it takes longer for the contact to push the dynamic object away. Also, in more smaller and it takes longer for the contact to push the dynamic object away. Also, in more complex simulations the fact
complex simulations the fact that we are doing something inconsistent with the physics can cause instabilities. that we are doing something inconsistent with the physics can cause instabilities.
There is however a better-behaved alternative. In addition to the mocap body, we include a second regular body and There is however a better-behaved alternative. In addition to the mocap body, we include a second regular body and
connect it to the mocap body with a weld equality constraint. In the plots below, the pink box is the mocap body and connect it to the mocap body with a weld equality constraint. In the plots below, the pink box is the mocap body and
-1
View File
@@ -58,7 +58,6 @@ mjCComposite::mjCComposite(void) {
type = mjCOMPTYPE_PARTICLE; type = mjCOMPTYPE_PARTICLE;
count[0] = count[1] = count[2] = 1; count[0] = count[1] = count[2] = 1;
mjuu_setvec(offset, 0, 0, 0); mjuu_setvec(offset, 0, 0, 0);
flatinertia = 0;
// plugin variables // plugin variables
mjs_defaultPlugin(&plugin); mjs_defaultPlugin(&plugin);
-6
View File
@@ -38,11 +38,6 @@ typedef enum _mjtCompType {
typedef enum _mjtCompKind { typedef enum _mjtCompKind {
mjCOMPKIND_JOINT = 0, mjCOMPKIND_JOINT = 0,
mjCOMPKIND_TWIST,
mjCOMPKIND_STRETCH,
mjCOMPKIND_TENDON,
mjCOMPKIND_SHEAR,
mjCOMPKIND_PARTICLE,
mjNCOMPKINDS mjNCOMPKINDS
} mjtCompKind; } mjtCompKind;
@@ -79,7 +74,6 @@ class mjCComposite {
mjtCompType type; // composite type mjtCompType type; // composite type
int count[3]; // geom count in each dimension int count[3]; // geom count in each dimension
double offset[3]; // position offset for particle and grid double offset[3]; // position offset for particle and grid
double flatinertia; // flatten ineria of cloth elements; 0: disable
// currently used only for cable // currently used only for cable
std::string initial; // root boundary type std::string initial; // root boundary type
+5 -9
View File
@@ -287,8 +287,8 @@ const char* MJCF[nMJCF][mjXATTRNUM] = {
{"<"}, {"<"},
{"config", "*", "2", "key", "value"}, {"config", "*", "2", "key", "value"},
{">"}, {">"},
{"composite", "*", "9", "prefix", "type", "count", "offset", {"composite", "*", "8", "prefix", "type", "count", "offset",
"flatinertia", "vertex", "initial", "curve", "size"}, "vertex", "initial", "curve", "size"},
{"<"}, {"<"},
{"joint", "*", "17", "kind", "group", "stiffness", "damping", "armature", {"joint", "*", "17", "kind", "group", "stiffness", "damping", "armature",
"solreffix", "solimpfix", "type", "axis", "solreffix", "solimpfix", "type", "axis",
@@ -742,11 +742,8 @@ const mjMap comp_map[mjNCOMPTYPES] = {
// composite joint kind // composite joint kind
const mjMap jkind_map[4] = { const mjMap jkind_map[1] = {
{"main", mjCOMPKIND_JOINT}, {"main", mjCOMPKIND_JOINT}
{"twist", mjCOMPKIND_TWIST},
{"stretch", mjCOMPKIND_STRETCH},
{"particle", mjCOMPKIND_PARTICLE}
}; };
@@ -2399,7 +2396,6 @@ void mjXReader::OneComposite(XMLElement* elem, mjsBody* body, const mjsDefault*
} }
ReadAttr(elem, "count", 3, comp.count, text, false, false); ReadAttr(elem, "count", 3, comp.count, text, false, false);
ReadAttr(elem, "offset", 3, comp.offset, text); ReadAttr(elem, "offset", 3, comp.offset, text);
ReadAttr(elem, "flatinertia", 1, &comp.flatinertia, text);
// plugin // plugin
XMLElement* eplugin = FirstChildElement(elem, "plugin"); XMLElement* eplugin = FirstChildElement(elem, "plugin");
@@ -2502,7 +2498,7 @@ void mjXReader::OneComposite(XMLElement* elem, mjsBody* body, const mjsDefault*
while (ejnt) { while (ejnt) {
// kind // kind
int kind; int kind;
MapValue(ejnt, "kind", &kind, jkind_map, 4, true); MapValue(ejnt, "kind", &kind, jkind_map, 1, true);
// create a new element if this kind already exists // create a new element if this kind already exists
if (comp.add[kind]) { if (comp.add[kind]) {