From 74cc904edc0537ef35c890a1e2622708f340a641 Mon Sep 17 00:00:00 2001 From: Google DeepMind Date: Thu, 22 May 2025 08:50:23 -0700 Subject: [PATCH] Convert light `directional` boolean into a `type` enum. PiperOrigin-RevId: 761983728 Change-Id: Id5bf93c103e5358d9c5cd9f1176532a978e0b3a8 --- doc/APIreference/APItypes.rst | 11 +++++++++++ doc/XMLreference.rst | 11 ++++++++++- doc/XMLschema.rst | 16 ++++++++-------- doc/changelog.rst | 3 +++ doc/includes/references.h | 12 +++++++++--- include/mujoco/mjmodel.h | 10 +++++++++- include/mujoco/mjspec.h | 2 +- include/mujoco/mjvisualize.h | 2 +- include/mujoco/mjxmacro.h | 2 +- mjx/mujoco/mjx/_src/types.py | 2 +- python/mujoco/indexer_xmacro.h | 2 +- python/mujoco/introspect/enums.py | 11 +++++++++++ python/mujoco/introspect/structs.py | 22 +++++++++++----------- python/mujoco/structs.cc | 2 +- src/engine/engine_vis_visualize.c | 6 +++--- src/render/render_gl3.c | 20 ++++++++++++++------ src/user/user_model.cc | 2 +- src/xml/xml_base.h | 4 ++-- src/xml/xml_native_reader.cc | 27 +++++++++++++++++++++++---- src/xml/xml_native_writer.cc | 2 +- unity/Runtime/Bindings/MjBindings.cs | 10 ++++++++-- 21 files changed, 130 insertions(+), 49 deletions(-) diff --git a/doc/APIreference/APItypes.rst b/doc/APIreference/APItypes.rst index 4ee6367d..f2ecf868 100644 --- a/doc/APIreference/APItypes.rst +++ b/doc/APIreference/APItypes.rst @@ -165,6 +165,17 @@ values are used in ``m->cam_mode`` and ``m->light_mode``. .. mujoco-include:: mjtCamLight +.. _mjtLightType: + +mjtLightType +~~~~~~~~~~~~ + +The type of a light source describing how its position, orientation and other properties will interact with the +objects in the scene. These values are used in ``m->light_type``. + +.. mujoco-include:: mjtLightType + + .. _mjtTexture: mjtTexture diff --git a/doc/XMLreference.rst b/doc/XMLreference.rst index 104a92ef..727950af 100644 --- a/doc/XMLreference.rst +++ b/doc/XMLreference.rst @@ -2909,10 +2909,17 @@ Attributes may be applied or ignored depending on the lighting model being used. This is identical to the target attribute of :ref:`camera ` above. It specifies which body should be targeted in "targetbody" and "targetbodycom" modes. +.. _body-light-type: + +:at:`type`: :at-val:`[spot, directional, point, image], "spot"` + Determines the type of light. Note that some light types may not be supported by some renderers (e.g. only spot and + directional lights are supported by the default native renderer). + .. _body-light-directional: :at:`directional`: :at-val:`[false, true], "false"` - The light is directional if this attribute is "true", otherwise it is a spotlight. + This is a deprecated legacy attribute. Please use :ref:`light ` type instead. If set to "true", and no + type is specified, this will change the light type to be directional. .. _body-light-castshadow: @@ -8288,6 +8295,8 @@ if omitted. .. _default-light-dir: +.. _default-light-type: + .. _default-light-directional: .. _default-light-castshadow: diff --git a/doc/XMLschema.rst b/doc/XMLschema.rst index bd71743b..a95e5211 100644 --- a/doc/XMLschema.rst +++ b/doc/XMLschema.rst @@ -313,15 +313,15 @@ | :ref:`light | \* | :class: mjcf-attributes | | ` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`name` | :ref:`class` | :ref:`directional` | :ref:`castshadow` | | +| | | | :ref:`name` | :ref:`class` | :ref:`directional` | :ref:`type` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`active` | :ref:`pos` | :ref:`dir` | :ref:`bulbradius` | | +| | | | :ref:`castshadow` | :ref:`active` | :ref:`pos` | :ref:`dir` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`intensity` | :ref:`range` | :ref:`attenuation` | :ref:`cutoff` | | +| | | | :ref:`bulbradius` | :ref:`intensity` | :ref:`range` | :ref:`attenuation` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`exponent` | :ref:`ambient` | :ref:`diffuse` | :ref:`specular` | | +| | | | :ref:`cutoff` | :ref:`exponent` | :ref:`ambient` | :ref:`diffuse` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`mode` | :ref:`target` | | | | +| | | | :ref:`specular` | :ref:`mode` | :ref:`target` | | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_| body |br| |_| |L| | | .. table:: | @@ -1465,11 +1465,11 @@ | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | | | | | :ref:`pos` | :ref:`dir` | :ref:`bulbradius` | :ref:`intensity` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`range` | :ref:`directional` | :ref:`castshadow` | :ref:`active` | | +| | | | :ref:`range` | :ref:`directional` | :ref:`type` | :ref:`castshadow` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`attenuation` | :ref:`cutoff` | :ref:`exponent` | :ref:`ambient` | | +| | | | :ref:`active` | :ref:`attenuation` | :ref:`cutoff` | :ref:`exponent` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`diffuse` | :ref:`specular` | :ref:`mode` | | | +| | | | :ref:`ambient` | :ref:`diffuse` | :ref:`specular` | :ref:`mode` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_| default |br| |_| |L| | | .. table:: | diff --git a/doc/changelog.rst b/doc/changelog.rst index 3fc979bd..3ddc1b51 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -11,6 +11,9 @@ General solver and clears the way for the addition of the Newton and PGS solvers (currently only CG is supported). - Removed the :at:`shell` plugin. This is now supported by :ref:`flexcomp` and is active depending on the :ref:`elastic2d` attribute (off by default). +- Replaced the :ref:`directional` (boolean) field for lights with a + :ref:`type` field (of type :ref:`mjtLightType`) to allow for additional lighting + types. Simulate ^^^^^^^^ diff --git a/doc/includes/references.h b/doc/includes/references.h index b9adc621..f61acd8e 100644 --- a/doc/includes/references.h +++ b/doc/includes/references.h @@ -526,6 +526,12 @@ typedef enum mjtCamLight_ { // tracking mode for camera and light mjCAMLIGHT_TARGETBODY, // pos fixed in body, rot tracks target body mjCAMLIGHT_TARGETBODYCOM // pos fixed in body, rot tracks target subtree com } mjtCamLight; +typedef enum mjtLightType_ { // type of light + mjLIGHT_SPOT = 0, // spot + mjLIGHT_DIRECTIONAL, // directional + mjLIGHT_POINT, // point + mjLIGHT_IMAGE, // image-based +} mjtLightType; typedef enum mjtTexture_ { // type of texture mjTEXTURE_2D = 0, // 2d texture, suitable for planes and hfields mjTEXTURE_CUBE, // cube texture, suitable for all other geom types @@ -1179,7 +1185,7 @@ struct mjModel_ { int* light_mode; // light tracking mode (mjtCamLight) (nlight x 1) int* light_bodyid; // id of light's body (nlight x 1) int* light_targetbodyid; // id of targeted body; -1: none (nlight x 1) - mjtByte* light_directional; // directional light (nlight x 1) + int* light_type; // spot, directional, etc. (mjtLightType) (nlight x 1) mjtByte* light_castshadow; // does light cast shadows (nlight x 1) float* light_bulbradius; // light radius for soft shadows (nlight x 1) float* light_intensity; // intensity, in candela (nlight x 1) @@ -2036,7 +2042,7 @@ typedef struct mjsLight_ { // light specification // intrinsics mjtByte active; // is light active - mjtByte directional; // is light directional or spot + mjtLightType type; // type of light mjtByte castshadow; // does light cast shadows float bulbradius; // bulb radius, for soft shadows float intensity; // intensity, in candelas @@ -2840,6 +2846,7 @@ typedef struct mjvGeom_ mjvGeom; struct mjvLight_ { // OpenGL light float pos[3]; // position rel. to body frame float dir[3]; // direction rel. to body frame + int type; // type (mjtLightType) float attenuation[3]; // OpenGL attenuation (quadratic model) float cutoff; // OpenGL cutoff float exponent; // OpenGL exponent @@ -2847,7 +2854,6 @@ struct mjvLight_ { // OpenGL light float diffuse[3]; // diffuse rgb (alpha=1) float specular[3]; // specular rgb (alpha=1) mjtByte headlight; // headlight - mjtByte directional; // directional light mjtByte castshadow; // does light cast shadows float bulbradius; // bulb radius for soft shadows float intensity; // intensity, in candelas diff --git a/include/mujoco/mjmodel.h b/include/mujoco/mjmodel.h index 05b3d832..8c50af50 100644 --- a/include/mujoco/mjmodel.h +++ b/include/mujoco/mjmodel.h @@ -129,6 +129,14 @@ typedef enum mjtCamLight_ { // tracking mode for camera and light } mjtCamLight; +typedef enum mjtLightType_ { // type of light + mjLIGHT_SPOT = 0, // spot + mjLIGHT_DIRECTIONAL, // directional + mjLIGHT_POINT, // point + mjLIGHT_IMAGE, // image-based +} mjtLightType; + + typedef enum mjtTexture_ { // type of texture mjTEXTURE_2D = 0, // 2d texture, suitable for planes and hfields mjTEXTURE_CUBE, // cube texture, suitable for all other geom types @@ -849,7 +857,7 @@ struct mjModel_ { int* light_mode; // light tracking mode (mjtCamLight) (nlight x 1) int* light_bodyid; // id of light's body (nlight x 1) int* light_targetbodyid; // id of targeted body; -1: none (nlight x 1) - mjtByte* light_directional; // directional light (nlight x 1) + int* light_type; // spot, directional, etc. (mjtLightType) (nlight x 1) mjtByte* light_castshadow; // does light cast shadows (nlight x 1) float* light_bulbradius; // light radius for soft shadows (nlight x 1) float* light_intensity; // intensity, in candela (nlight x 1) diff --git a/include/mujoco/mjspec.h b/include/mujoco/mjspec.h index 20568f2f..c422eedd 100644 --- a/include/mujoco/mjspec.h +++ b/include/mujoco/mjspec.h @@ -394,7 +394,7 @@ typedef struct mjsLight_ { // light specification // intrinsics mjtByte active; // is light active - mjtByte directional; // is light directional or spot + mjtLightType type; // type of light mjtByte castshadow; // does light cast shadows float bulbradius; // bulb radius, for soft shadows float intensity; // intensity, in candelas diff --git a/include/mujoco/mjvisualize.h b/include/mujoco/mjvisualize.h index 560b8f35..a61fe649 100644 --- a/include/mujoco/mjvisualize.h +++ b/include/mujoco/mjvisualize.h @@ -261,6 +261,7 @@ typedef struct mjvGeom_ mjvGeom; struct mjvLight_ { // OpenGL light float pos[3]; // position rel. to body frame float dir[3]; // direction rel. to body frame + int type; // type (mjtLightType) float attenuation[3]; // OpenGL attenuation (quadratic model) float cutoff; // OpenGL cutoff float exponent; // OpenGL exponent @@ -268,7 +269,6 @@ struct mjvLight_ { // OpenGL light float diffuse[3]; // diffuse rgb (alpha=1) float specular[3]; // specular rgb (alpha=1) mjtByte headlight; // headlight - mjtByte directional; // directional light mjtByte castshadow; // does light cast shadows float bulbradius; // bulb radius for soft shadows float intensity; // intensity, in candelas diff --git a/include/mujoco/mjxmacro.h b/include/mujoco/mjxmacro.h index 57673285..3a8a6fcf 100644 --- a/include/mujoco/mjxmacro.h +++ b/include/mujoco/mjxmacro.h @@ -299,7 +299,7 @@ X ( int, light_mode, nlight, 1 ) \ X ( int, light_bodyid, nlight, 1 ) \ X ( int, light_targetbodyid, nlight, 1 ) \ - X ( mjtByte, light_directional, nlight, 1 ) \ + X ( int, light_type, nlight, 1 ) \ X ( mjtByte, light_castshadow, nlight, 1 ) \ X ( float, light_bulbradius, nlight, 1 ) \ X ( float, light_intensity, nlight, 1 ) \ diff --git a/mjx/mujoco/mjx/_src/types.py b/mjx/mujoco/mjx/_src/types.py index 2950fb4a..3beb6b54 100644 --- a/mjx/mujoco/mjx/_src/types.py +++ b/mjx/mujoco/mjx/_src/types.py @@ -725,7 +725,7 @@ class Model(PyTreeNode): cam_sensorsize: np.ndarray cam_intrinsic: np.ndarray light_mode: np.ndarray - light_directional: jax.Array + light_type: jax.Array light_castshadow: jax.Array light_pos: jax.Array light_dir: jax.Array diff --git a/python/mujoco/indexer_xmacro.h b/python/mujoco/indexer_xmacro.h index f39d2da2..9f26000d 100644 --- a/python/mujoco/indexer_xmacro.h +++ b/python/mujoco/indexer_xmacro.h @@ -152,7 +152,7 @@ X( int, light_, mode, nlight, 1 ) \ X( int, light_, bodyid, nlight, 1 ) \ X( int, light_, targetbodyid, nlight, 1 ) \ - X( mjtByte, light_, directional, nlight, 1 ) \ + X( int, light_, type, nlight, 1 ) \ X( mjtByte, light_, castshadow, nlight, 1 ) \ X( mjtByte, light_, active, nlight, 1 ) \ X( mjtNum, light_, pos, nlight, 3 ) \ diff --git a/python/mujoco/introspect/enums.py b/python/mujoco/introspect/enums.py index dc828a57..7cbe18bc 100644 --- a/python/mujoco/introspect/enums.py +++ b/python/mujoco/introspect/enums.py @@ -111,6 +111,17 @@ ENUMS: Mapping[str, EnumDecl] = dict([ ('mjCAMLIGHT_TARGETBODYCOM', 4), ]), )), + ('mjtLightType', + EnumDecl( + name='mjtLightType', + declname='enum mjtLightType_', + values=dict([ + ('mjLIGHT_SPOT', 0), + ('mjLIGHT_DIRECTIONAL', 1), + ('mjLIGHT_POINT', 2), + ('mjLIGHT_IMAGE', 3), + ]), + )), ('mjtTexture', EnumDecl( name='mjtTexture', diff --git a/python/mujoco/introspect/structs.py b/python/mujoco/introspect/structs.py index 5685ac1c..8ab28046 100644 --- a/python/mujoco/introspect/structs.py +++ b/python/mujoco/introspect/structs.py @@ -2220,11 +2220,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([ array_extent=('nlight',), ), StructFieldDecl( - name='light_directional', + name='light_type', type=PointerType( - inner_type=ValueType(name='mjtByte'), + inner_type=ValueType(name='int'), ), - doc='directional light', + doc='spot, directional, etc. (mjtLightType)', array_extent=('nlight',), ), StructFieldDecl( @@ -6697,6 +6697,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([ ), doc='direction rel. to body frame', ), + StructFieldDecl( + name='type', + type=ValueType(name='int'), + doc='type (mjtLightType)', + ), StructFieldDecl( name='attenuation', type=ArrayType( @@ -6744,11 +6749,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([ type=ValueType(name='mjtByte'), doc='headlight', ), - StructFieldDecl( - name='directional', - type=ValueType(name='mjtByte'), - doc='directional light', - ), StructFieldDecl( name='castshadow', type=ValueType(name='mjtByte'), @@ -8992,9 +8992,9 @@ STRUCTS: Mapping[str, StructDecl] = dict([ doc='is light active', ), StructFieldDecl( - name='directional', - type=ValueType(name='mjtByte'), - doc='is light directional or spot', + name='type', + type=ValueType(name='mjtLightType'), + doc='type of light', ), StructFieldDecl( name='castshadow', diff --git a/python/mujoco/structs.cc b/python/mujoco/structs.cc index 735e0a0b..dc98e3dd 100644 --- a/python/mujoco/structs.cc +++ b/python/mujoco/structs.cc @@ -1073,7 +1073,7 @@ This is useful for example when the MJB is not available as a file on disk.)")); X(cutoff); X(exponent); X(headlight); - X(directional); + X(type); X(castshadow); X(bulbradius); X(intensity); diff --git a/src/engine/engine_vis_visualize.c b/src/engine/engine_vis_visualize.c index 0425b85c..6f9364f1 100644 --- a/src/engine/engine_vis_visualize.c +++ b/src/engine/engine_vis_visualize.c @@ -2143,7 +2143,7 @@ void mjv_makeLights(const mjModel* m, const mjData* d, mjvScene* scn) { // set default properties memset(thislight, 0, sizeof(mjvLight)); thislight->headlight = 1; - thislight->directional = 1; + thislight->type = mjLIGHT_DIRECTIONAL; thislight->castshadow = 0; // compute head position and gaze direction in model space @@ -2169,12 +2169,12 @@ void mjv_makeLights(const mjModel* m, const mjData* d, mjvScene* scn) { // copy properties memset(thislight, 0, sizeof(mjvLight)); - thislight->directional = m->light_directional[i]; + thislight->type = m->light_type[i]; thislight->castshadow = m->light_castshadow[i]; thislight->bulbradius = m->light_bulbradius[i]; thislight->intensity = m->light_intensity[i]; thislight->range = m->light_range[i]; - if (!thislight->directional) { + if (thislight->type == mjLIGHT_SPOT) { f2f(thislight->attenuation, m->light_attenuation+3*i, 3); thislight->exponent = m->light_exponent[i]; thislight->cutoff = m->light_cutoff[i]; diff --git a/src/render/render_gl3.c b/src/render/render_gl3.c index 9d168585..1660c67b 100644 --- a/src/render/render_gl3.c +++ b/src/render/render_gl3.c @@ -672,7 +672,7 @@ static void initLights(mjvScene* scn) { glLightfv(GL_LIGHT0+i, GL_SPECULAR, scn->lights[i].specular); // parameters for directional light - if (scn->lights[i].directional) { + if (scn->lights[i].type == mjLIGHT_DIRECTIONAL) { glLightf(GL_LIGHT0+i, GL_SPOT_EXPONENT, 0); glLightf(GL_LIGHT0+i, GL_SPOT_CUTOFF, 180); glLightf(GL_LIGHT0+i, GL_CONSTANT_ATTENUATION, 1); @@ -681,13 +681,17 @@ static void initLights(mjvScene* scn) { } // parameters for spot light - else { + else if (scn->lights[i].type == mjLIGHT_SPOT) { glLightf(GL_LIGHT0+i, GL_SPOT_EXPONENT, scn->lights[i].exponent); glLightf(GL_LIGHT0+i, GL_SPOT_CUTOFF, scn->lights[i].cutoff); glLightf(GL_LIGHT0+i, GL_CONSTANT_ATTENUATION, scn->lights[i].attenuation[0]); glLightf(GL_LIGHT0+i, GL_LINEAR_ATTENUATION, scn->lights[i].attenuation[1]); glLightf(GL_LIGHT0+i, GL_QUADRATIC_ATTENUATION, scn->lights[i].attenuation[2]); } + + else { + mju_error("Unsupported light type: %d", scn->lights[i].type); + } } // disable all lights (enable selectively in render) @@ -790,14 +794,16 @@ static void adjustLight(const mjvLight* thislight, int n) { float temp[4]; // set position and direction according to type - if (thislight->directional) { + if (thislight->type == mjLIGHT_DIRECTIONAL) { mjr_setf4(temp, -thislight->dir[0], -thislight->dir[1], -thislight->dir[2], 0); glLightfv(GL_LIGHT0+n, GL_POSITION, temp); - } else { + } else if (thislight->type == mjLIGHT_SPOT) { mjr_setf4(temp, thislight->dir[0], thislight->dir[1], thislight->dir[2], 0); glLightfv(GL_LIGHT0+n, GL_SPOT_DIRECTION, temp); mjr_setf4(temp, thislight->pos[0], thislight->pos[1], thislight->pos[2], 1); glLightfv(GL_LIGHT0+n, GL_POSITION, temp); + } else { + mju_error("Unsupported light type: %d", thislight->type); } } @@ -1183,13 +1189,15 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) { // reverse Z rendering mapping without shift [znear, zfar] -> [1, -1] (ndc) glScalef(1.0f, 1.0f, -1.0f); } - if (thislight->directional) { + if (thislight->type == mjLIGHT_DIRECTIONAL) { glOrtho(-con->shadowClip, con->shadowClip, -con->shadowClip, con->shadowClip, cam.frustum_near, cam.frustum_far); - } else { + } else if (thislight->type == mjLIGHT_SPOT) { mjr_perspective(mju_min(2*thislight->cutoff*con->shadowScale, 160), 1, cam.frustum_near, cam.frustum_far); + } else { + mju_error("Unsupported light type: %d", thislight->type); } glGetFloatv(GL_PROJECTION_MATRIX, lightProject); diff --git a/src/user/user_model.cc b/src/user/user_model.cc index bd3eb0ac..d7f862eb 100644 --- a/src/user/user_model.cc +++ b/src/user/user_model.cc @@ -2669,7 +2669,7 @@ void mjCModel::CopyTree(mjModel* m) { m->light_bodyid[lid] = pl->body->id; m->light_mode[lid] = (int)pl->mode; m->light_targetbodyid[lid] = pl->targetbodyid; - m->light_directional[lid] = (mjtByte)pl->directional; + m->light_type[lid] = pl->type; m->light_castshadow[lid] = (mjtByte)pl->castshadow; m->light_active[lid] = (mjtByte)pl->active; mjuu_copyvec(m->light_pos+3*lid, pl->pos, 3); diff --git a/src/xml/xml_base.h b/src/xml/xml_base.h index 4134f46f..f2aca5c8 100644 --- a/src/xml/xml_base.h +++ b/src/xml/xml_base.h @@ -27,7 +27,7 @@ // keyword maps (defined in implementation files) extern const int joint_sz; extern const int camlight_sz; -extern const int light_sz; +extern const int lighttype_sz; extern const int integrator_sz; extern const int collision_sz; extern const int cone_sz; @@ -51,7 +51,7 @@ extern const mjMap TFAuto_map[]; extern const mjMap joint_map[]; extern const mjMap geom_map[]; extern const mjMap camlight_map[]; -extern const mjMap light_map[]; +extern const mjMap lighttype_map[]; extern const mjMap integrator_map[]; extern const mjMap collision_map[]; extern const mjMap impedance_map[]; diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc index 52d3181a..02908ed2 100644 --- a/src/xml/xml_native_reader.cc +++ b/src/xml/xml_native_reader.cc @@ -167,8 +167,8 @@ const char* MJCF[nMJCF][mjXATTRNUM] = { {"camera", "?", "17", "orthographic", "fovy", "ipd", "resolution", "pos", "quat", "axisangle", "xyaxes", "zaxis", "euler", "mode", "focal", "focalpixel", "principal", "principalpixel", "sensorsize", "user"}, - {"light", "?", "15", "pos", "dir", "bulbradius", "intensity", "range", - "directional", "castshadow", "active", "attenuation", "cutoff", "exponent", + {"light", "?", "16", "pos", "dir", "bulbradius", "intensity", "range", + "directional", "type", "castshadow", "active", "attenuation", "cutoff", "exponent", "ambient", "diffuse", "specular", "mode"}, {"pair", "?", "7", "condim", "friction", "solref", "solreffriction", "solimp", "gap", "margin"}, @@ -281,7 +281,7 @@ const char* MJCF[nMJCF][mjXATTRNUM] = { {"camera", "*", "20", "name", "class", "orthographic", "fovy", "ipd", "resolution", "pos", "quat", "axisangle", "xyaxes", "zaxis", "euler", "mode", "target", "focal", "focalpixel", "principal", "principalpixel", "sensorsize", "user"}, - {"light", "*", "18", "name", "class", "directional", "castshadow", "active", + {"light", "*", "19", "name", "class", "directional", "type", "castshadow", "active", "pos", "dir", "bulbradius", "intensity", "range", "attenuation", "cutoff", "exponent", "ambient", "diffuse", "specular", "mode", "target"}, {"plugin", "*", "2", "plugin", "instance"}, @@ -580,6 +580,17 @@ const mjMap camlight_map[camlight_sz] = { {"targetbodycom", mjCAMLIGHT_TARGETBODYCOM} }; + +// light type +const int lighttype_sz = 4; +const mjMap lighttype_map[lighttype_sz] = { + {"spot", mjLIGHT_SPOT}, + {"directional", mjLIGHT_DIRECTIONAL}, + {"point", mjLIGHT_POINT}, + {"image", mjLIGHT_IMAGE} +}; + + // texmat role type const int texrole_sz = mjNTEXROLE - 1; const mjMap texrole_map[texrole_sz] = { @@ -1852,6 +1863,7 @@ void mjXReader::OneCamera(XMLElement* elem, mjsCamera* camera) { // light element parser void mjXReader::OneLight(XMLElement* elem, mjsLight* light) { int n; + bool has_directional = false; string text, name, targetbody; // read attributes @@ -1865,7 +1877,14 @@ void mjXReader::OneLight(XMLElement* elem, mjsLight* light) { light->mode = (mjtCamLight)n; } if (MapValue(elem, "directional", &n, bool_map, 2)) { - light->directional = (n == 1); + light->type = (n == 1) ? mjLIGHT_DIRECTIONAL : mjLIGHT_SPOT; + has_directional = true; + } + if (MapValue(elem, "type", &n, lighttype_map, lighttype_sz)) { + if (has_directional) { + throw mjXError(elem, "type and directional cannot both be defined"); + } + light->type = (mjtLightType)n; } if (MapValue(elem, "castshadow", &n, bool_map, 2)) { light->castshadow = (n == 1); diff --git a/src/xml/xml_native_writer.cc b/src/xml/xml_native_writer.cc index f850c82b..9f9a1b9d 100644 --- a/src/xml/xml_native_writer.cc +++ b/src/xml/xml_native_writer.cc @@ -607,7 +607,7 @@ void mjXWriter::OneLight(XMLElement* elem, const mjCLight* light, mjCDef* def, WriteAttr(elem, "bulbradius", 1, &light->bulbradius, &def->Light().bulbradius); WriteAttr(elem, "intensity", 1, &light->intensity, &def->Light().intensity); WriteAttr(elem, "range", 1, &light->range, &def->Light().range); - WriteAttrKey(elem, "directional", bool_map, 2, light->directional, def->Light().directional); + WriteAttrKey(elem, "type", lighttype_map, lighttype_sz, light->type, def->Light().type); WriteAttrKey(elem, "castshadow", bool_map, 2, light->castshadow, def->Light().castshadow); WriteAttrKey(elem, "active", bool_map, 2, light->active, def->Light().active); WriteAttr(elem, "attenuation", 3, light->attenuation, def->Light().attenuation); diff --git a/unity/Runtime/Bindings/MjBindings.cs b/unity/Runtime/Bindings/MjBindings.cs index 1172e758..ae6a9ac5 100644 --- a/unity/Runtime/Bindings/MjBindings.cs +++ b/unity/Runtime/Bindings/MjBindings.cs @@ -207,6 +207,12 @@ public enum mjtCamLight : int{ mjCAMLIGHT_TARGETBODY = 3, mjCAMLIGHT_TARGETBODYCOM = 4, } +public enum mjtLightType : int{ + mjLIGHT_SPOT = 0, + mjLIGHT_DIRECTIONAL = 1, + mjLIGHT_POINT = 2, + mjLIGHT_IMAGE = 3, +} public enum mjtTexture : int{ mjTEXTURE_2D = 0, mjTEXTURE_CUBE = 1, @@ -5434,7 +5440,7 @@ public unsafe struct mjModel_ { public int* light_mode; public int* light_bodyid; public int* light_targetbodyid; - public byte* light_directional; + public int* light_type; public byte* light_castshadow; public float* light_bulbradius; public float* light_intensity; @@ -6075,6 +6081,7 @@ public unsafe struct mjvGeom_ { public unsafe struct mjvLight_ { public fixed float pos[3]; public fixed float dir[3]; + public int type; public fixed float attenuation[3]; public float cutoff; public float exponent; @@ -6082,7 +6089,6 @@ public unsafe struct mjvLight_ { public fixed float diffuse[3]; public fixed float specular[3]; public byte headlight; - public byte directional; public byte castshadow; public float bulbradius; public float intensity;