Lights: Add normalize property

When enabled, this normalize the strength by the light area, to keep
the total output the same regardless of shape or size. This is the
existing behavior.

This is supported in Cycles, EEVEE, Hydra, USD, COLLADA.

For add-ons, an API function to compute the area is added for conversion,
in case there is no native support for normalization.

area = light.area(matrix_world=ob.matrix_world)

Co-authored-by: Brecht Van Lommel <brecht@blender.org>

Pull Request: https://projects.blender.org/blender/blender/pulls/136958
This commit is contained in:
Eqkoss / T1NT1N 2025-02-21 21:37:48 +01:00 • committed by Brecht Van Lommel
parent a428815716
commit bb9d5cdaad
42 changed files with 173 additions and 84 deletions

View file

@ -1559,6 +1559,7 @@ class CYCLES_LIGHT_PT_light(CyclesButtonsPanel, Panel):
col = layout.column()
col.prop(light, "energy")
col.prop(light, "exposure")
col.prop(light, "normalize")
layout.separator()

View file

@ -88,6 +88,9 @@ void BlenderSync::sync_light(BObjectInfo &b_ob_info, Light *light)
exp2f(b_light.exposure());
light->set_strength(strength);
/* normalize */
light->set_normalize(b_light.normalize());
/* shadow */
PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles");
light->set_cast_shadow(b_light.use_shadow());

View file

@ -182,6 +182,7 @@ class STORM_HYDRA_LIGHT_PT_light(Panel):
main_col = layout.column()
main_col.prop(light, "energy")
main_col.prop(light, "exposure")
main_col.prop(light, "normalize")
main_col.separator()
if light.type == 'POINT':

View file

@ -115,6 +115,7 @@ class DATA_PT_EEVEE_light(DataButtonsPanel, Panel):
col = layout.column()
col.prop(light, "energy")
col.prop(light, "exposure")
col.prop(light, "normalize")
layout.separator()

View file

@ -10,6 +10,7 @@
*/
#include "BLI_compiler_attrs.h"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_vector_types.hh"
struct Depsgraph;
@ -22,3 +23,4 @@ void BKE_light_eval(Depsgraph *depsgraph, Light *la);
float BKE_light_power(const Light &light);
blender::float3 BKE_light_color(const Light &light);
float BKE_light_area(const Light &light, const blender::float4x4 &object_to_world);

View file

@ -19,6 +19,9 @@
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "BLI_math_base.hh"
#include "BLI_math_matrix.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_utildefines.h"
#include "BKE_icons.h"
@ -219,3 +222,43 @@ blender::float3 BKE_light_color(const Light &light)
return color;
}
float BKE_light_area(const Light &light, const blender::float4x4 &object_to_world)
{
/* Make illumination power constant. */
switch (light.type) {
case LA_AREA: {
/* Rectangle area. */
const blender::float3x3 scalemat = object_to_world.view<3, 3>();
const blender::float3 scale = blender::math::to_scale(scalemat);
const float size_x = light.area_size * scale.x;
const float size_y = (ELEM(light.area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE) ?
light.area_sizey :
light.area_size) *
scale.y;
float area = size_x * size_y;
/* Scale for smaller area of the ellipse compared to the surrounding rectangle. */
if (ELEM(light.area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) {
area *= float(M_PI / 4.0f);
}
return area;
}
case LA_LOCAL:
case LA_SPOT: {
/* Sphere area. For legacy reasons object scale is not taken into account
* here, even though logically it should be. */
const float radius = light.radius;
return (radius > 0.0f) ? float(4.0f * M_PI) * blender::math::square(radius) : 4.0f;
}
case LA_SUN: {
/* Sun disk area. */
const float angle = light.sun_angle / 2.0f;
return (angle > 0.0f) ? float(M_PI) * blender::math::square(sinf(angle)) : 1.0f;
}
}
BLI_assert_unreachable();
return 1.0f;
}

View file

@ -15,6 +15,7 @@
#include "eevee_light.hh"
#include "DNA_defaults.h"
#include "DNA_light_types.h"
#include "DNA_sdna_type_ids.hh"
#include "BKE_light.h"
@ -69,6 +70,9 @@ void Light::sync(ShadowModule &shadows,
}
this->color = BKE_light_power(*la) * BKE_light_color(*la);
if (la->mode & LA_UNNORMALIZED) {
this->color *= BKE_light_area(*la, object_to_world);
}
float3 scale;
object_to_world.view<3, 3>() = normalize_and_get_size(object_to_world.view<3, 3>(), scale);

View file

@ -11,6 +11,7 @@
#include "COLLADASWColor.h"
#include "COLLADASWLight.h"
#include "DNA_light_types.h"
#include "LightExporter.h"
#include "collada_internal.h"
@ -48,7 +49,10 @@ 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));
const blender::float3 color = BKE_light_power(*la) * BKE_light_color(*la);
blender::float3 color = BKE_light_power(*la) * BKE_light_color(*la);
if (la->mode & LA_UNNORMALIZED) {
color *= BKE_light_area(*la, ob->runtime->object_to_world);
}
COLLADASW::Color col(color[0], color[1], color[2]);
/* sun */

