Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2021-03-19 14:07:23 +0300
committerClément Foucault <foucault.clem@gmail.com>2021-03-19 23:11:06 +0300
commit884f934a853f7043a7e5a6ea380d560c858a78b7 (patch)
tree14c4441579169bcc50de145d24dbff5ab206200a /source/blender/draw
parentfb3e5b7f986e7215c6488c2b93db8559e84cfb98 (diff)
EEVEE: Lights: Add Volume and diffuse light power slider
This adds 2 new sliders for light objects that modulates the diffuse light and the volume light intensities. This also changes the way volume light is computed using point lamp representation. We use "Point Light Attenuation Without Singularity" from Cem Yuksel instead of the usual inverse square law.
Diffstat (limited to 'source/blender/draw')
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c39
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h3
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lights_lib.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl51
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl2
7 files changed, 69 insertions, 41 deletions
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);