From f9a00bd5b59908e148bdd1dc70a65272b985dfb1 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Tue, 4 Aug 2026 18:11:03 -0700 Subject: [PATCH] Add light softness: spotlight edge softness for physically-based rendering. The new spotlight attribute softness (real in [0, 1], default 0) is the fraction of the cone, measured inward from the cutoff, over which intensity falls to zero. It is used by physically-based lighting models; the Phong model's corresponding knob remains exponent. The filament renderer previously hardcoded the inner cone angle to 0, making the entire beam penumbra: the shader attenuates by the squared smoothstep ((cos(theta) - cos(outer)) / (cos(inner) - cos(outer)))^2, so a cutoff-25 spot delivered its rated candela only exactly on-axis and about a third of it averaged over the light pool, with the deficit shrinking as the cutoff widens. The inner angle is now (1 - softness) * cutoff, so at the default the light delivers its full intensity everywhere inside the cone and illuminance follows E = I/d^2 independent of the cutoff. Setting softness to 1 reproduces the previous appearance exactly (verified bit-identical), which is the migration path for models tuned against the old behavior. The filament light type also changes from FOCUSED_SPOT to SPOT. With intensity given in candela and the cone set at build time the two types produce identical output (FOCUSED_SPOT's power-conserving rescale only applies when the cone changes after the intensity is set), but SPOT guarantees that candela never rescales with cone angle should the cone ever become runtime-editable. Verified with headless renders under a linear tone mapper against an equal-candela point light at cutoffs 25/45/80: softness 0 gives spot/point luminance ratio 1.000 at all sampled angles inside the cone; softness 0.2 is flat over the inner 80% of the cone; softness 1 matches the previous renderer with zero linear-pixel difference. XML round-trip and the [0, 1] compile-time check verified. Introspect and wasm bindings regenerated. PiperOrigin-RevId: 959334706 Change-Id: I0f0729781899880de1729ea9b3d8c055d715a025 --- doc/XMLreference.rst | 22 +++++++++++++++++---- doc/XMLschema.rst | 6 ++++++ doc/changelog.rst | 17 ++++++++++++++-- doc/includes/references.h | 4 ++++ include/mujoco/mjmodel.h | 1 + include/mujoco/mjrfilament.h | 1 + include/mujoco/mjspec.h | 1 + include/mujoco/mjspecmacro.h | 1 + include/mujoco/mjvisualize.h | 1 + include/mujoco/mjxmacro.h | 1 + model/adhesion/fridge_door.xml | 3 ++- python/mujoco/introspect/structs.py | 18 +++++++++++++++++ python/mujoco/structs.cc | 1 + src/engine/engine_vis_visualize.c | 1 + src/render/filament/core/light.cc | 14 +++++++++---- src/render/filament/mjrfilament.cc | 1 + src/render/filament/support/model_lights.cc | 1 + src/user/user_model.cc | 1 + src/user/user_objects.cc | 5 +++++ src/xml/generated/mjcf.xsd | 2 ++ src/xml/generated/mjcf_default_table.inc | 1 + src/xml/generated/mjcf_read_table.inc | 1 + src/xml/generated/mjcf_table.inc | 8 ++++---- src/xml/mjcf.schema | 1 + unity/Runtime/Bindings/MjBindings.cs | 2 ++ wasm/codegen/generated/bindings.cc | 3 +++ wasm/codegen/generated/bindings.h | 15 ++++++++++++++ 27 files changed, 118 insertions(+), 15 deletions(-) diff --git a/doc/XMLreference.rst b/doc/XMLreference.rst index 2de70ddf..c5c53c1f 100644 --- a/doc/XMLreference.rst +++ b/doc/XMLreference.rst @@ -3307,18 +3307,30 @@ Attributes may be applied or ignored depending on the lighting model being used. .. _body-light-attenuation: :at:`attenuation`: :at-val:`real(3), "1 0 0"` - These are the constant, linear and quadratic attenuation coefficients for Phong lighting. - The default corresponds to no attenuation. + These are the constant, linear and quadratic attenuation coefficients, used by the default Phong lighting model. + The default corresponds to no attenuation. Physically-based lighting models instead attenuate with the inverse + square of distance, scaled by :ref:`intensity` and limited by :ref:`range`. .. _body-light-cutoff: :at:`cutoff`: :at-val:`real, "45"` - Cutoff angle for spotlights, always in degrees regardless of the global angle setting. + Cutoff angle for spotlights, always in degrees regardless of the global angle setting. The falloff of intensity + inside the cone is controlled by :ref:`softness` for physically-based lighting models and by + :ref:`exponent` for the default Phong lighting model. + +.. _body-light-softness: + +:at:`softness`: :at-val:`real, "0"` + Edge softness for spotlights, as a fraction of the :ref:`cutoff` angle in [0, 1], used by + physically-based lighting models. The light delivers its full :ref:`intensity` inside the + cone, falling to zero over the outer softness fraction of the cone angle; the default corresponds to a sharp-edged + cone. This is unused by the default Phong lighting model, which uses :ref:`exponent`. .. _body-light-exponent: :at:`exponent`: :at-val:`real, "10"` - Exponent for spotlights. This setting controls the softness of the spotlight cutoff. + Exponent for spotlights, used by the default Phong lighting model. This setting controls the softness of the + spotlight cutoff. Physically-based lighting models use :ref:`softness` instead. .. _body-composite: @@ -10035,6 +10047,8 @@ if omitted. .. _default-light-cutoff: +.. _default-light-softness: + .. _default-light-exponent: .. _default-light-mode: diff --git a/doc/XMLschema.rst b/doc/XMLschema.rst index 85f3ffd4..ef80bf9b 100644 --- a/doc/XMLschema.rst +++ b/doc/XMLschema.rst @@ -1163,6 +1163,9 @@ .. grid-item:: :ref:`cutoff` + .. grid-item:: + :ref:`softness` + .. grid-item:: :ref:`exponent` @@ -5873,6 +5876,9 @@ .. grid-item:: :ref:`cutoff` + .. grid-item:: + :ref:`softness` + .. grid-item:: :ref:`exponent` diff --git a/doc/changelog.rst b/doc/changelog.rst index 25396fc1..b27170e2 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -13,8 +13,6 @@ General grammar table, presence constraints, keyword maps, typed attribute bindings and save policies are generated from it and gated by tests, as are the schema's enum keywords and declared defaults against the C headers and default-constructors. -- An XSD schema derived from the main schema is provided in - `model/mjcf.xsd `__. Actuation ^^^^^^^^^ @@ -58,6 +56,21 @@ Models Unlike the poncho models, which are bending-only, this model exercises the 2D :ref:`stretch` elasticity of a flex. +Rendering +^^^^^^^^^ + +.. admonition:: Breaking API changes + :class: attention + + - Added :ref:`light/softness`: edge softness for spotlights under physically-based lighting + models, given as the fraction of the cone over which intensity falls to zero. The default of 0 is a sharp-edged + cone which delivers the full :ref:`intensity` everywhere inside it, so that illuminance + follows :math:`E = I/d^2` independent of the :ref:`cutoff` angle. Previously the filament + renderer treated the entire cone as penumbra, dimming spotlights well below their rated intensity, increasingly + so for narrow cutoffs. + + **Migration:** Set :at:`softness` to 1 to reproduce the previous appearance of existing models. + Bug fixes ^^^^^^^^^ diff --git a/doc/includes/references.h b/doc/includes/references.h index 9acae221..1c6a25d1 100644 --- a/doc/includes/references.h +++ b/doc/includes/references.h @@ -860,6 +860,7 @@ typedef struct mjModel_ { mjtNum* light_dir0; // global direction in qpos0 (nlight x 3) float* light_attenuation; // OpenGL attenuation (quadratic model) (nlight x 3) float* light_cutoff; // OpenGL cutoff (nlight x 1) + float* light_softness; // spotlight edge softness (nlight x 1) float* light_exponent; // OpenGL exponent (nlight x 1) float* light_ambient; // ambient rgb (alpha=1) (nlight x 3) float* light_diffuse; // diffuse rgb (alpha=1) (nlight x 3) @@ -1606,6 +1607,7 @@ typedef struct mjrfLightParams_ { mjtBool cast_shadows; // if true, cast shadows float range; // effective range of light, in meters float spot_cone_angle; // spot light cone angle, in degrees + float spot_softness; // spot light edge softness, fraction of cone angle in [0, 1] int shadow_map_size; // size of shadow map texture, 0 to use default size float bulb_radius; // bulb radius, used for soft shadows float vsm_blur_width; // variance shadow map blur width @@ -1999,6 +2001,7 @@ typedef struct mjsLight_ { // light specification float range; // range of effectiveness float attenuation[3]; // OpenGL attenuation (quadratic model) float cutoff; // OpenGL cutoff + float softness; // spotlight edge softness float exponent; // OpenGL exponent float ambient[3]; // ambient color float diffuse[3]; // diffuse color @@ -3291,6 +3294,7 @@ typedef struct mjvLight_ { // OpenGL light float bulbradius; // bulb radius for soft shadows float intensity; // intensity, in candelas float range; // range of effectiveness + float softness; // spotlight edge softness } mjvLight; typedef struct mjvOption_ { // abstract visualization options int label; // what objects to label (mjtLabel) diff --git a/include/mujoco/mjmodel.h b/include/mujoco/mjmodel.h index dce083b1..1d34a094 100644 --- a/include/mujoco/mjmodel.h +++ b/include/mujoco/mjmodel.h @@ -532,6 +532,7 @@ typedef struct mjModel_ { mjtNum* light_dir0; // global direction in qpos0 (nlight x 3) float* light_attenuation; // OpenGL attenuation (quadratic model) (nlight x 3) float* light_cutoff; // OpenGL cutoff (nlight x 1) + float* light_softness; // spotlight edge softness (nlight x 1) float* light_exponent; // OpenGL exponent (nlight x 1) float* light_ambient; // ambient rgb (alpha=1) (nlight x 3) float* light_diffuse; // diffuse rgb (alpha=1) (nlight x 3) diff --git a/include/mujoco/mjrfilament.h b/include/mujoco/mjrfilament.h index 87e53aa1..21f0ed76 100644 --- a/include/mujoco/mjrfilament.h +++ b/include/mujoco/mjrfilament.h @@ -261,6 +261,7 @@ typedef struct mjrfLightParams_ { mjtBool cast_shadows; // if true, cast shadows float range; // effective range of light, in meters float spot_cone_angle; // spot light cone angle, in degrees + float spot_softness; // spot light edge softness, fraction of cone angle in [0, 1] int shadow_map_size; // size of shadow map texture, 0 to use default size float bulb_radius; // bulb radius, used for soft shadows float vsm_blur_width; // variance shadow map blur width diff --git a/include/mujoco/mjspec.h b/include/mujoco/mjspec.h index 5c0c64a7..eda69f15 100644 --- a/include/mujoco/mjspec.h +++ b/include/mujoco/mjspec.h @@ -455,6 +455,7 @@ typedef struct mjsLight_ { // light specification float range; // range of effectiveness float attenuation[3]; // OpenGL attenuation (quadratic model) float cutoff; // OpenGL cutoff + float softness; // spotlight edge softness float exponent; // OpenGL exponent float ambient[3]; // ambient color float diffuse[3]; // diffuse color diff --git a/include/mujoco/mjspecmacro.h b/include/mujoco/mjspecmacro.h index b7a9ff10..2da1165e 100644 --- a/include/mujoco/mjspecmacro.h +++ b/include/mujoco/mjspecmacro.h @@ -258,6 +258,7 @@ X ( float, range, 1 ) \ XVEC( float, attenuation, 3 ) \ X ( float, cutoff, 1 ) \ + X ( float, softness, 1 ) \ X ( float, exponent, 1 ) \ XVEC( float, ambient, 3 ) \ XVEC( float, diffuse, 3 ) \ diff --git a/include/mujoco/mjvisualize.h b/include/mujoco/mjvisualize.h index 9c483553..e8946742 100644 --- a/include/mujoco/mjvisualize.h +++ b/include/mujoco/mjvisualize.h @@ -277,6 +277,7 @@ typedef struct mjvLight_ { // OpenGL light float bulbradius; // bulb radius for soft shadows float intensity; // intensity, in candelas float range; // range of effectiveness + float softness; // spotlight edge softness } mjvLight; diff --git a/include/mujoco/mjxmacro.h b/include/mujoco/mjxmacro.h index 31eab570..59aebbd9 100644 --- a/include/mujoco/mjxmacro.h +++ b/include/mujoco/mjxmacro.h @@ -439,6 +439,7 @@ X ( mjtNum, light_dir0, nlight, 3 ) \ X ( float, light_attenuation, nlight, 3 ) \ X ( float, light_cutoff, nlight, 1 ) \ + X ( float, light_softness, nlight, 1 ) \ X ( float, light_exponent, nlight, 1 ) \ X ( float, light_ambient, nlight, 3 ) \ X ( float, light_diffuse, nlight, 3 ) \ diff --git a/model/adhesion/fridge_door.xml b/model/adhesion/fridge_door.xml index 68064003..70ae0161 100644 --- a/model/adhesion/fridge_door.xml +++ b/model/adhesion/fridge_door.xml @@ -22,7 +22,8 @@ - + diff --git a/python/mujoco/introspect/structs.py b/python/mujoco/introspect/structs.py index ddeface3..66ab4ec9 100644 --- a/python/mujoco/introspect/structs.py +++ b/python/mujoco/introspect/structs.py @@ -2644,6 +2644,14 @@ STRUCTS: Mapping[str, StructDecl] = dict([ doc='OpenGL cutoff', array_extent=('nlight',), ), + StructFieldDecl( + name='light_softness', + type=PointerType( + inner_type=ValueType(name='float'), + ), + doc='spotlight edge softness', + array_extent=('nlight',), + ), StructFieldDecl( name='light_exponent', type=PointerType( @@ -8411,6 +8419,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([ type=ValueType(name='float'), doc='OpenGL cutoff', ), + StructFieldDecl( + name='softness', + type=ValueType(name='float'), + doc='spotlight edge softness', + ), StructFieldDecl( name='exponent', type=ValueType(name='float'), @@ -10633,6 +10646,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([ type=ValueType(name='float'), doc='range of effectiveness', ), + StructFieldDecl( + name='softness', + type=ValueType(name='float'), + doc='spotlight edge softness', + ), ), )), ('mjvOption', diff --git a/python/mujoco/structs.cc b/python/mujoco/structs.cc index be329afe..2d5b7119 100644 --- a/python/mujoco/structs.cc +++ b/python/mujoco/structs.cc @@ -1259,6 +1259,7 @@ This is useful for example when the MJB is not available as a file on disk.)")); X(bulbradius); X(intensity); X(range); + X(softness); #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 229e26ee..5622348d 100644 --- a/src/engine/engine_vis_visualize.c +++ b/src/engine/engine_vis_visualize.c @@ -2986,6 +2986,7 @@ void mjv_makeLights(const mjModel* m, const mjData* d, mjvScene* scn) { f2f(thislight->attenuation, m->light_attenuation+3*i, 3); thislight->exponent = m->light_exponent[i]; thislight->cutoff = m->light_cutoff[i]; + thislight->softness = m->light_softness[i]; } // copy colors diff --git a/src/render/filament/core/light.cc b/src/render/filament/core/light.cc index 96af80c3..0733a7e6 100644 --- a/src/render/filament/core/light.cc +++ b/src/render/filament/core/light.cc @@ -60,7 +60,9 @@ Light::Light(filament::Engine* engine, const mjrfLightParams& params) filament::LightManager::Type type; switch (params.type) { case mjLIGHT_SPOT: - type = filament::LightManager::Type::FOCUSED_SPOT; + // SPOT rather than FOCUSED_SPOT: MJCF intensity is candela, which must + // not rescale with the cone angle. + type = filament::LightManager::Type::SPOT; break; case mjLIGHT_DIRECTIONAL: type = filament::LightManager::Type::DIRECTIONAL; @@ -77,9 +79,13 @@ Light::Light(filament::Engine* engine, const mjrfLightParams& params) builder.color(ReadFloat3(params.color)); builder.intensityCandela(params.intensity); builder.castShadows(params.cast_shadows); - if (type == filament::LightManager::Type::FOCUSED_SPOT) { - builder.spotLightCone(0, - params.spot_cone_angle * std::numbers::pi / 180.0f); + if (type == filament::LightManager::Type::SPOT) { + // The light delivers its full intensity inside the inner cone, so that + // illuminance follows E = I/d^2, and falls to zero over the outer + // softness fraction of the cone angle. + const float outer = params.spot_cone_angle * std::numbers::pi / 180.0f; + const float inner = (1.0f - params.spot_softness) * outer; + builder.spotLightCone(inner, outer); } if (type != filament::LightManager::Type::DIRECTIONAL) { builder.falloff(params.range); diff --git a/src/render/filament/mjrfilament.cc b/src/render/filament/mjrfilament.cc index 1be7e708..fadea235 100644 --- a/src/render/filament/mjrfilament.cc +++ b/src/render/filament/mjrfilament.cc @@ -85,6 +85,7 @@ void mjrf_defaultLightParams(mjrfLightParams* params) { params->cast_shadows = true; params->range = 10.0f; params->spot_cone_angle = 180.f; + params->spot_softness = 0.0f; params->bulb_radius = 0.0f; params->shadow_map_size = 2048; params->vsm_blur_width = 0.0f; diff --git a/src/render/filament/support/model_lights.cc b/src/render/filament/support/model_lights.cc index d264d342..b7ce722a 100644 --- a/src/render/filament/support/model_lights.cc +++ b/src/render/filament/support/model_lights.cc @@ -178,6 +178,7 @@ void ModelLights::Prepare() { params.shadow_map_size = default_shadow_map_size; if (params.type == mjLIGHT_SPOT) { params.spot_cone_angle = model->light_cutoff[i]; + params.spot_softness = model->light_softness[i]; } auto light_obj = CreateLight(ctx, params); diff --git a/src/user/user_model.cc b/src/user/user_model.cc index ce9170ae..7e9e7576 100644 --- a/src/user/user_model.cc +++ b/src/user/user_model.cc @@ -3163,6 +3163,7 @@ void mjCModel::CopyTree(mjModel* m) { m->light_range[lid] = pl->range; mjuu_copyvec(m->light_attenuation+3*lid, pl->attenuation, 3); m->light_cutoff[lid] = pl->cutoff; + m->light_softness[lid] = pl->softness; m->light_exponent[lid] = pl->exponent; mjuu_copyvec(m->light_ambient+3*lid, pl->ambient, 3); mjuu_copyvec(m->light_diffuse+3*lid, pl->diffuse, 3); diff --git a/src/user/user_objects.cc b/src/user/user_objects.cc index a4dafa2a..556547e6 100644 --- a/src/user/user_objects.cc +++ b/src/user/user_objects.cc @@ -4594,6 +4594,11 @@ void mjCLight::Compile(void) { throw mjCError(this, "zero direction in light"); } + // check softness range + if (softness < 0 || softness > 1) { + throw mjCError(this, "light softness must be in [0, 1]"); + } + // get targetbodyid and texid ResolveReferences(model); } diff --git a/src/xml/generated/mjcf.xsd b/src/xml/generated/mjcf.xsd index 03470869..61c1ab66 100644 --- a/src/xml/generated/mjcf.xsd +++ b/src/xml/generated/mjcf.xsd @@ -1495,6 +1495,7 @@ + @@ -2273,6 +2274,7 @@ + diff --git a/src/xml/generated/mjcf_default_table.inc b/src/xml/generated/mjcf_default_table.inc index 2b8857d3..2d737ae9 100644 --- a/src/xml/generated/mjcf_default_table.inc +++ b/src/xml/generated/mjcf_default_table.inc @@ -394,6 +394,7 @@ static const mjXDefaultEntry kDefaults_mjsLight[] = { {"range", (int)offsetof(mjsLight, range), 1, 1, 1, 0, {10.0}}, {"attenuation", (int)offsetof(mjsLight, attenuation), 1, 3, 3, 0, {1.0, 0.0, 0.0}}, {"cutoff", (int)offsetof(mjsLight, cutoff), 1, 1, 1, 0, {45.0}}, + {"softness", (int)offsetof(mjsLight, softness), 1, 1, 1, 0, {0.0}}, {"exponent", (int)offsetof(mjsLight, exponent), 1, 1, 1, 0, {10.0}}, {"ambient", (int)offsetof(mjsLight, ambient), 1, 3, 0, 0, {0}}, {"diffuse", (int)offsetof(mjsLight, diffuse), 1, 3, 3, 0, {0.7, 0.7, 0.7}}, diff --git a/src/xml/generated/mjcf_read_table.inc b/src/xml/generated/mjcf_read_table.inc index cae7c313..e30b091a 100644 --- a/src/xml/generated/mjcf_read_table.inc +++ b/src/xml/generated/mjcf_read_table.inc @@ -426,6 +426,7 @@ inline constexpr mjXAttr kLightAttrs[] = { {"range", mjXAttr::kFloat, 1, true, false, false, false, (int)offsetof(mjsLight, range)}, {"attenuation", mjXAttr::kFloat, 3, true, false, false, false, (int)offsetof(mjsLight, attenuation)}, {"cutoff", mjXAttr::kFloat, 1, true, false, false, false, (int)offsetof(mjsLight, cutoff)}, + {"softness", mjXAttr::kFloat, 1, true, false, false, false, (int)offsetof(mjsLight, softness)}, {"exponent", mjXAttr::kFloat, 1, true, false, false, false, (int)offsetof(mjsLight, exponent)}, {"ambient", mjXAttr::kFloat, 3, true, false, false, false, (int)offsetof(mjsLight, ambient)}, {"diffuse", mjXAttr::kFloat, 3, true, false, false, false, (int)offsetof(mjsLight, diffuse)}, diff --git a/src/xml/generated/mjcf_table.inc b/src/xml/generated/mjcf_table.inc index 7ce452dd..866adfd7 100644 --- a/src/xml/generated/mjcf_table.inc +++ b/src/xml/generated/mjcf_table.inc @@ -92,8 +92,8 @@ std::vector MJCF[] = { "axisangle", "xyaxes", "zaxis", "euler", "mode", "focal", "focalpixel", "principal", "principalpixel", "sensorsize", "user"}, {"light", "?", "directional", "type", "castshadow", "active", "pos", "dir", "bulbradius", - "intensity", "range", "attenuation", "cutoff", "exponent", "ambient", "diffuse", - "specular", "mode"}, + "intensity", "range", "attenuation", "cutoff", "softness", "exponent", "ambient", + "diffuse", "specular", "mode"}, {"pair", "?", "condim", "friction", "solref", "solreffriction", "solimp", "gap", "margin", "adhesion"}, {"equality", "?", "active", "solref", "solimp"}, @@ -204,8 +204,8 @@ std::vector MJCF[] = { "pos", "quat", "axisangle", "xyaxes", "zaxis", "euler", "mode", "target", "focal", "focalpixel", "principal", "principalpixel", "sensorsize", "user"}, {"light", "*", "name", "class", "directional", "type", "castshadow", "active", "pos", - "dir", "bulbradius", "intensity", "range", "attenuation", "cutoff", "exponent", - "ambient", "diffuse", "specular", "mode", "target", "texture"}, + "dir", "bulbradius", "intensity", "range", "attenuation", "cutoff", "softness", + "exponent", "ambient", "diffuse", "specular", "mode", "target", "texture"}, {"plugin", "*", "plugin", "instance"}, {"<"}, {"config", "*", "key", "value"}, diff --git a/src/xml/mjcf.schema b/src/xml/mjcf.schema index dc25eaaf..3848cd74 100644 --- a/src/xml/mjcf.schema +++ b/src/xml/mjcf.schema @@ -1117,6 +1117,7 @@ element light : mjsLight { range : float = 10 attenuation : float[3] = {1, 0, 0} cutoff : float = 45 + softness : float = 0 exponent : float = 10 ambient : float[3] diffuse : float[3] = {0.7, 0.7, 0.7} diff --git a/unity/Runtime/Bindings/MjBindings.cs b/unity/Runtime/Bindings/MjBindings.cs index d9de98c4..677500fe 100644 --- a/unity/Runtime/Bindings/MjBindings.cs +++ b/unity/Runtime/Bindings/MjBindings.cs @@ -1286,6 +1286,7 @@ public unsafe struct mjModel_ { public double* light_dir0; public float* light_attenuation; public float* light_cutoff; + public float* light_softness; public float* light_exponent; public float* light_ambient; public float* light_diffuse; @@ -6030,6 +6031,7 @@ public unsafe struct mjvLight_ { public float bulbradius; public float intensity; public float range; + public float softness; } [StructLayout(LayoutKind.Sequential)] diff --git a/wasm/codegen/generated/bindings.cc b/wasm/codegen/generated/bindings.cc index 6f0cb8af..2c103d22 100644 --- a/wasm/codegen/generated/bindings.cc +++ b/wasm/codegen/generated/bindings.cc @@ -5102,6 +5102,7 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) { .property("light_pos0", &MjModel::light_pos0) .property("light_poscom0", &MjModel::light_poscom0) .property("light_range", &MjModel::light_range) + .property("light_softness", &MjModel::light_softness) .property("light_specular", &MjModel::light_specular) .property("light_targetbodyid", &MjModel::light_targetbodyid) .property("light_texid", &MjModel::light_texid) @@ -5893,6 +5894,7 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) { .property("mode", &MjsLight::mode, &MjsLight::set_mode, reference()) .property("pos", &MjsLight::pos) .property("range", &MjsLight::range, &MjsLight::set_range, reference()) + .property("softness", &MjsLight::softness, &MjsLight::set_softness, reference()) .property("specular", &MjsLight::specular) .property("targetbody", &MjsLight::targetbody, &MjsLight::set_targetbody, reference()) .property("texture", &MjsLight::texture, &MjsLight::set_texture, reference()) @@ -6170,6 +6172,7 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) { .property("intensity", &MjvLight::intensity, &MjvLight::set_intensity, reference()) .property("pos", &MjvLight::pos) .property("range", &MjvLight::range, &MjvLight::set_range, reference()) + .property("softness", &MjvLight::softness, &MjvLight::set_softness, reference()) .property("specular", &MjvLight::specular) .property("texid", &MjvLight::texid, &MjvLight::set_texid, reference()) .property("type", &MjvLight::type, &MjvLight::set_type, reference()); diff --git a/wasm/codegen/generated/bindings.h b/wasm/codegen/generated/bindings.h index 2f82c8ff..9b235bd4 100644 --- a/wasm/codegen/generated/bindings.h +++ b/wasm/codegen/generated/bindings.h @@ -2033,6 +2033,12 @@ struct MjvLight { void set_range(float value) { ptr_->range = value; } + float softness() const { + return ptr_->softness; + } + void set_softness(float value) { + ptr_->softness = value; + } private: mjvLight* ptr_; @@ -2919,6 +2925,12 @@ struct MjsLight { void set_cutoff(float value) { ptr_->cutoff = value; } + float softness() const { + return ptr_->softness; + } + void set_softness(float value) { + ptr_->softness = value; + } float exponent() const { return ptr_->exponent; } @@ -4785,6 +4797,9 @@ struct MjModel { emscripten::val light_cutoff() const { return emscripten::val(emscripten::typed_memory_view(ptr_->nlight, ptr_->light_cutoff)); } + emscripten::val light_softness() const { + return emscripten::val(emscripten::typed_memory_view(ptr_->nlight, ptr_->light_softness)); + } emscripten::val light_exponent() const { return emscripten::val(emscripten::typed_memory_view(ptr_->nlight, ptr_->light_exponent)); }