View file

@ -95,7 +95,7 @@ void LightData::init()
data_[pxr::HdLightTokens->exposure] = light->exposure;
data_[pxr::HdLightTokens->diffuse] = light->diff_fac;
data_[pxr::HdLightTokens->specular] = light->spec_fac;
data_[pxr::HdLightTokens->normalize] = true;
data_[pxr::HdLightTokens->normalize] = (light->mode & LA_UNNORMALIZED) == 0;
prim_type_ = prim_type(light);

View file

@ -43,8 +43,6 @@ void USDLightReader::read_object_data(Main *bmain, const double motionSampleTime
return;
}
float light_surface_area = 1.0f;
if (prim_.IsA<pxr::UsdLuxDiskLight>()) {
/* Disk area light. */
blight->type = LA_AREA;
@ -59,9 +57,6 @@ void USDLightReader::read_object_data(Main *bmain, const double motionSampleTime
}
}
}
const float radius = 0.5f * blight->area_size;
light_surface_area = radius * radius * M_PI;
}
else if (prim_.IsA<pxr::UsdLuxRectLight>()) {
/* Rectangular area light. */
@ -84,8 +79,6 @@ void USDLightReader::read_object_data(Main *bmain, const double motionSampleTime
}
}
}
light_surface_area = blight->area_size * blight->area_sizey;
}
else if (prim_.IsA<pxr::UsdLuxSphereLight>()) {
/* Point and spot light. */
@ -108,8 +101,6 @@ void USDLightReader::read_object_data(Main *bmain, const double motionSampleTime
}
}
light_surface_area = 4.0f * M_PI * blight->radius * blight->radius;
pxr::UsdLuxShapingAPI shaping_api = pxr::UsdLuxShapingAPI(prim_);
if (shaping_api && shaping_api.GetShapingConeAngleAttr().IsAuthored()) {
blight->type = LA_SPOT;
@ -208,15 +199,14 @@ void USDLightReader::read_object_data(Main *bmain, const double motionSampleTime
}
}
/* Normalize: Blender lights are always normalized, so inverse correct for it
* TODO: take into account object transform, or natively support this as a
* setting on lights in Blender. */
bool normalize = false;
/* Normalize */
if (pxr::UsdAttribute normalize_attr = light_api.GetNormalizeAttr()) {
normalize_attr.Get(&normalize, motionSampleTime);
}
if (!normalize) {
blight->energy *= light_surface_area;
bool normalize = false;
if (normalize_attr.Get(&normalize, motionSampleTime)) {
if (!normalize) {
blight->mode |= LA_UNNORMALIZED;
}
}
}
USDXformReader::read_object_data(bmain, motionSampleTime);

View file

@ -169,8 +169,10 @@ void USDLightWriter::do_write(HierarchyContext &context)
light->spec_fac,
timecode,
usd_value_writer_);
set_attribute(
usd_light_api.CreateNormalizeAttr(pxr::VtValue(), true), true, timecode, usd_value_writer_);
set_attribute(usd_light_api.CreateNormalizeAttr(pxr::VtValue(), true),
(light->mode & LA_UNNORMALIZED) == 0,
timecode,
usd_value_writer_);
pxr::UsdPrim prim = usd_light_api.GetPrim();
write_id_properties(prim, light->id, timecode);

View file

@ -145,6 +145,7 @@ enum {
LA_SHAD_RES_ABSOLUTE = 1 << 22,
LA_SHADOW_JITTER = 1 << 23,
LA_USE_TEMPERATURE = 1 << 24,
LA_UNNORMALIZED = 1 << 25,
};
/** #Light::falloff_type */

View file

