diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 3e4009a112f..37a524c6399 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1533,8 +1533,30 @@ class CYCLES_LIGHT_PT_light(CyclesButtonsPanel, Panel): layout.row().prop(light, "type") col = layout.column() + heading = col.column(align=True, heading="Temperature") + row = heading.column(align=True).row(align=True) + row.prop(light, "use_temperature", text="") + # Don't show color preview for now, it is grayed out so the color + # is not accurate. Would not a change in the UI code to allow + # non-editable colors to be displayed as is. + if False: # light.use_temperature: + sub = row.split(factor=0.7, align=True) + sub.active = light.use_temperature + sub.prop(light, "temperature", text="") + sub.prop(light, "temperature_color", text="") + else: + sub = row.row() + sub.active = light.use_temperature + sub.prop(light, "temperature", text="") - col.prop(light, "color") + if light.use_temperature: + col.prop(light, "color", text="Tint") + else: + col.prop(light, "color", text="Color") + + layout.separator() + + col = layout.column() col.prop(light, "energy") col.prop(light, "exposure") @@ -1556,6 +1578,7 @@ class CYCLES_LIGHT_PT_light(CyclesButtonsPanel, Panel): sub.prop(light, "size", text="Size X") sub.prop(light, "size_y", text="Y") + class CYCLES_LIGHT_PT_settings(CyclesButtonsPanel, Panel): bl_label = "Settings" bl_context = "data" diff --git a/intern/cycles/blender/light.cpp b/intern/cycles/blender/light.cpp index d45df482bbf..99a7cc80504 100644 --- a/intern/cycles/blender/light.cpp +++ b/intern/cycles/blender/light.cpp @@ -4,6 +4,10 @@ #include "scene/light.h" +#include "DNA_light_types.h" + +#include "IMB_colormanagement.hh" + #include "blender/sync.h" #include "blender/util.h" #include "scene/object.h" @@ -74,9 +78,14 @@ void BlenderSync::sync_light(BObjectInfo &b_ob_info, Light *light) } } - /* strength */ - const float3 strength = get_float3(b_light.color()) * - (BL::PointLight(b_light).energy() * exp2f(b_light.exposure())); + /* Color and strength. */ + float3 light_color = get_float3(b_light.color()); + if (b_light.use_temperature()) { + light_color *= get_float3(b_light.temperature_color()); + } + + const float3 strength = 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 d211d4cfaf1..99c9ce28c3f 100644 --- a/scripts/addons_core/hydra_storm/ui.py +++ b/scripts/addons_core/hydra_storm/ui.py @@ -167,8 +167,19 @@ class STORM_HYDRA_LIGHT_PT_light(Panel): layout.use_property_decorate = False main_col = layout.column() + heading = main_col.column(align=True, heading="Temperature") + row = heading.column(align=True).row(align=True) + row.prop(light, "use_temperature", text="") + sub = row.row() + sub.active = light.use_temperature + sub.prop(light, "temperature", text="") - main_col.prop(light, "color") + if light.use_temperature: + main_col.prop(light, "color", text="Tint") + else: + main_col.prop(light, "color", text="Color") + + main_col = layout.column() main_col.prop(light, "energy") main_col.prop(light, "exposure") main_col.separator() 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 ec26a9099be..2d1781eca69 100644 --- a/scripts/addons_core/io_scene_fbx/export_fbx_bin.py +++ b/scripts/addons_core/io_scene_fbx/export_fbx_bin.py @@ -603,12 +603,18 @@ 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) + color = lamp.color + if lamp.use_temperature: + temperature_color = lamp.temperature_color + color[0] *= temperature_color[0] + color[1] *= temperature_color[1] + color[2] *= temperature_color[2] 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_color", b"Color", color) 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 diff --git a/scripts/startup/bl_ui/properties_data_light.py b/scripts/startup/bl_ui/properties_data_light.py index 1c1dc4c2c54..6d291ee2337 100644 --- a/scripts/startup/bl_ui/properties_data_light.py +++ b/scripts/startup/bl_ui/properties_data_light.py @@ -89,7 +89,30 @@ class DATA_PT_EEVEE_light(DataButtonsPanel, Panel): layout.row().prop(light, "type") col = layout.column() - col.prop(light, "color") + heading = col.column(align=True, heading="Temperature") + row = heading.column(align=True).row(align=True) + row.prop(light, "use_temperature", text="") + # Don't show color preview for now, it is grayed out so the color + # is not accurate. Would not a change in the UI code to allow + # non-editable colors to be displayed as is. + if False: # light.use_temperature: + sub = row.split(factor=0.7, align=True) + sub.active = light.use_temperature + sub.prop(light, "temperature", text="") + sub.prop(light, "temperature_color", text="") + else: + sub = row.row() + sub.active = light.use_temperature + sub.prop(light, "temperature", text="") + + if light.use_temperature: + col.prop(light, "color", text="Tint") + else: + col.prop(light, "color", text="Color") + + layout.separator() + + col = layout.column() col.prop(light, "energy") col.prop(light, "exposure") diff --git a/source/blender/blenkernel/BKE_light.h b/source/blender/blenkernel/BKE_light.h index 0d4fd85ea05..0897207ffc8 100644 --- a/source/blender/blenkernel/BKE_light.h +++ b/source/blender/blenkernel/BKE_light.h @@ -10,11 +10,15 @@ */ #include "BLI_compiler_attrs.h" +#include "BLI_math_vector_types.hh" struct Depsgraph; struct Light; struct Main; -struct Light *BKE_light_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT; +Light *BKE_light_add(Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT; -void BKE_light_eval(struct Depsgraph *depsgraph, struct Light *la); +void BKE_light_eval(Depsgraph *depsgraph, Light *la); + +float BKE_light_power(const Light &light); +blender::float3 BKE_light_color(const Light &light); diff --git a/source/blender/blenkernel/intern/light.cc b/source/blender/blenkernel/intern/light.cc index eca1ca87477..f91321b8abd 100644 --- a/source/blender/blenkernel/intern/light.cc +++ b/source/blender/blenkernel/intern/light.cc @@ -33,6 +33,8 @@ #include "DEG_depsgraph.hh" +#include "IMB_colormanagement.hh" + #include "BLO_read_write.hh" static void light_init_data(ID *id) @@ -199,3 +201,21 @@ void BKE_light_eval(Depsgraph *depsgraph, Light *la) { DEG_debug_print_eval(depsgraph, __func__, la->id.name, la); } + +float BKE_light_power(const Light &light) +{ + return light.energy * exp2f(light.exposure); +} + +blender::float3 BKE_light_color(const Light &light) +{ + blender::float3 color(&light.r); + + if (light.mode & LA_USE_TEMPERATURE) { + float temperature_color[4]; + IMB_colormanagement_blackbody_temperature_to_rgb(temperature_color, light.temperature); + color *= blender::float3(temperature_color); + } + + return color; +} diff --git a/source/blender/blenloader/intern/versioning_450.cc b/source/blender/blenloader/intern/versioning_450.cc index 4ab0d203d4a..923356c0f49 100644 --- a/source/blender/blenloader/intern/versioning_450.cc +++ b/source/blender/blenloader/intern/versioning_450.cc @@ -13,6 +13,7 @@ #include "DNA_anim_types.h" #include "DNA_brush_types.h" #include "DNA_defaults.h" +#include "DNA_light_types.h" #include "DNA_mesh_types.h" #include "DNA_sequence_types.h" @@ -5557,6 +5558,14 @@ void blo_do_versions_450(FileData * /*fd*/, Library * /*lib*/, Main *bmain) FOREACH_NODETREE_END; } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 76)) { + LISTBASE_FOREACH (Light *, light, &bmain->lights) { + if (light->temperature == 0.0f) { + light->temperature = 6500.0f; + } + } + } + /* Always run this versioning (keep at the bottom of the function). Meshes are written with the * legacy format which always needs to be converted to the new format on file load. To be moved * to a subversion check in 5.0. */ diff --git a/source/blender/draw/engines/eevee/eevee_light.cc b/source/blender/draw/engines/eevee/eevee_light.cc index 4e309ea616d..cf2116a0fbe 100644 --- a/source/blender/draw/engines/eevee/eevee_light.cc +++ b/source/blender/draw/engines/eevee/eevee_light.cc @@ -14,11 +14,11 @@ #include "eevee_light.hh" -#include "BLI_math_rotation.h" - #include "DNA_defaults.h" #include "DNA_sdna_type_ids.hh" +#include "BKE_light.h" + namespace blender::eevee { /* Convert by putting the least significant bits in the first component. */ @@ -68,7 +68,7 @@ void Light::sync(ShadowModule &shadows, shadow_discard_safe(shadows); } - this->color = float3(&la->r) * (la->energy * exp2f(la->exposure)); + this->color = BKE_light_power(*la) * BKE_light_color(*la); 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 0631eba619a..81600ef1337 100644 --- a/source/blender/io/collada/LightExporter.cpp +++ b/source/blender/io/collada/LightExporter.cpp @@ -14,6 +14,8 @@ #include "LightExporter.h" #include "collada_internal.h" +#include "BKE_light.h" + template void forEachLightObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set) { @@ -46,8 +48,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)); - const float energy = la->energy * exp2f(la->exposure); - COLLADASW::Color col(la->r * energy, la->g * energy, la->b * energy); + const blender::float3 color = BKE_light_power(*la) * BKE_light_color(*la); + COLLADASW::Color col(color[0], color[1], color[2]); /* 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 d92a3bd514c..4fdde741935 100644 --- a/source/blender/io/usd/hydra/light.cc +++ b/source/blender/io/usd/hydra/light.cc @@ -10,6 +10,8 @@ #include "DNA_light_types.h" +#include "IMB_colormanagement.hh" + #include "BLI_math_rotation.h" #include "hydra_scene_delegate.hh" @@ -84,9 +86,13 @@ void LightData::init() intensity = light->energy / M_PI; } + pxr::GfVec3f color(light->r, light->g, light->b); + data_[pxr::HdLightTokens->color] = color; // We multiply the Temperature by 1 + data_[pxr::HdLightTokens->enableColorTemperature] = (light->mode & LA_USE_TEMPERATURE) != 0; + data_[pxr::HdLightTokens->colorTemperature] = light->temperature; + data_[pxr::HdLightTokens->intensity] = intensity; 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; data_[pxr::HdLightTokens->normalize] = true; diff --git a/source/blender/io/usd/intern/usd_reader_light.cc b/source/blender/io/usd/intern/usd_reader_light.cc index 56cc8682270..e0cb1176e12 100644 --- a/source/blender/io/usd/intern/usd_reader_light.cc +++ b/source/blender/io/usd/intern/usd_reader_light.cc @@ -9,6 +9,8 @@ #include "BKE_light.h" #include "BKE_object.hh" +#include "IMB_colormanagement.hh" + #include "DNA_light_types.h" #include "DNA_object_types.h" @@ -175,6 +177,23 @@ void USDLightReader::read_object_data(Main *bmain, const double motionSampleTime } } + /* Temperature */ + if (pxr::UsdAttribute enable_temperature_attr = light_api.GetEnableColorTemperatureAttr()) { + bool enable_temperature = false; + if (enable_temperature_attr.Get(&enable_temperature, motionSampleTime)) { + if (enable_temperature) { + blight->mode |= LA_USE_TEMPERATURE; + } + } + } + + if (pxr::UsdAttribute color_temperature_attr = light_api.GetColorTemperatureAttr()) { + float color_temperature = 6500.0f; + if (color_temperature_attr.Get(&color_temperature, motionSampleTime)) { + blight->temperature = color_temperature; + } + } + /* Diffuse and Specular. */ if (pxr::UsdAttribute diff_attr = light_api.GetDiffuseAttr()) { float diff_fac = 1.0f; @@ -200,11 +219,6 @@ void USDLightReader::read_object_data(Main *bmain, const double motionSampleTime blight->energy *= light_surface_area; } - /* TODO: - * bool GetEnableColorTemperatureAttr - * float GetColorTemperatureAttr - */ - USDXformReader::read_object_data(bmain, motionSampleTime); } diff --git a/source/blender/io/usd/intern/usd_writer_light.cc b/source/blender/io/usd/intern/usd_writer_light.cc index d4a644dc703..0e0e62a0a1a 100644 --- a/source/blender/io/usd/intern/usd_writer_light.cc +++ b/source/blender/io/usd/intern/usd_writer_light.cc @@ -146,10 +146,21 @@ void USDLightWriter::do_write(HierarchyContext &context) light->exposure, timecode, usd_value_writer_); + set_attribute(usd_light_api.CreateColorAttr(pxr::VtValue(), true), pxr::GfVec3f(light->r, light->g, light->b), timecode, usd_value_writer_); + set_attribute(usd_light_api.CreateEnableColorTemperatureAttr( + pxr::VtValue(), (light->mode & LA_USE_TEMPERATURE) != 0), + true, + timecode, + usd_value_writer_); + set_attribute(usd_light_api.CreateColorTemperatureAttr(pxr::VtValue(), true), + light->temperature, + timecode, + usd_value_writer_); + set_attribute(usd_light_api.CreateDiffuseAttr(pxr::VtValue(), true), light->diff_fac, timecode, diff --git a/source/blender/makesdna/DNA_light_defaults.h b/source/blender/makesdna/DNA_light_defaults.h index 1d456dd7da2..6c95c44953b 100644 --- a/source/blender/makesdna/DNA_light_defaults.h +++ b/source/blender/makesdna/DNA_light_defaults.h @@ -19,6 +19,7 @@ .r = 1.0f, \ .g = 1.0f, \ .b = 1.0f, \ + .temperature = 6500.0f, \ .energy = 10.0f, \ .energy_deprecated = 10.0f, \ .spotsize = DEG2RADF(45.0f), \ diff --git a/source/blender/makesdna/DNA_light_types.h b/source/blender/makesdna/DNA_light_types.h index f5449ca7527..bb848e15823 100644 --- a/source/blender/makesdna/DNA_light_types.h +++ b/source/blender/makesdna/DNA_light_types.h @@ -34,11 +34,11 @@ typedef struct Light { short type, flag; int mode; - /* Color and energy. */ + /* Color, temperature and energy. */ float r, g, b; + float temperature; float energy; float exposure; - float _pad3; /* Point light. */ float radius; @@ -144,6 +144,7 @@ enum { /** Use absolute resolution clamping instead of relative. */ LA_SHAD_RES_ABSOLUTE = 1 << 22, LA_SHADOW_JITTER = 1 << 23, + LA_USE_TEMPERATURE = 1 << 24, }; /** #Light::falloff_type */ diff --git a/source/blender/makesrna/intern/rna_define.cc b/source/blender/makesrna/intern/rna_define.cc index 2455a4184ba..71aa8acc60e 100644 --- a/source/blender/makesrna/intern/rna_define.cc +++ b/source/blender/makesrna/intern/rna_define.cc @@ -1714,7 +1714,7 @@ void RNA_def_property_ui_range( DefRNA.error = true; } - if (step < 0 || step > 100) { + if (step < 0 || step > 1000) { CLOG_ERROR(&LOG, "\"%s.%s\", step outside range.", srna->identifier, prop->identifier); DefRNA.error = true; } diff --git a/source/blender/makesrna/intern/rna_light.cc b/source/blender/makesrna/intern/rna_light.cc index e65db70015d..c762009d596 100644 --- a/source/blender/makesrna/intern/rna_light.cc +++ b/source/blender/makesrna/intern/rna_light.cc @@ -14,10 +14,13 @@ #include "RNA_define.hh" #include "RNA_enum_types.hh" +#include "RNA_types.hh" #include "rna_internal.hh" #include "DNA_light_types.h" +#include "IMB_colormanagement.hh" + #ifdef RNA_RUNTIME # include "MEM_guardedalloc.h" @@ -77,6 +80,18 @@ static void rna_Light_use_nodes_update(bContext *C, PointerRNA *ptr) rna_Light_update(CTX_data_main(C), CTX_data_scene(C), ptr); } +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); + + color[0] = rgb[0]; + color[1] = rgb[1]; + color[2] = rgb[2]; +} + #else /* NOTE(@dingto): Don't define icons here, @@ -109,6 +124,13 @@ static void rna_def_light(BlenderRNA *brna) RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_LIGHT); RNA_def_property_update(prop, 0, "rna_Light_draw_update"); + prop = RNA_def_property(srna, "use_temperature", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, nullptr, "mode", LA_USE_TEMPERATURE); + RNA_def_property_ui_text( + prop, "Use Temperature", "Use blackbody temperature to define a natural light color"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_LIGHT); + RNA_def_property_update(prop, 0, "rna_Light_draw_update"); + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, nullptr, "r"); RNA_def_property_array(prop, 3); @@ -116,6 +138,20 @@ static void rna_def_light(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Color", "Light color"); RNA_def_property_update(prop, 0, "rna_Light_draw_update"); + prop = RNA_def_property(srna, "temperature", PROP_FLOAT, PROP_TEMPERATURE); + RNA_def_property_float_sdna(prop, nullptr, "temperature"); + RNA_def_property_range(prop, 800.0f, 20000.0f); + RNA_def_property_ui_range(prop, 800.0f, 20000.0f, 400.0f, 1); + RNA_def_property_ui_text(prop, "Temperature", "Light color temperature in Kelvin"); + RNA_def_property_update(prop, 0, "rna_Light_update"); + + prop = RNA_def_property(srna, "temperature_color", PROP_FLOAT, PROP_COLOR); + RNA_def_property_array(prop, 3); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_float_funcs(prop, "rna_Light_temperature_color_get", nullptr, nullptr); + RNA_def_property_ui_text(prop, "Temperature Color", "Color from Temperature"); + RNA_def_property_update(prop, 0, "rna_Light_draw_update"); + prop = RNA_def_property(srna, "specular_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, nullptr, "spec_fac"); RNA_def_property_range(prop, 0.0f, FLT_MAX); @@ -211,7 +247,7 @@ static void rna_def_light_energy(StructRNA *srna, const short light_type) /* Lights with a location have radiometric ppower in Watts, * which is sensitive to scene unit scale. */ prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_NONE); - RNA_def_property_ui_range(prop, 0.0f, 1000000.0f, 10, 5); + RNA_def_property_ui_range(prop, 0.0f, 1000000.0f, 10, 3); RNA_def_property_ui_text( prop, "Power", @@ -225,7 +261,7 @@ static void rna_def_light_energy(StructRNA *srna, const short light_type) /* Lights with a location have radiometric power in Watts, * which is sensitive to scene unit scale. */ prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_NONE); - RNA_def_property_ui_range(prop, 0.0f, 1000000.0f, 10, 5); + RNA_def_property_ui_range(prop, 0.0f, 1000000.0f, 10, 3); RNA_def_property_ui_text(prop, "Power", "Light energy emitted over the entire area of the light in all "