Add documentation for mjpDecoder.
PiperOrigin-RevId: 905048609 Change-Id: I6342673cdc53b80406ad77fc95cb8bb5790a5df6
This commit is contained in:
committed by
Copybara-Service
parent
a2ee85f477
commit
2f5e5d3da1
@@ -25,6 +25,11 @@ General
|
|||||||
|
|
||||||
**Migration:** The flag :ref:`multiccd<option-flag-multiccd>` must be explicitly disabled.
|
**Migration:** The flag :ref:`multiccd<option-flag-multiccd>` must be explicitly disabled.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
* Added :ref:`documentation<exDecoder>` for :ref:`mjpDecoder` plugins.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
Extensions
|
Extensions
|
||||||
----------
|
----------
|
||||||
|
|
||||||
This section describes MuJoCo's mechanisms for user-authored extensions. At present, extensibility is provided
|
This section describes MuJoCo's mechanisms for user-authored extensions. At present, extensibility is provided by
|
||||||
via :ref:`engine plugins<exPlugin>` and :ref:`resource providers<exProvider>`.
|
via :ref:`engine plugins<exPlugin>`, :ref:`decoders<exDecoder>`, and :ref:`resource providers<exProvider>`.
|
||||||
|
|
||||||
.. _exPlugin:
|
.. _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
|
Computes the axis-aligned bounding box in local coordinates. This volume is voxelized uniformly before the call to
|
||||||
the marching cubes algorithm.
|
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:
|
.. _exProvider:
|
||||||
|
|
||||||
Resource providers
|
Resource providers
|
||||||
|
|||||||
Reference in New Issue
Block a user