diff --git a/release/scripts/startup/bl_ui/properties_data_light.py b/release/scripts/startup/bl_ui/properties_data_light.py index cf894b48e1e..d5e0ecd9a4f 100644 --- a/release/scripts/startup/bl_ui/properties_data_light.py +++ b/release/scripts/startup/bl_ui/properties_data_light.py @@ -97,7 +97,12 @@ class DATA_PT_EEVEE_light(DataButtonsPanel, Panel): col = layout.column() col.prop(light, "color") col.prop(light, "energy") + + col.separator() + + col.prop(light, "diffuse_factor", text="Diffuse") col.prop(light, "specular_factor", text="Specular") + col.prop(light, "volume_factor", text="Volume") col.separator() diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index bf70a50631f..a4a16acf1d1 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -36,6 +36,7 @@ #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_hair_types.h" +#include "DNA_light_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" @@ -1915,5 +1916,12 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) */ { /* Keep this block, even when empty. */ + + if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "diff_fac")) { + LISTBASE_FOREACH (Light *, light, &bmain->lights) { + light->diff_fac = 1.0f; + light->volume_fac = 1.0f; + } + } } } diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index b773049f6f7..146dbc8fc28 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -50,7 +50,7 @@ static float light_attenuation_radius_get(const Light *la, float light_threshold /* Compute max light power. */ float power = max_fff(la->r, la->g, la->b); power *= fabsf(la->energy / 100.0f); - power *= max_ff(1.0f, la->spec_fac); + power *= max_fff(la->diff_fac, la->spec_fac, la->volume_fac); /* Compute the distance (using the inverse square law) * at which the light power reaches the light_threshold. */ float distance = sqrtf(max_ff(1e-16, power / max_ff(1e-16, light_threshold))); @@ -75,6 +75,8 @@ static void light_shape_parameters_set(EEVEE_Light *evli, const Light *la, const else { evli->sizey = max_ff(0.003f, la->area_size * scale[1] * 0.5f); } + /* For volume point lighting. */ + evli->radius = max_ff(0.001f, hypotf(evli->sizex, evli->sizey)); } else if (la->type == LA_SUN) { evli->radius = max_ff(0.001f, tanf(min_ff(la->sun_angle, DEG2RADF(179.9f)) / 2.0f)); @@ -103,8 +105,8 @@ static float light_shape_power_get(const Light *la, const EEVEE_Light *evli) /* for point lights (a.k.a radius == 0.0) */ // power = M_PI * M_PI * 0.78; /* XXX : Empirical, Fit cycles power */ } - else { - power = 1.0f / (evli->radius * evli->radius * M_PI); /* 1/(r²*Pi) */ + else { /* LA_SUN */ + power = 1.0f / (evli->radius * evli->radius * M_PI); /* Make illumination power closer to cycles for bigger radii. Cycles uses a cos^3 term that we * cannot reproduce so we account for that by scaling the light power. This function is the * result of a rough manual fitting. */ @@ -113,11 +115,30 @@ static float light_shape_power_get(const Light *la, const EEVEE_Light *evli) return power; } +static float light_shape_power_volume_get(const Light *la, float area_power) +{ + /* Volume light is evaluated as point lights. Remove the shape power. */ + float power = 1.0f / area_power; + /* Make illumination power constant */ + if (la->type == LA_AREA) { + /* Match cycles. Empirical fit... must correspond to some constant. */ + power *= 0.0792f * M_PI; + } + else if (ELEM(la->type, LA_SPOT, LA_LOCAL)) { + /* Match cycles. Empirical fit... must correspond to some constant. */ + power *= 0.0792f; + } + else { /* LA_SUN */ + /* Nothing to do. */ + } + return power; +} + /* Update buffer with light data */ static void eevee_light_setup(Object *ob, EEVEE_Light *evli) { - Light *la = (Light *)ob->data; - float mat[4][4], scale[3], power, att_radius; + const Light *la = (Light *)ob->data; + float mat[4][4], scale[3], att_radius; const DRWContextState *draw_ctx = DRW_context_state_get(); const float light_threshold = draw_ctx->scene->eevee.light_threshold; @@ -128,7 +149,9 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli) /* Color */ copy_v3_v3(evli->color, &la->r); + evli->diff = la->diff_fac; evli->spec = la->spec_fac; + evli->volume = la->volume_fac; /* Influence Radius */ att_radius = light_attenuation_radius_get(la, light_threshold); @@ -163,8 +186,10 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli) evli->light_type = LAMPTYPE_AREA_ELLIPSE; } - power = light_shape_power_get(la, evli); - mul_v3_fl(evli->color, power * la->energy); + float shape_power = light_shape_power_get(la, evli); + mul_v3_fl(evli->color, shape_power * la->energy); + + evli->volume *= light_shape_power_volume_get(la, shape_power); /* No shadow by default */ evli->shadow_id = -1.0f; diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index e98ba4136ed..ca10e01e3f5 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -484,11 +484,12 @@ typedef struct EEVEE_RenderPassData { /* ************ LIGHT UBO ************* */ typedef struct EEVEE_Light { float position[3], invsqrdist; - float color[3], spec; + float color[3], invsqrdist_volume; float spotsize, spotblend, radius, shadow_id; float rightvec[3], sizex; float upvec[3], sizey; float forwardvec[3], light_type; + float diff, spec, volume, _pad0[1]; } EEVEE_Light; /* Special type for elliptic area lights, matches lamps_lib.glsl */ diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl index c5996f5160a..4f9791ac95f 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl @@ -45,7 +45,8 @@ void closure_Diffuse_light_eval(ClosureInputDiffuse cl_in, float radiance = light_diffuse(light.data, cl_in.N, cl_common.V, light.L); /* TODO(fclem) We could try to shadow lights that are shadowless with the ambient_occlusion * factor here. */ - cl_out.radiance += light.data.l_color * (light.vis * light.contact_shadow * radiance); + cl_out.radiance += light.data.l_color * + (light.data.l_diff * light.vis * light.contact_shadow * radiance); } void closure_Diffuse_grid_eval(ClosureInputDiffuse cl_in, diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl index 66c467af29b..183219c9088 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl @@ -32,7 +32,7 @@ void closure_Translucent_light_eval(ClosureInputTranslucent cl_in, inout ClosureOutputTranslucent cl_out) { float radiance = light_diffuse(light.data, cl_in.N, cl_common.V, light.L); - cl_out.radiance += light.data.l_color * (light.vis * radiance); + cl_out.radiance += light.data.l_color * (light.data.l_diff * light.vis * radiance); } void closure_Translucent_grid_eval(ClosureInputTranslucent cl_in, diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl index 87934027361..d2daa5a1092 100644 --- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl @@ -14,18 +14,22 @@ struct LightData { vec4 position_influence; /* w : InfluenceRadius (inversed and squared) */ - vec4 color_spec; /* w : Spec Intensity */ + vec4 color_influence_volume; /* w : InfluenceRadius but for Volume power */ vec4 spotdata_radius_shadow; /* x : spot size, y : spot blend, z : radius, w: shadow id */ vec4 rightvec_sizex; /* xyz: Normalized up vector, w: area size X or spot scale X */ vec4 upvec_sizey; /* xyz: Normalized right vector, w: area size Y or spot scale Y */ vec4 forwardvec_type; /* xyz: Normalized forward vector, w: Light Type */ + vec4 diff_spec_volume; /* xyz: Diffuse/Spec/Volume power, w: unused. */ }; /* convenience aliases */ -#define l_color color_spec.rgb -#define l_spec color_spec.a +#define l_color color_influence_volume.rgb +#define l_diff diff_spec_volume.x +#define l_spec diff_spec_volume.y +#define l_volume diff_spec_volume.z #define l_position position_influence.xyz #define l_influence position_influence.w +#define l_influence_volume color_influence_volume.w #define l_sizex rightvec_sizex.w #define l_sizey upvec_sizey.w #define l_right rightvec_sizex.xyz diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl index b1e3a40e8d2..5b747d66e4d 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl @@ -64,38 +64,35 @@ float phase_function(vec3 v, vec3 l, float g) vec3 light_volume(LightData ld, vec4 l_vector) { - float power; - /* TODO : Area lighting ? */ - /* XXX : Removing Area Power. */ - /* TODO : put this out of the shader. */ - /* See eevee_light_setup(). */ - if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) { - power = (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0); - if (ld.l_type == AREA_ELLIPSE) { - power *= M_PI * 0.25; + float power = 1.0; + if (ld.l_type != SUN) { + /** + * Using "Point Light Attenuation Without Singularity" from Cem Yuksel + * http://www.cemyuksel.com/research/pointlightattenuation/pointlightattenuation.pdf + * http://www.cemyuksel.com/research/pointlightattenuation/ + **/ + float d = l_vector.w; + float d_sqr = sqr(d); + float r_sqr = sqr(ld.l_radius); + /* Using reformulation that has better numerical percision. */ + power = 2.0 / (d_sqr + r_sqr + d * sqrt(d_sqr + r_sqr)); + + if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) { + /* Modulate by light plane orientation / solid angle. */ + power *= saturate(dot(-ld.l_forward, l_vector.xyz / l_vector.w)); } - power *= 20.0 * - max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */ } - else if (ld.l_type == SUN) { - power = ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/ - power /= 1.0f + (ld.l_radius * ld.l_radius * 0.5f); - power *= M_PI * 0.5; /* Matching cycles. */ + return ld.l_color * ld.l_volume * power; +} + +vec3 light_volume_light_vector(LightData ld, vec3 P) +{ + if (ld.l_type == SUN) { + return -ld.l_forward; } else { - power = (4.0 * ld.l_radius * ld.l_radius) * (1.0 / 10.0); - power *= M_2PI; /* Matching cycles with point light. */ + return ld.l_position - P; } - - power /= (l_vector.w * l_vector.w); - - /* OPTI: find a better way than calculating this on the fly */ - float lum = dot(ld.l_color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */ - vec3 tint = (lum > 0.0) ? ld.l_color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */ - - lum = min(lum * power, volLightClamp); - - return tint * lum; } #define VOLUMETRIC_SHADOW_MAX_STEP 128.0 diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl index e72bf8b9150..f75108babe6 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl @@ -44,7 +44,7 @@ void main() LightData ld = lights_data[i]; vec4 l_vector; - l_vector.xyz = (ld.l_type == SUN) ? -ld.l_forward : ld.l_position - P; + l_vector.xyz = light_volume_light_vector(ld, P); l_vector.w = length(l_vector.xyz); float Vis = light_visibility(ld, P, l_vector); diff --git a/source/blender/makesdna/DNA_light_defaults.h b/source/blender/makesdna/DNA_light_defaults.h index 6ac52c1b356..f3ccf14ac5b 100644 --- a/source/blender/makesdna/DNA_light_defaults.h +++ b/source/blender/makesdna/DNA_light_defaults.h @@ -63,7 +63,9 @@ .contact_bias = 0.03f, \ .contact_spread = 0.2f, \ .contact_thickness = 0.2f, \ + .diff_fac = 1.0f, \ .spec_fac = 1.0f, \ + .volume_fac = 1.0f, \ .att_dist = 40.0f, \ .sun_angle = DEG2RADF(0.526f), \ } diff --git a/source/blender/makesdna/DNA_light_types.h b/source/blender/makesdna/DNA_light_types.h index 9ca75347d23..3b7440aedd2 100644 --- a/source/blender/makesdna/DNA_light_types.h +++ b/source/blender/makesdna/DNA_light_types.h @@ -93,6 +93,7 @@ typedef struct Light { float contact_spread; /* DEPRECATED kept for compatibility. */ float contact_thickness; + float diff_fac, volume_fac; float spec_fac, att_dist; /* preview */ diff --git a/source/blender/makesrna/intern/rna_light.c b/source/blender/makesrna/intern/rna_light.c index 52ebd5af993..bb99e5c6c1d 100644 --- a/source/blender/makesrna/intern/rna_light.c +++ b/source/blender/makesrna/intern/rna_light.c @@ -150,11 +150,25 @@ static void rna_def_light(BlenderRNA *brna) prop = RNA_def_property(srna, "specular_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "spec_fac"); - RNA_def_property_range(prop, 0.0f, 9999.0f); + RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 2); RNA_def_property_ui_text(prop, "Specular Factor", "Specular reflection multiplier"); RNA_def_property_update(prop, 0, "rna_Light_update"); + prop = RNA_def_property(srna, "diffuse_factor", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "diff_fac"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 2); + RNA_def_property_ui_text(prop, "Diffuse Factor", "Diffuse reflection multiplier"); + RNA_def_property_update(prop, 0, "rna_Light_update"); + + prop = RNA_def_property(srna, "volume_factor", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "volume_fac"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 2); + RNA_def_property_ui_text(prop, "Volume Factor", "Volume light multiplier"); + RNA_def_property_update(prop, 0, "rna_Light_update"); + prop = RNA_def_property(srna, "use_custom_distance", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_CUSTOM_ATTENUATION); RNA_def_property_ui_text(prop,