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:
committed by
Brecht Van Lommel
parent
a428815716
commit
bb9d5cdaad
@@ -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()
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
BIN
tests/files/render/integrator/cycles_renders/light_path_ray_depth.png
(Stored with Git LFS)
BIN
tests/files/render/integrator/cycles_renders/light_path_ray_depth.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/integrator/storm_usd_renders/clamp_both.png
(Stored with Git LFS)
BIN
tests/files/render/integrator/storm_usd_renders/clamp_both.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/integrator/storm_usd_renders/clamp_direct.png
(Stored with Git LFS)
BIN
tests/files/render/integrator/storm_usd_renders/clamp_direct.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/integrator/storm_usd_renders/clamp_indirect.png
(Stored with Git LFS)
BIN
tests/files/render/integrator/storm_usd_renders/clamp_indirect.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/integrator/storm_usd_renders/light_path_ray_depth.png
(Stored with Git LFS)
BIN
tests/files/render/integrator/storm_usd_renders/light_path_ray_depth.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light/cycles_renders/multiple_area_lights.png
(Stored with Git LFS)
BIN
tests/files/render/light/cycles_renders/multiple_area_lights.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light/storm_usd_renders/cast_shadow_versioning.png
(Stored with Git LFS)
BIN
tests/files/render/light/storm_usd_renders/cast_shadow_versioning.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light/storm_usd_renders/multiple_area_lights.png
(Stored with Git LFS)
BIN
tests/files/render/light/storm_usd_renders/multiple_area_lights.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light/storm_usd_renders/spot_light_adaptive_split.png
(Stored with Git LFS)
BIN
tests/files/render/light/storm_usd_renders/spot_light_adaptive_split.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light_linking/cycles_renders/shadow_link_clamp.png
(Stored with Git LFS)
BIN
tests/files/render/light_linking/cycles_renders/shadow_link_clamp.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light_linking/cycles_renders/shadow_link_transparency.png
(Stored with Git LFS)
BIN
tests/files/render/light_linking/cycles_renders/shadow_link_transparency.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light_linking/storm_usd_renders/light_link_hidden.png
(Stored with Git LFS)
BIN
tests/files/render/light_linking/storm_usd_renders/light_link_hidden.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light_linking/storm_usd_renders/light_link_instanced_receiver.png
(Stored with Git LFS)
BIN
tests/files/render/light_linking/storm_usd_renders/light_link_instanced_receiver.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light_linking/storm_usd_renders/light_link_simple.png
(Stored with Git LFS)
BIN
tests/files/render/light_linking/storm_usd_renders/light_link_simple.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light_linking/storm_usd_renders/light_link_simple_tree.png
(Stored with Git LFS)
BIN
tests/files/render/light_linking/storm_usd_renders/light_link_simple_tree.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light_linking/storm_usd_renders/shadow_link_clamp.png
(Stored with Git LFS)
BIN
tests/files/render/light_linking/storm_usd_renders/shadow_link_clamp.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light_linking/storm_usd_renders/shadow_link_simple_3D_curve.png
(Stored with Git LFS)
BIN
tests/files/render/light_linking/storm_usd_renders/shadow_link_simple_3D_curve.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light_linking/storm_usd_renders/shadow_link_simple_ribbon_curve.png
(Stored with Git LFS)
BIN
tests/files/render/light_linking/storm_usd_renders/shadow_link_simple_ribbon_curve.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light_linking/storm_usd_renders/shadow_link_transparency.png
(Stored with Git LFS)
BIN
tests/files/render/light_linking/storm_usd_renders/shadow_link_transparency.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/light_linking/storm_usd_renders/shadow_link_volume.png
(Stored with Git LFS)
BIN
tests/files/render/light_linking/storm_usd_renders/shadow_link_volume.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/openvdb/cycles_renders/smoke_color.png
(Stored with Git LFS)
BIN
tests/files/render/openvdb/cycles_renders/smoke_color.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/openvdb/storm_usd_renders/smoke_color.png
(Stored with Git LFS)
BIN
tests/files/render/openvdb/storm_usd_renders/smoke_color.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/principled_bsdf/storm_usd_renders/principled_bsdf_default.png
(Stored with Git LFS)
BIN
tests/files/render/principled_bsdf/storm_usd_renders/principled_bsdf_default.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/principled_bsdf/storm_usd_renders/principled_bsdf_emission_alpha.png
(Stored with Git LFS)
BIN
tests/files/render/principled_bsdf/storm_usd_renders/principled_bsdf_emission_alpha.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/shader/storm_usd_renders/diffuse_normal_map.png
(Stored with Git LFS)
BIN
tests/files/render/shader/storm_usd_renders/diffuse_normal_map.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/volume/storm_usd_renders/principled_absorption.png
(Stored with Git LFS)
BIN
tests/files/render/volume/storm_usd_renders/principled_absorption.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/volume/storm_usd_renders/volume_overlap.png
(Stored with Git LFS)
BIN
tests/files/render/volume/storm_usd_renders/volume_overlap.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/volume/storm_usd_renders/volume_step_offset.png
(Stored with Git LFS)
BIN
tests/files/render/volume/storm_usd_renders/volume_step_offset.png
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/render/volume/storm_usd_renders/world_volume.png
(Stored with Git LFS)
BIN
tests/files/render/volume/storm_usd_renders/world_volume.png
(Stored with Git LFS)
Binary file not shown.
Reference in New Issue
Block a user