Merge branch 'main' into open3d-removal
This commit is contained in:
+121
-1
@@ -1636,6 +1636,11 @@ still be specified here but this functionality is now deprecated and will be rem
|
|||||||
:at:`vflip`: :at-val:`[false, true], "false"`
|
:at:`vflip`: :at-val:`[false, true], "false"`
|
||||||
If true, images loaded from file are flipped in the vertical direction. Does not affect procedural textures.
|
If true, images loaded from file are flipped in the vertical direction. Does not affect procedural textures.
|
||||||
|
|
||||||
|
.. _asset-texture-nchannel:
|
||||||
|
|
||||||
|
:at:`nchannel`: :at-val:`int, "3"`
|
||||||
|
The number of channels in the texture image file. This allows loading 4-channel textures (RGBA) or single-channel
|
||||||
|
textures (e.g., for Physics-Based Rendering properties such as roughness or metallic).
|
||||||
|
|
||||||
|
|
||||||
.. _asset-material:
|
.. _asset-material:
|
||||||
@@ -1666,7 +1671,12 @@ properties are grouped together.
|
|||||||
If this attribute is specified, the material has a texture associated with it. Referencing the material from a model
|
If this attribute is specified, the material has a texture associated with it. Referencing the material from a model
|
||||||
element will cause the texture to be applied to that element. Note that the value of this attribute is the name of a
|
element will cause the texture to be applied to that element. Note that the value of this attribute is the name of a
|
||||||
texture asset, not a texture file name. Textures cannot be loaded in the material definition; instead they must be
|
texture asset, not a texture file name. Textures cannot be loaded in the material definition; instead they must be
|
||||||
loaded explicitly via the :ref:`texture <asset-texture>` element and then referenced here.
|
loaded explicitly via the :ref:`texture <asset-texture>` element and then referenced here. The texture referenced
|
||||||
|
here is used for specifying the RGB values. For advanced rendering (e.g., Physics-Based Rendering), more texture
|
||||||
|
types need to be specified (e.g., roughness, metallic). In this case, this texture attribute should be omitted, and
|
||||||
|
the texture types should be specified explicitly via the specific role child elements, e.g.,
|
||||||
|
:ref:`texture <material-orm>`. Note however that the built-in renderer does not support PBR properties, so these
|
||||||
|
advanced rendering features are only available when using an external renderer.
|
||||||
|
|
||||||
.. _asset-material-texrepeat:
|
.. _asset-material-texrepeat:
|
||||||
|
|
||||||
@@ -1738,6 +1748,116 @@ properties are grouped together.
|
|||||||
model element which defines its own local rgba attribute, the local definition has precedence. Note that this "local"
|
model element which defines its own local rgba attribute, the local definition has precedence. Note that this "local"
|
||||||
definition could in fact come from a defaults class. The remaining material properties always apply.
|
definition could in fact come from a defaults class. The remaining material properties always apply.
|
||||||
|
|
||||||
|
.. _material-rgb:
|
||||||
|
|
||||||
|
:el-prefix:`material/` |-| **rgb** (?)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This element references a texture asset used to specify base color / albedo values.
|
||||||
|
|
||||||
|
.. _material-rgb-texture:
|
||||||
|
|
||||||
|
:at:`texture`: :at-val:`string, required`
|
||||||
|
Name of the texture, expected to have exactly 3 channels.
|
||||||
|
|
||||||
|
.. _material-normal:
|
||||||
|
|
||||||
|
:el-prefix:`material/` |-| **normal** (?)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This element references a texture asset used to specify the bump map (surface normals).
|
||||||
|
|
||||||
|
.. _material-normal-texture:
|
||||||
|
|
||||||
|
:at:`texture`: :at-val:`string, required`
|
||||||
|
Name of the texture, expected to have exactly 3 channels.
|
||||||
|
|
||||||
|
.. _material-occlusion:
|
||||||
|
|
||||||
|
:el-prefix:`material/` |-| **occlusion** (?)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This element references a texture asset used to specify ambient occlusion.
|
||||||
|
|
||||||
|
.. _material-occlusion-texture:
|
||||||
|
|
||||||
|
:at:`texture`: :at-val:`string, required`
|
||||||
|
Name of the texture, expected to have exactly one channel.
|
||||||
|
|
||||||
|
.. _material-roughness:
|
||||||
|
|
||||||
|
:el-prefix:`material/` |-| **roughness** (?)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This element references a texture asset used to specify the roughness map.
|
||||||
|
|
||||||
|
.. _material-roughness-texture:
|
||||||
|
|
||||||
|
:at:`texture`: :at-val:`string, required`
|
||||||
|
Name of the texture, expected to have exactly one channel.
|
||||||
|
|
||||||
|
.. _material-metallic:
|
||||||
|
|
||||||
|
:el-prefix:`material/` |-| **metallic** (?)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This element references a texture asset used to specify the metallic map.
|
||||||
|
|
||||||
|
.. _material-metallic-texture:
|
||||||
|
|
||||||
|
:at:`texture`: :at-val:`string, required`
|
||||||
|
Name of the texture, expected to have exactly one channel.
|
||||||
|
|
||||||
|
.. _material-opacity:
|
||||||
|
|
||||||
|
:el-prefix:`material/` |-| **opacity** (?)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This element references a texture asset used to specify the opacity map (alpha channel, transparency).
|
||||||
|
|
||||||
|
.. _material-opacity-texture:
|
||||||
|
|
||||||
|
:at:`texture`: :at-val:`string, required`
|
||||||
|
Name of the texture, expected to have exactly one channel.
|
||||||
|
|
||||||
|
.. _material-emissive:
|
||||||
|
|
||||||
|
:el-prefix:`material/` |-| **emissive** (?)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This element references a texture asset used to specify light emission.
|
||||||
|
|
||||||
|
.. _material-emissive-texture:
|
||||||
|
|
||||||
|
:at:`texture`: :at-val:`string, required`
|
||||||
|
Name of the texture, expected to have exactly 4 channels.
|
||||||
|
|
||||||
|
.. _material-orm:
|
||||||
|
|
||||||
|
:el-prefix:`material/` |-| **orm** (?)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This element references a texture asset used to specify a packed ORM map, where occlusion, roughness, and metallic
|
||||||
|
are joined into the corresponding RGB values of a single texture.
|
||||||
|
|
||||||
|
.. _material-orm-texture:
|
||||||
|
|
||||||
|
:at:`texture`: :at-val:`string, required`
|
||||||
|
Name of the texture, expected to have exactly 3 channels.
|
||||||
|
|
||||||
|
.. _material-rgba:
|
||||||
|
|
||||||
|
:el-prefix:`material/` |-| **rgba** (?)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This element references a texture asset used to specify a packed map where albedo and opacity are joined into the same
|
||||||
|
4-channel texture.
|
||||||
|
|
||||||
|
.. _material-rgba-texture:
|
||||||
|
|
||||||
|
:at:`texture`: :at-val:`string, required`
|
||||||
|
Name of the texture, expected to have exactly 4 channels.
|
||||||
|
|
||||||
|
|
||||||
.. _asset-model:
|
.. _asset-model:
|
||||||
|
|
||||||
|
|||||||
+64
-1
@@ -163,7 +163,7 @@
|
|||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
| | | | :ref:`markrgb<asset-texture-markrgb>` | :ref:`random<asset-texture-random>` | :ref:`width<asset-texture-width>` | :ref:`height<asset-texture-height>` | |
|
| | | | :ref:`markrgb<asset-texture-markrgb>` | :ref:`random<asset-texture-random>` | :ref:`width<asset-texture-width>` | :ref:`height<asset-texture-height>` | |
|
||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
| | | | :ref:`hflip<asset-texture-hflip>` | :ref:`vflip<asset-texture-vflip>` | | | |
|
| | | | :ref:`hflip<asset-texture-hflip>` | :ref:`vflip<asset-texture-vflip>` | :ref:`nchannel<asset-texture-nchannel>` | | |
|
||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
| |_| asset |br| |_| |L| | | .. table:: |
|
| |_| asset |br| |_| |L| | | .. table:: |
|
||||||
@@ -177,6 +177,69 @@
|
|||||||
| | | | :ref:`reflectance<asset-material-reflectance>` | :ref:`metallic<asset-material-metallic>` | :ref:`roughness<asset-material-roughness>` | :ref:`rgba<asset-material-rgba>` | |
|
| | | | :ref:`reflectance<asset-material-reflectance>` | :ref:`metallic<asset-material-metallic>` | :ref:`roughness<asset-material-roughness>` | :ref:`rgba<asset-material-rgba>` | |
|
||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||||
|
| :ref:`rgb | ? | :class: mjcf-attributes |
|
||||||
|
| <material-rgb>` | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
| | | | :ref:`texture<material-rgb-texture>` | | | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||||
|
| :ref:`occlusion | ? | :class: mjcf-attributes |
|
||||||
|
| <material-occlusion>` | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
| | | | :ref:`texture<material-occlusion-texture>` | | | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||||
|
| :ref:`roughness | ? | :class: mjcf-attributes |
|
||||||
|
| <material-roughness>` | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
| | | | :ref:`texture<material-roughness-texture>` | | | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||||
|
| :ref:`metallic | ? | :class: mjcf-attributes |
|
||||||
|
| <material-metallic>` | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
| | | | :ref:`texture<material-metallic-texture>` | | | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||||
|
| :ref:`normal | ? | :class: mjcf-attributes |
|
||||||
|
| <material-normal>` | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
| | | | :ref:`texture<material-normal-texture>` | | | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||||
|
| :ref:`opacity | ? | :class: mjcf-attributes |
|
||||||
|
| <material-opacity>` | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
| | | | :ref:`texture<material-opacity-texture>` | | | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||||
|
| :ref:`emissive | ? | :class: mjcf-attributes |
|
||||||
|
| <material-emissive>` | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
| | | | :ref:`texture<material-emissive-texture>` | | | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||||
|
| :ref:`rgba | ? | :class: mjcf-attributes |
|
||||||
|
| <material-rgba>` | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
| | | | :ref:`texture<material-rgba-texture>` | | | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||||
|
| :ref:`orm | ? | :class: mjcf-attributes |
|
||||||
|
| <material-orm>` | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
| | | | :ref:`texture<material-orm-texture>` | | | | |
|
||||||
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
| |_| asset |br| |_| |L| | | .. table:: |
|
| |_| asset |br| |_| |L| | | .. table:: |
|
||||||
| :ref:`model | \* | :class: mjcf-attributes |
|
| :ref:`model | \* | :class: mjcf-attributes |
|
||||||
| <asset-model>` | | |
|
| <asset-model>` | | |
|
||||||
|
|||||||
+9
-2
@@ -10,15 +10,22 @@ General
|
|||||||
|
|
||||||
1. Renamed ``mjModel.tex_rbg`` to ``mjModel.tex_data``.
|
1. Renamed ``mjModel.tex_rbg`` to ``mjModel.tex_data``.
|
||||||
2. Added a new disable flag ``mjDSBL_AUTORESETNAN`` to disable automatic reset when NaNs or infinities are produced.
|
2. Added a new disable flag ``mjDSBL_AUTORESETNAN`` to disable automatic reset when NaNs or infinities are produced.
|
||||||
|
3. Added sub-elements to the MJCF :ref:`material<asset-material>` element, to allow specification of multiple textures
|
||||||
|
for rendering (e.g., :ref:`occlusion-roughness-metallic<material-orm>`). Note that the MuJoCo renderer doesn't support
|
||||||
|
these new features, and they are made available for use with external renderers.
|
||||||
|
|
||||||
MJX
|
MJX
|
||||||
^^^
|
^^^
|
||||||
|
|
||||||
3. Added more fields to ``mjx.Model`` and ``mjx.Data`` for further compatibility with the corresponding MuJoCo structs.
|
4. Added more fields to ``mjx.Model`` and ``mjx.Data`` for further compatibility with the corresponding MuJoCo structs.
|
||||||
|
5. Added support for :ref:`fixed tendons <tendon-fixed>`.
|
||||||
|
6. Added support for tendon length limits (``mjCNSTR_LIMIT_TENDON`` in :ref:`mjtConstraint`).
|
||||||
|
7. Added support for tendon equality constraints (``mjEQ_TENDON`` in :ref:`mjtEq`).
|
||||||
|
8. Added support for tendon actuator transmission (``mjTRN_TENDON`` in :ref:`mjtTrn`).
|
||||||
|
|
||||||
Python bindings
|
Python bindings
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
4. Added support for asset dictionary argument in ``mujoco.spec.from_file``, ``mujoco.spec.from_string`` and
|
9. Added support for asset dictionary argument in ``mujoco.spec.from_file``, ``mujoco.spec.from_string`` and
|
||||||
``mujoco.spec.compile``.
|
``mujoco.spec.compile``.
|
||||||
|
|
||||||
Version 3.2.0 (Jul 15, 2024)
|
Version 3.2.0 (Jul 15, 2024)
|
||||||
|
|||||||
@@ -2015,6 +2015,7 @@ typedef struct mjsTexture_ { // texture specification
|
|||||||
double random; // probability of random dots
|
double random; // probability of random dots
|
||||||
int height; // height in pixels (square for cube and skybox)
|
int height; // height in pixels (square for cube and skybox)
|
||||||
int width; // width in pixels
|
int width; // width in pixels
|
||||||
|
int nchannel; // number of channels
|
||||||
|
|
||||||
// method 2: single file
|
// method 2: single file
|
||||||
mjString* content_type; // content type of file
|
mjString* content_type; // content type of file
|
||||||
@@ -2035,7 +2036,7 @@ typedef struct mjsTexture_ { // texture specification
|
|||||||
typedef struct mjsMaterial_ { // material specification
|
typedef struct mjsMaterial_ { // material specification
|
||||||
mjsElement* element; // element type
|
mjsElement* element; // element type
|
||||||
mjString* name; // name
|
mjString* name; // name
|
||||||
mjString* texture; // name of texture (empty: none)
|
mjStringVec* textures; // names of textures (empty: none)
|
||||||
mjtByte texuniform; // make texture cube uniform
|
mjtByte texuniform; // make texture cube uniform
|
||||||
float texrepeat[2]; // texture repetition for 2D mapping
|
float texrepeat[2]; // texture repetition for 2D mapping
|
||||||
float emission; // emission
|
float emission; // emission
|
||||||
|
|||||||
+5
-7
@@ -188,7 +188,7 @@ The following features are **fully supported** in MJX:
|
|||||||
* - :ref:`Joint <mjtJoint>`
|
* - :ref:`Joint <mjtJoint>`
|
||||||
- ``FREE``, ``BALL``, ``SLIDE``, ``HINGE``
|
- ``FREE``, ``BALL``, ``SLIDE``, ``HINGE``
|
||||||
* - :ref:`Transmission <mjtTrn>`
|
* - :ref:`Transmission <mjtTrn>`
|
||||||
- ``TRN_JOINT``, ``TRN_SITE``
|
- ``TRN_JOINT``, ``TRN_SITE``, ``TRN_TENDON``
|
||||||
* - :ref:`Actuator Dynamics <mjtDyn>`
|
* - :ref:`Actuator Dynamics <mjtDyn>`
|
||||||
- ``NONE``, ``INTEGRATOR``, ``FILTER``, ``FILTEREXACT``
|
- ``NONE``, ``INTEGRATOR``, ``FILTER``, ``FILTEREXACT``
|
||||||
* - :ref:`Actuator Gain <mjtGain>`
|
* - :ref:`Actuator Gain <mjtGain>`
|
||||||
@@ -200,7 +200,7 @@ The following features are **fully supported** in MJX:
|
|||||||
* - :ref:`Constraint <mjtConstraint>`
|
* - :ref:`Constraint <mjtConstraint>`
|
||||||
- ``EQUALITY``, ``LIMIT_JOINT``, ``CONTACT_FRICTIONLESS``, ``CONTACT_PYRAMIDAL``, ``CONTACT_ELLIPTIC``
|
- ``EQUALITY``, ``LIMIT_JOINT``, ``CONTACT_FRICTIONLESS``, ``CONTACT_PYRAMIDAL``, ``CONTACT_ELLIPTIC``
|
||||||
* - :ref:`Equality <mjtEq>`
|
* - :ref:`Equality <mjtEq>`
|
||||||
- ``CONNECT``, ``WELD``, ``JOINT``
|
- ``CONNECT``, ``WELD``, ``JOINT``, ``TENDON``
|
||||||
* - :ref:`Integrator <mjtIntegrator>`
|
* - :ref:`Integrator <mjtIntegrator>`
|
||||||
- ``EULER``, ``RK4``
|
- ``EULER``, ``RK4``
|
||||||
* - :ref:`Cone <mjtCone>`
|
* - :ref:`Cone <mjtCone>`
|
||||||
@@ -211,6 +211,8 @@ The following features are **fully supported** in MJX:
|
|||||||
- ``CG``, ``NEWTON``
|
- ``CG``, ``NEWTON``
|
||||||
* - Fluid Model
|
* - Fluid Model
|
||||||
- :ref:`flInertia`
|
- :ref:`flInertia`
|
||||||
|
* - :ref:`Tendons <tendon>`
|
||||||
|
- :ref:`Fixed <tendon-fixed>`
|
||||||
|
|
||||||
The following features are **in development** and coming soon:
|
The following features are **in development** and coming soon:
|
||||||
|
|
||||||
@@ -230,8 +232,6 @@ The following features are **in development** and coming soon:
|
|||||||
- ``IMPLICIT``, ``IMPLICITFAST``
|
- ``IMPLICIT``, ``IMPLICITFAST``
|
||||||
* - Dynamics
|
* - Dynamics
|
||||||
- :ref:`Inverse <mj_inverse>`
|
- :ref:`Inverse <mj_inverse>`
|
||||||
* - :ref:`Transmission <mjtTrn>`
|
|
||||||
- ``TRN_TENDON``
|
|
||||||
* - :ref:`Actuator Dynamics <mjtDyn>`
|
* - :ref:`Actuator Dynamics <mjtDyn>`
|
||||||
- ``MUSCLE``
|
- ``MUSCLE``
|
||||||
* - :ref:`Actuator Gain <mjtGain>`
|
* - :ref:`Actuator Gain <mjtGain>`
|
||||||
@@ -243,9 +243,7 @@ The following features are **in development** and coming soon:
|
|||||||
* - Fluid Model
|
* - Fluid Model
|
||||||
- :ref:`flEllipsoid`
|
- :ref:`flEllipsoid`
|
||||||
* - :ref:`Tendons <tendon>`
|
* - :ref:`Tendons <tendon>`
|
||||||
- :ref:`Spatial <tendon-spatial>`, :ref:`Fixed <tendon-fixed>`
|
- :ref:`Spatial <tendon-spatial>`
|
||||||
* - :ref:`Equality <mjtEq>`
|
|
||||||
- ``TENDON``
|
|
||||||
* - :ref:`Sensors <mjtSensor>`
|
* - :ref:`Sensors <mjtSensor>`
|
||||||
- All except ``PLUGIN``, ``USER``
|
- All except ``PLUGIN``, ``USER``
|
||||||
* - Lights
|
* - Lights
|
||||||
|
|||||||
@@ -500,6 +500,7 @@ typedef struct mjsTexture_ { // texture specification
|
|||||||
double random; // probability of random dots
|
double random; // probability of random dots
|
||||||
int height; // height in pixels (square for cube and skybox)
|
int height; // height in pixels (square for cube and skybox)
|
||||||
int width; // width in pixels
|
int width; // width in pixels
|
||||||
|
int nchannel; // number of channels
|
||||||
|
|
||||||
// method 2: single file
|
// method 2: single file
|
||||||
mjString* content_type; // content type of file
|
mjString* content_type; // content type of file
|
||||||
@@ -522,7 +523,7 @@ typedef struct mjsTexture_ { // texture specification
|
|||||||
typedef struct mjsMaterial_ { // material specification
|
typedef struct mjsMaterial_ { // material specification
|
||||||
mjsElement* element; // element type
|
mjsElement* element; // element type
|
||||||
mjString* name; // name
|
mjString* name; // name
|
||||||
mjString* texture; // name of texture (empty: none)
|
mjStringVec* textures; // names of textures (empty: none)
|
||||||
mjtByte texuniform; // make texture cube uniform
|
mjtByte texuniform; // make texture cube uniform
|
||||||
float texrepeat[2]; // texture repetition for 2D mapping
|
float texrepeat[2]; // texture repetition for 2D mapping
|
||||||
float emission; // emission
|
float emission; // emission
|
||||||
|
|||||||
@@ -9969,6 +9969,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
type=ValueType(name='int'),
|
type=ValueType(name='int'),
|
||||||
doc='width in pixels',
|
doc='width in pixels',
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='nchannel',
|
||||||
|
type=ValueType(name='int'),
|
||||||
|
doc='number of channels',
|
||||||
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='content_type',
|
name='content_type',
|
||||||
type=PointerType(
|
type=PointerType(
|
||||||
@@ -10045,11 +10050,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
doc='name',
|
doc='name',
|
||||||
),
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='texture',
|
name='textures',
|
||||||
type=PointerType(
|
type=PointerType(
|
||||||
inner_type=ValueType(name='mjString'),
|
inner_type=ValueType(name='mjStringVec'),
|
||||||
),
|
),
|
||||||
doc='name of texture (empty: none)',
|
doc='names of textures (empty: none)',
|
||||||
),
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='texuniform',
|
name='texuniform',
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ from mujoco.mjx._src.smooth import crb
|
|||||||
from mujoco.mjx._src.smooth import factor_m
|
from mujoco.mjx._src.smooth import factor_m
|
||||||
from mujoco.mjx._src.smooth import kinematics
|
from mujoco.mjx._src.smooth import kinematics
|
||||||
from mujoco.mjx._src.smooth import rne
|
from mujoco.mjx._src.smooth import rne
|
||||||
|
from mujoco.mjx._src.smooth import tendon
|
||||||
from mujoco.mjx._src.smooth import transmission
|
from mujoco.mjx._src.smooth import transmission
|
||||||
from mujoco.mjx._src.solver import solve
|
from mujoco.mjx._src.solver import solve
|
||||||
from mujoco.mjx._src.support import full_m
|
from mujoco.mjx._src.support import full_m
|
||||||
|
|||||||
@@ -205,6 +205,44 @@ def _efc_equality_joint(m: Model, d: Data) -> Optional[_Efc]:
|
|||||||
return rows(*args)
|
return rows(*args)
|
||||||
|
|
||||||
|
|
||||||
|
def _efc_equality_tendon(m: Model, d: Data) -> Optional[_Efc]:
|
||||||
|
"""Calculates constraint rows for tendon equality constraints."""
|
||||||
|
|
||||||
|
eq_id = np.nonzero(m.eq_type == EqType.TENDON)[0]
|
||||||
|
|
||||||
|
if (m.opt.disableflags & DisableBit.EQUALITY) or eq_id.size == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
obj1id, obj2id, data, solref, solimp = jax.tree_util.tree_map(
|
||||||
|
lambda x: x[eq_id],
|
||||||
|
(
|
||||||
|
m.eq_obj1id,
|
||||||
|
m.eq_obj2id,
|
||||||
|
m.eq_data,
|
||||||
|
m.eq_solref,
|
||||||
|
m.eq_solimp,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@jax.vmap
|
||||||
|
def rows(obj2id, data, solref, solimp, invweight, jac1, jac2, pos1, pos2):
|
||||||
|
dif = pos2 * (obj2id > -1)
|
||||||
|
dif_power = jp.power(dif, jp.arange(0, 5))
|
||||||
|
pos = pos1 - jp.dot(data[:5], dif_power)
|
||||||
|
deriv = jp.dot(data[1:5], dif_power[:4] * jp.arange(1, 5)) * (obj2id > -1)
|
||||||
|
j = jac1 + jac2 * -deriv
|
||||||
|
|
||||||
|
return _row(j, pos, pos, invweight, solref, solimp)
|
||||||
|
|
||||||
|
inv1, inv2 = m.tendon_invweight0[obj1id], m.tendon_invweight0[obj2id]
|
||||||
|
jac1, jac2 = d.ten_J[obj1id], d.ten_J[obj2id]
|
||||||
|
pos1 = d.ten_length[obj1id] - m.tendon_length0[obj1id]
|
||||||
|
pos2 = d.ten_length[obj2id] - m.tendon_length0[obj2id]
|
||||||
|
invweight = inv1 + inv2 * (obj2id > -1)
|
||||||
|
|
||||||
|
return rows(obj2id, data, solref, solimp, invweight, jac1, jac2, pos1, pos2)
|
||||||
|
|
||||||
|
|
||||||
def _efc_friction(m: Model, d: Data) -> Optional[_Efc]:
|
def _efc_friction(m: Model, d: Data) -> Optional[_Efc]:
|
||||||
# TODO(robotics-team): implement _instantiate_friction
|
# TODO(robotics-team): implement _instantiate_friction
|
||||||
del m, d
|
del m, d
|
||||||
@@ -222,6 +260,8 @@ def _efc_limit_ball(m: Model, d: Data) -> Optional[_Efc]:
|
|||||||
@jax.vmap
|
@jax.vmap
|
||||||
def rows(qposadr, dofadr, jnt_range, jnt_margin, solref, solimp):
|
def rows(qposadr, dofadr, jnt_range, jnt_margin, solref, solimp):
|
||||||
axis, angle = math.quat_to_axis_angle(d.qpos[jp.arange(4) + qposadr])
|
axis, angle = math.quat_to_axis_angle(d.qpos[jp.arange(4) + qposadr])
|
||||||
|
# ball rotation angle is always positive
|
||||||
|
axis, angle = math.normalize_with_norm(axis * angle)
|
||||||
pos = jp.amax(jnt_range) - angle - jnt_margin
|
pos = jp.amax(jnt_range) - angle - jnt_margin
|
||||||
active = pos < 0
|
active = pos < 0
|
||||||
j = jp.zeros(m.nv).at[jp.arange(3) + dofadr].set(-axis)
|
j = jp.zeros(m.nv).at[jp.arange(3) + dofadr].set(-axis)
|
||||||
@@ -263,6 +303,34 @@ def _efc_limit_slide_hinge(m: Model, d: Data) -> Optional[_Efc]:
|
|||||||
return rows(*args)
|
return rows(*args)
|
||||||
|
|
||||||
|
|
||||||
|
def _efc_limit_tendon(m: Model, d: Data) -> Optional[_Efc]:
|
||||||
|
"""Calculates constraint rows for tendon limits."""
|
||||||
|
tendon_id = np.nonzero(m.tendon_limited)[0]
|
||||||
|
|
||||||
|
if (m.opt.disableflags & DisableBit.LIMIT) or tendon_id.size == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
length, j, range_, margin, invweight, solref, solimp = jax.tree_util.tree_map(
|
||||||
|
lambda x: x[tendon_id],
|
||||||
|
(
|
||||||
|
d.ten_length,
|
||||||
|
d.ten_J,
|
||||||
|
m.tendon_range,
|
||||||
|
m.tendon_margin,
|
||||||
|
m.tendon_invweight0,
|
||||||
|
m.tendon_solref_lim,
|
||||||
|
m.tendon_solimp_lim,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
dist_min, dist_max = length - range_[:, 0], range_[:, 1] - length
|
||||||
|
pos = jp.minimum(dist_min, dist_max) - margin
|
||||||
|
active = pos < 0
|
||||||
|
j = jax.vmap(jp.multiply)(j, ((dist_min < dist_max) * 2 - 1) * active)
|
||||||
|
|
||||||
|
return jax.vmap(_row)(j, pos * active, pos, invweight, solref, solimp)
|
||||||
|
|
||||||
|
|
||||||
def _efc_contact_frictionless(m: Model, d: Data) -> Optional[_Efc]:
|
def _efc_contact_frictionless(m: Model, d: Data) -> Optional[_Efc]:
|
||||||
"""Calculates constraint rows for frictionless contacts."""
|
"""Calculates constraint rows for frictionless contacts."""
|
||||||
|
|
||||||
@@ -365,6 +433,7 @@ def counts(efc_type: np.ndarray) -> Tuple[int, int, int, int]:
|
|||||||
ne = (efc_type == ConstraintType.EQUALITY).sum()
|
ne = (efc_type == ConstraintType.EQUALITY).sum()
|
||||||
nf = 0 # no support for friction loss yet
|
nf = 0 # no support for friction loss yet
|
||||||
nl = (efc_type == ConstraintType.LIMIT_JOINT).sum()
|
nl = (efc_type == ConstraintType.LIMIT_JOINT).sum()
|
||||||
|
nl += (efc_type == ConstraintType.LIMIT_TENDON).sum()
|
||||||
nc_f = (efc_type == ConstraintType.CONTACT_FRICTIONLESS).sum()
|
nc_f = (efc_type == ConstraintType.CONTACT_FRICTIONLESS).sum()
|
||||||
nc_p = (efc_type == ConstraintType.CONTACT_PYRAMIDAL).sum()
|
nc_p = (efc_type == ConstraintType.CONTACT_PYRAMIDAL).sum()
|
||||||
nc_e = (efc_type == ConstraintType.CONTACT_ELLIPTIC).sum()
|
nc_e = (efc_type == ConstraintType.CONTACT_ELLIPTIC).sum()
|
||||||
@@ -387,10 +456,12 @@ def make_efc_type(
|
|||||||
num_rows = (m.eq_type == EqType.CONNECT).sum() * 3
|
num_rows = (m.eq_type == EqType.CONNECT).sum() * 3
|
||||||
num_rows += (m.eq_type == EqType.WELD).sum() * 6
|
num_rows += (m.eq_type == EqType.WELD).sum() * 6
|
||||||
num_rows += (m.eq_type == EqType.JOINT).sum()
|
num_rows += (m.eq_type == EqType.JOINT).sum()
|
||||||
|
num_rows += (m.eq_type == EqType.TENDON).sum()
|
||||||
efc_types += [ConstraintType.EQUALITY] * num_rows
|
efc_types += [ConstraintType.EQUALITY] * num_rows
|
||||||
|
|
||||||
if not m.opt.disableflags & DisableBit.LIMIT:
|
if not m.opt.disableflags & DisableBit.LIMIT:
|
||||||
efc_types += [ConstraintType.LIMIT_JOINT] * m.jnt_limited.sum()
|
efc_types += [ConstraintType.LIMIT_JOINT] * m.jnt_limited.sum()
|
||||||
|
efc_types += [ConstraintType.LIMIT_TENDON] * m.tendon_limited.sum()
|
||||||
|
|
||||||
if not m.opt.disableflags & DisableBit.CONTACT:
|
if not m.opt.disableflags & DisableBit.CONTACT:
|
||||||
for condim in (1, 3, 4, 6):
|
for condim in (1, 3, 4, 6):
|
||||||
@@ -441,9 +512,11 @@ def make_constraint(m: Model, d: Data) -> Data:
|
|||||||
_efc_equality_connect(m, d),
|
_efc_equality_connect(m, d),
|
||||||
_efc_equality_weld(m, d),
|
_efc_equality_weld(m, d),
|
||||||
_efc_equality_joint(m, d),
|
_efc_equality_joint(m, d),
|
||||||
|
_efc_equality_tendon(m, d),
|
||||||
_efc_friction(m, d),
|
_efc_friction(m, d),
|
||||||
_efc_limit_ball(m, d),
|
_efc_limit_ball(m, d),
|
||||||
_efc_limit_slide_hinge(m, d),
|
_efc_limit_slide_hinge(m, d),
|
||||||
|
_efc_limit_tendon(m, d),
|
||||||
_efc_contact_frictionless(m, d),
|
_efc_contact_frictionless(m, d),
|
||||||
)
|
)
|
||||||
if m.opt.cone == ConeType.ELLIPTIC:
|
if m.opt.cone == ConeType.ELLIPTIC:
|
||||||
|
|||||||
@@ -96,21 +96,21 @@ class ConstraintTest(parameterized.TestCase):
|
|||||||
ne, nf, nl, nc = constraint.counts(constraint.make_efc_type(m))
|
ne, nf, nl, nc = constraint.counts(constraint.make_efc_type(m))
|
||||||
self.assertEqual(ne, 0)
|
self.assertEqual(ne, 0)
|
||||||
self.assertEqual(nf, 0)
|
self.assertEqual(nf, 0)
|
||||||
self.assertEqual(nl, 3)
|
self.assertEqual(nl, 5)
|
||||||
self.assertEqual(nc, 148)
|
self.assertEqual(nc, 148)
|
||||||
dx = constraint.make_constraint(mjx.put_model(m), mjx.make_data(m))
|
dx = constraint.make_constraint(mjx.put_model(m), mjx.make_data(m))
|
||||||
self.assertEqual(dx.efc_J.shape[0], 151) # only joint range, contact
|
self.assertEqual(dx.efc_J.shape[0], 153) # only joint/tendon limit, contact
|
||||||
|
|
||||||
def test_disable_contact(self):
|
def test_disable_contact(self):
|
||||||
m = test_util.load_test_file('constraints.xml')
|
m = test_util.load_test_file('constraints.xml')
|
||||||
m.opt.disableflags = m.opt.disableflags | mjx.DisableBit.CONTACT
|
m.opt.disableflags = m.opt.disableflags | mjx.DisableBit.CONTACT
|
||||||
ne, nf, nl, nc = constraint.counts(constraint.make_efc_type(m))
|
ne, nf, nl, nc = constraint.counts(constraint.make_efc_type(m))
|
||||||
self.assertEqual(ne, 10)
|
self.assertEqual(ne, 11)
|
||||||
self.assertEqual(nf, 0)
|
self.assertEqual(nf, 0)
|
||||||
self.assertEqual(nl, 3)
|
self.assertEqual(nl, 5)
|
||||||
self.assertEqual(nc, 0)
|
self.assertEqual(nc, 0)
|
||||||
dx = constraint.make_constraint(mjx.put_model(m), mjx.make_data(m))
|
dx = constraint.make_constraint(mjx.put_model(m), mjx.make_data(m))
|
||||||
self.assertEqual(dx.efc_J.shape[0], 13) # only joint range, limit
|
self.assertEqual(dx.efc_J.shape[0], 16) # only equality, joint/tendon limit
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ def fwd_position(m: Model, d: Data) -> Data:
|
|||||||
d = smooth.kinematics(m, d)
|
d = smooth.kinematics(m, d)
|
||||||
d = smooth.com_pos(m, d)
|
d = smooth.com_pos(m, d)
|
||||||
d = smooth.camlight(m, d)
|
d = smooth.camlight(m, d)
|
||||||
|
d = smooth.tendon(m, d)
|
||||||
d = smooth.crb(m, d)
|
d = smooth.crb(m, d)
|
||||||
d = smooth.factor_m(m, d)
|
d = smooth.factor_m(m, d)
|
||||||
d = collision_driver.collision(m, d)
|
d = collision_driver.collision(m, d)
|
||||||
@@ -77,7 +78,10 @@ def fwd_position(m: Model, d: Data) -> Data:
|
|||||||
@named_scope
|
@named_scope
|
||||||
def fwd_velocity(m: Model, d: Data) -> Data:
|
def fwd_velocity(m: Model, d: Data) -> Data:
|
||||||
"""Velocity-dependent computations."""
|
"""Velocity-dependent computations."""
|
||||||
d = d.replace(actuator_velocity=d.actuator_moment @ d.qvel)
|
d = d.replace(
|
||||||
|
actuator_velocity=d.actuator_moment @ d.qvel,
|
||||||
|
ten_velocity=d.ten_J @ d.qvel,
|
||||||
|
)
|
||||||
d = smooth.com_vel(m, d)
|
d = smooth.com_vel(m, d)
|
||||||
d = passive.passive(m, d)
|
d = passive.passive(m, d)
|
||||||
d = smooth.rne(m, d)
|
d = smooth.rne(m, d)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
"""Functions to initialize, load, or save data."""
|
"""Functions to initialize, load, or save data."""
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
from typing import Any, Dict, List, Tuple, Union
|
from typing import List, Tuple, Union
|
||||||
|
|
||||||
import jax
|
import jax
|
||||||
from jax import numpy as jp
|
from jax import numpy as jp
|
||||||
@@ -74,9 +74,6 @@ def put_model(
|
|||||||
) -> types.Model:
|
) -> types.Model:
|
||||||
"""Puts mujoco.MjModel onto a device, resulting in mjx.Model."""
|
"""Puts mujoco.MjModel onto a device, resulting in mjx.Model."""
|
||||||
|
|
||||||
if _check_unsupported and m.ntendon:
|
|
||||||
raise NotImplementedError('tendons are not supported')
|
|
||||||
|
|
||||||
mesh_geomid = set()
|
mesh_geomid = set()
|
||||||
for g1, g2, ip in collision_driver.geom_pairs(m):
|
for g1, g2, ip in collision_driver.geom_pairs(m):
|
||||||
t1, t2 = m.geom_type[[g1, g2]]
|
t1, t2 = m.geom_type[[g1, g2]]
|
||||||
@@ -104,6 +101,7 @@ def put_model(
|
|||||||
(m.actuator_gaintype, types.GainType, mujoco.mjtGain),
|
(m.actuator_gaintype, types.GainType, mujoco.mjtGain),
|
||||||
(m.actuator_trntype, types.TrnType, mujoco.mjtTrn),
|
(m.actuator_trntype, types.TrnType, mujoco.mjtTrn),
|
||||||
(m.eq_type, types.EqType, mujoco.mjtEq),
|
(m.eq_type, types.EqType, mujoco.mjtEq),
|
||||||
|
(m.wrap_type, types.WrapType, mujoco.mjtWrap),
|
||||||
):
|
):
|
||||||
missing = set(enum_field) - set(enum_type)
|
missing = set(enum_field) - set(enum_type)
|
||||||
if _check_unsupported and missing:
|
if _check_unsupported and missing:
|
||||||
|
|||||||
@@ -148,20 +148,28 @@ class ModelIOTest(parameterized.TestCase):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_tendon_not_implemented(self):
|
def test_spatial_tendon_not_implemented(self):
|
||||||
with self.assertRaises(NotImplementedError):
|
with self.assertRaises(NotImplementedError):
|
||||||
mjx.put_model(mujoco.MjModel.from_xml_string("""
|
mjx.put_model(mujoco.MjModel.from_xml_string("""
|
||||||
<mujoco>
|
<mujoco>
|
||||||
<worldbody>
|
<worldbody>
|
||||||
<body>
|
<body name="arm">
|
||||||
<joint name="left_hip" type="hinge"/>
|
<joint name="arm" axis="0 1 0"/>
|
||||||
<geom size="0.05"/>
|
<geom name="shoulder" type="sphere" size=".05"/>
|
||||||
|
<site name="arm" pos="-.1 0 .05"/>
|
||||||
|
</body>
|
||||||
|
<body name="slider" pos=".05 0 -.2">
|
||||||
|
<joint name="slider" type="slide" damping="1"/>
|
||||||
|
<geom name="slider" type="box" size=".01 .01 .01"/>
|
||||||
|
<site name="slider" pos="0 0 .01"/>
|
||||||
</body>
|
</body>
|
||||||
</worldbody>
|
</worldbody>
|
||||||
|
|
||||||
<tendon>
|
<tendon>
|
||||||
<fixed>
|
<spatial name="rope" range="0 .35">
|
||||||
<joint coef="1" joint="left_hip"/>
|
<site site="slider"/>
|
||||||
</fixed>
|
<site site="arm"/>
|
||||||
|
</spatial>
|
||||||
</tendon>
|
</tendon>
|
||||||
</mujoco>"""))
|
</mujoco>"""))
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,13 @@ def _spring_damper(m: Model, d: Data) -> jax.Array:
|
|||||||
# dof-level dampers
|
# dof-level dampers
|
||||||
qfrc -= m.dof_damping * d.qvel
|
qfrc -= m.dof_damping * d.qvel
|
||||||
|
|
||||||
|
# tendon-level spring-dampers
|
||||||
|
below, above = m.tendon_lengthspring.T - d.ten_length
|
||||||
|
frc_spring = jp.where(below > 0, m.tendon_stiffness * below, 0)
|
||||||
|
frc_spring = jp.where(above < 0, m.tendon_stiffness * above, frc_spring)
|
||||||
|
frc_damper = -m.tendon_damping * d.ten_velocity
|
||||||
|
qfrc += d.ten_J.T @ (frc_spring + frc_damper)
|
||||||
|
|
||||||
return qfrc
|
return qfrc
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class PassiveTest(absltest.TestCase):
|
|||||||
m = test_util.load_test_file('pendula.xml')
|
m = test_util.load_test_file('pendula.xml')
|
||||||
d = mujoco.MjData(m)
|
d = mujoco.MjData(m)
|
||||||
# give the system a little kick to ensure we have non-identity rotations
|
# give the system a little kick to ensure we have non-identity rotations
|
||||||
d.ctrl = np.array([0.1, -0.1, 0.2, 0.3, -0.4, 0.5, -0.6, 0.1])
|
d.ctrl = np.array([0.1, -0.1, 0.2, 0.3, -0.4, 0.5, -0.6, 0.1, -0.2])
|
||||||
mujoco.mj_step(m, d, 10) # let dynamics get state significantly non-zero
|
mujoco.mj_step(m, d, 10) # let dynamics get state significantly non-zero
|
||||||
mujoco.mj_forward(m, d)
|
mujoco.mj_forward(m, d)
|
||||||
mx = mjx.put_model(m)
|
mx = mjx.put_model(m)
|
||||||
|
|||||||
@@ -311,7 +311,9 @@ def factor_m(m: Model, d: Data) -> Data:
|
|||||||
if j == -1:
|
if j == -1:
|
||||||
break
|
break
|
||||||
out_beg, out_end = tuple(m.dof_Madr[j : j + 2])
|
out_beg, out_end = tuple(m.dof_Madr[j : j + 2])
|
||||||
updates.setdefault(depth[j], []).append((out_beg, out_end, madr_d, madr_ij))
|
updates.setdefault(depth[j], []).append(
|
||||||
|
(out_beg, out_end, madr_d, madr_ij)
|
||||||
|
)
|
||||||
|
|
||||||
qld = d.qM
|
qld = d.qM
|
||||||
|
|
||||||
@@ -463,6 +465,20 @@ def rne(m: Model, d: Data) -> Data:
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def tendon(m: Model, d: Data) -> Data:
|
||||||
|
"""Computes tendon lengths and moments."""
|
||||||
|
if not m.ntendon:
|
||||||
|
return d
|
||||||
|
|
||||||
|
ten_id = np.repeat(np.arange(m.ntendon), m.tendon_num)
|
||||||
|
length = m.wrap_prm * d.qpos[m.jnt_qposadr[m.wrap_objid]]
|
||||||
|
ten_length = jax.ops.segment_sum(length, ten_id, m.ntendon)
|
||||||
|
ten_j = jp.zeros((m.ntendon, m.nv))
|
||||||
|
ten_j = ten_j.at[ten_id, m.jnt_dofadr[m.wrap_objid]].set(m.wrap_prm)
|
||||||
|
|
||||||
|
return d.replace(ten_length=ten_length, ten_J=ten_j)
|
||||||
|
|
||||||
|
|
||||||
def _site_dof_mask(m: Model) -> np.ndarray:
|
def _site_dof_mask(m: Model) -> np.ndarray:
|
||||||
"""Creates a dof mask for site transmissions."""
|
"""Creates a dof mask for site transmissions."""
|
||||||
mask = np.ones((m.nu, m.nv))
|
mask = np.ones((m.nu, m.nv))
|
||||||
@@ -494,7 +510,6 @@ def _site_dof_mask(m: Model) -> np.ndarray:
|
|||||||
|
|
||||||
def transmission(m: Model, d: Data) -> Data:
|
def transmission(m: Model, d: Data) -> Data:
|
||||||
"""Computes actuator/transmission lengths and moments."""
|
"""Computes actuator/transmission lengths and moments."""
|
||||||
# TODO: consider combining transmission calculation into fwd_actuation.
|
|
||||||
if not m.nu:
|
if not m.nu:
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@@ -545,6 +560,9 @@ def transmission(m: Model, d: Data) -> Data:
|
|||||||
jac = jp.concatenate((jacp, jacr), axis=1) * site_dof_mask[:, None]
|
jac = jp.concatenate((jacp, jacr), axis=1) * site_dof_mask[:, None]
|
||||||
wrench = jp.concatenate((frame_xmat @ gear[:3], frame_xmat @ gear[3:]))
|
wrench = jp.concatenate((frame_xmat @ gear[:3], frame_xmat @ gear[3:]))
|
||||||
moment = jac @ wrench
|
moment = jac @ wrench
|
||||||
|
elif trntype == TrnType.TENDON:
|
||||||
|
length = d.ten_length[trnid[0]] * gear[:1]
|
||||||
|
moment = d.ten_J[trnid[0]] * gear[0]
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(f'unrecognized trntype: {TrnType(trntype)}')
|
raise RuntimeError(f'unrecognized trntype: {TrnType(trntype)}')
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class SmoothTest(absltest.TestCase):
|
|||||||
"""Tests MJX smooth functions match MuJoCo smooth functions."""
|
"""Tests MJX smooth functions match MuJoCo smooth functions."""
|
||||||
|
|
||||||
m = test_util.load_test_file('pendula.xml')
|
m = test_util.load_test_file('pendula.xml')
|
||||||
# # force MJX sparse for testing:
|
# tell MJX to use sparse mass matrices:
|
||||||
m.opt.jacobian = mujoco.mjtJacobian.mjJAC_SPARSE
|
m.opt.jacobian = mujoco.mjtJacobian.mjJAC_SPARSE
|
||||||
d = mujoco.MjData(m)
|
d = mujoco.MjData(m)
|
||||||
# give the system a little kick to ensure we have non-identity rotations
|
# give the system a little kick to ensure we have non-identity rotations
|
||||||
@@ -75,6 +75,10 @@ class SmoothTest(absltest.TestCase):
|
|||||||
_assert_attr_eq(d, dx, 'subtree_com')
|
_assert_attr_eq(d, dx, 'subtree_com')
|
||||||
_assert_attr_eq(d, dx, 'cinert')
|
_assert_attr_eq(d, dx, 'cinert')
|
||||||
_assert_attr_eq(d, dx, 'cdof')
|
_assert_attr_eq(d, dx, 'cdof')
|
||||||
|
# camlight
|
||||||
|
dx = jax.jit(mjx.camlight)(mx, mjx.put_data(m, d))
|
||||||
|
_assert_attr_eq(d, dx, 'cam_xpos')
|
||||||
|
_assert_eq(d.cam_xmat.reshape((-1, 3, 3)), dx.cam_xmat, 'cam_xmat')
|
||||||
# crb
|
# crb
|
||||||
dx = jax.jit(mjx.crb)(mx, mjx.put_data(m, d))
|
dx = jax.jit(mjx.crb)(mx, mjx.put_data(m, d))
|
||||||
_assert_attr_eq(d, dx, 'crb')
|
_assert_attr_eq(d, dx, 'crb')
|
||||||
@@ -90,14 +94,22 @@ class SmoothTest(absltest.TestCase):
|
|||||||
# rne
|
# rne
|
||||||
dx = jax.jit(mjx.rne)(mx, mjx.put_data(m, d))
|
dx = jax.jit(mjx.rne)(mx, mjx.put_data(m, d))
|
||||||
_assert_attr_eq(d, dx, 'qfrc_bias')
|
_assert_attr_eq(d, dx, 'qfrc_bias')
|
||||||
|
|
||||||
|
# set dense jacobian for tendon:
|
||||||
|
m.opt.jacobian = mujoco.mjtJacobian.mjJAC_DENSE
|
||||||
|
d = mujoco.MjData(m)
|
||||||
|
# give the system a little kick to ensure we have non-identity rotations
|
||||||
|
d.qvel = np.random.random(m.nv)
|
||||||
|
mujoco.mj_step(m, d, 10) # let dynamics get state significantly non-zero
|
||||||
|
mujoco.mj_forward(m, d)
|
||||||
|
# tendon
|
||||||
|
dx = jax.jit(mjx.tendon)(mx, mjx.put_data(m, d))
|
||||||
|
_assert_attr_eq(d, dx, 'ten_J')
|
||||||
|
_assert_attr_eq(d, dx, 'ten_length')
|
||||||
# transmission
|
# transmission
|
||||||
dx = jax.jit(mjx.transmission)(mx, mjx.put_data(m, d))
|
dx = jax.jit(mjx.transmission)(mx, dx)
|
||||||
_assert_attr_eq(d, dx, 'actuator_length')
|
_assert_attr_eq(d, dx, 'actuator_length')
|
||||||
_assert_attr_eq(d, dx, 'actuator_moment')
|
_assert_attr_eq(d, dx, 'actuator_moment')
|
||||||
# camlight
|
|
||||||
dx = jax.jit(mjx.camlight)(mx, mjx.put_data(m, d))
|
|
||||||
_assert_attr_eq(d, dx, 'cam_xpos')
|
|
||||||
_assert_eq(d.cam_xmat.reshape((-1, 3, 3)), dx.cam_xmat, 'cam_xmat')
|
|
||||||
|
|
||||||
def test_disable_gravity(self):
|
def test_disable_gravity(self):
|
||||||
m = mujoco.MjModel.from_xml_string("""
|
m = mujoco.MjModel.from_xml_string("""
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import numpy as np
|
|||||||
class DisableBit(enum.IntFlag):
|
class DisableBit(enum.IntFlag):
|
||||||
"""Disable default feature bitflags.
|
"""Disable default feature bitflags.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
CONSTRAINT: entire constraint solver
|
CONSTRAINT: entire constraint solver
|
||||||
EQUALITY: equality constraints
|
EQUALITY: equality constraints
|
||||||
FRICTIONLOSS: joint and tendon frictionloss constraints
|
FRICTIONLOSS: joint and tendon frictionloss constraints
|
||||||
@@ -56,7 +56,7 @@ class DisableBit(enum.IntFlag):
|
|||||||
class JointType(enum.IntEnum):
|
class JointType(enum.IntEnum):
|
||||||
"""Type of degree of freedom.
|
"""Type of degree of freedom.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
FREE: global position and orientation (quat) (7,)
|
FREE: global position and orientation (quat) (7,)
|
||||||
BALL: orientation (quat) relative to parent (4,)
|
BALL: orientation (quat) relative to parent (4,)
|
||||||
SLIDE: sliding distance along body-fixed axis (1,)
|
SLIDE: sliding distance along body-fixed axis (1,)
|
||||||
@@ -77,7 +77,7 @@ class JointType(enum.IntEnum):
|
|||||||
class IntegratorType(enum.IntEnum):
|
class IntegratorType(enum.IntEnum):
|
||||||
"""Integrator mode.
|
"""Integrator mode.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
EULER: semi-implicit Euler
|
EULER: semi-implicit Euler
|
||||||
RK4: 4th-order Runge Kutta
|
RK4: 4th-order Runge Kutta
|
||||||
"""
|
"""
|
||||||
@@ -89,7 +89,7 @@ class IntegratorType(enum.IntEnum):
|
|||||||
class GeomType(enum.IntEnum):
|
class GeomType(enum.IntEnum):
|
||||||
"""Type of geometry.
|
"""Type of geometry.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
PLANE: plane
|
PLANE: plane
|
||||||
HFIELD: height field
|
HFIELD: height field
|
||||||
SPHERE: sphere
|
SPHERE: sphere
|
||||||
@@ -115,7 +115,7 @@ class GeomType(enum.IntEnum):
|
|||||||
class ConvexMesh(PyTreeNode):
|
class ConvexMesh(PyTreeNode):
|
||||||
"""Geom properties for convex meshes.
|
"""Geom properties for convex meshes.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
vert: vertices of the convex mesh
|
vert: vertices of the convex mesh
|
||||||
face: faces of the convex mesh
|
face: faces of the convex mesh
|
||||||
face_normal: normal vectors for the faces
|
face_normal: normal vectors for the faces
|
||||||
@@ -133,7 +133,7 @@ class ConvexMesh(PyTreeNode):
|
|||||||
class ConeType(enum.IntEnum):
|
class ConeType(enum.IntEnum):
|
||||||
"""Type of friction cone.
|
"""Type of friction cone.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
PYRAMIDAL: pyramidal
|
PYRAMIDAL: pyramidal
|
||||||
ELLIPTIC: elliptic
|
ELLIPTIC: elliptic
|
||||||
"""
|
"""
|
||||||
@@ -144,7 +144,7 @@ class ConeType(enum.IntEnum):
|
|||||||
class JacobianType(enum.IntEnum):
|
class JacobianType(enum.IntEnum):
|
||||||
"""Type of constraint Jacobian.
|
"""Type of constraint Jacobian.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
DENSE: dense
|
DENSE: dense
|
||||||
SPARSE: sparse
|
SPARSE: sparse
|
||||||
AUTO: sparse if nv>60 and device is TPU, dense otherwise
|
AUTO: sparse if nv>60 and device is TPU, dense otherwise
|
||||||
@@ -157,7 +157,7 @@ class JacobianType(enum.IntEnum):
|
|||||||
class SolverType(enum.IntEnum):
|
class SolverType(enum.IntEnum):
|
||||||
"""Constraint solver algorithm.
|
"""Constraint solver algorithm.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
CG: Conjugate gradient (primal)
|
CG: Conjugate gradient (primal)
|
||||||
"""
|
"""
|
||||||
# unsupported: PGS
|
# unsupported: PGS
|
||||||
@@ -168,33 +168,46 @@ class SolverType(enum.IntEnum):
|
|||||||
class EqType(enum.IntEnum):
|
class EqType(enum.IntEnum):
|
||||||
"""Type of equality constraint.
|
"""Type of equality constraint.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
CONNECT: connect two bodies at a point (ball joint)
|
CONNECT: connect two bodies at a point (ball joint)
|
||||||
WELD: fix relative position and orientation of two bodies
|
WELD: fix relative position and orientation of two bodies
|
||||||
JOINT: couple the values of two scalar joints with cubic
|
JOINT: couple the values of two scalar joints with cubic
|
||||||
|
TENDON: couple the lengths of two tendons with cubic
|
||||||
"""
|
"""
|
||||||
CONNECT = mujoco.mjtEq.mjEQ_CONNECT
|
CONNECT = mujoco.mjtEq.mjEQ_CONNECT
|
||||||
WELD = mujoco.mjtEq.mjEQ_WELD
|
WELD = mujoco.mjtEq.mjEQ_WELD
|
||||||
JOINT = mujoco.mjtEq.mjEQ_JOINT
|
JOINT = mujoco.mjtEq.mjEQ_JOINT
|
||||||
# unsupported: TENDON, DISTANCE
|
TENDON = mujoco.mjtEq.mjEQ_TENDON
|
||||||
|
# unsupported: DISTANCE
|
||||||
|
|
||||||
|
|
||||||
|
class WrapType(enum.IntEnum):
|
||||||
|
"""Type of tendon wrap object.
|
||||||
|
|
||||||
|
Members:
|
||||||
|
JOINT: constant moment arm
|
||||||
|
"""
|
||||||
|
JOINT = mujoco.mjtWrap.mjWRAP_JOINT
|
||||||
|
# unsupported: NONE, PULLEY, SITE, SPHERE, CYLINDER
|
||||||
|
|
||||||
|
|
||||||
class TrnType(enum.IntEnum):
|
class TrnType(enum.IntEnum):
|
||||||
"""Type of actuator transmission.
|
"""Type of actuator transmission.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
JOINT: force on joint
|
JOINT: force on joint
|
||||||
SITE: force on site
|
SITE: force on site
|
||||||
"""
|
"""
|
||||||
JOINT = mujoco.mjtTrn.mjTRN_JOINT
|
JOINT = mujoco.mjtTrn.mjTRN_JOINT
|
||||||
SITE = mujoco.mjtTrn.mjTRN_SITE
|
SITE = mujoco.mjtTrn.mjTRN_SITE
|
||||||
# unsupported: JOINTINPARENT, SLIDERCRANK, TENDON, BODY
|
TENDON = mujoco.mjtTrn.mjTRN_TENDON
|
||||||
|
# unsupported: JOINTINPARENT, SLIDERCRANK, BODY
|
||||||
|
|
||||||
|
|
||||||
class DynType(enum.IntEnum):
|
class DynType(enum.IntEnum):
|
||||||
"""Type of actuator dynamics.
|
"""Type of actuator dynamics.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
NONE: no internal dynamics; ctrl specifies force
|
NONE: no internal dynamics; ctrl specifies force
|
||||||
INTEGRATOR: integrator: da/dt = u
|
INTEGRATOR: integrator: da/dt = u
|
||||||
FILTER: linear filter: da/dt = (u-a) / tau
|
FILTER: linear filter: da/dt = (u-a) / tau
|
||||||
@@ -210,7 +223,7 @@ class DynType(enum.IntEnum):
|
|||||||
class GainType(enum.IntEnum):
|
class GainType(enum.IntEnum):
|
||||||
"""Type of actuator gain.
|
"""Type of actuator gain.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
FIXED: fixed gain
|
FIXED: fixed gain
|
||||||
AFFINE: const + kp*length + kv*velocity
|
AFFINE: const + kp*length + kv*velocity
|
||||||
"""
|
"""
|
||||||
@@ -222,7 +235,7 @@ class GainType(enum.IntEnum):
|
|||||||
class BiasType(enum.IntEnum):
|
class BiasType(enum.IntEnum):
|
||||||
"""Type of actuator bias.
|
"""Type of actuator bias.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
NONE: no bias
|
NONE: no bias
|
||||||
AFFINE: const + kp*length + kv*velocity
|
AFFINE: const + kp*length + kv*velocity
|
||||||
"""
|
"""
|
||||||
@@ -234,16 +247,17 @@ class BiasType(enum.IntEnum):
|
|||||||
class ConstraintType(enum.IntEnum):
|
class ConstraintType(enum.IntEnum):
|
||||||
"""Type of constraint.
|
"""Type of constraint.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
EQUALITY: equality constraint
|
EQUALITY: equality constraint
|
||||||
LIMIT_JOINT: joint limit
|
LIMIT_JOINT: joint limit
|
||||||
|
LIMIT_TENDON: tendon limit
|
||||||
CONTACT_FRICTIONLESS: frictionless contact
|
CONTACT_FRICTIONLESS: frictionless contact
|
||||||
CONTACT_PYRAMIDAL: frictional contact, pyramidal friction cone
|
CONTACT_PYRAMIDAL: frictional contact, pyramidal friction cone
|
||||||
"""
|
"""
|
||||||
EQUALITY = mujoco.mjtConstraint.mjCNSTR_EQUALITY
|
EQUALITY = mujoco.mjtConstraint.mjCNSTR_EQUALITY
|
||||||
# unsupported: FRICTION_DOF, FRICTION_TENDON
|
# unsupported: FRICTION_DOF, FRICTION_TENDON
|
||||||
LIMIT_JOINT = mujoco.mjtConstraint.mjCNSTR_LIMIT_JOINT
|
LIMIT_JOINT = mujoco.mjtConstraint.mjCNSTR_LIMIT_JOINT
|
||||||
# unsupported: LIMIT_TENDON
|
LIMIT_TENDON = mujoco.mjtConstraint.mjCNSTR_LIMIT_TENDON
|
||||||
CONTACT_FRICTIONLESS = mujoco.mjtConstraint.mjCNSTR_CONTACT_FRICTIONLESS
|
CONTACT_FRICTIONLESS = mujoco.mjtConstraint.mjCNSTR_CONTACT_FRICTIONLESS
|
||||||
CONTACT_PYRAMIDAL = mujoco.mjtConstraint.mjCNSTR_CONTACT_PYRAMIDAL
|
CONTACT_PYRAMIDAL = mujoco.mjtConstraint.mjCNSTR_CONTACT_PYRAMIDAL
|
||||||
CONTACT_ELLIPTIC = mujoco.mjtConstraint.mjCNSTR_CONTACT_ELLIPTIC
|
CONTACT_ELLIPTIC = mujoco.mjtConstraint.mjCNSTR_CONTACT_ELLIPTIC
|
||||||
@@ -252,7 +266,7 @@ class ConstraintType(enum.IntEnum):
|
|||||||
class CamLightType(enum.IntEnum):
|
class CamLightType(enum.IntEnum):
|
||||||
"""Type of camera light.
|
"""Type of camera light.
|
||||||
|
|
||||||
Attributes:
|
Members:
|
||||||
FIXED: pos and rot fixed in body
|
FIXED: pos and rot fixed in body
|
||||||
TRACK: pos tracks body, rot fixed in global
|
TRACK: pos tracks body, rot fixed in global
|
||||||
TRACKCOM: pos tracks subtree com, rot fixed in body
|
TRACKCOM: pos tracks subtree com, rot fixed in body
|
||||||
@@ -900,18 +914,18 @@ class Model(PyTreeNode):
|
|||||||
tendon_adr: np.ndarray
|
tendon_adr: np.ndarray
|
||||||
tendon_num: np.ndarray
|
tendon_num: np.ndarray
|
||||||
tendon_limited: np.ndarray
|
tendon_limited: np.ndarray
|
||||||
tendon_solref_lim: np.ndarray
|
tendon_solref_lim: jax.Array
|
||||||
tendon_solimp_lim: np.ndarray
|
tendon_solimp_lim: jax.Array
|
||||||
tendon_solref_fri: np.ndarray
|
tendon_solref_fri: jax.Array
|
||||||
tendon_solimp_fri: np.ndarray
|
tendon_solimp_fri: jax.Array
|
||||||
tendon_range: np.ndarray
|
tendon_range: jax.Array
|
||||||
tendon_margin: np.ndarray
|
tendon_margin: jax.Array
|
||||||
tendon_stiffness: np.ndarray
|
tendon_stiffness: jax.Array
|
||||||
tendon_damping: np.ndarray
|
tendon_damping: jax.Array
|
||||||
tendon_frictionloss: np.ndarray
|
tendon_frictionloss: jax.Array
|
||||||
tendon_lengthspring: np.ndarray
|
tendon_lengthspring: jax.Array
|
||||||
tendon_length0: np.ndarray
|
tendon_length0: jax.Array
|
||||||
tendon_invweight0: np.ndarray
|
tendon_invweight0: jax.Array
|
||||||
wrap_type: np.ndarray
|
wrap_type: np.ndarray
|
||||||
wrap_objid: np.ndarray
|
wrap_objid: np.ndarray
|
||||||
wrap_prm: np.ndarray
|
wrap_prm: np.ndarray
|
||||||
@@ -1193,7 +1207,7 @@ class Data(PyTreeNode):
|
|||||||
qM: jax.Array # pylint:disable=invalid-name
|
qM: jax.Array # pylint:disable=invalid-name
|
||||||
qLD: jax.Array # pylint:disable=invalid-name
|
qLD: jax.Array # pylint:disable=invalid-name
|
||||||
qLDiagInv: jax.Array # pylint:disable=invalid-name
|
qLDiagInv: jax.Array # pylint:disable=invalid-name
|
||||||
qLDiagSqrtInv: jax.Array
|
qLDiagSqrtInv: jax.Array # pylint:disable=invalid-name
|
||||||
bvh_aabb_dyn: jax.Array
|
bvh_aabb_dyn: jax.Array
|
||||||
bvh_active: jax.Array
|
bvh_active: jax.Array
|
||||||
# position, velocity dependent:
|
# position, velocity dependent:
|
||||||
@@ -1243,6 +1257,6 @@ class Data(PyTreeNode):
|
|||||||
efc_force: jax.Array
|
efc_force: jax.Array
|
||||||
# sparse representation of qM, qLD, qLDiagInv, for compatibility with MuJoCo
|
# sparse representation of qM, qLD, qLDiagInv, for compatibility with MuJoCo
|
||||||
# when in dense mode
|
# when in dense mode
|
||||||
_qM_sparse: jax.Array
|
_qM_sparse: jax.Array # pylint:disable=invalid-name
|
||||||
_qLD_sparse: jax.Array
|
_qLD_sparse: jax.Array # pylint:disable=invalid-name
|
||||||
_qLDiagInv_sparse: jax.Array
|
_qLDiagInv_sparse: jax.Array # pylint:disable=invalid-name
|
||||||
|
|||||||
@@ -64,10 +64,22 @@
|
|||||||
</body>
|
</body>
|
||||||
</worldbody>
|
</worldbody>
|
||||||
|
|
||||||
|
<tendon>
|
||||||
|
<fixed name="tendon_1" limited="true" range="-0.3 0.1" stiffness=".1" damping=".2">
|
||||||
|
<joint joint="joint3" coef=".1"/>
|
||||||
|
<joint joint="joint4" coef="-.2"/>
|
||||||
|
</fixed>
|
||||||
|
<fixed name="tendon_2" limited="true" range="-0.3 2" solreflimit="0.03 0.9" solimplimit="0.89 0.9 0.01 2.1">
|
||||||
|
<joint joint="joint4" coef=".3"/>
|
||||||
|
<joint joint="joint5" coef="-.4"/>
|
||||||
|
</fixed>
|
||||||
|
</tendon>
|
||||||
|
|
||||||
<equality>
|
<equality>
|
||||||
<connect name="connect" body1="anchor1" body2="beam1" anchor="1 0 -1" />
|
<connect name="connect" body1="anchor1" body2="beam1" anchor="1 0 -1" />
|
||||||
<weld name="weld" body1="anchor2" body2="beam2" relpose="0 0 0 1 -.3 0 0" torquescale="0.002" anchor="0 -2 0"/>
|
<weld name="weld" body1="anchor2" body2="beam2" relpose="0 0 0 1 -.3 0 0" torquescale="0.002" anchor="0 -2 0"/>
|
||||||
<joint name="joint" joint1="joint3" joint2="joint4" polycoef="0.5 -1 0.1 0.15 0.2" />
|
<joint name="joint" joint1="joint3" joint2="joint4" polycoef="0.5 -1 0.1 0.15 0.2" />
|
||||||
|
<tendon name="tendon" tendon1="tendon_1" tendon2="tendon_2" polycoef="0.5 -1 0.1 0.15 0.2"/>
|
||||||
</equality>
|
</equality>
|
||||||
|
|
||||||
<actuator>
|
<actuator>
|
||||||
|
|||||||
@@ -126,6 +126,17 @@
|
|||||||
</body>
|
</body>
|
||||||
</worldbody>
|
</worldbody>
|
||||||
|
|
||||||
|
<tendon>
|
||||||
|
<fixed name="tendon_1" limited="true" range="-0.3 0.1" stiffness=".1" damping=".2">
|
||||||
|
<joint joint="joint2" coef=".1"/>
|
||||||
|
<joint joint="joint3" coef="-.2"/>
|
||||||
|
</fixed>
|
||||||
|
<fixed name="tendon_2" limited="true" range="-0.3 2" springlength="0 0.05" stiffness=".3" damping=".4">
|
||||||
|
<joint joint="joint4" coef=".3"/>
|
||||||
|
<joint joint="joint5" coef="-.4"/>
|
||||||
|
</fixed>
|
||||||
|
</tendon>
|
||||||
|
|
||||||
<actuator>
|
<actuator>
|
||||||
<motor gear="250 0 0" joint="joint1" name="act1"/>
|
<motor gear="250 0 0" joint="joint1" name="act1"/>
|
||||||
<motor gear="0 275 0" joint="joint1" name="act2"/>
|
<motor gear="0 275 0" joint="joint1" name="act2"/>
|
||||||
@@ -135,5 +146,6 @@
|
|||||||
<motor gear="150" joint="joint15" name="act6"/>
|
<motor gear="150" joint="joint15" name="act6"/>
|
||||||
<motor gear="150" joint="joint16" name="act7"/>
|
<motor gear="150" joint="joint16" name="act7"/>
|
||||||
<motor gear="150" joint="joint17" name="act8"/>
|
<motor gear="150" joint="joint17" name="act8"/>
|
||||||
|
<position tendon="tendon_2" kp="100"/>
|
||||||
</actuator>
|
</actuator>
|
||||||
</mujoco>
|
</mujoco>
|
||||||
|
|||||||
@@ -1304,7 +1304,7 @@ static void makeMaterial(const mjModel* m, mjrContext* con) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m->nmat >= mjMAXMATERIAL-1) {
|
if (m->nmat >= mjMAXMATERIAL-1) {
|
||||||
mju_error("Maximum number of materials is %d", mjMAXMATERIAL);
|
mju_error("Maximum number of materials is 100, got %d", m->nmat);
|
||||||
}
|
}
|
||||||
for (int i=0; i < m->nmat; i++) {
|
for (int i=0; i < m->nmat; i++) {
|
||||||
if (m->mat_texid[i*mjNTEXROLE + mjTEXROLE_RGB] >= 0) {
|
if (m->mat_texid[i*mjNTEXROLE + mjTEXROLE_RGB] >= 0) {
|
||||||
@@ -1320,7 +1320,8 @@ static void makeMaterial(const mjModel* m, mjrContext* con) {
|
|||||||
for (int i=0; i < m->ntex; i++) {
|
for (int i=0; i < m->ntex; i++) {
|
||||||
if (m->tex_type[i] == mjTEXTURE_SKYBOX) {
|
if (m->tex_type[i] == mjTEXTURE_SKYBOX) {
|
||||||
if (m->nmat >= mjMAXMATERIAL-2) {
|
if (m->nmat >= mjMAXMATERIAL-2) {
|
||||||
mju_error("With skybox, maximum number of materials is %d", mjMAXMATERIAL);
|
mju_error("With skybox, maximum number of materials is 99, got %d",
|
||||||
|
m->nmat);
|
||||||
}
|
}
|
||||||
for (int j=0; j < mjNTEXROLE; j++) {
|
for (int j=0; j < mjNTEXROLE; j++) {
|
||||||
con->mat_texid[mjNTEXROLE * (mjMAXMATERIAL-1) + j] = -1;
|
con->mat_texid[mjNTEXROLE * (mjMAXMATERIAL-1) + j] = -1;
|
||||||
|
|||||||
+18
-18
@@ -947,13 +947,11 @@ void mjCModel::DeleteMaterial(std::vector<T*>& list, std::string_view name) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// delete texture with given name or all textures if the name is omitted
|
// delete all textures
|
||||||
template <class T>
|
template <class T>
|
||||||
static void DeleteTexture(std::vector<T*>& list, std::string_view name = "") {
|
static void DeleteAllTextures(std::vector<T*>& list) {
|
||||||
for (T* plist : list) {
|
for (T* plist : list) {
|
||||||
if (name.empty() || plist->get_texture() == name) {
|
plist->del_textures();
|
||||||
plist->del_texture();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1046,7 +1044,7 @@ void mjCModel::DeleteAll<mjCMaterial>(std::vector<mjCMaterial*>& elements) {
|
|||||||
|
|
||||||
template <>
|
template <>
|
||||||
void mjCModel::DeleteAll<mjCTexture>(std::vector<mjCTexture*>& elements) {
|
void mjCModel::DeleteAll<mjCTexture>(std::vector<mjCTexture*>& elements) {
|
||||||
DeleteTexture(materials_);
|
DeleteAllTextures(materials_);
|
||||||
for (mjCTexture* element : elements) {
|
for (mjCTexture* element : elements) {
|
||||||
delete element;
|
delete element;
|
||||||
}
|
}
|
||||||
@@ -1202,13 +1200,15 @@ void mjCModel::IndexAssets(bool discard) {
|
|||||||
for (int i=0; i<materials_.size(); i++) {
|
for (int i=0; i<materials_.size(); i++) {
|
||||||
mjCMaterial* material = materials_[i];
|
mjCMaterial* material = materials_[i];
|
||||||
|
|
||||||
// find texture by name
|
// find textures by name
|
||||||
if (!material->texture_.empty()) {
|
for (int j=0; j<mjNTEXROLE; j++) {
|
||||||
mjCBase* texture = FindObject(mjOBJ_TEXTURE, material->texture_);
|
if (!material->textures_[j].empty()) {
|
||||||
if (texture) {
|
mjCBase* texture = FindObject(mjOBJ_TEXTURE, material->textures_[j]);
|
||||||
material->texid = texture->id;
|
if (texture) {
|
||||||
} else {
|
material->texid[j] = texture->id;
|
||||||
throw mjCError(material, "texture '%s' not found in material %d", material->texture_.c_str(), i);
|
} else {
|
||||||
|
throw mjCError(material, "texture '%s' not found in material %d", material->textures_[j].c_str(), i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2504,14 +2504,15 @@ void mjCModel::CopyObjects(mjModel* m) {
|
|||||||
m->tex_type[i] = ptex->type;
|
m->tex_type[i] = ptex->type;
|
||||||
m->tex_height[i] = ptex->height;
|
m->tex_height[i] = ptex->height;
|
||||||
m->tex_width[i] = ptex->width;
|
m->tex_width[i] = ptex->width;
|
||||||
|
m->tex_nchannel[i] = ptex->nchannel;
|
||||||
m->tex_adr[i] = data_adr;
|
m->tex_adr[i] = data_adr;
|
||||||
m->tex_nchannel[i] = 3;
|
|
||||||
|
|
||||||
// copy rgb data
|
// copy rgb data
|
||||||
memcpy(m->tex_data + data_adr, ptex->rgb.data(), 3*ptex->width*ptex->height);
|
memcpy(m->tex_data + data_adr, ptex->data.data(),
|
||||||
|
ptex->nchannel * ptex->width * ptex->height);
|
||||||
|
|
||||||
// advance counter
|
// advance counter
|
||||||
data_adr += 3*ptex->width*ptex->height;
|
data_adr += ptex->nchannel * ptex->width * ptex->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
// materials
|
// materials
|
||||||
@@ -2521,9 +2522,8 @@ void mjCModel::CopyObjects(mjModel* m) {
|
|||||||
|
|
||||||
// set fields
|
// set fields
|
||||||
for (int j=0; j<mjNTEXROLE; j++) {
|
for (int j=0; j<mjNTEXROLE; j++) {
|
||||||
m->mat_texid[mjNTEXROLE*i+j] = -1;
|
m->mat_texid[mjNTEXROLE*i+j] = pmat->texid[j];
|
||||||
}
|
}
|
||||||
m->mat_texid[mjNTEXROLE*i+mjTEXROLE_RGB] = pmat->texid;
|
|
||||||
m->mat_texuniform[i] = pmat->texuniform;
|
m->mat_texuniform[i] = pmat->texuniform;
|
||||||
mjuu_copyvec(m->mat_texrepeat+2*i, pmat->texrepeat, 2);
|
mjuu_copyvec(m->mat_texrepeat+2*i, pmat->texrepeat, 2);
|
||||||
m->mat_emission[i] = pmat->emission;
|
m->mat_emission[i] = pmat->emission;
|
||||||
|
|||||||
+86
-64
@@ -3217,7 +3217,7 @@ mjCTexture::mjCTexture(mjCModel* _model) {
|
|||||||
spec_cubefiles_.assign(6, "");
|
spec_cubefiles_.assign(6, "");
|
||||||
|
|
||||||
// clear internal variables
|
// clear internal variables
|
||||||
rgb.clear();
|
data.clear();
|
||||||
|
|
||||||
// point to local
|
// point to local
|
||||||
PointToLocal();
|
PointToLocal();
|
||||||
@@ -3266,14 +3266,14 @@ void mjCTexture::CopyFromSpec() {
|
|||||||
cubefiles_ = spec_cubefiles_;
|
cubefiles_ = spec_cubefiles_;
|
||||||
|
|
||||||
// clear precompiled asset. TODO: use asset cache
|
// clear precompiled asset. TODO: use asset cache
|
||||||
rgb.clear();
|
data.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// free data storage allocated by lodepng
|
// free data storage allocated by lodepng
|
||||||
mjCTexture::~mjCTexture() {
|
mjCTexture::~mjCTexture() {
|
||||||
rgb.clear();
|
data.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3366,21 +3366,21 @@ void mjCTexture::Builtin2D(void) {
|
|||||||
double pos = 2*sqrt(x*x+y*y) - 1;
|
double pos = 2*sqrt(x*x+y*y) - 1;
|
||||||
|
|
||||||
// interpolate through sigmoid
|
// interpolate through sigmoid
|
||||||
interp(rgb.data() + 3*(r*width+c), rgb2, rgb1, pos);
|
interp(data.data() + 3*(r*width+c), rgb2, rgb1, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// checker
|
// checker
|
||||||
else if (builtin==mjBUILTIN_CHECKER) {
|
else if (builtin==mjBUILTIN_CHECKER) {
|
||||||
checker(rgb.data(), RGB1, RGB2, width, height);
|
checker(data.data(), RGB1, RGB2, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// flat
|
// flat
|
||||||
else if (builtin==mjBUILTIN_FLAT) {
|
else if (builtin==mjBUILTIN_FLAT) {
|
||||||
for (int r=0; r<height; r++) {
|
for (int r=0; r<height; r++) {
|
||||||
for (int c=0; c<width; c++) {
|
for (int c=0; c<width; c++) {
|
||||||
memcpy(rgb.data()+3*(r*width+c), RGB1, 3);
|
memcpy(data.data()+3*(r*width+c), RGB1, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3390,28 +3390,28 @@ void mjCTexture::Builtin2D(void) {
|
|||||||
// edge
|
// edge
|
||||||
if (mark==mjMARK_EDGE) {
|
if (mark==mjMARK_EDGE) {
|
||||||
for (int r=0; r<height; r++) {
|
for (int r=0; r<height; r++) {
|
||||||
memcpy(rgb.data()+3*(r*width+0), RGBm, 3);
|
memcpy(data.data()+3*(r*width+0), RGBm, 3);
|
||||||
memcpy(rgb.data()+3*(r*width+width-1), RGBm, 3);
|
memcpy(data.data()+3*(r*width+width-1), RGBm, 3);
|
||||||
}
|
}
|
||||||
for (int c=0; c<width; c++) {
|
for (int c=0; c<width; c++) {
|
||||||
memcpy(rgb.data()+3*(0*width+c), RGBm, 3);
|
memcpy(data.data()+3*(0*width+c), RGBm, 3);
|
||||||
memcpy(rgb.data()+3*((height-1)*width+c), RGBm, 3);
|
memcpy(data.data()+3*((height-1)*width+c), RGBm, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// cross
|
// cross
|
||||||
else if (mark==mjMARK_CROSS) {
|
else if (mark==mjMARK_CROSS) {
|
||||||
for (int r=0; r<height; r++) {
|
for (int r=0; r<height; r++) {
|
||||||
memcpy(rgb.data()+3*(r*width+width/2), RGBm, 3);
|
memcpy(data.data()+3*(r*width+width/2), RGBm, 3);
|
||||||
}
|
}
|
||||||
for (int c=0; c<width; c++) {
|
for (int c=0; c<width; c++) {
|
||||||
memcpy(rgb.data()+3*(height/2*width+c), RGBm, 3);
|
memcpy(data.data()+3*(height/2*width+c), RGBm, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// random dots
|
// random dots
|
||||||
else if (mark==mjMARK_RANDOM && random>0) {
|
else if (mark==mjMARK_RANDOM && random>0) {
|
||||||
randomdot(rgb.data(), markrgb, width, height, random);
|
randomdot(data.data(), markrgb, width, height, random);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3446,26 +3446,26 @@ void mjCTexture::BuiltinCube(void) {
|
|||||||
|
|
||||||
// set sides
|
// set sides
|
||||||
interp(RGBi, rgb1, rgb2, elside);
|
interp(RGBi, rgb1, rgb2, elside);
|
||||||
memcpy(rgb.data() + 0 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 0: right
|
memcpy(data.data() + 0 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 0: right
|
||||||
memcpy(rgb.data() + 1 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 1: left
|
memcpy(data.data() + 1 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 1: left
|
||||||
memcpy(rgb.data() + 4 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 4: front
|
memcpy(data.data() + 4 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 4: front
|
||||||
memcpy(rgb.data() + 5 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 5: back
|
memcpy(data.data() + 5 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 5: back
|
||||||
|
|
||||||
// set up and down
|
// set up and down
|
||||||
interp(rgb.data() + 2 * 3 * ww + 3 * (r * w + c), rgb1, rgb2, elup); // 2: up
|
interp(data.data() + 2 * 3 * ww + 3 * (r * w + c), rgb1, rgb2, elup); // 2: up
|
||||||
interp(rgb.data() + 3 * 3 * ww + 3 * (r * w + c), rgb1, rgb2, -elup); // 3: down
|
interp(data.data() + 3 * 3 * ww + 3 * (r * w + c), rgb1, rgb2, -elup); // 3: down
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// checker
|
// checker
|
||||||
else if (builtin == mjBUILTIN_CHECKER) {
|
else if (builtin == mjBUILTIN_CHECKER) {
|
||||||
checker(rgb.data() + 0 * 3 * ww, RGB1, RGB2, w, w);
|
checker(data.data() + 0 * 3 * ww, RGB1, RGB2, w, w);
|
||||||
checker(rgb.data() + 1 * 3 * ww, RGB1, RGB2, w, w);
|
checker(data.data() + 1 * 3 * ww, RGB1, RGB2, w, w);
|
||||||
checker(rgb.data() + 2 * 3 * ww, RGB1, RGB2, w, w);
|
checker(data.data() + 2 * 3 * ww, RGB1, RGB2, w, w);
|
||||||
checker(rgb.data() + 3 * 3 * ww, RGB1, RGB2, w, w);
|
checker(data.data() + 3 * 3 * ww, RGB1, RGB2, w, w);
|
||||||
checker(rgb.data() + 4 * 3 * ww, RGB2, RGB1, w, w);
|
checker(data.data() + 4 * 3 * ww, RGB2, RGB1, w, w);
|
||||||
checker(rgb.data() + 5 * 3 * ww, RGB2, RGB1, w, w);
|
checker(data.data() + 5 * 3 * ww, RGB2, RGB1, w, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
// flat
|
// flat
|
||||||
@@ -3473,14 +3473,14 @@ void mjCTexture::BuiltinCube(void) {
|
|||||||
for (int r = 0; r < w; r++) {
|
for (int r = 0; r < w; r++) {
|
||||||
for (int c = 0; c < w; c++) {
|
for (int c = 0; c < w; c++) {
|
||||||
// set sides and up
|
// set sides and up
|
||||||
memcpy(rgb.data() + 0 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
memcpy(data.data() + 0 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||||
memcpy(rgb.data() + 1 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
memcpy(data.data() + 1 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||||
memcpy(rgb.data() + 2 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
memcpy(data.data() + 2 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||||
memcpy(rgb.data() + 4 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
memcpy(data.data() + 4 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||||
memcpy(rgb.data() + 5 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
memcpy(data.data() + 5 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||||
|
|
||||||
// set down
|
// set down
|
||||||
memcpy(rgb.data() + 3 * 3 * ww + 3 * (r * w + c), RGB2, 3);
|
memcpy(data.data() + 3 * 3 * ww + 3 * (r * w + c), RGB2, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3491,12 +3491,12 @@ void mjCTexture::BuiltinCube(void) {
|
|||||||
if (mark == mjMARK_EDGE) {
|
if (mark == mjMARK_EDGE) {
|
||||||
for (int j = 0; j < 6; j++) {
|
for (int j = 0; j < 6; j++) {
|
||||||
for (int r = 0; r < w; r++) {
|
for (int r = 0; r < w; r++) {
|
||||||
memcpy(rgb.data() + j * 3 * ww + 3 * (r * w + 0), RGBm, 3);
|
memcpy(data.data() + j * 3 * ww + 3 * (r * w + 0), RGBm, 3);
|
||||||
memcpy(rgb.data() + j * 3 * ww + 3 * (r * w + w - 1), RGBm, 3);
|
memcpy(data.data() + j * 3 * ww + 3 * (r * w + w - 1), RGBm, 3);
|
||||||
}
|
}
|
||||||
for (int c = 0; c < w; c++) {
|
for (int c = 0; c < w; c++) {
|
||||||
memcpy(rgb.data() + j * 3 * ww + 3 * (0 * w + c), RGBm, 3);
|
memcpy(data.data() + j * 3 * ww + 3 * (0 * w + c), RGBm, 3);
|
||||||
memcpy(rgb.data() + j * 3 * ww + 3 * ((w - 1) * w + c), RGBm, 3);
|
memcpy(data.data() + j * 3 * ww + 3 * ((w - 1) * w + c), RGBm, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3505,17 +3505,17 @@ void mjCTexture::BuiltinCube(void) {
|
|||||||
else if (mark == mjMARK_CROSS) {
|
else if (mark == mjMARK_CROSS) {
|
||||||
for (int j = 0; j < 6; j++) {
|
for (int j = 0; j < 6; j++) {
|
||||||
for (int r = 0; r < w; r++) {
|
for (int r = 0; r < w; r++) {
|
||||||
memcpy(rgb.data() + j * 3 * ww + 3 * (r * w + w / 2), RGBm, 3);
|
memcpy(data.data() + j * 3 * ww + 3 * (r * w + w / 2), RGBm, 3);
|
||||||
}
|
}
|
||||||
for (int c = 0; c < w; c++) {
|
for (int c = 0; c < w; c++) {
|
||||||
memcpy(rgb.data() + j * 3 * ww + 3 * (w / 2 * w + c), RGBm, 3);
|
memcpy(data.data() + j * 3 * ww + 3 * (w / 2 * w + c), RGBm, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// random dots
|
// random dots
|
||||||
else if (mark == mjMARK_RANDOM && random > 0) {
|
else if (mark == mjMARK_RANDOM && random > 0) {
|
||||||
randomdot(rgb.data(), markrgb, w, height, random);
|
randomdot(data.data(), markrgb, w, height, random);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3523,14 +3523,23 @@ void mjCTexture::BuiltinCube(void) {
|
|||||||
void mjCTexture::LoadPNG(mjResource* resource,
|
void mjCTexture::LoadPNG(mjResource* resource,
|
||||||
std::vector<unsigned char>& image,
|
std::vector<unsigned char>& image,
|
||||||
unsigned int& w, unsigned int& h) {
|
unsigned int& w, unsigned int& h) {
|
||||||
PNGImage png_image = PNGImage::Load(this, resource, LCT_RGB);
|
LodePNGColorType color_type;
|
||||||
|
if (nchannel == 4) {
|
||||||
|
color_type = LCT_RGBA;
|
||||||
|
} else if (nchannel == 3) {
|
||||||
|
color_type = LCT_RGB;
|
||||||
|
} else if (nchannel == 1) {
|
||||||
|
color_type = LCT_GREY;
|
||||||
|
} else {
|
||||||
|
throw mjCError(this, "Unsupported number of channels: %s",
|
||||||
|
std::to_string(nchannel).c_str());
|
||||||
|
}
|
||||||
|
PNGImage png_image = PNGImage::Load(this, resource, color_type);
|
||||||
w = png_image.Width();
|
w = png_image.Width();
|
||||||
h = png_image.Height();
|
h = png_image.Height();
|
||||||
image = png_image.MoveData();
|
image = png_image.MoveData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// load custom file
|
// load custom file
|
||||||
void mjCTexture::LoadCustom(mjResource* resource,
|
void mjCTexture::LoadCustom(mjResource* resource,
|
||||||
std::vector<unsigned char>& image,
|
std::vector<unsigned char>& image,
|
||||||
@@ -3601,6 +3610,10 @@ void mjCTexture::LoadFlip(std::string filename, const mjVFS* vfs,
|
|||||||
|
|
||||||
// horizontal flip
|
// horizontal flip
|
||||||
if (hflip) {
|
if (hflip) {
|
||||||
|
if (nchannel != 3) {
|
||||||
|
throw mjCError(
|
||||||
|
this, "currently only 3-channel textures support horizontal flip");
|
||||||
|
}
|
||||||
for (int r=0; r<h; r++) {
|
for (int r=0; r<h; r++) {
|
||||||
for (int c=0; c<w/2; c++) {
|
for (int c=0; c<w/2; c++) {
|
||||||
int c1 = w-1-c;
|
int c1 = w-1-c;
|
||||||
@@ -3623,6 +3636,10 @@ void mjCTexture::LoadFlip(std::string filename, const mjVFS* vfs,
|
|||||||
|
|
||||||
// vertical flip
|
// vertical flip
|
||||||
if (vflip) {
|
if (vflip) {
|
||||||
|
if (nchannel != 3) {
|
||||||
|
throw mjCError(
|
||||||
|
this, "currently only 3-channel textures support vertical flip");
|
||||||
|
}
|
||||||
for (int r=0; r<h/2; r++) {
|
for (int r=0; r<h/2; r++) {
|
||||||
for (int c=0; c<w; c++) {
|
for (int c=0; c<w; c++) {
|
||||||
int r1 = h-1-r;
|
int r1 = h-1-r;
|
||||||
@@ -3658,12 +3675,12 @@ void mjCTexture::Load2D(std::string filename, const mjVFS* vfs) {
|
|||||||
height = h;
|
height = h;
|
||||||
|
|
||||||
// allocate and copy data
|
// allocate and copy data
|
||||||
rgb.assign(3*width*height, 0);
|
data.assign(nchannel*width*height, 0);
|
||||||
if (rgb.empty()) {
|
if (data.empty()) {
|
||||||
throw mjCError(this, "Could not allocate memory for texture '%s' (id %d)",
|
throw mjCError(this, "Could not allocate memory for texture '%s' (id %d)",
|
||||||
(const char*)file_.c_str(), id);
|
(const char*)file_.c_str(), id);
|
||||||
}
|
}
|
||||||
memcpy(rgb.data(), image.data(), 3*width*height);
|
memcpy(data.data(), image.data(), nchannel*width*height);
|
||||||
image.clear();
|
image.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3697,8 +3714,8 @@ void mjCTexture::LoadCubeSingle(std::string filename, const mjVFS* vfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// allocate data
|
// allocate data
|
||||||
rgb.assign(3*width*height, 0);
|
data.assign(3*width*height, 0);
|
||||||
if (rgb.empty()) {
|
if (data.empty()) {
|
||||||
throw mjCError(this,
|
throw mjCError(this,
|
||||||
"Could not allocate memory for texture '%s' (id %d)",
|
"Could not allocate memory for texture '%s' (id %d)",
|
||||||
(const char*)file_.c_str(), id);
|
(const char*)file_.c_str(), id);
|
||||||
@@ -3706,7 +3723,7 @@ void mjCTexture::LoadCubeSingle(std::string filename, const mjVFS* vfs) {
|
|||||||
|
|
||||||
// copy: repeated
|
// copy: repeated
|
||||||
if (gridsize[0]==1 && gridsize[1]==1) {
|
if (gridsize[0]==1 && gridsize[1]==1) {
|
||||||
memcpy(rgb.data(), image.data(), 3*width*width);
|
memcpy(data.data(), image.data(), 3*width*width);
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy: grid
|
// copy: grid
|
||||||
@@ -3739,7 +3756,7 @@ void mjCTexture::LoadCubeSingle(std::string filename, const mjVFS* vfs) {
|
|||||||
int rstart = width*(k/gridsize[1]);
|
int rstart = width*(k/gridsize[1]);
|
||||||
int cstart = width*(k%gridsize[1]);
|
int cstart = width*(k%gridsize[1]);
|
||||||
for (int j=0; j<width; j++) {
|
for (int j=0; j<width; j++) {
|
||||||
memcpy(rgb.data()+i*3*width*width+j*3*width, image.data()+(j+rstart)*3*w+3*cstart, 3*width);
|
memcpy(data.data()+i*3*width*width+j*3*width, image.data()+(j+rstart)*3*w+3*cstart, 3*width);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark as defined
|
// mark as defined
|
||||||
@@ -3753,7 +3770,7 @@ void mjCTexture::LoadCubeSingle(std::string filename, const mjVFS* vfs) {
|
|||||||
for (int k=0; k<width; k++) {
|
for (int k=0; k<width; k++) {
|
||||||
for (int s=0; s<width; s++) {
|
for (int s=0; s<width; s++) {
|
||||||
for (int j=0; j<3; j++) {
|
for (int j=0; j<3; j++) {
|
||||||
rgb[i*3*width*width + 3*(k*width+s) + j] = (mjtByte)(255*rgb1[j]);
|
data[i*3*width*width + 3*(k*width+s) + j] = (mjtByte)(255*rgb1[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3795,11 +3812,11 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// first file: set size and allocate data
|
// first file: set size and allocate data
|
||||||
if (rgb.empty()) {
|
if (data.empty()) {
|
||||||
width = w;
|
width = w;
|
||||||
height = 6*width;
|
height = 6*width;
|
||||||
rgb.assign(3*width*height, 0);
|
data.assign(3*width*height, 0);
|
||||||
if (rgb.empty()) {
|
if (data.empty()) {
|
||||||
throw mjCError(this, "Could not allocate memory for texture");
|
throw mjCError(this, "Could not allocate memory for texture");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3812,7 +3829,7 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// copy data
|
// copy data
|
||||||
memcpy(rgb.data()+i*3*width*width, image.data(), 3*width*width);
|
memcpy(data.data()+i*3*width*width, image.data(), 3*width*width);
|
||||||
image.clear();
|
image.clear();
|
||||||
|
|
||||||
// mark as defined
|
// mark as defined
|
||||||
@@ -3826,7 +3843,7 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) {
|
|||||||
for (int k=0; k<width; k++) {
|
for (int k=0; k<width; k++) {
|
||||||
for (int s=0; s<width; s++) {
|
for (int s=0; s<width; s++) {
|
||||||
for (int j=0; j<3; j++) {
|
for (int j=0; j<3; j++) {
|
||||||
rgb[i*3*width*width + 3*(k*width+s) + j] = (mjtByte)(255*rgb1[j]);
|
data[i*3*width*width + 3*(k*width+s) + j] = (mjtByte)(255*rgb1[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3857,8 +3874,8 @@ void mjCTexture::Compile(const mjVFS* vfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// allocate data
|
// allocate data
|
||||||
rgb.assign(3*width*height, 0);
|
data.assign(nchannel*width*height, 0);
|
||||||
if (rgb.empty()) {
|
if (data.empty()) {
|
||||||
throw mjCError(this, "Could not allocate memory for texture");
|
throw mjCError(this, "Could not allocate memory for texture");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3914,7 +3931,7 @@ void mjCTexture::Compile(const mjVFS* vfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make sure someone allocated data; SHOULD NOT OCCUR
|
// make sure someone allocated data; SHOULD NOT OCCUR
|
||||||
if (rgb.empty()) {
|
if (data.empty()) {
|
||||||
throw mjCError(this, "texture '%s' (id %d) was not specified", name.c_str(), id);
|
throw mjCError(this, "texture '%s' (id %d) was not specified", name.c_str(), id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3927,10 +3944,13 @@ void mjCTexture::Compile(const mjVFS* vfs) {
|
|||||||
mjCMaterial::mjCMaterial(mjCModel* _model, mjCDef* _def) {
|
mjCMaterial::mjCMaterial(mjCModel* _model, mjCDef* _def) {
|
||||||
mjs_defaultMaterial(&spec);
|
mjs_defaultMaterial(&spec);
|
||||||
elemtype = mjOBJ_MATERIAL;
|
elemtype = mjOBJ_MATERIAL;
|
||||||
|
textures_.assign(mjNTEXROLE, "");
|
||||||
|
spec_textures_.assign(mjNTEXROLE, "");
|
||||||
|
|
||||||
// clear internal
|
// clear internal
|
||||||
spec_texture_.clear();
|
for (int i=0; i<mjNTEXROLE; i++) {
|
||||||
texid = -1;
|
texid[i] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
// reset to default if given
|
// reset to default if given
|
||||||
if (_def) {
|
if (_def) {
|
||||||
@@ -3969,16 +3989,16 @@ mjCMaterial& mjCMaterial::operator=(const mjCMaterial& other) {
|
|||||||
void mjCMaterial::PointToLocal() {
|
void mjCMaterial::PointToLocal() {
|
||||||
spec.element = static_cast<mjsElement*>(this);
|
spec.element = static_cast<mjsElement*>(this);
|
||||||
spec.name = &name;
|
spec.name = &name;
|
||||||
spec.texture = &spec_texture_;
|
spec.textures = &spec_textures_;
|
||||||
spec.info = &info;
|
spec.info = &info;
|
||||||
texture = nullptr;
|
textures = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void mjCMaterial::CopyFromSpec() {
|
void mjCMaterial::CopyFromSpec() {
|
||||||
*static_cast<mjsMaterial*>(this) = spec;
|
*static_cast<mjsMaterial*>(this) = spec;
|
||||||
texture_ = spec_texture_;
|
textures_ = spec_textures_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3987,8 +4007,10 @@ void mjCMaterial::NameSpace(const mjCModel* m) {
|
|||||||
if (!name.empty()) {
|
if (!name.empty()) {
|
||||||
name = m->prefix + name + m->suffix;
|
name = m->prefix + name + m->suffix;
|
||||||
}
|
}
|
||||||
if (!spec_texture_.empty() && model != m) {
|
for (int i=0; i<mjNTEXROLE; i++) {
|
||||||
spec_texture_ = m->prefix + spec_texture_ + m->suffix;
|
if (!spec_textures_[i].empty() && model != m) {
|
||||||
|
spec_textures_[i] = m->prefix + spec_textures_[i] + m->suffix;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1003,7 +1003,7 @@ class mjCHField : public mjCHField_, private mjsHField {
|
|||||||
|
|
||||||
class mjCTexture_ : public mjCBase {
|
class mjCTexture_ : public mjCBase {
|
||||||
protected:
|
protected:
|
||||||
std::vector<mjtByte> rgb; // rgb data
|
std::vector<mjtByte> data; // texture data (rgb, roughness, etc.)
|
||||||
|
|
||||||
std::string file_;
|
std::string file_;
|
||||||
std::string content_type_;
|
std::string content_type_;
|
||||||
@@ -1063,9 +1063,9 @@ class mjCTexture : public mjCTexture_, private mjsTexture {
|
|||||||
|
|
||||||
class mjCMaterial_ : public mjCBase {
|
class mjCMaterial_ : public mjCBase {
|
||||||
protected:
|
protected:
|
||||||
int texid; // id of material's texture
|
int texid[mjNTEXROLE]; // id of material's textures
|
||||||
std::string texture_;
|
std::vector<std::string> textures_;
|
||||||
std::string spec_texture_;
|
std::vector<std::string> spec_textures_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class mjCMaterial : public mjCMaterial_, private mjsMaterial {
|
class mjCMaterial : public mjCMaterial_, private mjsMaterial {
|
||||||
@@ -1086,8 +1086,8 @@ class mjCMaterial : public mjCMaterial_, private mjsMaterial {
|
|||||||
void PointToLocal();
|
void PointToLocal();
|
||||||
void NameSpace(const mjCModel* m);
|
void NameSpace(const mjCModel* m);
|
||||||
|
|
||||||
const std::string& get_texture() const { return texture_; }
|
const std::string& get_texture(int i) const { return textures_[i]; }
|
||||||
void del_texture() { texture_.clear(); }
|
void del_textures() { for (auto& t : textures_) t.clear(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Compile(void); // compiler
|
void Compile(void); // compiler
|
||||||
|
|||||||
@@ -239,12 +239,23 @@ const char* MJCF[nMJCF][mjXATTRNUM] = {
|
|||||||
{"<"},
|
{"<"},
|
||||||
{"bone", "*", "5", "body", "bindpos", "bindquat", "vertid", "vertweight"},
|
{"bone", "*", "5", "body", "bindpos", "bindquat", "vertid", "vertweight"},
|
||||||
{">"},
|
{">"},
|
||||||
{"texture", "*", "22", "name", "type", "content_type", "file", "gridsize", "gridlayout",
|
{"texture", "*", "23", "name", "type", "content_type", "file", "gridsize", "gridlayout",
|
||||||
"fileright", "fileleft", "fileup", "filedown", "filefront", "fileback",
|
"fileright", "fileleft", "fileup", "filedown", "filefront", "fileback",
|
||||||
"builtin", "rgb1", "rgb2", "mark", "markrgb", "random", "width", "height",
|
"builtin", "rgb1", "rgb2", "mark", "markrgb", "random", "width", "height",
|
||||||
"hflip", "vflip"},
|
"hflip", "vflip", "nchannel"},
|
||||||
{"material", "*", "12", "name", "class", "texture", "texrepeat", "texuniform",
|
{"material", "*", "12", "name", "class", "texture", "texrepeat", "texuniform",
|
||||||
"emission", "specular", "shininess", "reflectance", "metallic", "roughness", "rgba"},
|
"emission", "specular", "shininess", "reflectance", "metallic", "roughness", "rgba"},
|
||||||
|
{"<"},
|
||||||
|
{"rgb", "?", "1", "texture"},
|
||||||
|
{"occlusion", "?", "1", "texture"},
|
||||||
|
{"roughness", "?", "1", "texture"},
|
||||||
|
{"metallic", "?", "1", "texture"},
|
||||||
|
{"normal", "?", "1", "texture"},
|
||||||
|
{"opacity", "?", "1", "texture"},
|
||||||
|
{"emissive", "?", "1", "texture"},
|
||||||
|
{"rgba", "?", "1", "texture"},
|
||||||
|
{"orm", "?", "1", "texture"},
|
||||||
|
{">"},
|
||||||
{"model", "*", "2", "name", "file"},
|
{"model", "*", "2", "name", "file"},
|
||||||
{">"},
|
{">"},
|
||||||
|
|
||||||
@@ -577,6 +588,19 @@ const mjMap camlight_map[camlight_sz] = {
|
|||||||
{"targetbodycom", mjCAMLIGHT_TARGETBODYCOM}
|
{"targetbodycom", mjCAMLIGHT_TARGETBODYCOM}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// texmat role type
|
||||||
|
const int texrole_sz = mjNTEXROLE - 1;
|
||||||
|
const mjMap texrole_map[texrole_sz] = {
|
||||||
|
{"rgb", mjTEXROLE_RGB},
|
||||||
|
{"occlusion", mjTEXROLE_OCCLUSION},
|
||||||
|
{"roughness", mjTEXROLE_ROUGHNESS},
|
||||||
|
{"metallic", mjTEXROLE_METALLIC},
|
||||||
|
{"normal", mjTEXROLE_NORMAL},
|
||||||
|
{"opacity", mjTEXROLE_OPACITY},
|
||||||
|
{"emissive", mjTEXROLE_EMISSIVE},
|
||||||
|
{"rgba", mjTEXROLE_RGBA},
|
||||||
|
{"orm", mjTEXROLE_ORM},
|
||||||
|
};
|
||||||
|
|
||||||
// integrator type
|
// integrator type
|
||||||
const int integrator_sz = 4;
|
const int integrator_sz = 4;
|
||||||
@@ -1534,9 +1558,26 @@ void mjXReader::OneMaterial(XMLElement* elem, mjsMaterial* pmat) {
|
|||||||
if (ReadAttrTxt(elem, "name", name)) {
|
if (ReadAttrTxt(elem, "name", name)) {
|
||||||
mjs_setString(pmat->name, name.c_str());
|
mjs_setString(pmat->name, name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool tex_attributes_found = false;
|
||||||
if (ReadAttrTxt(elem, "texture", texture)) {
|
if (ReadAttrTxt(elem, "texture", texture)) {
|
||||||
mjs_setString(pmat->texture, texture.c_str());
|
mjs_setInStringVec(pmat->textures, mjTEXROLE_RGB, texture.c_str());
|
||||||
|
tex_attributes_found = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XMLElement* tex_elem = FirstChildElement(elem);
|
||||||
|
while (tex_elem) {
|
||||||
|
if (tex_attributes_found) {
|
||||||
|
throw mjXError(tex_elem, "A material with a texture attribute cannot have texture sub-elements");
|
||||||
|
}
|
||||||
|
// texture sub-element
|
||||||
|
int role = FindKey(texrole_map, texrole_sz, tex_elem->Name());
|
||||||
|
string texmat;
|
||||||
|
ReadAttrTxt(tex_elem, "texture", texmat, true);
|
||||||
|
mjs_setInStringVec(pmat->textures, role, texmat.c_str());
|
||||||
|
tex_elem = NextSiblingElement(tex_elem);
|
||||||
|
}
|
||||||
|
|
||||||
if (MapValue(elem, "texuniform", &n, bool_map, 2)) {
|
if (MapValue(elem, "texuniform", &n, bool_map, 2)) {
|
||||||
pmat->texuniform = (n==1);
|
pmat->texuniform = (n==1);
|
||||||
}
|
}
|
||||||
@@ -3095,6 +3136,9 @@ void mjXReader::Asset(XMLElement* section, const mjVFS* vfs) {
|
|||||||
}
|
}
|
||||||
ReadAttrInt(elem, "width", &ptex->width);
|
ReadAttrInt(elem, "width", &ptex->width);
|
||||||
ReadAttrInt(elem, "height", &ptex->height);
|
ReadAttrInt(elem, "height", &ptex->height);
|
||||||
|
if (!ReadAttrInt(elem, "nchannel", &ptex->nchannel)) {
|
||||||
|
ptex->nchannel = 3;
|
||||||
|
}
|
||||||
ReadAttr(elem, "rgb1", 3, ptex->rgb1, text);
|
ReadAttr(elem, "rgb1", 3, ptex->rgb1, text);
|
||||||
ReadAttr(elem, "rgb2", 3, ptex->rgb2, text);
|
ReadAttr(elem, "rgb2", 3, ptex->rgb2, text);
|
||||||
ReadAttr(elem, "markrgb", 3, ptex->markrgb, text);
|
ReadAttr(elem, "markrgb", 3, ptex->markrgb, text);
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ class mjXReader : public mjXBase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// MJCF schema
|
// MJCF schema
|
||||||
#define nMJCF 232
|
#define nMJCF 243
|
||||||
extern const char* MJCF[nMJCF][mjXATTRNUM];
|
extern const char* MJCF[nMJCF][mjXATTRNUM];
|
||||||
|
|
||||||
#endif // MUJOCO_SRC_XML_XML_NATIVE_READER_H_
|
#endif // MUJOCO_SRC_XML_XML_NATIVE_READER_H_
|
||||||
|
|||||||
@@ -305,8 +305,20 @@ void mjXWriter::OneMaterial(XMLElement* elem, const mjCMaterial* pmat, mjCDef* d
|
|||||||
}
|
}
|
||||||
|
|
||||||
// defaults and regular
|
// defaults and regular
|
||||||
if (pmat->texture != def->Material().texture) {
|
bool has_non_rgb = false;
|
||||||
WriteAttrTxt(elem, "texture", pmat->get_texture());
|
for (int i=1; i<mjNTEXROLE; i++) {
|
||||||
|
if (!pmat->textures_[i].empty()) {
|
||||||
|
if (i != mjTEXROLE_RGB) {
|
||||||
|
has_non_rgb = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pmat->textures_[i] != def->Material().textures_[i]) {
|
||||||
|
WriteAttrTxt(elem, "texture", pmat->get_texture(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (has_non_rgb) {
|
||||||
|
// // TODO elem = InsertEnd(section, "role");
|
||||||
|
mju_error("mjXWriter: no support for non-RGB textures.");
|
||||||
}
|
}
|
||||||
WriteAttrKey(elem, "texuniform", bool_map, 2, pmat->texuniform, def->Material().texuniform);
|
WriteAttrKey(elem, "texuniform", bool_map, 2, pmat->texuniform, def->Material().texuniform);
|
||||||
WriteAttr(elem, "texrepeat", 2, pmat->texrepeat, def->Material().texrepeat);
|
WriteAttr(elem, "texrepeat", 2, pmat->texrepeat, def->Material().texrepeat);
|
||||||
|
|||||||
@@ -782,12 +782,108 @@ TEST_F(XMLReaderTest, FallbackIncludePathTest) {
|
|||||||
std::array<char, 1024> error;
|
std::array<char, 1024> error;
|
||||||
mjModel* model = mj_loadXML(modelpath.c_str(), nullptr,
|
mjModel* model = mj_loadXML(modelpath.c_str(), nullptr,
|
||||||
error.data(), error.size());
|
error.data(), error.size());
|
||||||
ASSERT_THAT(model, NotNull());
|
ASSERT_THAT(model, NotNull()) << error.data();
|
||||||
EXPECT_EQ(mj_name2id(model, mjOBJ_GEOM, "ball"), 2);
|
EXPECT_EQ(mj_name2id(model, mjOBJ_GEOM, "ball"), 2);
|
||||||
EXPECT_EQ(mj_name2id(model, mjOBJ_GEOM, "another_box"), 3);
|
EXPECT_EQ(mj_name2id(model, mjOBJ_GEOM, "another_box"), 3);
|
||||||
mj_deleteModel(model);
|
mj_deleteModel(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(XMLReaderTest, MaterialTextureTest) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<asset>
|
||||||
|
<texture file="tiny0.png" type="2d" name="tiny0"/>
|
||||||
|
<texture file="tiny1.png" type="2d" name="tiny1"/>
|
||||||
|
<material name="material">
|
||||||
|
<occlusion texture="tiny0"/>
|
||||||
|
<roughness texture="tiny0"/>
|
||||||
|
<metallic texture="tiny0"/>
|
||||||
|
<rgb texture="tiny1"/>
|
||||||
|
</material>
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<geom type="plane" material="material" size="4 4 4"/>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
|
||||||
|
MockFilesystem fs("MaterialTextureTest");
|
||||||
|
fs.AddFile("tiny0.png", kTinyPng, sizeof(kTinyPng));
|
||||||
|
fs.AddFile("tiny1.png", kTinyPng, sizeof(kTinyPng));
|
||||||
|
fs.AddFile("model.xml", (const unsigned char*) xml, sizeof(xml));
|
||||||
|
std::string modelpath = fs.FullPath("model.xml");
|
||||||
|
|
||||||
|
char error[1024];
|
||||||
|
mjModel* model = mj_loadXML(modelpath.c_str(), nullptr, error, 1024);
|
||||||
|
|
||||||
|
EXPECT_THAT(model, NotNull()) << error;
|
||||||
|
EXPECT_EQ(model->mat_texid[mjTEXROLE_RGB], 1);
|
||||||
|
EXPECT_EQ(model->mat_texid[mjTEXROLE_METALLIC], 0);
|
||||||
|
EXPECT_EQ(model->mat_texid[mjTEXROLE_ROUGHNESS], 0);
|
||||||
|
EXPECT_EQ(model->mat_texid[mjTEXROLE_OCCLUSION], 0);
|
||||||
|
|
||||||
|
mj_deleteModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(XMLReaderTest, LegacyMaterialTextureTest) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<asset>
|
||||||
|
<texture file="tiny0.png" type="2d" name="tiny0"/>
|
||||||
|
<texture file="tiny1.png" type="2d" name="tiny1"/>
|
||||||
|
<material name="material" texture="tiny1"/>
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<geom type="plane" material="material" size="4 4 4"/>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
|
||||||
|
MockFilesystem fs("LegacyMaterialTextureTest");
|
||||||
|
fs.AddFile("tiny0.png", kTinyPng, sizeof(kTinyPng));
|
||||||
|
fs.AddFile("tiny1.png", kTinyPng, sizeof(kTinyPng));
|
||||||
|
fs.AddFile("model.xml", (const unsigned char*) xml, sizeof(xml));
|
||||||
|
std::string modelpath = fs.FullPath("model.xml");
|
||||||
|
|
||||||
|
char error[1024];
|
||||||
|
mjModel* model = mj_loadXML(modelpath.c_str(), nullptr, error, 1024);
|
||||||
|
|
||||||
|
EXPECT_THAT(model, NotNull()) << error;
|
||||||
|
EXPECT_EQ(model->mat_texid[mjTEXROLE_RGB], 1);
|
||||||
|
|
||||||
|
mj_deleteModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(XMLReaderTest, MaterialTextureFailTest) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<asset>
|
||||||
|
<texture file="tiny0.png" type="2d" name="tiny0"/>
|
||||||
|
<texture file="tiny1.png" type="2d" name="tiny1"/>
|
||||||
|
<material name="material" texture="tiny1">
|
||||||
|
<rgb texture="tiny1"/>
|
||||||
|
<occlusion texture="tiny0"/>
|
||||||
|
</material>
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<geom type="plane" material="material" size="4 4 4"/>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
|
||||||
|
MockFilesystem fs("MaterialTextureFailTest");
|
||||||
|
fs.AddFile("tiny0.png", kTinyPng, sizeof(kTinyPng));
|
||||||
|
fs.AddFile("tiny1.png", kTinyPng, sizeof(kTinyPng));
|
||||||
|
fs.AddFile("model.xml", (const unsigned char*) xml, sizeof(xml));
|
||||||
|
std::string modelpath = fs.FullPath("model.xml");
|
||||||
|
|
||||||
|
std::array<char, 1024> error;
|
||||||
|
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||||
|
EXPECT_THAT(m, IsNull());
|
||||||
|
EXPECT_THAT(error.data(), HasSubstr("A material with a texture attribute "
|
||||||
|
"cannot have texture sub-elements"));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(XMLReaderTest, IncludeAssetsTest) {
|
TEST_F(XMLReaderTest, IncludeAssetsTest) {
|
||||||
static constexpr char xml[] = R"(
|
static constexpr char xml[] = R"(
|
||||||
<mujoco>
|
<mujoco>
|
||||||
|
|||||||
Reference in New Issue
Block a user