Add documentation for mjpDecoder.

PiperOrigin-RevId: 905048609
Change-Id: I6342673cdc53b80406ad77fc95cb8bb5790a5df6
This commit is contained in:
Michael Moss
2026-04-24 08:37:43 -07:00
committed by Copybara-Service
parent a2ee85f477
commit 2f5e5d3da1
2 changed files with 140 additions and 2 deletions
+5
View File
@@ -25,6 +25,11 @@ General
**Migration:** The flag :ref:`multiccd<option-flag-multiccd>` must be explicitly disabled.
Documentation
^^^^^^^^^^^^^
* Added :ref:`documentation<exDecoder>` for :ref:`mjpDecoder` plugins.
Bug fixes
^^^^^^^^^
+135 -2
View File
@@ -3,8 +3,8 @@
Extensions
----------
This section describes MuJoCo's mechanisms for user-authored extensions. At present, extensibility is provided
via :ref:`engine plugins<exPlugin>` and :ref:`resource providers<exProvider>`.
This section describes MuJoCo's mechanisms for user-authored extensions. At present, extensibility is provided by
via :ref:`engine plugins<exPlugin>`, :ref:`decoders<exDecoder>`, and :ref:`resource providers<exProvider>`.
.. _exPlugin:
@@ -337,6 +337,139 @@ For the sdf plugin, the following methods need to be specified
Computes the axis-aligned bounding box in local coordinates. This volume is voxelized uniformly before the call to
the marching cubes algorithm.
.. _exDecoder:
Decoders
~~~~~~~~
Decoder plugins extend asset loading capabilities beyond MJCF and URDF. They are :ref:`registered<mjPLUGIN_LIB_INIT>`
similarly to other MuJoCo plugins.
MuJoCo ships with two built-in decoders for common mesh formats:
- **OBJ decoder** (``plugin/obj_decoder``) -- `Wavefront OBJ <https://en.wikipedia.org/wiki/Wavefront_.obj_file>`_.
- **STL decoder** (``plugin/stl_decoder``) -- `STL <https://en.wikipedia.org/wiki/STL_(file_format)>`_.
Additionally, we provide the following optional decoder plugins:
- **USD decoder** (``plugin/usd_decoder``) -- `Universal Scene Description <https://openusd.org/release/index.html>`_.
These plugins also serve as examples for how to write custom decoders. The obj decoder is perhaps the simplest to
understand, while the USD decoder is more complex due to its support for entire scenes.
.. _exDecoderInterface:
Decoder interface
^^^^^^^^^^^^^^^^^
A decoder is described by the :ref:`mjpDecoder` struct, which has the following fields:
``content_type``
A MIME-like content type string identifying the format. For example, ``"model/obj"``, or ``"model/stl"``.
When a mesh asset specifies a ``content-type`` attribute in MJCF, this string is used
to find the appropriate decoder.
``extension``
A file extension string (including the dot) used for matching when no content type is specified. Multiple
extensions can be separated by pipes (`|`) for formats with multiple extensions such as ``.usd|.usda|.usdc|.usdz``.
``can_decode``
A callback of type :ref:`mjfCanDecode` that determines whether the decoder can handle a given resource. This is
typically implemented by checking the file extension but may also check the file contents to differentiate between
formats. For example, URDF and MJCF files both have a ``.xml`` extension. Returns nonzero if the decoder can handle
the resource.
``decode``
A callback of type :ref:`mjfDecode` that performs the actual decoding. It receives an :ref:`mjResource` and
returns a newly allocated :ref:`mjSpec` containing the decoded asset data. The caller takes
ownership of the returned spec and is responsible for freeing it with :ref:`mj_deleteSpec`. Returns ``NULL`` on
failure.
When a decoder is invoked for a mesh asset, the compiler will reference the first mesh element in the spec returned
by the ``decode`` callback.
When a decoder is invoked for a model asset, the spec returned by the ``decode`` callback may contain any number of
elements of any type.
.. _exDecoderRegistration:
Registration
^^^^^^^^^^^^
Decoders must be registered before they can be used. Registration is performed via
:ref:`mjp_registerDecoder`. The :ref:`mjp_defaultDecoder` function initializes an :ref:`mjpDecoder` struct with
default values. The :ref:`mjPLUGIN_LIB_INIT` macro is used to define the initialization function that registers the
decoder when the library is loaded.
.. code-block:: C
mjPLUGIN_LIB_INIT(my_format_decoder) {
mjpDecoder decoder;
mjp_defaultDecoder(&decoder);
decoder.content_type = "model/my-format";
decoder.extension = ".myf|.myfa|.myfc";
decoder.decode = MyDecode;
decoder.can_decode = MyCanDecode;
mjp_registerDecoder(&decoder);
}
.. _exDecoderExample:
Example
^^^^^^^
Below is a minimal decoder that reads a hypothetical binary mesh format:
.. code-block:: C
#include <mujoco.h>
static mjSpec* MyDecode(mjResource* resource, const mjVFS* vfs) {
const void* bytes = NULL;
int nbytes = mju_readResource(resource, &bytes);
if (nbytes < 0) {
mju_warning("failed to read resource '%s'", resource->name);
return NULL;
}
/* ... parse bytes into vertex/face arrays ... */
mjSpec* spec = mj_makeSpec();
mjsMesh* mesh = mjs_addMesh(spec, NULL);
mjs_setString(mesh->file, resource->name);
mjs_setFloat(mesh->uservert, vertices, nvert * 3);
mjs_setInt(mesh->userface, faces, nface * 3);
return spec;
}
static int MyCanDecode(const mjResource* resource) {
/* check file extension */
const char* name = resource->name;
int len = strlen(name);
return len > 4 && strcmp(name + len - 4, ".myf") == 0;
}
mjPLUGIN_LIB_INIT(my_format_decoder) {
mjpDecoder decoder;
mjp_defaultDecoder(&decoder);
decoder.content_type = "model/my-format";
decoder.extension = ".myf";
decoder.decode = MyDecode;
decoder.can_decode = MyCanDecode;
mjp_registerDecoder(&decoder);
}
Once registered, the decoder is used automatically when MuJoCo encounters an asset with a matching file extension
or content type:
.. code-block:: xml
<asset>
<mesh file="my_mesh.myf"/>
</asset>
.. _exProvider:
Resource providers