From 7e0dad0580124ac00a2a1c36f382b1310883ebd8 Mon Sep 17 00:00:00 2001 From: Eqkoss / T1NT1N Date: Thu, 13 Feb 2025 21:21:02 +0100 Subject: [PATCH] Lights: Add exposure property Similar to other renderers, this adds an exposure property to multiply the light power by 2^exposure. This can be more convenient to control a wide range of values. This is supported in Cycles, EEVEE, Hydra, USD, COLLADA and FBX. Pull Request: https://projects.blender.org/blender/blender/pulls/134528 --- intern/cycles/blender/addon/ui.py | 1 + intern/cycles/blender/light.cpp | 3 ++- scripts/addons_core/hydra_storm/ui.py | 1 + scripts/addons_core/io_scene_fbx/export_fbx_bin.py | 5 ++++- scripts/addons_core/io_scene_fbx/import_fbx.py | 1 + scripts/startup/bl_ui/properties_data_light.py | 1 + source/blender/blenkernel/intern/light.cc | 2 +- source/blender/draw/engines/eevee/eevee_light.cc | 2 +- source/blender/io/collada/LightExporter.cpp | 3 ++- source/blender/io/usd/hydra/light.cc | 2 +- source/blender/io/usd/intern/usd_reader_light.cc | 2 +- source/blender/io/usd/intern/usd_writer_light.cc | 6 ++++-- source/blender/makesdna/DNA_light_types.h | 2 ++ source/blender/makesrna/intern/rna_light.cc | 10 ++++++++++ 14 files changed, 32 insertions(+), 9 deletions(-) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index d8743a9b7db..3e4009a112f 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1536,6 +1536,7 @@ class CYCLES_LIGHT_PT_light(CyclesButtonsPanel, Panel): col.prop(light, "color") col.prop(light, "energy") + col.prop(light, "exposure") layout.separator() diff --git a/intern/cycles/blender/light.cpp b/intern/cycles/blender/light.cpp index 0797f5b6c43..d45df482bbf 100644 --- a/intern/cycles/blender/light.cpp +++ b/intern/cycles/blender/light.cpp @@ -75,7 +75,8 @@ void BlenderSync::sync_light(BObjectInfo &b_ob_info, Light *light) } /* strength */ - const float3 strength = get_float3(b_light.color()) * BL::PointLight(b_light).energy(); + const float3 strength = get_float3(b_light.color()) * + (BL::PointLight(b_light).energy() * exp2f(b_light.exposure())); light->set_strength(strength); /* shadow */ diff --git a/scripts/addons_core/hydra_storm/ui.py b/scripts/addons_core/hydra_storm/ui.py index 01c259f0da7..d211d4cfaf1 100644 --- a/scripts/addons_core/hydra_storm/ui.py +++ b/scripts/addons_core/hydra_storm/ui.py @@ -170,6 +170,7 @@ class STORM_HYDRA_LIGHT_PT_light(Panel): main_col.prop(light, "color") main_col.prop(light, "energy") + main_col.prop(light, "exposure") main_col.separator() if light.type == 'POINT': diff --git a/scripts/addons_core/io_scene_fbx/export_fbx_bin.py b/scripts/addons_core/io_scene_fbx/export_fbx_bin.py index 69e2b54f7fe..ec26a9099be 100644 --- a/scripts/addons_core/io_scene_fbx/export_fbx_bin.py +++ b/scripts/addons_core/io_scene_fbx/export_fbx_bin.py @@ -204,6 +204,7 @@ def fbx_template_def_light(scene, settings, override_defaults=None, nbr_users=0) b"CastLight": (True, "p_bool", False), b"Color": ((1.0, 1.0, 1.0), "p_color", True), b"Intensity": (100.0, "p_number", True), # Times 100 compared to Blender values... + b"Exposure" : (0.0, "p_number", True ), b"DecayType": (2, "p_enum", False), # Quadratic. b"DecayStart": (30.0 * gscale, "p_double", False), b"CastShadows": (True, "p_bool", False), @@ -601,12 +602,14 @@ def fbx_data_light_elements(root, lamp, scene_data): elem_data_single_int32(light, b"GeometryVersion", FBX_GEOMETRY_VERSION) # Sic... + intensity = lamp.energy * 100.0 * pow(2.0, lamp.exposure) + tmpl = elem_props_template_init(scene_data.templates, b"Light") props = elem_properties(light) elem_props_template_set(tmpl, props, "p_enum", b"LightType", FBX_LIGHT_TYPES[lamp.type]) elem_props_template_set(tmpl, props, "p_bool", b"CastLight", do_light) elem_props_template_set(tmpl, props, "p_color", b"Color", lamp.color) - elem_props_template_set(tmpl, props, "p_number", b"Intensity", lamp.energy * 100.0) + elem_props_template_set(tmpl, props, "p_number", b"Intensity", intensity) elem_props_template_set(tmpl, props, "p_enum", b"DecayType", FBX_LIGHT_DECAY_TYPES['INVERSE_SQUARE']) elem_props_template_set(tmpl, props, "p_double", b"DecayStart", 25.0 * gscale) # 25 is old Blender default elem_props_template_set(tmpl, props, "p_bool", b"CastShadows", do_shadow) diff --git a/scripts/addons_core/io_scene_fbx/import_fbx.py b/scripts/addons_core/io_scene_fbx/import_fbx.py index 9d224ad3e94..7d1620bac28 100644 --- a/scripts/addons_core/io_scene_fbx/import_fbx.py +++ b/scripts/addons_core/io_scene_fbx/import_fbx.py @@ -2236,6 +2236,7 @@ def blen_read_light(fbx_tmpl, fbx_obj, settings): # TODO, cycles nodes??? lamp.color = elem_props_get_color_rgb(fbx_props, b'Color', (1.0, 1.0, 1.0)) lamp.energy = elem_props_get_number(fbx_props, b'Intensity', 100.0) / 100.0 + lamp.exposure = elem_props_get_number(fbx_props, b'Exposure', 0.0) lamp.use_shadow = elem_props_get_bool(fbx_props, b'CastShadow', True) if hasattr(lamp, "cycles"): lamp.cycles.cast_shadow = lamp.use_shadow diff --git a/scripts/startup/bl_ui/properties_data_light.py b/scripts/startup/bl_ui/properties_data_light.py index 874c37c5ab0..1c1dc4c2c54 100644 --- a/scripts/startup/bl_ui/properties_data_light.py +++ b/scripts/startup/bl_ui/properties_data_light.py @@ -91,6 +91,7 @@ class DATA_PT_EEVEE_light(DataButtonsPanel, Panel): col = layout.column() col.prop(light, "color") col.prop(light, "energy") + col.prop(light, "exposure") layout.separator() diff --git a/source/blender/blenkernel/intern/light.cc b/source/blender/blenkernel/intern/light.cc index 17563973a4e..eca1ca87477 100644 --- a/source/blender/blenkernel/intern/light.cc +++ b/source/blender/blenkernel/intern/light.cc @@ -128,7 +128,7 @@ static void light_blend_write(BlendWriter *writer, ID *id, const void *id_addres Light *la = (Light *)id; /* Forward compatibility for energy. */ - la->energy_deprecated = la->energy; + la->energy_deprecated = la->energy * exp2f(la->exposure); if (la->type == LA_AREA) { la->energy_deprecated /= M_PI_4; } diff --git a/source/blender/draw/engines/eevee/eevee_light.cc b/source/blender/draw/engines/eevee/eevee_light.cc index 9bb2a603c91..4e309ea616d 100644 --- a/source/blender/draw/engines/eevee/eevee_light.cc +++ b/source/blender/draw/engines/eevee/eevee_light.cc @@ -68,7 +68,7 @@ void Light::sync(ShadowModule &shadows, shadow_discard_safe(shadows); } - this->color = float3(&la->r) * la->energy; + this->color = float3(&la->r) * (la->energy * exp2f(la->exposure)); float3 scale; object_to_world.view<3, 3>() = normalize_and_get_size(object_to_world.view<3, 3>(), scale); diff --git a/source/blender/io/collada/LightExporter.cpp b/source/blender/io/collada/LightExporter.cpp index a29a4a7d417..0631eba619a 100644 --- a/source/blender/io/collada/LightExporter.cpp +++ b/source/blender/io/collada/LightExporter.cpp @@ -46,7 +46,8 @@ void LightsExporter::operator()(Object *ob) Light *la = (Light *)ob->data; std::string la_id(get_light_id(ob)); std::string la_name(id_name(la)); - COLLADASW::Color col(la->r * la->energy, la->g * la->energy, la->b * la->energy); + const float energy = la->energy * exp2f(la->exposure); + COLLADASW::Color col(la->r * energy, la->g * energy, la->b * energy); /* sun */ if (la->type == LA_SUN) { diff --git a/source/blender/io/usd/hydra/light.cc b/source/blender/io/usd/hydra/light.cc index d9db32a32ae..d92a3bd514c 100644 --- a/source/blender/io/usd/hydra/light.cc +++ b/source/blender/io/usd/hydra/light.cc @@ -85,7 +85,7 @@ void LightData::init() } data_[pxr::HdLightTokens->intensity] = intensity; - data_[pxr::HdLightTokens->exposure] = 0.0f; + data_[pxr::HdLightTokens->exposure] = light->exposure; data_[pxr::HdLightTokens->color] = pxr::GfVec3f(light->r, light->g, light->b); data_[pxr::HdLightTokens->diffuse] = light->diff_fac; data_[pxr::HdLightTokens->specular] = light->spec_fac; diff --git a/source/blender/io/usd/intern/usd_reader_light.cc b/source/blender/io/usd/intern/usd_reader_light.cc index d272fe6eef5..56cc8682270 100644 --- a/source/blender/io/usd/intern/usd_reader_light.cc +++ b/source/blender/io/usd/intern/usd_reader_light.cc @@ -161,7 +161,7 @@ void USDLightReader::read_object_data(Main *bmain, const double motionSampleTime if (pxr::UsdAttribute exposure_attr = light_api.GetExposureAttr()) { float exposure = 0.0f; if (exposure_attr.Get(&exposure, motionSampleTime)) { - blight->energy *= pow(2.0f, exposure); + blight->exposure = exposure; } } diff --git a/source/blender/io/usd/intern/usd_writer_light.cc b/source/blender/io/usd/intern/usd_writer_light.cc index c6c85f4bb50..d4a644dc703 100644 --- a/source/blender/io/usd/intern/usd_writer_light.cc +++ b/source/blender/io/usd/intern/usd_writer_light.cc @@ -142,8 +142,10 @@ void USDLightWriter::do_write(HierarchyContext &context) intensity, timecode, usd_value_writer_); - set_attribute( - usd_light_api.CreateExposureAttr(pxr::VtValue(), true), 0.0f, timecode, usd_value_writer_); + set_attribute(usd_light_api.CreateExposureAttr(pxr::VtValue(), true), + light->exposure, + timecode, + usd_value_writer_); set_attribute(usd_light_api.CreateColorAttr(pxr::VtValue(), true), pxr::GfVec3f(light->r, light->g, light->b), timecode, diff --git a/source/blender/makesdna/DNA_light_types.h b/source/blender/makesdna/DNA_light_types.h index 8d41ae97e78..f5449ca7527 100644 --- a/source/blender/makesdna/DNA_light_types.h +++ b/source/blender/makesdna/DNA_light_types.h @@ -37,6 +37,8 @@ typedef struct Light { /* Color and energy. */ float r, g, b; float energy; + float exposure; + float _pad3; /* Point light. */ float radius; diff --git a/source/blender/makesrna/intern/rna_light.cc b/source/blender/makesrna/intern/rna_light.cc index ac55f2fdaaa..e65db70015d 100644 --- a/source/blender/makesrna/intern/rna_light.cc +++ b/source/blender/makesrna/intern/rna_light.cc @@ -163,6 +163,16 @@ static void rna_def_light(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, nullptr, "mode", LA_SHADOW); RNA_def_property_update(prop, 0, "rna_Light_draw_update"); + prop = RNA_def_property(srna, "exposure", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_default(prop, 0.0f); + RNA_def_property_range(prop, -20.0f, 20.0f); + RNA_def_property_ui_range(prop, -20.0f, 20.0f, 0.01f, 2); + RNA_def_property_ui_text( + prop, + "Exposure", + "Scales the power of the light exponentially, multiplying the intensity by 2^exposure"); + RNA_def_property_update(prop, 0, "rna_Light_update"); + /* nodes */ prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, nullptr, "nodetree");