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>2019-08-22 17:04:25 +0300
committerClément Foucault <foucault.clem@gmail.com>2019-09-05 18:37:50 +0300
commitd8aaf25c23fa10ee121dc4fdd1cafe544bcca355 (patch)
treeb5a16157beac22e4b474c699c1ce25f3d8c5be51 /source/blender/draw/engines/eevee/shaders/lights_lib.glsl
parentca58936f2ff2b14a649722be20d98f8fa35831ff (diff)
Eevee: Shadow map refactor
Reviewed By: brecht Differential Revision: http://developer.blender.org/D5659
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders/lights_lib.glsl')
-rw-r--r--source/blender/draw/engines/eevee/shaders/lights_lib.glsl407
1 files changed, 126 insertions, 281 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
index c3643cccbfc..72017e971fc 100644
--- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
@@ -1,6 +1,6 @@
-uniform sampler2DArray shadowCubeTexture;
-uniform sampler2DArray shadowCascadeTexture;
+uniform sampler2DArrayShadow shadowCubeTexture;
+uniform sampler2DArrayShadow shadowCascadeTexture;
#define LAMPS_LIB
@@ -24,129 +24,115 @@ layout(std140) uniform light_block
/* Used to define the area light shape, doesn't directly correspond to a Blender light type. */
#define AREA_ELLIPSE 100.0
-#if defined(SHADOW_VSM)
-# define ShadowSample vec2
-# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).rg
-# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).rg
-#elif defined(SHADOW_ESM)
-# define ShadowSample float
-# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).r
-# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).r
-#else
-# define ShadowSample float
-# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).r
-# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).r
-#endif
-
-#if defined(SHADOW_VSM)
-# define get_depth_delta(dist, s) (dist - s.x)
-#else
-# define get_depth_delta(dist, s) (dist - s)
-#endif
-
- /* ----------------------------------------------------------- */
- /* ----------------------- Shadow tests ---------------------- */
- /* ----------------------------------------------------------- */
-
-#if defined(SHADOW_VSM)
-
-float shadow_test(ShadowSample moments, float dist, ShadowData sd)
+float cubeFaceIndexEEVEE(vec3 P)
{
- float p = 0.0;
-
- if (dist <= moments.x) {
- p = 1.0;
+ vec3 aP = abs(P);
+ if (all(greaterThan(aP.xx, aP.yz))) {
+ return (P.x > 0.0) ? 0.0 : 1.0;
+ }
+ else if (all(greaterThan(aP.yy, aP.xz))) {
+ return (P.y > 0.0) ? 2.0 : 3.0;
+ }
+ else {
+ return (P.z > 0.0) ? 4.0 : 5.0;
}
-
- float variance = moments.y - (moments.x * moments.x);
- variance = max(variance, sd.sh_bias / 10.0);
-
- float d = moments.x - dist;
- float p_max = variance / (variance + d * d);
-
- /* Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] */
- p_max = clamp((p_max - sd.sh_bleed) / (1.0 - sd.sh_bleed), 0.0, 1.0);
-
- return max(p, p_max);
}
-#elif defined(SHADOW_ESM)
-
-float shadow_test(ShadowSample z, float dist, ShadowData sd)
+vec2 cubeFaceCoordEEVEE(vec3 P, float face, float scale)
{
- return saturate(exp(sd.sh_exp * (z - dist + sd.sh_bias)));
+ if (face < 2.0) {
+ return (P.zy / P.x) * scale * vec2(-0.5, -sign(P.x) * 0.5) + 0.5;
+ }
+ else if (face < 4.0) {
+ return (P.xz / P.y) * scale * vec2(sign(P.y) * 0.5, 0.5) + 0.5;
+ }
+ else {
+ return (P.xy / P.z) * scale * vec2(0.5, -sign(P.z) * 0.5) + 0.5;
+ }
}
-#else
-
-float shadow_test(ShadowSample z, float dist, ShadowData sd)
+vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArray tex)
{
- return step(0, z - dist + sd.sh_bias);
+ /* Scaling to compensate the 1px border around the face. */
+ float cube_res = float(textureSize(tex, 0).x);
+ float scale = (cube_res) / (cube_res + 1.0);
+ return cubeFaceCoordEEVEE(P, face, scale);
}
-#endif
-
-/* ----------------------------------------------------------- */
-/* ----------------------- Shadow types ---------------------- */
-/* ----------------------------------------------------------- */
-
-float shadow_cubemap(ShadowData sd, ShadowCubeData scd, float texid, vec3 W)
+vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArrayShadow tex)
{
- vec3 cubevec = W - scd.position.xyz;
- float dist = length(cubevec);
+ /* Scaling to compensate the 1px border around the face. */
+ float cube_res = float(textureSize(tex, 0).x);
+ float scale = (cube_res) / (cube_res + 1.0);
+ return cubeFaceCoordEEVEE(P, face, scale);
+}
- cubevec /= dist;
+vec4 sample_cube(sampler2DArray tex, vec3 cubevec, float cube)
+{
+ /* Manual Shadow Cube Layer indexing. */
+ /* TODO Shadow Cube Array. */
+ float face = cubeFaceIndexEEVEE(cubevec);
+ vec2 uv = cubeFaceCoordEEVEE(cubevec, face, tex);
- ShadowSample s = sample_cube(cubevec, texid);
- return shadow_test(s, dist, sd);
+ vec3 coord = vec3(uv, cube * 6.0 + face);
+ return texture(tex, coord);
}
-float evaluate_cascade(ShadowData sd, mat4 shadowmat, vec3 W, float range, float texid)
+vec4 sample_cascade(sampler2DArray tex, vec2 co, float cascade_id)
{
- vec4 shpos = shadowmat * vec4(W, 1.0);
- float dist = shpos.z * range;
+ return texture(tex, vec3(co, cascade_id));
+}
- ShadowSample s = sample_cascade(shpos.xy, texid);
- float vis = shadow_test(s, dist, sd);
+/* Some driver poorly optimize this code. Use direct reference to matrices. */
+#define sd(x) shadows_data[x]
+#define scube(x) shadows_cube_data[x]
+#define scascade(x) shadows_cascade_data[x]
- /* If fragment is out of shadowmap range, do not occlude */
- if (shpos.z < 1.0 && shpos.z > 0.0) {
- return vis;
- }
- else {
- return 1.0;
- }
+float sample_cube_shadow(int shadow_id, vec3 W)
+{
+ int data_id = int(sd(shadow_id).sh_data_index);
+ vec3 cubevec = transform_point(scube(data_id).shadowmat, W);
+ float dist = max_v3(abs(cubevec)) - sd(shadow_id).sh_bias;
+ dist = buffer_depth(true, dist, sd(shadow_id).sh_far, sd(shadow_id).sh_near);
+ /* Manual Shadow Cube Layer indexing. */
+ /* TODO Shadow Cube Array. */
+ float face = cubeFaceIndexEEVEE(cubevec);
+ vec2 coord = cubeFaceCoordEEVEE(cubevec, face, shadowCubeTexture);
+ /* tex_id == data_id for cube shadowmap */
+ float tex_id = float(data_id);
+ return texture(shadowCubeTexture, vec4(coord, tex_id * 6.0 + face, dist));
}
-float shadow_cascade(ShadowData sd, int scd_id, float texid, vec3 W)
+float sample_cascade_shadow(int shadow_id, vec3 W)
{
+ int data_id = int(sd(shadow_id).sh_data_index);
+ float tex_id = scascade(data_id).sh_tex_index;
vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
- vec4 weights = smoothstep(shadows_cascade_data[scd_id].split_end_distances,
- shadows_cascade_data[scd_id].split_start_distances.yzwx,
- view_z);
-
- weights.yzw -= weights.xyz;
-
- vec4 vis = vec4(1.0);
- float range = abs(sd.sh_far - sd.sh_near); /* Same factor as in get_cascade_world_distance(). */
-
- /* Branching using (weights > 0.0) is reaally slooow on intel so avoid it for now. */
- /* TODO OPTI: Only do 2 samples and blend. */
- vis.x = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[0], W, range, texid + 0);
- vis.y = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[1], W, range, texid + 1);
- vis.z = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[2], W, range, texid + 2);
- vis.w = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[3], W, range, texid + 3);
-
- float weight_sum = dot(vec4(1.0), weights);
- if (weight_sum > 0.9999) {
- float vis_sum = dot(vec4(1.0), vis * weights);
- return vis_sum / weight_sum;
- }
- else {
- float vis_sum = dot(vec4(1.0), vis * step(0.001, weights));
- return mix(1.0, vis_sum, weight_sum);
- }
+ vec4 weights = 1.0 - smoothstep(scascade(data_id).split_end_distances,
+ scascade(data_id).split_start_distances.yzwx,
+ view_z);
+ float tot_weight = dot(weights.xyz, vec3(1.0));
+
+ int cascade = int(clamp(tot_weight, 0.0, 3.0));
+ float blend = fract(tot_weight);
+ float vis = weights.w;
+ vec4 coord, shpos;
+ /* Main cascade. */
+ shpos = scascade(data_id).shadowmat[cascade] * vec4(W, 1.0);
+ coord = vec4(shpos.xy, tex_id + float(cascade), shpos.z - sd(shadow_id).sh_bias);
+ vis += texture(shadowCascadeTexture, coord) * (1.0 - blend);
+
+ cascade = min(3, cascade + 1);
+ /* Second cascade. */
+ shpos = scascade(data_id).shadowmat[cascade] * vec4(W, 1.0);
+ coord = vec4(shpos.xy, tex_id + float(cascade), shpos.z - sd(shadow_id).sh_bias);
+ vis += texture(shadowCascadeTexture, coord) * blend;
+
+ return saturate(vis);
}
+#undef sd
+#undef scube
+#undef scsmd
/* ----------------------------------------------------------- */
/* --------------------- Light Functions --------------------- */
@@ -173,16 +159,9 @@ float spot_attenuation(LightData ld, vec3 l_vector)
return spotmask;
}
-float light_visibility(LightData ld,
- vec3 W,
-#ifndef VOLUMETRICS
- vec3 viewPosition,
- vec3 vN,
-#endif
- vec4 l_vector)
+float light_attenuation(LightData ld, vec4 l_vector)
{
float vis = 1.0;
-
if (ld.l_type == SPOT) {
vis *= spot_attenuation(ld, l_vector.xyz);
}
@@ -192,69 +171,66 @@ float light_visibility(LightData ld,
if (ld.l_type != SUN) {
vis *= distance_attenuation(l_vector.w * l_vector.w, ld.l_influence);
}
+ return vis;
+}
+
+float light_visibility(LightData ld,
+ vec3 W,
+#ifndef VOLUMETRICS
+ vec3 viewPosition,
+ float tracing_depth,
+ vec3 true_normal,
+ float rand_x,
+ const bool use_contact_shadows,
+#endif
+ vec4 l_vector)
+{
+ float vis = light_attenuation(ld, l_vector);
#if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW)
/* shadowing */
if (ld.l_shadowid >= 0.0 && vis > 0.001) {
- ShadowData data = shadows_data[int(ld.l_shadowid)];
if (ld.l_type == SUN) {
- vis *= shadow_cascade(data, int(data.sh_data_start), data.sh_tex_start, W);
+ vis *= sample_cascade_shadow(int(ld.l_shadowid), W);
}
else {
- vis *= shadow_cubemap(
- data, shadows_cube_data[int(data.sh_data_start)], data.sh_tex_start, W);
+ vis *= sample_cube_shadow(int(ld.l_shadowid), W);
}
# ifndef VOLUMETRICS
+ ShadowData sd = shadows_data[int(ld.l_shadowid)];
/* Only compute if not already in shadow. */
- if (data.sh_contact_dist > 0.0) {
- vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
- float trace_distance = (ld.l_type != SUN) ? min(data.sh_contact_dist, l_vector.w) :
- data.sh_contact_dist;
-
- vec3 T, B;
- make_orthonormal_basis(L.xyz / L.w, T, B);
-
- vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
- rand.zw *= fast_sqrt(rand.y) * data.sh_contact_spread;
-
- /* We use the full l_vector.xyz so that the spread is minimize
- * if the shading point is further away from the light source */
- vec3 ray_dir = L.xyz + T * rand.z + B * rand.w;
- ray_dir = transform_direction(ViewMatrix, ray_dir);
- ray_dir = normalize(ray_dir);
-
- vec3 ray_ori = viewPosition;
-
- /* Fix translucency shadowed by contact shadows. */
- vN = (gl_FrontFacing) ? vN : -vN;
-
- if (dot(vN, ray_dir) <= 0.0) {
- return vis;
+ if (use_contact_shadows && sd.sh_contact_dist > 0.0 && vis > 1e-8) {
+ /* Contact Shadows. */
+ vec3 ray_ori, ray_dir;
+ float trace_distance;
+
+ if (ld.l_type == SUN) {
+ trace_distance = sd.sh_contact_dist;
+ ray_dir = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec * trace_distance;
+ }
+ else {
+ ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - W;
+ float len = length(ray_dir);
+ trace_distance = min(sd.sh_contact_dist, len);
+ ray_dir *= trace_distance / len;
}
- float bias = 0.5; /* Constant Bias */
- bias += 1.0 - abs(dot(vN, ray_dir)); /* Angle dependent bias */
- bias *= gl_FrontFacing ? data.sh_contact_offset : -data.sh_contact_offset;
-
- vec3 nor_bias = vN * bias;
- ray_ori += nor_bias;
-
- ray_dir *= trace_distance;
- ray_dir -= nor_bias;
+ ray_dir = transform_direction(ViewMatrix, ray_dir);
+ ray_ori = vec3(viewPosition.xy, tracing_depth) + true_normal * sd.sh_contact_offset;
vec3 hit_pos = raycast(
- -1, ray_ori, ray_dir, data.sh_contact_thickness, rand.x, 0.1, 0.001, false);
+ -1, ray_ori, ray_dir, sd.sh_contact_thickness, rand_x, 0.1, 0.001, false);
if (hit_pos.z > 0.0) {
hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
float hit_dist = distance(viewPosition, hit_pos);
float dist_ratio = hit_dist / trace_distance;
- return vis * saturate(dist_ratio * dist_ratio * dist_ratio);
+ return vis * saturate(dist_ratio * 3.0 - 2.0);
}
}
-# endif
+# endif /* VOLUMETRICS */
}
#endif
@@ -325,134 +301,3 @@ float light_specular(LightData ld, vec4 ltc_mat, vec3 N, vec3 V, vec4 l_vector)
}
}
#endif
-
-#define MAX_SSS_SAMPLES 65
-#define SSS_LUT_SIZE 64.0
-#define SSS_LUT_SCALE ((SSS_LUT_SIZE - 1.0) / float(SSS_LUT_SIZE))
-#define SSS_LUT_BIAS (0.5 / float(SSS_LUT_SIZE))
-
-#ifdef USE_TRANSLUCENCY
-layout(std140) uniform sssProfile
-{
- vec4 kernel[MAX_SSS_SAMPLES];
- vec4 radii_max_radius;
- int sss_samples;
-};
-
-uniform sampler1D sssTexProfile;
-
-vec3 sss_profile(float s)
-{
- s /= radii_max_radius.w;
- return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb;
-}
-#endif
-
-vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale)
-{
-#if !defined(USE_TRANSLUCENCY) || defined(VOLUMETRICS)
- return vec3(0.0);
-#else
- vec3 vis = vec3(1.0);
-
- if (ld.l_type == SPOT) {
- vis *= spot_attenuation(ld, l_vector.xyz);
- }
- if (ld.l_type >= SPOT) {
- vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward));
- }
- if (ld.l_type != SUN) {
- vis *= distance_attenuation(l_vector.w * l_vector.w, ld.l_influence);
- }
-
- /* Only shadowed light can produce translucency */
- if (ld.l_shadowid >= 0.0 && vis.x > 0.001) {
- ShadowData data = shadows_data[int(ld.l_shadowid)];
- float delta;
-
- vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
-
- vec3 T, B;
- make_orthonormal_basis(L.xyz / L.w, T, B);
-
- vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
- rand.zw *= fast_sqrt(rand.y) * data.sh_blur;
-
- /* We use the full l_vector.xyz so that the spread is minimize
- * if the shading point is further away from the light source */
- W = W + T * rand.z + B * rand.w;
-
- if (ld.l_type == SUN) {
- int scd_id = int(data.sh_data_start);
- vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
-
- vec4 weights = step(shadows_cascade_data[scd_id].split_end_distances, view_z);
- float id = abs(4.0 - dot(weights, weights));
-
- if (id > 3.0) {
- return vec3(0.0);
- }
-
- /* Same factor as in get_cascade_world_distance(). */
- float range = abs(data.sh_far - data.sh_near);
-
- vec4 shpos = shadows_cascade_data[scd_id].shadowmat[int(id)] * vec4(W, 1.0);
- float dist = shpos.z * range;
-
- if (shpos.z > 1.0 || shpos.z < 0.0) {
- return vec3(0.0);
- }
-
- ShadowSample s = sample_cascade(shpos.xy, data.sh_tex_start + id);
- delta = get_depth_delta(dist, s);
- }
- else {
- vec3 cubevec = W - shadows_cube_data[int(data.sh_data_start)].position.xyz;
- float dist = length(cubevec);
- cubevec /= dist;
-
- ShadowSample s = sample_cube(cubevec, data.sh_tex_start);
- delta = get_depth_delta(dist, s);
- }
-
- /* XXX : Removing Area Power. */
- /* TODO : put this out of the shader. */
- float falloff;
- if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) {
- vis *= (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
- if (ld.l_type == AREA_ELLIPSE) {
- vis *= M_PI * 0.25;
- }
- vis *= 0.3 * 20.0 *
- max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
- vis /= (l_vector.w * l_vector.w);
- falloff = dot(N, l_vector.xyz / l_vector.w);
- }
- else if (ld.l_type == SUN) {
- vis /= 1.0f + (ld.l_radius * ld.l_radius * 0.5f);
- vis *= ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/
- vis *= M_2PI * 0.78; /* Matching cycles with point light. */
- vis *= 0.082; /* XXX ad hoc, empirical */
- falloff = dot(N, -ld.l_forward);
- }
- else {
- vis *= (4.0 * ld.l_radius * ld.l_radius) * (1.0 / 10.0);
- vis *= 1.5; /* XXX ad hoc, empirical */
- vis /= (l_vector.w * l_vector.w);
- falloff = dot(N, l_vector.xyz / l_vector.w);
- }
- // vis *= M_1_PI; /* Normalize */
-
- /* Applying profile */
- vis *= sss_profile(abs(delta) / scale);
-
- /* No transmittance at grazing angle (hide artifacts) */
- vis *= saturate(falloff * 2.0);
- }
- else {
- vis = vec3(0.0);
- }
-
- return vis;
-#endif
-}