Improve ordering of asset documentation, sort by category and usefulness.

- Old: texture, hfield, mesh, skin, material.
- New: mesh, hfield, skin, texture, material.

Rationale: First 3D assets, then surface assets. Mesh is the most common asset type. Materials reference textures so should come right after.
PiperOrigin-RevId: 602075615
Change-Id: I13e4404640184fb0717a442827cd76da31705648
This commit is contained in:
Yuval Tassa
2024-01-27 17:23:41 -08:00
committed by Copybara-Service
parent 3b0a680fa7
commit 70021a7236
+327 -322
View File
@@ -1138,6 +1138,8 @@ disables the rendering of the corresponding object.
:at:`bvactive`: :at-val:`real(4), "1 0 0 0.5"`
Color used to render active bounding volumes, if the :ref:`bvactive<visual-global-bvactive>` flag is "true".
.. _asset:
**asset** (*)
@@ -1151,6 +1153,331 @@ extension if no ``content_type`` attribute is specified. The content type is ign
file.
.. _asset-mesh:
:el-prefix:`asset/` |-| **mesh** (*)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This element creates a mesh asset, which can then be referenced from geoms. If the referencing geom type is
:at-val:`mesh` the mesh is instantiated in the model, otherwise a geometric primitive is automatically fitted to it; see
the :ref:`geom <body-geom>` element below.
MuJoCo works with triangulated meshes. They can be loaded from binary STL files, OBJ files or MSH files with custom
format described below, or vertex and face data specified directly in the XML. Software such as MeshLab can be used to
convert from other mesh formats to STL or OBJ. While any collection of triangles can be loaded as a mesh and rendered,
collision detection works with the convex hull of the mesh as explained in :ref:`Collision`. See also the convexhull
attribute of the :ref:`compiler <compiler>` element which controls the automatic generation of convex hulls. The mesh
appearance (including texture mapping) is controlled by the :at:`material` and :at:`rgba` attributes of the referencing
geom, similarly to height fields.
Meshes can have explicit texture coordinates instead of relying on the automated texture
mapping mechanism. When provided, these explicit coordinates have priority. Note that texture coordinates can be
specified with OBJ files and MSH files, as well as explicitly in the XML with the :at:`texcoord` attribute, but not via
STL files. These mechanism cannot be mixed. So if you have an STL mesh, the only way to add texture coordinates to it is
to convert to one of the other supported formats.
MSH file format
The binary MSH file starts with 4 integers specifying the number of vertex positions (nvertex), vertex normals
(nnormal), vertex texture coordinates (ntexcoord), and vertex indices making up the faces (nface), followed by the
numeric data. nvertex must be at least 4. nnormal and ntexcoord can be zero (in which case the corresponding data is
not defined) or equal to nvertex. nface can also be zero, in which case faces are constructed automatically from the
convex hull of the vertex positions. The file size in bytes must be exactly: 16 + 12*(nvertex + nnormal + nface) +
8*ntexcoord. The contents of the file must be as follows:
.. code:: Text
(int32) nvertex
(int32) nnormal
(int32) ntexcoord
(int32) nface
(float) vertex_positions[3*nvertex]
(float) vertex_normals[3*nnormal]
(float) vertex_texcoords[2*ntexcoord]
(int32) face_vertex_indices[3*nface]
Poorly designed meshes can display rendering artifacts. In particular, the shadow mapping mechanism relies on having
some distance between front and back-facing triangle faces. If the faces are repeated, with opposite normals as
determined by the vertex order in each triangle, this causes shadow aliasing. The solution is to remove the repeated
faces (which can be done in MeshLab) or use a better designed mesh. Flipped faces are checked by MuJoCo for meshes
specified as OBJ or XML and an error message is returned.
The size of the mesh is determined by the 3D coordinates of the vertex data in the mesh file, multiplied by the
components of the :at:`scale` attribute below. Scaling is applied separately for each coordinate axis. Note that
negative scaling values can be used to flip the mesh; this is a legitimate operation. The size parameters of the
referening geoms are ignored, similarly to height fields. We also provide a mechanism to translate and
rotate the 3D coordinates, using the attributes :ref:`refpos<asset-mesh-refpos>` and :ref:`refquat<asset-mesh-refquat>`.
A mesh can also be defined without faces (a point cloud essentially). In that case
the convex hull is constructed automatically, even if the compiler attribute convexhull is false. This makes it easy to
construct simple shapes directly in the XML. For example, a pyramid can be created as:
.. code-block:: xml
<asset>
<mesh name="tetrahedron" vertex="0 0 0 1 0 0 0 1 0 0 0 1"/>
</asset>
Positioning and orienting is complicated by the fact that vertex data are often designed relative to coordinate frames
whose origin is not inside the mesh. In contrast, MuJoCo expects the origin of a geom's local frame to coincide with the
geometric center of the shape. We resolve this discrepancy by pre-processing the mesh in the compiler, so that it is
centered around (0,0,0) and its principal axes of inertia are the coordinate axes. We also save the translation and
rotation offsets needed to achieve such alignment in :ref:`mjModel.mesh_pos<mjModel>` and
:ref:`mjModel.mesh_quat<mjModel>`. These offsets are then applied to the referencing geom's position and orientation; see
also :at:`mesh` attribute of :ref:`geom <body-geom>` below. Fortunately most meshes used in robot models are designed in
a coordinate frame centered at the joint. This makes the corresponding MJCF model intuitive: we set the body frame at the
joint, so that the joint position is (0,0,0) in the body frame, and simply reference the mesh. Below is an MJCF model
fragment of a forearm, containing all the information needed to put the mesh where one would expect it to be. The body
position is specified relative to the parent body, namely the upper arm (not shown). It is offset by 35 cm which is the
typical length of the human upper arm. If the mesh vertex data were not designed in the above convention, we would have
to use the geom position and orientation (or the new refpos, refquat mechanism) to compensate, but in practice this is
rarely needed.
.. code-block:: xml
<asset>
<mesh file="forearm.stl"/>
</asset>
<body pos="0 0 0.35"/>
<joint type="hinge" axis="1 0 0"/>
<geom type="mesh" mesh="forearm"/>
</body>
The inertial computation mentioned above is part of an algorithm used not only to center and align the mesh, but also to
infer the mass and inertia of the body to which it is attached. This is done by computing the centroid of the triangle
faces, connecting each face with the centroid to form a triangular pyramid, computing the mass and signed inertia of all
pyramids (considered solid or hollow if :at:`shellinertia` is true) and accumulating them. The sign ensures that
pyramids on the outside of the surfaces are subtracted, as it can occur with concave geometries. This algorithm can be
found in section 1.3.8 of Computational Geometry in C (Second Edition) by Joseph O'Rourke.
The full list of processing steps applied by the compiler to each mesh is as follows:
#. For STL meshes, remove any repeated vertices and re-index the faces if needed. If the mesh is not STL, we assume that
the desired vertices and faces have already been generated and do not apply removal or re-indexing;
#. If vertex normals are not provided, generate normals automatically, using a weighted average of the surrounding face
normals. If sharp edges are encountered, the renderer uses the face normals to preserve the visual information about
the edge, unless smoothnormal is true. Note that normals cannot be provided with STL meshes;
#. Scale, translate and rotate the vertices and normals, re-normalize the normals in case of scaling;
#. Construct the convex hull if specified;
#. Find the centroid of all triangle faces, and construct the union-of-pyramids representation. Triangles whose area is
too small (below the :ref:`mjMINVAL <glNumeric>` value of 1E-14) result in compile error;
#. Compute the center of mass and inertia matrix of the union-of-pyramids. Use eigenvalue decomposition to find the
principal axes of inertia. Center and align the mesh, saving the translational and rotational offsets for subsequent
geom-related computations.
.. _asset-mesh-name:
:at:`name`: :at-val:`string, optional`
Name of the mesh, used for referencing. If omitted, the mesh name equals the file name without the path and
extension.
.. _asset-mesh-class:
:at:`class`: :at-val:`string, optional`
Defaults class for setting unspecified attributes (only scale in this case).
.. _asset-mesh-content_type:
:at:`content_type`: :at-val:`string, optional`
If the file attribute is specified, then this sets the
`Media Type <https://www.iana.org/assignments/media-types/media-types.xhtml>`_ (formerly known as MIME type) of the
file to be loaded. Any filename extensions will be overloaded. Currently ``model/vnd.mujoco.msh``, ``model/obj``,
and ``model/stl`` are supported.
.. _asset-mesh-file:
:at:`file`: :at-val:`string, optional`
The file from which the mesh will be loaded. The path is determined as described in the meshdir attribute of
:ref:`compiler <compiler>`. The file extension must be "stl", "msh", or "obj" (not case sensitive) specifying the
file type. If the file name is omitted, the vertex attribute becomes required.
.. _asset-mesh-scale:
:at:`scale`: :at-val:`real(3), "1 1 1"`
This attribute specifies the scaling that will be applied to the vertex data along each coordinate axis. Negative
values are allowed, resulting in flipping the mesh along the corresponding axis.
.. _asset-mesh-smoothnormal:
:at:`smoothnormal`: :at-val:`[false, true], "false"`
Controls the automatic generation of vertex normals when normals are not given explicitly. If true, smooth normals
are generated by averaging the face normals at each vertex, with weight proportional to the face area. If false,
faces at large angles relative to the average normal are excluded from the average. In this way, sharp edges (as in
cube edges) are not smoothed.
.. _asset-mesh-vertex:
:at:`vertex`: :at-val:`real(3*nvert), optional`
Vertex 3D position data. You can specify position data in the XML using this attribute, or using a binary file, but
not both.
.. _asset-mesh-normal:
:at:`normal`: :at-val:`real(3*nvert), optional`
Vertex 3D normal data. If specified, the number of normals must equal the number of vertices. The model compiler
normalizes the normals automatically.
.. _asset-mesh-texcoord:
:at:`texcoord`: :at-val:`real(2*nvert), optional`
Vertex 2D texture coordinates, which are numbers between 0 and 1. If specified, the number of texture coordinate
pairs must equal the number of vertices.
.. _asset-mesh-face:
:at:`face`: :at-val:`int(3*nface), optional`
Faces of the mesh. Each face is a sequence of 3 vertex indices, in counter-clockwise order. The indices must be
integers between 0 and nvert-1.
.. _asset-mesh-refpos:
:at:`refpos`: :at-val:`real(3), "0 0 0"`
Reference position relative to which the 3D vertex coordinates are defined. This vector is subtracted from the
positions.
.. _asset-mesh-refquat:
:at:`refquat`: :at-val:`real(4), "1 0 0 0"`
Reference orientation relative to which the 3D vertex coordinates and normals are defined. The conjugate of this
quaternion is used to rotate the positions and normals. The model compiler normalizes the quaternion automatically.
.. _mesh-plugin:
:el-prefix:`mesh/` |-| **plugin** (?)
'''''''''''''''''''''''''''''''''''''
Associate this mesh with an :ref:`engine plugin<exPlugin>`. Either :at:`plugin` or :at:`instance` are required.
.. _mesh-plugin-plugin:
:at:`plugin`: :at-val:`string, optional`
Plugin identifier, used for implicit plugin instantiation.
.. _mesh-plugin-instance:
:at:`instance`: :at-val:`string, optional`
Instance name, used for explicit plugin instantiation.
.. _asset-hfield:
:el-prefix:`asset/` |-| **hfield** (*)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This element creates a height field asset, which can then be referenced from geoms with type "hfield". A height field,
also known as terrain map, is a 2D matrix of elevation data. The data can be specified in one of three ways:
#. The elevation data can be loaded from a PNG file. The image is converted internally to gray scale, and the intensity
of each pixel is used to define elevation; white is high and black is low.
#. The elevation data can be loaded from a binary file in the custom format described below. As with all other matrices
used in MuJoCo, the data ordering is row-major, like pixels in an image. If the data size is nrow-by-ncol, the file
must have 4*(2+nrow*ncol) bytes:
::
(int32) nrow
(int32) ncol
(float32) data[nrow*ncol]
#. The elevation data can be left undefined at compile time. This is done by specifying the attributes nrow and ncol.
The compiler allocates space for the height field data in mjModel and sets it to 0. The user can then generate a
custom height field at runtime, either programmatically or using sensor data.
| Regardless of which method is used to specify the elevation data, the compiler always normalizes it to the range [0
1]. However if the data is left undefined at compile time and generated later at runtime, it is the user's
responsibility to normalize it.
| The position and orientation of the height field is determined by the geom that references it. The spatial extent on
the other hand is specified by the height field asset itself via the size attribute, and cannot be modified by the
referencing geom (the geom size parameters are ignored in this case). The same approach is used for meshes below:
positioning is done by the geom while sizing is done by the asset. This is because height fields and meshes involve
sizing operations that are not common to other geoms.
| For collision detection, a height field is treated as a union of triangular prisms. Collisions between height fields
and other geoms (except for planes and other height fields which are not supported) are computed by first selecting
the sub-grid of prisms that could collide with the geom based on its bounding box, and then using the general convex
collider. The number of possible contacts between a height field and a geom is limited to 50
(:ref:`mjMAXCONPAIR <glNumeric>`); any contacts beyond that are discarded. To avoid penetration due to discarded
contacts, the spatial features of the height field should be large compared to the geoms it collides with.
.. _asset-hfield-name:
:at:`name`: :at-val:`string, optional`
Name of the height field, used for referencing. If the name is omitted and a file name is specified, the height field
name equals the file name without the path and extension.
.. _asset-hfield-content_type:
:at:`content_type`: :at-val:`string, optional`
If the file attribute is specified, then this sets the
`Media Type <https://www.iana.org/assignments/media-types/media-types.xhtml>`__ (formerly known as MIME types) of the
file to be loaded. Any filename extensions will be overloaded. Currently ``image/png`` and
``image/vnd.mujoco.hfield`` are supported.
.. _asset-hfield-file:
:at:`file`: :at-val:`string, optional`
If this attribute is specified, the elevation data is loaded from the given file. If the file extension is ".png",
not case-sensitive, the file is treated as a PNG file. Otherwise it is treated as a binary file in the above custom
format. The number of rows and columns in the data are determined from the file contents. Loading data from a file
and setting nrow or ncol below to non-zero values results is compile error, even if these settings are consistent
with the file contents.
.. _asset-hfield-nrow:
:at:`nrow`: :at-val:`int, "0"`
This attribute and the next are used to allocate a height field in mjModel and leave the elevation data undefined
(i.e., set to 0). This attribute specifies the number of rows in the elevation data matrix. The default value of 0
means that the data will be loaded from a file, which will be used to infer the size of the matrix.
.. _asset-hfield-ncol:
:at:`ncol`: :at-val:`int, "0"`
This attribute specifies the number of columns in the elevation data matrix.
.. _asset-hfield-size:
:at:`size`: :at-val:`real(4), required`
.. figure:: images/XMLreference/peaks.png
:width: 350px
:align: right
The four numbers here are (radius_x, radius_y, elevation_z, base_z). The height field is centered at the referencing
geom's local frame. Elevation is in the +Z direction. The first two numbers specify the X and Y extent (or "radius")
of the rectangle over which the height field is defined. This may seem unnatural for rectangles, but it is natural
for spheres and other geom types, and we prefer to use the same convention throughout the model. The third number is
the maximum elevation; it scales the elevation data which is normalized to [0-1]. Thus the minimum elevation point is
at Z=0 and the maximum elevation point is at Z=elevation_z. The last number is the depth of a box in the -Z direction
serving as a "base" for the height field. Without this automatically generated box, the height field would have zero
thickness at places there the normalized elevation data is zero. Unlike planes which impose global unilateral
constraints, height fields are treated as unions of regular geoms, so there is no notion of being "under" the height
field. Instead a geom is either inside or outside the height field - which is why the inside part must have non-zero
thickness. The example on the right is the MATLAB "peaks" surface saved in our custom height field format, and loaded
as an asset with size = "1 1 1 0.1". The horizontal size of the box is 2, the difference between the maximum and
minimum elevation is 1, and the depth of the base added below the minimum elevation point is 0.1.
.. _asset-skin:
:el-prefix:`asset/` |-| **skin** (*)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. _asset-skin-name:
.. _asset-skin-file:
.. _asset-skin-vertex:
.. _asset-skin-texcoord:
.. _asset-skin-face:
.. _asset-skin-inflate:
.. _asset-skin-material:
.. _asset-skin-rgba:
.. _asset-skin-group:
:ref:`Skins<deformable-skin>` have been moved under the new grouping element :ref:`deformable<deformable>`. They can
still be specified here but this functionality is now deprecated and will be removed in the future.
.. _asset-texture:
:el-prefix:`asset/` |-| **texture** (*)
@@ -1363,328 +1690,6 @@ file.
If true, images loaded from file are flipped in the vertical direction. Does not affect procedural textures.
.. _asset-hfield:
:el-prefix:`asset/` |-| **hfield** (*)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This element creates a height field asset, which can then be referenced from geoms with type "hfield". A height field,
also known as terrain map, is a 2D matrix of elevation data. The data can be specified in one of three ways:
#. The elevation data can be loaded from a PNG file. The image is converted internally to gray scale, and the intensity
of each pixel is used to define elevation; white is high and black is low.
#. The elevation data can be loaded from a binary file in the custom format described below. As with all other matrices
used in MuJoCo, the data ordering is row-major, like pixels in an image. If the data size is nrow-by-ncol, the file
must have 4*(2+nrow*ncol) bytes:
::
(int32) nrow
(int32) ncol
(float32) data[nrow*ncol]
#. The elevation data can be left undefined at compile time. This is done by specifying the attributes nrow and ncol.
The compiler allocates space for the height field data in mjModel and sets it to 0. The user can then generate a
custom height field at runtime, either programmatically or using sensor data.
| Regardless of which method is used to specify the elevation data, the compiler always normalizes it to the range [0
1]. However if the data is left undefined at compile time and generated later at runtime, it is the user's
responsibility to normalize it.
| The position and orientation of the height field is determined by the geom that references it. The spatial extent on
the other hand is specified by the height field asset itself via the size attribute, and cannot be modified by the
referencing geom (the geom size parameters are ignored in this case). The same approach is used for meshes below:
positioning is done by the geom while sizing is done by the asset. This is because height fields and meshes involve
sizing operations that are not common to other geoms.
| For collision detection, a height field is treated as a union of triangular prisms. Collisions between height fields
and other geoms (except for planes and other height fields which are not supported) are computed by first selecting
the sub-grid of prisms that could collide with the geom based on its bounding box, and then using the general convex
collider. The number of possible contacts between a height field and a geom is limited to 50
(:ref:`mjMAXCONPAIR <glNumeric>`); any contacts beyond that are discarded. To avoid penetration due to discarded
contacts, the spatial features of the height field should be large compared to the geoms it collides with.
.. _asset-hfield-name:
:at:`name`: :at-val:`string, optional`
Name of the height field, used for referencing. If the name is omitted and a file name is specified, the height field
name equals the file name without the path and extension.
.. _asset-hfield-content_type:
:at:`content_type`: :at-val:`string, optional`
If the file attribute is specified, then this sets the
`Media Type <https://www.iana.org/assignments/media-types/media-types.xhtml>`__ (formerly known as MIME types) of the
file to be loaded. Any filename extensions will be overloaded. Currently ``image/png`` and
``image/vnd.mujoco.hfield`` are supported.
.. _asset-hfield-file:
:at:`file`: :at-val:`string, optional`
If this attribute is specified, the elevation data is loaded from the given file. If the file extension is ".png",
not case-sensitive, the file is treated as a PNG file. Otherwise it is treated as a binary file in the above custom
format. The number of rows and columns in the data are determined from the file contents. Loading data from a file
and setting nrow or ncol below to non-zero values results is compile error, even if these settings are consistent
with the file contents.
.. _asset-hfield-nrow:
:at:`nrow`: :at-val:`int, "0"`
This attribute and the next are used to allocate a height field in mjModel and leave the elevation data undefined
(i.e., set to 0). This attribute specifies the number of rows in the elevation data matrix. The default value of 0
means that the data will be loaded from a file, which will be used to infer the size of the matrix.
.. _asset-hfield-ncol:
:at:`ncol`: :at-val:`int, "0"`
This attribute specifies the number of columns in the elevation data matrix.
.. _asset-hfield-size:
:at:`size`: :at-val:`real(4), required`
.. figure:: images/XMLreference/peaks.png
:width: 350px
:align: right
The four numbers here are (radius_x, radius_y, elevation_z, base_z). The height field is centered at the referencing
geom's local frame. Elevation is in the +Z direction. The first two numbers specify the X and Y extent (or "radius")
of the rectangle over which the height field is defined. This may seem unnatural for rectangles, but it is natural
for spheres and other geom types, and we prefer to use the same convention throughout the model. The third number is
the maximum elevation; it scales the elevation data which is normalized to [0-1]. Thus the minimum elevation point is
at Z=0 and the maximum elevation point is at Z=elevation_z. The last number is the depth of a box in the -Z direction
serving as a "base" for the height field. Without this automatically generated box, the height field would have zero
thickness at places there the normalized elevation data is zero. Unlike planes which impose global unilateral
constraints, height fields are treated as unions of regular geoms, so there is no notion of being "under" the height
field. Instead a geom is either inside or outside the height field - which is why the inside part must have non-zero
thickness. The example on the right is the MATLAB "peaks" surface saved in our custom height field format, and loaded
as an asset with size = "1 1 1 0.1". The horizontal size of the box is 2, the difference between the maximum and
minimum elevation is 1, and the depth of the base added below the minimum elevation point is 0.1.
.. _asset-mesh:
:el-prefix:`asset/` |-| **mesh** (*)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This element creates a mesh asset, which can then be referenced from geoms. If the referencing geom type is
:at-val:`mesh` the mesh is instantiated in the model, otherwise a geometric primitive is automatically fitted to it; see
the :ref:`geom <body-geom>` element below.
MuJoCo works with triangulated meshes. They can be loaded from binary STL files, OBJ files or MSH files with custom
format described below, or vertex and face data specified directly in the XML. Software such as MeshLab can be used to
convert from other mesh formats to STL or OBJ. While any collection of triangles can be loaded as a mesh and rendered,
collision detection works with the convex hull of the mesh as explained in :ref:`Collision`. See also the convexhull
attribute of the :ref:`compiler <compiler>` element which controls the automatic generation of convex hulls. The mesh
appearance (including texture mapping) is controlled by the :at:`material` and :at:`rgba` attributes of the referencing
geom, similarly to height fields.
Meshes can have explicit texture coordinates instead of relying on the automated texture
mapping mechanism. When provided, these explicit coordinates have priority. Note that texture coordinates can be
specified with OBJ files and MSH files, as well as explicitly in the XML with the :at:`texcoord` attribute, but not via
STL files. These mechanism cannot be mixed. So if you have an STL mesh, the only way to add texture coordinates to it is
to convert to one of the other supported formats.
MSH file format
The binary MSH file starts with 4 integers specifying the number of vertex positions (nvertex), vertex normals
(nnormal), vertex texture coordinates (ntexcoord), and vertex indices making up the faces (nface), followed by the
numeric data. nvertex must be at least 4. nnormal and ntexcoord can be zero (in which case the corresponding data is
not defined) or equal to nvertex. nface can also be zero, in which case faces are constructed automatically from the
convex hull of the vertex positions. The file size in bytes must be exactly: 16 + 12*(nvertex + nnormal + nface) +
8*ntexcoord. The contents of the file must be as follows:
.. code:: Text
(int32) nvertex
(int32) nnormal
(int32) ntexcoord
(int32) nface
(float) vertex_positions[3*nvertex]
(float) vertex_normals[3*nnormal]
(float) vertex_texcoords[2*ntexcoord]
(int32) face_vertex_indices[3*nface]
Poorly designed meshes can display rendering artifacts. In particular, the shadow mapping mechanism relies on having
some distance between front and back-facing triangle faces. If the faces are repeated, with opposite normals as
determined by the vertex order in each triangle, this causes shadow aliasing. The solution is to remove the repeated
faces (which can be done in MeshLab) or use a better designed mesh. Flipped faces are checked by MuJoCo for meshes
specified as OBJ or XML and an error message is returned.
The size of the mesh is determined by the 3D coordinates of the vertex data in the mesh file, multiplied by the
components of the :at:`scale` attribute below. Scaling is applied separately for each coordinate axis. Note that
negative scaling values can be used to flip the mesh; this is a legitimate operation. The size parameters of the
referening geoms are ignored, similarly to height fields. We also provide a mechanism to translate and
rotate the 3D coordinates, using the attributes :ref:`refpos<asset-mesh-refpos>` and :ref:`refquat<asset-mesh-refquat>`.
A mesh can also be defined without faces (a point cloud essentially). In that case
the convex hull is constructed automatically, even if the compiler attribute convexhull is false. This makes it easy to
construct simple shapes directly in the XML. For example, a pyramid can be created as:
.. code-block:: xml
<asset>
<mesh name="tetrahedron" vertex="0 0 0 1 0 0 0 1 0 0 0 1"/>
</asset>
Positioning and orienting is complicated by the fact that vertex data are often designed relative to coordinate frames
whose origin is not inside the mesh. In contrast, MuJoCo expects the origin of a geom's local frame to coincide with the
geometric center of the shape. We resolve this discrepancy by pre-processing the mesh in the compiler, so that it is
centered around (0,0,0) and its principal axes of inertia are the coordinate axes. We also save the translation and
rotation offsets needed to achieve such alignment in :ref:`mjModel.mesh_pos<mjModel>` and
:ref:`mjModel.mesh_quat<mjModel>`. These offsets are then applied to the referencing geom's position and orientation; see
also :at:`mesh` attribute of :ref:`geom <body-geom>` below. Fortunately most meshes used in robot models are designed in
a coordinate frame centered at the joint. This makes the corresponding MJCF model intuitive: we set the body frame at the
joint, so that the joint position is (0,0,0) in the body frame, and simply reference the mesh. Below is an MJCF model
fragment of a forearm, containing all the information needed to put the mesh where one would expect it to be. The body
position is specified relative to the parent body, namely the upper arm (not shown). It is offset by 35 cm which is the
typical length of the human upper arm. If the mesh vertex data were not designed in the above convention, we would have
to use the geom position and orientation (or the new refpos, refquat mechanism) to compensate, but in practice this is
rarely needed.
.. code-block:: xml
<asset>
<mesh file="forearm.stl"/>
</asset>
<body pos="0 0 0.35"/>
<joint type="hinge" axis="1 0 0"/>
<geom type="mesh" mesh="forearm"/>
</body>
The inertial computation mentioned above is part of an algorithm used not only to center and align the mesh, but also to
infer the mass and inertia of the body to which it is attached. This is done by computing the centroid of the triangle
faces, connecting each face with the centroid to form a triangular pyramid, computing the mass and signed inertia of all
pyramids (considered solid or hollow if :at:`shellinertia` is true) and accumulating them. The sign ensures that
pyramids on the outside of the surfaces are subtracted, as it can occur with concave geometries. This algorithm can be
found in section 1.3.8 of Computational Geometry in C (Second Edition) by Joseph O'Rourke.
The full list of processing steps applied by the compiler to each mesh is as follows:
#. For STL meshes, remove any repeated vertices and re-index the faces if needed. If the mesh is not STL, we assume that
the desired vertices and faces have already been generated and do not apply removal or re-indexing;
#. If vertex normals are not provided, generate normals automatically, using a weighted average of the surrounding face
normals. If sharp edges are encountered, the renderer uses the face normals to preserve the visual information about
the edge, unless smoothnormal is true. Note that normals cannot be provided with STL meshes;
#. Scale, translate and rotate the vertices and normals, re-normalize the normals in case of scaling;
#. Construct the convex hull if specified;
#. Find the centroid of all triangle faces, and construct the union-of-pyramids representation. Triangles whose area is
too small (below the :ref:`mjMINVAL <glNumeric>` value of 1E-14) result in compile error;
#. Compute the center of mass and inertia matrix of the union-of-pyramids. Use eigenvalue decomposition to find the
principal axes of inertia. Center and align the mesh, saving the translational and rotational offsets for subsequent
geom-related computations.
.. _asset-mesh-name:
:at:`name`: :at-val:`string, optional`
Name of the mesh, used for referencing. If omitted, the mesh name equals the file name without the path and
extension.
.. _asset-mesh-class:
:at:`class`: :at-val:`string, optional`
Defaults class for setting unspecified attributes (only scale in this case).
.. _asset-mesh-content_type:
:at:`content_type`: :at-val:`string, optional`
If the file attribute is specified, then this sets the
`Media Type <https://www.iana.org/assignments/media-types/media-types.xhtml>`_ (formerly known as MIME type) of the
file to be loaded. Any filename extensions will be overloaded. Currently ``model/vnd.mujoco.msh``, ``model/obj``,
and ``model/stl`` are supported.
.. _asset-mesh-file:
:at:`file`: :at-val:`string, optional`
The file from which the mesh will be loaded. The path is determined as described in the meshdir attribute of
:ref:`compiler <compiler>`. The file extension must be "stl", "msh", or "obj" (not case sensitive) specifying the
file type. If the file name is omitted, the vertex attribute becomes required.
.. _asset-mesh-scale:
:at:`scale`: :at-val:`real(3), "1 1 1"`
This attribute specifies the scaling that will be applied to the vertex data along each coordinate axis. Negative
values are allowed, resulting in flipping the mesh along the corresponding axis.
.. _asset-mesh-smoothnormal:
:at:`smoothnormal`: :at-val:`[false, true], "false"`
Controls the automatic generation of vertex normals when normals are not given explicitly. If true, smooth normals
are generated by averaging the face normals at each vertex, with weight proportional to the face area. If false,
faces at large angles relative to the average normal are excluded from the average. In this way, sharp edges (as in
cube edges) are not smoothed.
.. _asset-mesh-vertex:
:at:`vertex`: :at-val:`real(3*nvert), optional`
Vertex 3D position data. You can specify position data in the XML using this attribute, or using a binary file, but
not both.
.. _asset-mesh-normal:
:at:`normal`: :at-val:`real(3*nvert), optional`
Vertex 3D normal data. If specified, the number of normals must equal the number of vertices. The model compiler
normalizes the normals automatically.
.. _asset-mesh-texcoord:
:at:`texcoord`: :at-val:`real(2*nvert), optional`
Vertex 2D texture coordinates, which are numbers between 0 and 1. If specified, the number of texture coordinate
pairs must equal the number of vertices.
.. _asset-mesh-face:
:at:`face`: :at-val:`int(3*nface), optional`
Faces of the mesh. Each face is a sequence of 3 vertex indices, in counter-clockwise order. The indices must be
integers between 0 and nvert-1.
.. _asset-mesh-refpos:
:at:`refpos`: :at-val:`real(3), "0 0 0"`
Reference position relative to which the 3D vertex coordinates are defined. This vector is subtracted from the
positions.
.. _asset-mesh-refquat:
:at:`refquat`: :at-val:`real(4), "1 0 0 0"`
Reference orientation relative to which the 3D vertex coordinates and normals are defined. The conjugate of this
quaternion is used to rotate the positions and normals. The model compiler normalizes the quaternion automatically.
.. _mesh-plugin:
:el-prefix:`mesh/` |-| **plugin** (?)
'''''''''''''''''''''''''''''''''''''
Associate this mesh with an :ref:`engine plugin<exPlugin>`. Either :at:`plugin` or :at:`instance` are required.
.. _mesh-plugin-plugin:
:at:`plugin`: :at-val:`string, optional`
Plugin identifier, used for implicit plugin instantiation.
.. _mesh-plugin-instance:
:at:`instance`: :at-val:`string, optional`
Instance name, used for explicit plugin instantiation.
.. _asset-skin:
:el-prefix:`asset/` |-| **skin** (*)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. _asset-skin-name:
.. _asset-skin-file:
.. _asset-skin-vertex:
.. _asset-skin-texcoord:
.. _asset-skin-face:
.. _asset-skin-inflate:
.. _asset-skin-material:
.. _asset-skin-rgba:
.. _asset-skin-group:
:ref:`Skins<deformable-skin>` have been moved under the new grouping element :ref:`deformable<deformable>`. They can
still be specified here but this functionality is now deprecated and will be removed in the future.
.. _asset-material: