From caf215e3423c4a4d5e1a760972f36a24bf08c3dc Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Mon, 22 Apr 2024 07:37:52 -0700 Subject: [PATCH] Add metallic and roughness scalar attributes to materials. Rename `light_radius` -> `light_bulbradius`, make the default value 0.02. PiperOrigin-RevId: 627032170 Change-Id: I1e01e2eca028c0aefc2e7dc384e8b34abac184aa --- doc/XMLreference.rst | 30 ++++++++++++---- doc/XMLschema.rst | 10 +++--- doc/changelog.rst | 10 ++++-- doc/includes/references.h | 8 ++++- include/mujoco/mjmodel.h | 4 ++- include/mujoco/mjvisualize.h | 4 +++ include/mujoco/mjxmacro.h | 4 ++- introspect/structs.py | 54 ++++++++++++++++++++++++---- python/mujoco/structs.cc | 1 + src/engine/engine_vis_visualize.c | 1 + src/user/user_api.h | 4 ++- src/user/user_init.cc | 3 ++ src/user/user_model.cc | 4 ++- src/xml/xml_native_reader.cc | 16 +++++---- src/xml/xml_native_writer.cc | 4 ++- test/xml/xml_native_reader_test.cc | 10 +++--- test/xml/xml_native_writer_test.cc | 40 ++++++++++++++++++--- unity/Runtime/Bindings/MjBindings.cs | 8 ++++- 18 files changed, 170 insertions(+), 45 deletions(-) diff --git a/doc/XMLreference.rst b/doc/XMLreference.rst index 90e8f04a..44230bb8 100644 --- a/doc/XMLreference.rst +++ b/doc/XMLreference.rst @@ -1788,6 +1788,18 @@ properties are grouped together. instead. Only the first reflective geom in the model is rendered as such. This adds one extra rendering pass through all geoms, in addition to the extra rendering pass added by each shadow-casting light. +.. _asset-material-metallic: + +:at:`metallic`: :at-val:`real, "0"` + This attribute corresponds to uniform metallicity coefficient applied to the entire material. This attribute has no + effect in MuJoCo's native renderer, but it can be useful when rendering scenes with an external renderer. + +.. _asset-material-roughness: + +:at:`roughness`: :at-val:`real, "1"` + This attribute corresponds to uniform roughness coefficient applied to the entire material. This attribute has no + effect in MuJoCo's native renderer, but it can be useful when rendering scenes with an external renderer. + .. _asset-material-rgba: :at:`rgba`: :at-val:`real(4), "1 1 1 1"` @@ -3165,6 +3177,12 @@ the direction specified by the dir attribute. It does not have a full spatial fr these clipping planes bound the cone or box shadow volume in the light direction. As a result, some shadows (especially those very close to the light) may be clipped. +.. _body-light-bulbradius: + +:at:`radius`: :at-val:`real, "0.02"` + Radius of the light, affects shadow softness. This attribute has no effect in MuJoCo's native renderer, but it can be + useful when rendering scenes with an external renderer. + .. _body-light-active: :at:`active`: :at-val:`[false, true], "true"` @@ -3181,12 +3199,6 @@ the direction specified by the dir attribute. It does not have a full spatial fr :at:`dir`: :at-val:`real(3), "0 0 -1"` Direction of the light. -.. _body-light-radius: - -:at:`radius`: :at-val:`real, "0"` - Radius of the light, affects shadow softness. This attribute has no effect in MuJoCo's native renderer, but it can be - useful when rendering scenes with an external renderer. - .. _body-light-attenuation: :at:`attenuation`: :at-val:`real(3), "1 0 0"` @@ -7372,6 +7384,10 @@ if omitted. .. _default-material-reflectance: +.. _default-material-metallic: + +.. _default-material-roughness: + .. _default-material-rgba: .. _default-material-texrepeat: @@ -7592,7 +7608,7 @@ if omitted. .. _default-light-dir: -.. _default-light-radius: +.. _default-light-bulbradius: .. _default-light-directional: diff --git a/doc/XMLschema.rst b/doc/XMLschema.rst index c374cfa0..236ab005 100644 --- a/doc/XMLschema.rst +++ b/doc/XMLschema.rst @@ -213,7 +213,7 @@ | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | | | | | :ref:`texuniform` | :ref:`emission` | :ref:`specular` | :ref:`shininess` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`reflectance` | :ref:`rgba` | | | | +| | | | :ref:`reflectance` | :ref:`metallic` | :ref:`roughness` | :ref:`rgba` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | mujoco |br| |L| | | .. table:: | @@ -369,7 +369,7 @@ | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | | | | | :ref:`name` | :ref:`class` | :ref:`directional` | :ref:`castshadow` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`active` | :ref:`pos` | :ref:`dir` | :ref:`radius` | | +| | | | :ref:`active` | :ref:`pos` | :ref:`dir` | :ref:`bulbradius` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | | | | | :ref:`attenuation` | :ref:`cutoff` | :ref:`exponent` | :ref:`ambient` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | @@ -1307,7 +1307,9 @@ | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | | | | | :ref:`texture` | :ref:`emission` | :ref:`specular` | :ref:`shininess` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`reflectance` | :ref:`rgba` | :ref:`texrepeat` | :ref:`texuniform` | | +| | | | :ref:`reflectance` | :ref:`metallic` | :ref:`roughness` | :ref:`rgba` | | +| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +| | | | :ref:`texrepeat` | :ref:`texuniform` | | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_| default |br| |_| |L| | | .. table:: | @@ -1378,7 +1380,7 @@ | :ref:`light | ? | :class: mjcf-attributes | | ` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`pos` | :ref:`dir` | :ref:`radius` | :ref:`directional` | | +| | | | :ref:`pos` | :ref:`dir` | :ref:`bulbradius` | :ref:`directional` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | | | | | :ref:`castshadow` | :ref:`active` | :ref:`attenuation` | :ref:`cutoff` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | diff --git a/doc/changelog.rst b/doc/changelog.rst index 7d0ecc4c..9b9b8a7a 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -9,8 +9,12 @@ General ^^^^^^^ 1. Added ``mjModel.mesh_scale``: the scaling applied to asset vertices, as specified in the :ref:`scale` attribute. -2. Added the :ref:`light/radius` attribute and corresponding ``mjModel.light_radius`` field. This - value has no effect in MuJoCo's native renderer, but can be usful when rendering scenes with an external renderer. +2. Added visual properties which are ignored by the native renderer, but can be used by external renderers: + + - :ref:`light/bulbradius` attribute and corresponding ``mjModel.light_bulbradius`` field. + - :ref:`material/metallic` attribute and corresponding ``mjModel.material_metallic`` field. + - :ref:`material/roughness` attribute and corresponding ``mjModel.material_roughness`` + field. MJX ^^^ @@ -36,7 +40,7 @@ MJX Bug fixes ^^^^^^^^^ 12. Defaults of lights were not being saved, now fixed. -13. Prevent overwriting of frame names by body names when saving an XML. Introduced in 3.1.4. +13. Prevent overwriting of frame names by body names when saving an XML. Bug introduced in 3.1.4. 14. Fixed bug in Python binding of :ref:`mj_saveModel`: ``buffer`` argument was documented as optional but was actually not optional. diff --git a/doc/includes/references.h b/doc/includes/references.h index e0a77d94..8a59d8c3 100644 --- a/doc/includes/references.h +++ b/doc/includes/references.h @@ -1079,10 +1079,10 @@ struct mjModel_ { int* light_targetbodyid; // id of targeted body; -1: none (nlight x 1) mjtByte* light_directional; // directional light (nlight x 1) mjtByte* light_castshadow; // does light cast shadows (nlight x 1) + float* light_bulbradius; // light radius for soft shadows (nlight x 1) mjtByte* light_active; // is light on (nlight x 1) mjtNum* light_pos; // position rel. to body frame (nlight x 3) mjtNum* light_dir; // direction rel. to body frame (nlight x 3) - mjtNum* light_radius; // radius of the light (nlight x 1) mjtNum* light_poscom0; // global position rel. to sub-com in qpos0 (nlight x 3) mjtNum* light_pos0; // global position rel. to body in qpos0 (nlight x 3) mjtNum* light_dir0; // global direction in qpos0 (nlight x 3) @@ -1219,6 +1219,8 @@ struct mjModel_ { float* mat_specular; // specular (x white) (nmat x 1) float* mat_shininess; // shininess coef (nmat x 1) float* mat_reflectance; // reflectance (0: disable) (nmat x 1) + float* mat_metallic; // metallic coef (nmat x 1) + float* mat_roughness; // roughness coef (nmat x 1) float* mat_rgba; // rgba (nmat x 4) // predefined geom pairs for collision detection; has precedence over exclude @@ -2022,6 +2024,7 @@ struct mjvLight_ { // OpenGL light mjtByte headlight; // headlight mjtByte directional; // directional light mjtByte castshadow; // does light cast shadows + float bulbradius; // bulb radius for soft shadows }; typedef struct mjvLight_ mjvLight; struct mjvOption_ { // abstract visualization options @@ -2236,6 +2239,7 @@ struct mjvSceneState_ { mjtByte* light_directional; mjtByte* light_castshadow; + float* light_bulbradius; mjtByte* light_active; float* light_attenuation; float* light_cutoff; @@ -2303,6 +2307,8 @@ struct mjvSceneState_ { float* mat_specular; float* mat_shininess; float* mat_reflectance; + float* mat_metallic; + float* mat_roughness; float* mat_rgba; int* eq_type; diff --git a/include/mujoco/mjmodel.h b/include/mujoco/mjmodel.h index 37e2a9f4..79ec6ad9 100644 --- a/include/mujoco/mjmodel.h +++ b/include/mujoco/mjmodel.h @@ -794,10 +794,10 @@ struct mjModel_ { int* light_targetbodyid; // id of targeted body; -1: none (nlight x 1) mjtByte* light_directional; // directional light (nlight x 1) mjtByte* light_castshadow; // does light cast shadows (nlight x 1) + float* light_bulbradius; // light radius for soft shadows (nlight x 1) mjtByte* light_active; // is light on (nlight x 1) mjtNum* light_pos; // position rel. to body frame (nlight x 3) mjtNum* light_dir; // direction rel. to body frame (nlight x 3) - mjtNum* light_radius; // radius of the light (nlight x 1) mjtNum* light_poscom0; // global position rel. to sub-com in qpos0 (nlight x 3) mjtNum* light_pos0; // global position rel. to body in qpos0 (nlight x 3) mjtNum* light_dir0; // global direction in qpos0 (nlight x 3) @@ -934,6 +934,8 @@ struct mjModel_ { float* mat_specular; // specular (x white) (nmat x 1) float* mat_shininess; // shininess coef (nmat x 1) float* mat_reflectance; // reflectance (0: disable) (nmat x 1) + float* mat_metallic; // metallic coef (nmat x 1) + float* mat_roughness; // roughness coef (nmat x 1) float* mat_rgba; // rgba (nmat x 4) // predefined geom pairs for collision detection; has precedence over exclude diff --git a/include/mujoco/mjvisualize.h b/include/mujoco/mjvisualize.h index dc8a4bc6..350f9c1e 100644 --- a/include/mujoco/mjvisualize.h +++ b/include/mujoco/mjvisualize.h @@ -263,6 +263,7 @@ struct mjvLight_ { // OpenGL light mjtByte headlight; // headlight mjtByte directional; // directional light mjtByte castshadow; // does light cast shadows + float bulbradius; // bulb radius for soft shadows }; typedef struct mjvLight_ mjvLight; @@ -493,6 +494,7 @@ struct mjvSceneState_ { mjtByte* light_directional; mjtByte* light_castshadow; + float* light_bulbradius; mjtByte* light_active; float* light_attenuation; float* light_cutoff; @@ -560,6 +562,8 @@ struct mjvSceneState_ { float* mat_specular; float* mat_shininess; float* mat_reflectance; + float* mat_metallic; + float* mat_roughness; float* mat_rgba; int* eq_type; diff --git a/include/mujoco/mjxmacro.h b/include/mujoco/mjxmacro.h index 6ad3093b..daf1d30b 100644 --- a/include/mujoco/mjxmacro.h +++ b/include/mujoco/mjxmacro.h @@ -292,10 +292,10 @@ X ( int, light_targetbodyid, nlight, 1 ) \ XMJV( mjtByte, light_directional, nlight, 1 ) \ XMJV( mjtByte, light_castshadow, nlight, 1 ) \ + XMJV( float, light_bulbradius, nlight, 1 ) \ XMJV( mjtByte, light_active, nlight, 1 ) \ X ( mjtNum, light_pos, nlight, 3 ) \ X ( mjtNum, light_dir, nlight, 3 ) \ - X ( mjtNum, light_radius, nlight, 1 ) \ X ( mjtNum, light_poscom0, nlight, 3 ) \ X ( mjtNum, light_pos0, nlight, 3 ) \ X ( mjtNum, light_dir0, nlight, 3 ) \ @@ -418,6 +418,8 @@ XMJV( float, mat_specular, nmat, 1 ) \ XMJV( float, mat_shininess, nmat, 1 ) \ XMJV( float, mat_reflectance, nmat, 1 ) \ + XMJV( float, mat_metallic, nmat, 1 ) \ + XMJV( float, mat_roughness, nmat, 1 ) \ XMJV( float, mat_rgba, nmat, 4 ) \ X ( int, pair_dim, npair, 1 ) \ X ( int, pair_geom1, npair, 1 ) \ diff --git a/introspect/structs.py b/introspect/structs.py index 112cb730..45199a98 100644 --- a/introspect/structs.py +++ b/introspect/structs.py @@ -2095,6 +2095,13 @@ STRUCTS: Mapping[str, StructDecl] = dict([ ), doc='does light cast shadows (nlight x 1)', ), + StructFieldDecl( + name='light_bulbradius', + type=PointerType( + inner_type=ValueType(name='float'), + ), + doc='light radius for soft shadows (nlight x 1)', + ), StructFieldDecl( name='light_active', type=PointerType( @@ -2116,13 +2123,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([ ), doc='direction rel. to body frame (nlight x 3)', ), - StructFieldDecl( - name='light_radius', - type=PointerType( - inner_type=ValueType(name='mjtNum'), - ), - doc='radius of the light (nlight x 1)', - ), StructFieldDecl( name='light_poscom0', type=PointerType( @@ -2977,6 +2977,20 @@ STRUCTS: Mapping[str, StructDecl] = dict([ ), doc='reflectance (0: disable) (nmat x 1)', ), + StructFieldDecl( + name='mat_metallic', + type=PointerType( + inner_type=ValueType(name='float'), + ), + doc='metallic coef (nmat x 1)', + ), + StructFieldDecl( + name='mat_roughness', + type=PointerType( + inner_type=ValueType(name='float'), + ), + doc='roughness coef (nmat x 1)', + ), StructFieldDecl( name='mat_rgba', type=PointerType( @@ -5624,6 +5638,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([ type=ValueType(name='mjtByte'), doc='does light cast shadows', ), + StructFieldDecl( + name='bulbradius', + type=ValueType(name='float'), + doc='bulb radius for soft shadows', + ), ), )), ('mjvOption', @@ -6719,6 +6738,13 @@ STRUCTS: Mapping[str, StructDecl] = dict([ ), doc='', ), + StructFieldDecl( + name='light_bulbradius', + type=PointerType( + inner_type=ValueType(name='float'), + ), + doc='', + ), StructFieldDecl( name='light_active', type=PointerType( @@ -7146,6 +7172,20 @@ STRUCTS: Mapping[str, StructDecl] = dict([ ), doc='', ), + StructFieldDecl( + name='mat_metallic', + type=PointerType( + inner_type=ValueType(name='float'), + ), + doc='', + ), + StructFieldDecl( + name='mat_roughness', + type=PointerType( + inner_type=ValueType(name='float'), + ), + doc='', + ), StructFieldDecl( name='mat_rgba', type=PointerType( diff --git a/python/mujoco/structs.cc b/python/mujoco/structs.cc index 40457f04..ebe134a8 100644 --- a/python/mujoco/structs.cc +++ b/python/mujoco/structs.cc @@ -2226,6 +2226,7 @@ This is useful for example when the MJB is not available as a file on disk.)")); X(headlight); X(directional); X(castshadow); + X(bulbradius); #undef X #define X(var) DefinePyArray(mjvLight, #var, &MjvLightWrapper::var) diff --git a/src/engine/engine_vis_visualize.c b/src/engine/engine_vis_visualize.c index 74bd9cd5..5de671f1 100644 --- a/src/engine/engine_vis_visualize.c +++ b/src/engine/engine_vis_visualize.c @@ -2091,6 +2091,7 @@ void mjv_makeLights(const mjModel* m, mjData* d, mjvScene* scn) { memset(thislight, 0, sizeof(mjvLight)); thislight->directional = m->light_directional[i]; thislight->castshadow = m->light_castshadow[i]; + thislight->bulbradius = m->light_bulbradius[i]; if (!thislight->directional) { f2f(thislight->attenuation, m->light_attenuation+3*i, 3); thislight->exponent = m->light_exponent[i]; diff --git a/src/user/user_api.h b/src/user/user_api.h index bd2dc044..7361ff86 100644 --- a/src/user/user_api.h +++ b/src/user/user_api.h @@ -347,7 +347,6 @@ typedef struct _mjsLight { // light specification // frame double pos[3]; // position double dir[3]; // direction - double radius; // radius mjtCamLight mode; // tracking mode mjString targetbody; // target body for targeting @@ -355,6 +354,7 @@ typedef struct _mjsLight { // light specification mjtByte active; // is light active mjtByte directional; // is light directional or spot mjtByte castshadow; // does light cast shadows + double bulbradius; // bulb radius, for soft shadows float attenuation[3]; // OpenGL attenuation (quadratic model) float cutoff; // OpenGL cutoff float exponent; // OpenGL exponent @@ -515,6 +515,8 @@ typedef struct _mjsMaterial { // material specification float specular; // specular float shininess; // shininess float reflectance; // reflectance + float metallic; // metallic + float roughness; // roughness float rgba[4]; // rgba mjString info; // message appended to compiler errors } mjsMaterial; diff --git a/src/user/user_init.cc b/src/user/user_init.cc index b9553933..4fc27110 100644 --- a/src/user/user_init.cc +++ b/src/user/user_init.cc @@ -218,6 +218,7 @@ void mjs_defaultLight(mjsLight& light) { // intrinsics light.castshadow = 1; + light.bulbradius = 0.02; light.active = 1; light.dir[2] = -1; light.attenuation[0] = 1; @@ -305,6 +306,8 @@ void mjs_defaultMaterial(mjsMaterial& material) { material.specular = 0.5; material.shininess = 0.5; material.reflectance = 0; + material.metallic = 1.0; + material.roughness = 1.0; material.rgba[0] = material.rgba[1] = material.rgba[2] = material.rgba[3] = 1; } diff --git a/src/user/user_model.cc b/src/user/user_model.cc index 45357e62..5abf4163 100644 --- a/src/user/user_model.cc +++ b/src/user/user_model.cc @@ -2070,7 +2070,7 @@ void mjCModel::CopyTree(mjModel* m) { m->light_active[lid] = (mjtByte)pl->active; copyvec(m->light_pos+3*lid, pl->pos, 3); copyvec(m->light_dir+3*lid, pl->dir, 3); - m->light_radius[lid] = pl->radius; + m->light_bulbradius[lid] = pl->bulbradius; copyvec(m->light_attenuation+3*lid, pl->attenuation, 3); m->light_cutoff[lid] = pl->cutoff; m->light_exponent[lid] = pl->exponent; @@ -2487,6 +2487,8 @@ void mjCModel::CopyObjects(mjModel* m) { m->mat_specular[i] = pmat->specular; m->mat_shininess[i] = pmat->shininess; m->mat_reflectance[i] = pmat->reflectance; + m->mat_metallic[i] = pmat->metallic; + m->mat_roughness[i] = pmat->roughness; copyvec(m->mat_rgba+4*i, pmat->rgba, 4); } diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc index 7427f019..334adebe 100644 --- a/src/xml/xml_native_reader.cc +++ b/src/xml/xml_native_reader.cc @@ -136,8 +136,8 @@ const char* MJCF[nMJCF][mjXATTRNUM] = { {"default", "R", "1", "class"}, {"<"}, {"mesh", "?", "1", "scale"}, - {"material", "?", "8", "texture", "emission", "specular", "shininess", - "reflectance", "rgba", "texrepeat", "texuniform"}, + {"material", "?", "10", "texture", "emission", "specular", "shininess", + "reflectance", "metallic", "roughness", "rgba", "texrepeat", "texuniform"}, {"joint", "?", "22", "type", "group", "pos", "axis", "springdamper", "limited", "actuatorfrclimited", "solreflimit", "solimplimit", "solreffriction", "solimpfriction", "stiffness", "range", "actuatorfrcrange", @@ -153,7 +153,7 @@ const char* MJCF[nMJCF][mjXATTRNUM] = { {"camera", "?", "16", "fovy", "ipd", "resolution", "pos", "quat", "axisangle", "xyaxes", "zaxis", "euler", "mode", "focal", "focalpixel", "principal", "principalpixel", "sensorsize", "user"}, - {"light", "?", "13", "pos", "dir", "radius", "directional", "castshadow", "active", + {"light", "?", "13", "pos", "dir", "bulbradius", "directional", "castshadow", "active", "attenuation", "cutoff", "exponent", "ambient", "diffuse", "specular", "mode"}, {"pair", "?", "7", "condim", "friction", "solref", "solreffriction", "solimp", "gap", "margin"}, @@ -232,8 +232,8 @@ const char* MJCF[nMJCF][mjXATTRNUM] = { "fileright", "fileleft", "fileup", "filedown", "filefront", "fileback", "builtin", "rgb1", "rgb2", "mark", "markrgb", "random", "width", "height", "hflip", "vflip"}, - {"material", "*", "10", "name", "class", "texture", "texrepeat", "texuniform", - "emission", "specular", "shininess", "reflectance", "rgba"}, + {"material", "*", "12", "name", "class", "texture", "texrepeat", "texuniform", + "emission", "specular", "shininess", "reflectance", "metallic", "roughness", "rgba"}, {">"}, {"body", "R", "11", "name", "childclass", "pos", "quat", "mocap", @@ -264,7 +264,7 @@ const char* MJCF[nMJCF][mjXATTRNUM] = { "axisangle", "xyaxes", "zaxis", "euler", "mode", "target", "focal", "focalpixel", "principal", "principalpixel", "sensorsize", "user"}, {"light", "*", "16", "name", "class", "directional", "castshadow", "active", - "pos", "dir", "radius", "attenuation", "cutoff", "exponent", "ambient", "diffuse", + "pos", "dir", "bulbradius", "attenuation", "cutoff", "exponent", "ambient", "diffuse", "specular", "mode", "target"}, {"plugin", "*", "2", "plugin", "instance"}, {"<"}, @@ -1530,6 +1530,8 @@ void mjXReader::OneMaterial(XMLElement* elem, mjsMaterial* pmat) { ReadAttr(elem, "specular", 1, &pmat->specular, text); ReadAttr(elem, "shininess", 1, &pmat->shininess, text); ReadAttr(elem, "reflectance", 1, &pmat->reflectance, text); + ReadAttr(elem, "metallic", 1, &pmat->metallic, text); + ReadAttr(elem, "roughness", 1, &pmat->roughness, text); ReadAttr(elem, "rgba", 4, pmat->rgba, text); // write error info @@ -1783,7 +1785,7 @@ void mjXReader::OneLight(XMLElement* elem, mjsLight* plight) { } ReadAttr(elem, "pos", 3, plight->pos, text); ReadAttr(elem, "dir", 3, plight->dir, text); - ReadAttr(elem, "radius", 1, &plight->radius, text); + ReadAttr(elem, "bulbradius", 1, &plight->bulbradius, text); ReadAttr(elem, "attenuation", 3, plight->attenuation, text); ReadAttr(elem, "cutoff", 1, &plight->cutoff, text); ReadAttr(elem, "exponent", 1, &plight->exponent, text); diff --git a/src/xml/xml_native_writer.cc b/src/xml/xml_native_writer.cc index cfbdfee4..2e729966 100644 --- a/src/xml/xml_native_writer.cc +++ b/src/xml/xml_native_writer.cc @@ -268,6 +268,8 @@ void mjXWriter::OneMaterial(XMLElement* elem, mjCMaterial* pmat, mjCDef* def) { WriteAttr(elem, "specular", 1, &pmat->specular, &def->material.specular); WriteAttr(elem, "shininess", 1, &pmat->shininess, &def->material.shininess); WriteAttr(elem, "reflectance", 1, &pmat->reflectance, &def->material.reflectance); + WriteAttr(elem, "metallic", 1, &pmat->metallic, &def->material.metallic); + WriteAttr(elem, "roughness", 1, &pmat->roughness, &def->material.roughness); WriteAttr(elem, "rgba", 4, pmat->rgba, def->material.rgba); } @@ -508,7 +510,7 @@ void mjXWriter::OneLight(XMLElement* elem, mjCLight* plight, mjCDef* def) { } // defaults and regular - WriteAttr(elem, "radius", 1, &plight->radius, &def->light.radius); + WriteAttr(elem, "bulbradius", 1, &plight->bulbradius, &def->light.bulbradius); WriteAttrKey(elem, "directional", bool_map, 2, plight->directional, def->light.directional); WriteAttrKey(elem, "castshadow", bool_map, 2, plight->castshadow, def->light.castshadow); WriteAttrKey(elem, "active", bool_map, 2, plight->active, def->light.active); diff --git a/test/xml/xml_native_reader_test.cc b/test/xml/xml_native_reader_test.cc index 61253f35..5b800405 100644 --- a/test/xml/xml_native_reader_test.cc +++ b/test/xml/xml_native_reader_test.cc @@ -1873,22 +1873,22 @@ TEST_F(XMLReaderTest, LightRadius) { - + - + )"; std::array error; mjModel* model = LoadModelFromString(xml, error.data(), error.size()); ASSERT_THAT(model, NotNull()) << error.data(); - EXPECT_EQ(model->light_radius[0], 0); - EXPECT_EQ(model->light_radius[1], 1); - EXPECT_EQ(model->light_radius[2], 2); + EXPECT_FLOAT_EQ(model->light_bulbradius[0], 0.02); + EXPECT_FLOAT_EQ(model->light_bulbradius[1], 1); + EXPECT_FLOAT_EQ(model->light_bulbradius[2], 2); mj_deleteModel(model); } diff --git a/test/xml/xml_native_writer_test.cc b/test/xml/xml_native_writer_test.cc index e86e3254..92131025 100644 --- a/test/xml/xml_native_writer_test.cc +++ b/test/xml/xml_native_writer_test.cc @@ -943,13 +943,13 @@ TEST_F(XMLWriterTest, WritesLight) { - + - + )"; @@ -959,9 +959,39 @@ TEST_F(XMLWriterTest, WritesLight) { // save and read, compare data mjModel* mtemp = LoadModelFromString(SaveAndReadXml(model)); EXPECT_EQ(mtemp->nlight, 3); - EXPECT_EQ(mtemp->light_radius[0], 0); - EXPECT_EQ(mtemp->light_radius[1], 1); - EXPECT_EQ(mtemp->light_radius[2], 2); + EXPECT_FLOAT_EQ(mtemp->light_bulbradius[0], 0.02); + EXPECT_FLOAT_EQ(mtemp->light_bulbradius[1], 1); + EXPECT_FLOAT_EQ(mtemp->light_bulbradius[2], 2); + + mj_deleteModel(mtemp); + mj_deleteModel(model); +} + +TEST_F(XMLWriterTest, WritesMaterial) { + static constexpr char xml[] = R"( + + + + + + + + + + + + )"; + std::array error; + mjModel* model = LoadModelFromString(xml, error.data(), error.size()); + ASSERT_THAT(model, NotNull()) << error.data(); + + // save and read, compare data + mjModel* mtemp = LoadModelFromString(SaveAndReadXml(model)); + EXPECT_EQ(mtemp->nmat, 2); + EXPECT_EQ(mtemp->mat_metallic[0], 2); + EXPECT_EQ(mtemp->mat_metallic[1], 4); + EXPECT_EQ(mtemp->mat_roughness[0], 3); + EXPECT_EQ(mtemp->mat_roughness[1], 5); mj_deleteModel(mtemp); mj_deleteModel(model); diff --git a/unity/Runtime/Bindings/MjBindings.cs b/unity/Runtime/Bindings/MjBindings.cs index 4b8d6f84..28a0d0d8 100644 --- a/unity/Runtime/Bindings/MjBindings.cs +++ b/unity/Runtime/Bindings/MjBindings.cs @@ -5294,10 +5294,10 @@ public unsafe struct mjModel_ { public int* light_targetbodyid; public byte* light_directional; public byte* light_castshadow; + public float* light_bulbradius; public byte* light_active; public double* light_pos; public double* light_dir; - public double* light_radius; public double* light_poscom0; public double* light_pos0; public double* light_dir0; @@ -5420,6 +5420,8 @@ public unsafe struct mjModel_ { public float* mat_specular; public float* mat_shininess; public float* mat_reflectance; + public float* mat_metallic; + public float* mat_roughness; public float* mat_rgba; public int* pair_dim; public int* pair_geom1; @@ -5872,6 +5874,7 @@ public unsafe struct mjvLight_ { public byte headlight; public byte directional; public byte castshadow; + public float bulbradius; } [StructLayout(LayoutKind.Sequential)] @@ -6149,6 +6152,7 @@ public unsafe struct model { public float* cam_sensorsize; public byte* light_directional; public byte* light_castshadow; + public float* light_bulbradius; public byte* light_active; public float* light_attenuation; public float* light_cutoff; @@ -6210,6 +6214,8 @@ public unsafe struct model { public float* mat_specular; public float* mat_shininess; public float* mat_reflectance; + public float* mat_metallic; + public float* mat_roughness; public float* mat_rgba; public int* eq_type; public int* eq_obj1id;