@ -25,7 +25,10 @@
# include "MEM_guardedalloc.h"
# include "BLI_math_matrix_types.hh"
# include "BKE_context.hh"
# include "BKE_light.h"
# include "BKE_main.hh"
# include "BKE_texture.h"
@ -84,12 +87,23 @@ static void rna_Light_temperature_color_get(PointerRNA *ptr, float *color)
{
Light *la = (Light *)ptr->data;
float rgb[4];
IMB_colormanagement_blackbody_temperature_to_rgb(rgb, la->temperature);
if (la->mode & LA_USE_TEMPERATURE) {
float rgb[4];
IMB_colormanagement_blackbody_temperature_to_rgb(rgb, la->temperature);
color[0] = rgb[0];
color[1] = rgb[1];
color[2] = rgb[2];
color[0] = rgb[0];
color[1] = rgb[1];
color[2] = rgb[2];
}
else {
copy_v3_fl(color, 1.0f);
}
}
static float rna_Light_area(Light *light, const float matrix_world[16])
{
blender::float4x4 mat(matrix_world);
return BKE_light_area(*light, mat);
}
#else
@ -105,6 +119,19 @@ const EnumPropertyItem rna_enum_light_type_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
static void rna_def_light_api(StructRNA *srna)
{
FunctionRNA *func = RNA_def_function(srna, "area", "rna_Light_area");
RNA_def_function_ui_description(func,
"Compute light area based on type and shape. The normalize "
"option divides light intensity by this area");
PropertyRNA *parm = RNA_def_property(func, "matrix_world", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
RNA_def_property_ui_text(parm, "", "Object to world space transformation matrix");
parm = RNA_def_property(func, "area", PROP_FLOAT, PROP_NONE);
RNA_def_function_return(func, parm);
}
static void rna_def_light(BlenderRNA *brna)
{
StructRNA *srna;
@ -209,6 +236,15 @@ static void rna_def_light(BlenderRNA *brna)
"Scales the power of the light exponentially, multiplying the intensity by 2^exposure");
RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "normalize", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, nullptr, "mode", LA_UNNORMALIZED);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop,
"Normalize",
"Normalize intensity by light area, for consistent total light "
"output regardless of size and shape");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
/* nodes */
prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, nullptr, "nodetree");
@ -225,6 +261,7 @@ static void rna_def_light(BlenderRNA *brna)
/* common */
rna_def_animdata_common(srna);
rna_def_light_api(srna);
}
static void rna_def_light_energy(StructRNA *srna, const short light_type)

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:10f9e507d61470a8019828c92aa47b1ff40173098a504804e372908451371700
size 27204
oid sha256:1ccdfbd360fb1446b5e295f84b8e62b71b69041fc267f04d8ddb2ce32f6cd13d
size 27211

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ca1a42907e79b2b7d08decac29b006c8a313f469a3e4560ab2c460518a243477
size 6859
oid sha256:fac979b958c94799b50371b090478ca379c88c54c843c7f2e7a8b0c156b34eb2
size 6775

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:87ac413c8275964fd5af6820eb79dd572a8a09e6b4d3f93d47dd9e841889a833
size 6861
oid sha256:9748535d87ebcc41ef3288249cbb7d2fb8a119c86ac9dde15e20ff7197986d41
size 6777

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b85e581067e7635ac590f38616fe2b816d036090d908397bbaeae1781dc92f49
size 6863
oid sha256:3d1f44b45107943584fdf44c756bf29c42e4f75b7f862fb674f72b4aefc41a7e
size 6779

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bedfa6c180e790f113d5faf9feff29352379845d068026b4fe58410f58aa70c3
size 10287
oid sha256:7e01368a23a094d987b46830d2e4cee803eed8436cd4efc0baee937d14cc094a
size 14936

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3bd384a2a0c43e5e5244e42da4f43faa4bea6b0aeaa2fb9aea8c8a73dc13e6c8
size 19952
oid sha256:63e50c82aedfc17485d043205008206b290a2d1681bdddb85475470cbcf07639
size 19921

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1d5ad6be23f2ee9bebcb8c817721609beda043a48e0ab1b8592ca3e7e84f81a0
size 11939
oid sha256:c2156edd85d37dfbdaa0e383aae3234385a378e3c8601d89e04883f66ec3f3b2
size 12024

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:50cc39bc32d67d47531c45e4af2dacfb12580c792db6645041bebb6dd2b394fc
size 9858
oid sha256:61a803f285f864675d896989991a49dfcdabd2bd04bab7d21bcc5b75738a652b
size 9787

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7ae40eabb3ac1e3bbc3a4b51622c02cd4e62486d1e0d870a500919f5b9cbd491
size 6075
oid sha256:9a60822eed74efd8a685e33a66a8e4b7b99cb56c50c6beab76f0d6fa712377e3
size 5979

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e58ce8a2ac70f160cf494e751542fb0f3842d47db968c08a2b8345a4bdbce0df
size 29757
oid sha256:68aec63ad699d783807c5c734e37e3f22d847d154655d32489d16ac030157c9a
size 29713

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ce70cd48cc180e7170b44a483542f876e6de9c7c55658caf27d3dd16be81d979
size 22824
oid sha256:d8bb9887c54227a100494b72f13b899e4f9f9bda79887b5c346a8d01f1f61a6a
size 22840

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0db9cbc39d68c90652589f632d7d857e169db539b3456e9b81974e1ded094d9f
size 13735
oid sha256:f57e498a62583537c19b4591c42504813d72aa8f964bea6dd8c4884b6658cd49
size 13548

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:21bc38d113b8ec1ede6a4d0b561a83da2b2ad820c65a9647ab548b3bc9741825
size 12584
oid sha256:cf142d9a3a586e1eb36ee56a89e098bebd52c2d82fe25029c16e8b22f966e000
size 12623

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1a4074bbc8dca819e50d51b11704eb0c3973681f32a2a36f65fa888f1755c891
size 14672
oid sha256:4aed9a3b8b5fd8756ab02868e89c8806b3b1aa4e98384ca866b77c80cf3be9df
size 14509

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4522f3d92a9961255eba3a36cd311929cce54899690653fb41445c4b5cb98fbe
size 14677
oid sha256:dc01c39bd2064605087b008cff43bf0a733c6b9e4176f664d7ea5ca8184eee8c
size 14514

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:53dd89516ed704acbaa0b933294700514bbc83d9281ad34e91abcc887433b6ed
size 13744
oid sha256:d30723fcae68458cbb74c0c243fb7e441fcae5dfddf81614f7faba63f33cc8db
size 13726

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4cd2f990029e035f01e4ffa41e1c6524114bfcd59958a3ab00f2832fa62f2bbf
size 9097
oid sha256:9cde412bac71595aae27d945035958e336c4ab54c92d1cd624d429036882aad0
size 9171

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d4de435c5dbdf7303ca369fa7cb9c5580a208b513daa6e5a056bab75caf4df0f
size 9101
oid sha256:e7d6a31da51130d8528c6f496a5e2315b1f5f62d077dfead5d3f39a14f7460fc
size 9175

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ae430bb206848d080dee07ba7f4d4c97ff3bac6648eea278501a49e52f228b4f
size 12840
oid sha256:8d93d7c8c3cd7a7540d175d3b3765e3cc982ec304c6ad41e5917256dbe75996d
size 12473

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fb9d5565f5f96ee24b9a09a13d4e40edb9398b6550cd7a7026f4dd4daced90d2
size 12017
oid sha256:a16df0d32e9d4a50d1078c80d5e6f6a288286b24cd8964e8ad84256667eef326
size 11808

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e9d3ef19fc739d9ad6d58bf415ee64891961ce714e36132627c0007df3e820b3
size 28015
oid sha256:0897e3a60632d0e2d82abaa494262b31eecf945069a489f5de4304785e562e82
size 28034

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d8e1db324066f09ed5242bf64959807d7fe244fb4e6ce919fa35b46af6e9986b
size 10874
oid sha256:a2a77004d8b96b2c9e2b092b74aca0a25dcafb395536025b4135d28ce8331c14
size 10862

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ce76831d525d606a780bd3797e54b1ac4a762a4677d16c034d2e9e1ae830fb1e
size 12543
oid sha256:cc53e118f02e73879710cd2ed9e61a6271fa5a340c289eca7fd07b4f9b2aa295
size 12631

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:414b6c576bca9ce23d0d84a65eeb5ccf15d38c438c7b107de32c8513000072db
size 4185
oid sha256:394c845d71ef6e392f5d6eed7210d481ed32e4361ab6c57adadf7008826a03e4
size 6557

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2d7e603c8716ede770c5c5572a25efcd2eca9076a5d62733609d146b26950ef4
size 43462
oid sha256:3e70d4b1f3e5490f45eda2411ac9d4d56b62a324973050ceb21c1f2957fd2123
size 73900

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c5449059c015a80919a51d0eeafea97995c14af4572e4fab093c3b29687c865f
size 13971
oid sha256:5f279fc8f4edafb38d880e5249a15000808b219015e8a11ea02c881875f45750
size 13885

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f8c7601624ce93f91bf64cbd722e9b88ad73852a4298376d7b3536b2bd651e81
size 8021
oid sha256:e96d41f91aae1597cd8759aa6886e3008220cba8f354f1b6efed15f6cbcd105a
size 8012

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:570dd56cd5235e33237481d6430a7627d5e59dc606019475c4b48ee22c6a971f
size 7973
oid sha256:a7b4d7a5590597012de161e12c85a3be20e1bda6ef1b098a2d533c9f52c250a9
size 10693

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:43f600d94a97b5660af3564779e62e4bbb56a2e1710bfbcb12dffa1d6f8feef6
size 14186
oid sha256:ac42d5fe52cc9eab05d1d883dc325304844ccb2a026efc21639e0e747b477262
size 15383