diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2019-08-22 17:04:25 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2019-09-05 18:37:50 +0300 |
commit | d8aaf25c23fa10ee121dc4fdd1cafe544bcca355 (patch) | |
tree | b5a16157beac22e4b474c699c1ce25f3d8c5be51 /source/blender/draw/engines/eevee/shaders | |
parent | ca58936f2ff2b14a649722be20d98f8fa35831ff (diff) |
Eevee: Shadow map refactor
Reviewed By: brecht
Differential Revision: http://developer.blender.org/D5659
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders')
11 files changed, 383 insertions, 974 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 7f795eaac2b..98012aea303 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -56,12 +56,12 @@ struct LightData { #endif struct ShadowData { - vec4 near_far_bias_exp; - vec4 shadow_data_start_end; + vec4 near_far_bias_id; vec4 contact_shadow_data; }; struct ShadowCubeData { + mat4 shadowmat; vec4 position; }; @@ -69,22 +69,20 @@ struct ShadowCascadeData { mat4 shadowmat[MAX_CASCADE_NUM]; vec4 split_start_distances; vec4 split_end_distances; + vec4 shadow_vec_id; }; /* convenience aliases */ -#define sh_near near_far_bias_exp.x -#define sh_far near_far_bias_exp.y -#define sh_bias near_far_bias_exp.z -#define sh_exp near_far_bias_exp.w -#define sh_bleed near_far_bias_exp.w -#define sh_tex_start shadow_data_start_end.x -#define sh_data_start shadow_data_start_end.y -#define sh_multi_nbr shadow_data_start_end.z -#define sh_blur shadow_data_start_end.w +#define sh_near near_far_bias_id.x +#define sh_far near_far_bias_id.y +#define sh_bias near_far_bias_id.z +#define sh_data_index near_far_bias_id.w #define sh_contact_dist contact_shadow_data.x #define sh_contact_offset contact_shadow_data.y #define sh_contact_spread contact_shadow_data.z #define sh_contact_thickness contact_shadow_data.w +#define sh_shadow_vec shadow_vec_id.xyz +#define sh_tex_index shadow_vec_id.w /* ------- Convenience functions --------- */ @@ -777,10 +775,9 @@ struct Closure { vec3 transmittance; float holdout; # ifdef USE_SSS - vec4 sss_data; -# ifdef USE_SSS_ALBEDO + vec3 sss_irradiance; vec3 sss_albedo; -# endif + float sss_radius; # endif vec4 ssr_data; vec2 ssr_normal; @@ -796,13 +793,8 @@ Closure nodetree_exec(void); /* Prototype */ # define CLOSURE_HOLDOUT_FLAG 4 # ifdef USE_SSS -# ifdef USE_SSS_ALBEDO -# define CLOSURE_DEFAULT \ - Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec3(0.0), vec4(0.0), vec2(0.0), 0) -# else -# define CLOSURE_DEFAULT \ - Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec4(0.0), vec2(0.0), 0) -# endif +# define CLOSURE_DEFAULT \ + Closure(vec3(0.0), vec3(0.0), 0.0, vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec2(0.0), 0) # else # define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec2(0.0), 0) # endif @@ -823,30 +815,22 @@ void closure_load_ssr_data( } } -# ifdef USE_SSS -void closure_load_sss_data(float radius, - vec3 sss_radiance, -# ifdef USE_SSS_ALBEDO - vec3 sss_albedo, -# endif - int sss_id, - inout Closure cl) +void closure_load_sss_data( + float radius, vec3 sss_irradiance, vec3 sss_albedo, int sss_id, inout Closure cl) { +# ifdef USE_SSS if (sss_id == outputSssId) { - cl.sss_data = vec4(sss_radiance, radius); -# ifdef USE_SSS_ALBEDO + cl.sss_irradiance = sss_irradiance; + cl.sss_radius = radius; cl.sss_albedo = sss_albedo; -# endif cl.flag |= CLOSURE_SSS_FLAG; } - else { - cl.radiance += sss_radiance; -# ifdef USE_SSS_ALBEDO - cl.radiance += sss_radiance * sss_albedo; -# endif + else +# endif + { + cl.radiance += sss_irradiance * sss_albedo; } } -# endif Closure closure_mix(Closure cl1, Closure cl2, float fac) { @@ -862,13 +846,11 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac) cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal; # ifdef USE_SSS - cl.sss_data = mix(cl1.sss_data, cl2.sss_data, fac); + cl.sss_albedo = mix(cl1.sss_albedo, cl2.sss_albedo, fac); bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG); - /* It also does not make sense to mix SSS radius or albedo. */ - cl.sss_data.w = (use_cl1_sss) ? cl1.sss_data.w : cl2.sss_data.w; -# ifdef USE_SSS_ALBEDO - cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo; -# endif + /* It also does not make sense to mix SSS radius or irradiance. */ + cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius; + cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance; # endif return cl; } @@ -887,13 +869,11 @@ Closure closure_add(Closure cl1, Closure cl2) cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal; # ifdef USE_SSS - cl.sss_data = cl1.sss_data + cl2.sss_data; + cl.sss_albedo = cl1.sss_albedo + cl2.sss_albedo; bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG); - /* It also does not make sense to mix SSS radius or albedo. */ - cl.sss_data.w = (use_cl1_sss) ? cl1.sss_data.w : cl2.sss_data.w; -# ifdef USE_SSS_ALBEDO - cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo; -# endif + /* It also does not make sense to mix SSS radius or irradiance. */ + cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius; + cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance; # endif return cl; } @@ -914,10 +894,9 @@ layout(location = 0) out vec4 outRadiance; layout(location = 1) out vec2 ssrNormals; layout(location = 2) out vec4 ssrData; # ifdef USE_SSS -layout(location = 3) out vec4 sssData; -# ifdef USE_SSS_ALBEDO -layout(location = 4) out vec4 sssAlbedo; -# endif +layout(location = 3) out vec3 sssIrradiance; +layout(location = 4) out float sssRadius; +layout(location = 5) out vec3 sssAlbedo; # endif # else /* USE_ALPHA_BLEND */ /* Use dual source blending to be able to make a whole range of effects. */ @@ -953,10 +932,9 @@ void main() ssrNormals = cl.ssr_normal; ssrData = cl.ssr_data; # ifdef USE_SSS - sssData = cl.sss_data; -# ifdef USE_SSS_ALBEDO - sssAlbedo = cl.sss_albedo.rgbb; -# endif + sssIrradiance = cl.sss_irradiance; + sssRadius = cl.sss_radius; + sssAlbedo = cl.sss_albedo; # endif # endif @@ -964,6 +942,8 @@ void main() # ifdef USE_SSS float fac = float(!sssToggle); + /* TODO(fclem) we shouldn't need this. + * Just disable USE_SSS when USE_REFRACTION is enabled. */ # ifdef USE_REFRACTION /* SSRefraction pass is done after the SSS pass. * In order to not loose the diffuse light totally we @@ -971,11 +951,7 @@ void main() fac = 1.0; # endif -# ifdef USE_SSS_ALBEDO - outRadiance.rgb += cl.sss_data.rgb * cl.sss_albedo.rgb * fac; -# else - outRadiance.rgb += cl.sss_data.rgb * fac; -# endif + outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac; # endif } diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl index 1f60661d234..ca06d458f6e 100644 --- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl @@ -31,7 +31,7 @@ Closure nodetree_exec(void) vec3 f0 = mix(dielectric, basecol, metallic); vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic); vec3 out_diff, out_spec, ssr_spec; - eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, out_diff, out_spec, ssr_spec); + eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, true, out_diff, out_spec, ssr_spec); Closure cl = CLOSURE_DEFAULT; cl.radiance = out_spec + out_diff * albedo; diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl index 4260c601543..1241cf0e387 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl @@ -10,7 +10,8 @@ layout(std140) uniform sssProfile }; uniform sampler2D depthBuffer; -uniform sampler2D sssData; +uniform sampler2D sssIrradiance; +uniform sampler2D sssRadius; uniform sampler2D sssAlbedo; #ifndef UTIL_TEX @@ -19,9 +20,12 @@ uniform sampler2DArray utilTex; # define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ -layout(location = 0) out vec4 FragColor; #ifdef RESULT_ACCUM +/* Render Passes Accumulation */ +layout(location = 0) out vec4 sssDirect; layout(location = 1) out vec4 sssColor; +#else +layout(location = 0) out vec4 sssRadiance; #endif float get_view_z_from_depth(float depth) @@ -43,7 +47,8 @@ void main(void) { vec2 pixel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy); /* TODO precompute */ vec2 uvs = gl_FragCoord.xy * pixel_size; - vec4 sss_data = texture(sssData, uvs).rgba; + vec3 sss_irradiance = texture(sssIrradiance, uvs).rgb; + float sss_radius = texture(sssRadius, uvs).r; float depth_view = get_view_z_from_depth(texture(depthBuffer, uvs).r); float rand = texelfetch_noise_tex(gl_FragCoord.xy).r; @@ -58,44 +63,36 @@ void main(void) /* Compute kernel bounds in 2D. */ float homcoord = ProjectionMatrix[2][3] * depth_view + ProjectionMatrix[3][3]; - vec2 scale = vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * sss_data.aa / homcoord; + vec2 scale = vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * sss_radius / homcoord; vec2 finalStep = scale * radii_max_radius.w; finalStep *= 0.5; /* samples range -1..1 */ /* Center sample */ - vec3 accum = sss_data.rgb * kernel[0].rgb; + vec3 accum = sss_irradiance * kernel[0].rgb; for (int i = 1; i < sss_samples && i < MAX_SSS_SAMPLES; i++) { vec2 sample_uv = uvs + kernel[i].a * finalStep * ((abs(kernel[i].a) > sssJitterThreshold) ? dir : dir_rand); - vec3 color = texture(sssData, sample_uv).rgb; + vec3 color = texture(sssIrradiance, sample_uv).rgb; float sample_depth = texture(depthBuffer, sample_uv).r; sample_depth = get_view_z_from_depth(sample_depth); - /* Depth correction factor. */ float depth_delta = depth_view - sample_depth; - float s = clamp(1.0 - exp(-(depth_delta * depth_delta) / (2.0 * sss_data.a)), 0.0, 1.0); - + float s = clamp(1.0 - exp(-(depth_delta * depth_delta) / (2.0 * sss_radius)), 0.0, 1.0); /* Out of view samples. */ if (any(lessThan(sample_uv, vec2(0.0))) || any(greaterThan(sample_uv, vec2(1.0)))) { s = 1.0; } - - accum += kernel[i].rgb * mix(color, sss_data.rgb, s); + /* Mix with first sample in failure case and apply kernel color. */ + accum += kernel[i].rgb * mix(color, sss_irradiance, s); } -#ifdef FIRST_PASS - FragColor = vec4(accum, sss_data.a); +#ifdef RESULT_ACCUM + sssDirect = vec4(accum, 1.0); + sssColor = vec4(texture(sssAlbedo, uvs).rgb, 1.0); +#elif defined(FIRST_PASS) + sssRadiance = vec4(accum, 1.0); #else /* SECOND_PASS */ -# ifdef USE_SEP_ALBEDO -# ifdef RESULT_ACCUM - FragColor = vec4(accum, 1.0); - sssColor = texture(sssAlbedo, uvs); -# else - FragColor = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0); -# endif -# else - FragColor = vec4(accum, 1.0); -# endif + sssRadiance = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0); #endif } diff --git a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl new file mode 100644 index 00000000000..7edb0053da7 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl @@ -0,0 +1,165 @@ + +in vec4 uvcoordsvar; + +out vec4 FragColor; + +uniform sampler1D sssTexProfile; +uniform sampler2D sssRadius; + +uniform sampler2DArray sssShadowCubes; +uniform sampler2DArray sssShadowCascades; + +#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)) + +layout(std140) uniform sssProfile +{ + vec4 kernel[MAX_SSS_SAMPLES]; + vec4 radii_max_radius; + int sss_samples; +}; + +vec3 sss_profile(float s) +{ + s /= radii_max_radius.w; + return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb; +} + +#ifndef UTIL_TEX +# define UTIL_TEX +uniform sampler2DArray utilTex; +# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) +#endif /* UTIL_TEX */ + +float light_translucent_power_with_falloff(LightData ld, vec3 N, vec4 l_vector) +{ + float power, falloff; + /* XXX : Removing Area Power. */ + /* TODO : put this out of the shader. */ + if (ld.l_type >= AREA_RECT) { + 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; + } + power *= 0.3 * 20.0 * + max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */ + power /= (l_vector.w * l_vector.w); + falloff = dot(N, l_vector.xyz / l_vector.w); + } + else if (ld.l_type == SUN) { + power = 1.0 / (1.0 + (ld.l_radius * ld.l_radius * 0.5)); + power *= ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/ + power *= M_2PI * 0.78; /* Matching cycles with point light. */ + power *= 0.082; /* XXX ad hoc, empirical */ + falloff = dot(N, -ld.l_forward); + } + else { + power = (4.0 * ld.l_radius * ld.l_radius) * (1.0 / 10.0); + power *= 1.5; /* XXX ad hoc, empirical */ + power /= (l_vector.w * l_vector.w); + falloff = dot(N, l_vector.xyz / l_vector.w); + } + /* No transmittance at grazing angle (hide artifacts) */ + return power * saturate(falloff * 2.0); +} + +/* 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] + +vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, float sss_scale) +{ + int shadow_id = int(ld.l_shadowid); + + vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0); + + /* We use the full l_vector.xyz so that the spread is minimize + * if the shading point is further away from the light source */ + /* TODO(fclem) do something better than this. */ + // vec3 T, B; + // make_orthonormal_basis(L.xyz / L.w, T, B); + // rand.xy *= data.sh_blur; + // W = W + T * rand.x + B * rand.y; + + float s, dist; + int data_id = int(sd(shadow_id).sh_data_index); + if (ld.l_type == SUN) { + vec4 view_z = vec4(dot(W - cameraPos, cameraForward)); + + vec4 weights = step(scascade(data_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(sd(shadow_id).sh_far - sd(shadow_id).sh_near); + + vec4 shpos = scascade(data_id).shadowmat[int(id)] * vec4(W, 1.0); + dist = shpos.z * range; + + if (shpos.z > 1.0 || shpos.z < 0.0) { + return vec3(0.0); + } + + float tex_id = scascade(data_id).sh_tex_index; + s = sample_cascade(sssShadowCascades, shpos.xy, tex_id + id).r; + s *= range; + } + else { + vec3 cubevec = transform_point(scube(data_id).shadowmat, W); + dist = length(cubevec); + cubevec /= dist; + /* tex_id == data_id for cube shadowmap */ + float tex_id = float(data_id); + s = sample_cube(sssShadowCubes, cubevec, tex_id).r; + s = length(cubevec / max_v3(abs(cubevec))) * + linear_depth(true, s, sd(shadow_id).sh_far, sd(shadow_id).sh_near); + } + float delta = dist - s; + + float power = light_translucent_power_with_falloff(ld, N, l_vector); + + return power * sss_profile(abs(delta) / sss_scale); +} + +#undef sd +#undef scube +#undef scsmd + +void main(void) +{ + vec2 uvs = uvcoordsvar.xy; + float sss_scale = texture(sssRadius, uvs).r; + vec3 W = get_world_space_from_depth(uvs, texture(depthBuffer, uvs).r); + vec3 N = normalize(cross(dFdx(W), dFdy(W))); + + vec3 rand = texelfetch_noise_tex(gl_FragCoord.xy).zwy; + rand.xy *= fast_sqrt(rand.z); + + vec3 accum = vec3(0.0); + for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) { + LightData ld = lights_data[i]; + + /* Only shadowed light can produce translucency */ + if (ld.l_shadowid < 0.0) { + continue; + } + + vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */ + l_vector.xyz = ld.l_position - W; + l_vector.w = length(l_vector.xyz); + + float att = light_attenuation(ld, l_vector); + if (att < 1e-8) { + continue; + } + + accum += att * ld.l_color * light_translucent(ld, W, -N, l_vector, rand.xy, sss_scale); + } + + FragColor = vec4(accum, 1.0); +} 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 -} diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index 53f1517505c..e9bdfec008f 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -144,14 +144,12 @@ void CLOSURE_NAME(vec3 N , float ior #endif + , + const bool use_contact_shadows #ifdef CLOSURE_DIFFUSE , out vec3 out_diff #endif -#ifdef CLOSURE_SUBSURFACE - , - out vec3 out_trans -#endif #ifdef CLOSURE_GLOSSY , out vec3 out_spec @@ -170,10 +168,6 @@ void CLOSURE_NAME(vec3 N out_diff = vec3(0.0); #endif -#ifdef CLOSURE_SUBSURFACE - out_trans = vec3(0.0); -#endif - #ifdef CLOSURE_GLOSSY out_spec = vec3(0.0); #endif @@ -230,6 +224,16 @@ void CLOSURE_NAME(vec3 N vec3 out_spec_clear = vec3(0.0); # endif + float tracing_depth = gl_FragCoord.z; + /* Constant bias (due to depth buffer precision) */ + /* Magic numbers for 24bits of precision. + * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */ + tracing_depth -= mix(2.4e-7, 4.8e-7, gl_FragCoord.z); + /* Convert to view Z. */ + tracing_depth = get_view_z_from_depth(tracing_depth); + + vec3 true_normal = normalize(cross(dFdx(viewPosition), dFdy(viewPosition))); + for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) { LightData ld = lights_data[i]; @@ -237,7 +241,14 @@ void CLOSURE_NAME(vec3 N l_vector.xyz = ld.l_position - worldPosition; l_vector.w = length(l_vector.xyz); - float l_vis = light_visibility(ld, worldPosition, viewPosition, viewNormal, l_vector); + float l_vis = light_visibility(ld, + worldPosition, + viewPosition, + tracing_depth, + true_normal, + rand.x, + use_contact_shadows, + l_vector); if (l_vis < 1e-8) { continue; @@ -249,10 +260,6 @@ void CLOSURE_NAME(vec3 N out_diff += l_color_vis * light_diffuse(ld, N, V, l_vector); # endif -# ifdef CLOSURE_SUBSURFACE - out_trans += ld.l_color * light_translucent(ld, worldPosition, -N, l_vector, sss_scale); -# endif - # ifdef CLOSURE_GLOSSY out_spec += l_color_vis * light_specular(ld, ltc_mat, N, V, l_vector) * ld.l_spec; # endif @@ -441,10 +448,17 @@ void CLOSURE_NAME(vec3 N /* Ambient Occlusion */ /* ---------------------------- */ # if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE) - /* HACK: Fix for translucent BSDF. (see T65631) */ - bool same_side = dot((gl_FrontFacing) ? worldNormal : -worldNormal, N) > 0.0; + if (!use_contact_shadows) { + /* HACK: Fix for translucent BSDF. (see T65631) */ + N = -N; + } vec3 bent_normal; - float final_ao = occlusion_compute(same_side ? N : -N, viewPosition, ao, rand, bent_normal); + float final_ao = occlusion_compute(gl_FrontFacing ? N : -N, viewPosition, ao, rand, bent_normal); + if (!use_contact_shadows) { + N = -N; + /* Bypass bent normal. */ + bent_normal = N; + } # endif /* ---------------------------- */ diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index 14e0c947b47..f88cfdf3787 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -120,7 +120,8 @@ void prepare_raycast(vec3 ray_origin, ss_ray = ss_start * m.xyyy + 0.5; ss_step *= m.xyyy; - ss_ray.xy += m * ssrPixelSize * 2.0; /* take the center of the texel. * 2 because halfres. */ + /* take the center of the texel. */ + // ss_ray.xy += sign(ss_ray.xy) * m * ssrPixelSize * (1.0 + hizMipOffset); } /* See times_and_deltas. */ diff --git a/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl deleted file mode 100644 index 5646c257562..00000000000 --- a/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl +++ /dev/null @@ -1,199 +0,0 @@ -/* Copy the depth only shadowmap into another texture while converting - * to linear depth (or other storage method) and doing a 3x3 box filter. */ - -layout(std140) uniform shadow_render_block -{ - /* Use vectors to avoid alignment padding. */ - ivec4 shadowSampleCount; - vec4 shadowInvSampleCount; - vec4 filterSize; - int viewCount; - int baseId; - float cubeTexelSize; - float storedTexelSize; - float nearClip; - float farClip; - float exponent; -}; - -#ifdef CSM -uniform sampler2DArray shadowTexture; -#else -uniform samplerCube shadowTexture; -#endif - -flat in int layerID; - -#ifdef CSM -# define cascadeID layerID -#else -# define cascadeID 0 -#endif - -out vec4 FragColor; - -#define linear_depth(z) \ - ((nearClip * farClip) / (clamp(z, 0.0, 0.999999) * (nearClip - farClip) + farClip)) - -/* add bias so background filtering does not bleed into shadow map */ -#define BACKGROUND_BIAS 0.05 - -#ifdef CSM -vec4 get_world_distance(vec4 depths, vec3 cos[4]) -{ - depths += step(vec4(0.9999), depths) * BACKGROUND_BIAS; - return clamp( - depths * abs(farClip - nearClip), 0.0, 1e10); /* Same factor as in shadow_cascade(). */ -} - -float get_world_distance(float depth, vec3 cos) -{ - depth += step(0.9999, depth) * BACKGROUND_BIAS; - return clamp( - depth * abs(farClip - nearClip), 0.0, 1e10); /* Same factor as in shadow_cascade(). */ -} - -#else /* CUBEMAP */ -vec4 get_world_distance(vec4 depths, vec3 cos[4]) -{ - depths = linear_depth(depths); - cos[0] = normalize(abs(cos[0])); - cos[1] = normalize(abs(cos[1])); - cos[2] = normalize(abs(cos[2])); - cos[3] = normalize(abs(cos[3])); - vec4 cos_vec; - cos_vec.x = max(cos[0].x, max(cos[0].y, cos[0].z)); - cos_vec.y = max(cos[1].x, max(cos[1].y, cos[1].z)); - cos_vec.z = max(cos[2].x, max(cos[2].y, cos[2].z)); - cos_vec.w = max(cos[3].x, max(cos[3].y, cos[3].z)); - return depths / cos_vec; -} - -float get_world_distance(float depth, vec3 cos) -{ - depth = linear_depth(depth); - cos = normalize(abs(cos)); - float cos_vec = max(cos.x, max(cos.y, cos.z)); - return depth / cos_vec; -} -#endif - -/* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */ -#define ln_space_prefilter_step(ref, sample) exp(sample - ref) -#define ln_space_prefilter_finalize(ref, sum) (ref + log(SAMPLE_WEIGHT * sum)) - -#define SAMPLE_WEIGHT 0.11111 - -#ifdef ESM -void prefilter(vec4 depths, float ref, inout float accum) -{ - accum += dot(ln_space_prefilter_step(ref, depths), vec4(1.0)); -} -#else /* VSM */ -void prefilter(vec4 depths, float ref, inout vec2 accum) -{ - vec4 depths_sqr = depths * depths; - accum += vec2(dot(vec4(1.0), depths), dot(vec4(1.0), depths_sqr)) * SAMPLE_WEIGHT; -} -#endif - -#ifdef CSM -vec3 get_texco(vec2 uvs, vec2 ofs) -{ - return vec3(uvs + ofs, float(cascadeID)); -} -#else /* CUBEMAP */ -const vec3 minorAxisX[6] = vec3[6](vec3(0.0f, 0.0f, -1.0f), - vec3(0.0f, 0.0f, 1.0f), - vec3(1.0f, 0.0f, 0.0f), - vec3(1.0f, 0.0f, 0.0f), - vec3(1.0f, 0.0f, 0.0f), - vec3(-1.0f, 0.0f, 0.0f)); - -const vec3 minorAxisY[6] = vec3[6](vec3(0.0f, -1.0f, 0.0f), - vec3(0.0f, -1.0f, 0.0f), - vec3(0.0f, 0.0f, 1.0f), - vec3(0.0f, 0.0f, -1.0f), - vec3(0.0f, -1.0f, 0.0f), - vec3(0.0f, -1.0f, 0.0f)); - -const vec3 majorAxis[6] = vec3[6](vec3(1.0f, 0.0f, 0.0f), - vec3(-1.0f, 0.0f, 0.0f), - vec3(0.0f, 1.0f, 0.0f), - vec3(0.0f, -1.0f, 0.0f), - vec3(0.0f, 0.0f, 1.0f), - vec3(0.0f, 0.0f, -1.0f)); - -vec3 get_texco(vec2 uvs, vec2 ofs) -{ - uvs += ofs; - return majorAxis[layerID] + uvs.x * minorAxisX[layerID] + uvs.y * minorAxisY[layerID]; -} -#endif - -void main() -{ - /* Copy the depth only shadowmap into another texture while converting - * to linear depth and do a 3x3 box blur. */ - -#ifdef CSM - vec2 uvs = gl_FragCoord.xy * storedTexelSize; -#else /* CUBEMAP */ - vec2 uvs = gl_FragCoord.xy * cubeTexelSize * 2.0 - 1.0; -#endif - - /* Center texel */ - vec3 co = get_texco(uvs, vec2(0.0)); - float depth = texture(shadowTexture, co).r; - depth = get_world_distance(depth, co); - - if (filterSize[cascadeID] == 0.0) { -#ifdef ESM - FragColor = vec4(depth); -#else /* VSM */ - FragColor = vec2(depth, depth * depth).xyxy; -#endif - return; - } - -#ifdef ESM - float ref = depth; - float accum = 1.0; -#else /* VSM */ - float ref = 0.0; /* UNUSED */ - vec2 accum = vec2(depth, depth * depth) * SAMPLE_WEIGHT; -#endif - - vec3 ofs = vec3(1.0, 0.0, -1.0) * filterSize[cascadeID]; - - vec3 cos[4]; - cos[0] = get_texco(uvs, ofs.zz); - cos[1] = get_texco(uvs, ofs.yz); - cos[2] = get_texco(uvs, ofs.xz); - cos[3] = get_texco(uvs, ofs.zy); - - vec4 depths; - depths.x = texture(shadowTexture, cos[0]).r; - depths.y = texture(shadowTexture, cos[1]).r; - depths.z = texture(shadowTexture, cos[2]).r; - depths.w = texture(shadowTexture, cos[3]).r; - depths = get_world_distance(depths, cos); - prefilter(depths, ref, accum); - - cos[0] = get_texco(uvs, ofs.xy); - cos[1] = get_texco(uvs, ofs.zx); - cos[2] = get_texco(uvs, ofs.yx); - cos[3] = get_texco(uvs, ofs.xx); - depths.x = texture(shadowTexture, cos[0]).r; - depths.y = texture(shadowTexture, cos[1]).r; - depths.z = texture(shadowTexture, cos[2]).r; - depths.w = texture(shadowTexture, cos[3]).r; - depths = get_world_distance(depths, cos); - prefilter(depths, ref, accum); - -#ifdef ESM - accum = ln_space_prefilter_finalize(ref, accum); -#endif - /* Clamp infinite sum. */ - FragColor = vec2(clamp(accum, 0.0, 1e16)).xyxy; -} diff --git a/source/blender/draw/engines/eevee/shaders/shadow_process_geom.glsl b/source/blender/draw/engines/eevee/shaders/shadow_process_geom.glsl deleted file mode 100644 index 591666560c4..00000000000 --- a/source/blender/draw/engines/eevee/shaders/shadow_process_geom.glsl +++ /dev/null @@ -1,36 +0,0 @@ - -layout(triangles) in; -layout(triangle_strip, max_vertices = 3) out; - -layout(std140) uniform shadow_render_block -{ - /* Use vectors to avoid alignment padding. */ - ivec4 shadowSampleCount; - vec4 shadowInvSampleCount; - vec4 filterSize; - int viewCount; - int baseId; - float cubeTexelSize; - float storedTexelSize; - float nearClip; - float farClip; - float exponent; -}; - -in int layerID_g[]; - -flat out int layerID; - -void main() -{ - gl_Layer = layerID_g[0]; - layerID = gl_Layer - baseId; - - gl_Position = gl_in[0].gl_Position; - EmitVertex(); - gl_Position = gl_in[1].gl_Position; - EmitVertex(); - gl_Position = gl_in[2].gl_Position; - EmitVertex(); - EndPrimitive(); -} diff --git a/source/blender/draw/engines/eevee/shaders/shadow_process_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_process_vert.glsl deleted file mode 100644 index 95e6a48b81f..00000000000 --- a/source/blender/draw/engines/eevee/shaders/shadow_process_vert.glsl +++ /dev/null @@ -1,32 +0,0 @@ - -layout(std140) uniform shadow_render_block -{ - /* Use vectors to avoid alignment padding. */ - ivec4 shadowSampleCount; - vec4 shadowInvSampleCount; - vec4 filterSize; - int viewCount; - int baseId; - float cubeTexelSize; - float storedTexelSize; - float nearClip; - float farClip; - float exponent; -}; - -out int layerID_g; - -void main() -{ - int v = gl_VertexID % 3; - layerID_g = gl_VertexID / 3; - float x = -1.0 + float((v & 1) << 2); - float y = -1.0 + float((v & 2) << 1); - gl_Position = vec4(x, y, 1.0, 1.0); - - /* HACK avoid changing drawcall parameters. */ - if (layerID_g >= viewCount) { - gl_Position = vec4(0.0); - } - layerID_g += baseId; -} diff --git a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl deleted file mode 100644 index 5c19ccd5ce1..00000000000 --- a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl +++ /dev/null @@ -1,322 +0,0 @@ - -layout(std140) uniform shadow_render_block -{ - /* Use vectors to avoid alignment padding. */ - ivec4 shadowSampleCount; - vec4 shadowInvSampleCount; - vec4 filterSize; - int viewCount; - int baseId; - float cubeTexelSize; - float storedTexelSize; - float nearClip; - float farClip; - float exponent; -}; - -#ifdef CSM -uniform sampler2DArray shadowTexture; -#else -uniform samplerCube shadowTexture; -#endif - -flat in int layerID; - -#ifdef CSM -# define cascadeID layerID -#else -# define cascadeID 0 -#endif - -out vec4 FragColor; - -vec3 octahedral_to_cubemap_proj(vec2 co) -{ - co = co * 2.0 - 1.0; - - vec2 abs_co = abs(co); - vec3 v = vec3(co, 1.0 - (abs_co.x + abs_co.y)); - - if (abs_co.x + abs_co.y > 1.0) { - v.xy = (abs(co.yx) - 1.0) * -sign(co.xy); - } - - return v; -} - -/* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */ -/* http://advances.realtimerendering.com/s2009/SIGGRAPH%202009%20-%20Lighting%20Research%20at%20Bungie.pdf - * Slide 55. */ -#define ln_space_prefilter_step(ref, sample) exp(sample - ref) -#define ln_space_prefilter_finalize(ref, sum) (ref + log(shadowInvSampleCount[cascadeID] * sum)) - -#ifdef CSM -vec3 get_texco(vec3 cos, const vec2 ofs) -{ - cos.xy += ofs * filterSize[cascadeID]; - return cos; -} -#else /* CUBEMAP */ -/* global vars */ -vec3 T = vec3(0.0); -vec3 B = vec3(0.0); - -void make_orthonormal_basis(vec3 N) -{ - vec3 UpVector = (abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); - T = normalize(cross(UpVector, N)); - B = cross(N, T); -} - -vec3 get_texco(vec3 cos, const vec2 ofs) -{ - return cos + ofs.x * T + ofs.y * B; -} - -#endif - -#ifdef ESM -void grouped_samples_accum(vec3 cos, - const vec2 co1, - const vec2 co2, - const vec2 co3, - const vec2 co4, - float ref, - inout vec4 accum) -{ - vec4 depths; - depths.x = texture(shadowTexture, get_texco(cos, co1)).r; - depths.y = texture(shadowTexture, get_texco(cos, co2)).r; - depths.z = texture(shadowTexture, get_texco(cos, co3)).r; - depths.w = texture(shadowTexture, get_texco(cos, co4)).r; - - accum += ln_space_prefilter_step(ref, depths); -} -#else /* VSM */ -void grouped_samples_accum(vec3 cos, - const vec2 co1, - const vec2 co2, - const vec2 co3, - const vec2 co4, - float ref, - inout vec2 accum) -{ - vec4 depths1, depths2; - depths1.xy = texture(shadowTexture, get_texco(cos, co1)).rg; - depths1.zw = texture(shadowTexture, get_texco(cos, co2)).rg; - depths2.xy = texture(shadowTexture, get_texco(cos, co3)).rg; - depths2.zw = texture(shadowTexture, get_texco(cos, co4)).rg; - - accum += depths1.xy + depths1.zw + depths2.xy + depths2.zw; -} -#endif - -void main() -{ - vec3 cos; - - cos.xy = gl_FragCoord.xy * storedTexelSize; - -#ifdef CSM - cos.z = float(cascadeID); -#else /* CUBEMAP */ - /* add a 2 pixel border to ensure filtering is correct */ - cos.xy *= 1.0 + storedTexelSize * 2.0; - cos.xy -= storedTexelSize; - - float pattern = 1.0; - - /* edge mirroring : only mirror if directly adjacent - * (not diagonally adjacent) */ - vec2 m = abs(cos.xy - 0.5) + 0.5; - vec2 f = floor(m); - if (f.x - f.y != 0.0) { - cos.xy = 1.0 - cos.xy; - } - - /* clamp to [0-1] */ - cos.xy = fract(cos.xy); - - /* get cubemap vector */ - cos = normalize(octahedral_to_cubemap_proj(cos.xy)); - make_orthonormal_basis(cos); - - T *= filterSize[cascadeID]; - B *= filterSize[cascadeID]; -#endif - -#ifdef ESM - /* disc blur in log space. */ - vec4 depths; - depths.x = texture(shadowTexture, get_texco(cos, concentric[0])).r; - depths.y = texture(shadowTexture, get_texco(cos, concentric[1])).r; - depths.z = texture(shadowTexture, get_texco(cos, concentric[2])).r; - depths.w = texture(shadowTexture, get_texco(cos, concentric[3])).r; - float ref = depths.x; - vec4 accum = ln_space_prefilter_step(ref, depths); - -#else /* VSM */ - float ref = 0.0; /* UNUSED */ - vec2 accum = vec2(0.0); - grouped_samples_accum( - cos, concentric[0], concentric[1], concentric[2], concentric[3], ref, accum); -#endif - - /** - * Making the `grouped_samples_accum` be called within a loop would be - * the most conventional solution, however in some older gpus, transverse the huge - * `const vec2 concentric[]` array with variable indices is extremely slow. - * The solution is to use constant indices to access the array. - */ - if (shadowSampleCount[cascadeID] > 4) { - grouped_samples_accum( - cos, concentric[4], concentric[5], concentric[6], concentric[7], ref, accum); - grouped_samples_accum( - cos, concentric[8], concentric[9], concentric[10], concentric[11], ref, accum); - grouped_samples_accum( - cos, concentric[12], concentric[13], concentric[14], concentric[15], ref, accum); - } - if (shadowSampleCount[cascadeID] > 16) { - grouped_samples_accum( - cos, concentric[16], concentric[17], concentric[18], concentric[19], ref, accum); - grouped_samples_accum( - cos, concentric[20], concentric[21], concentric[22], concentric[23], ref, accum); - grouped_samples_accum( - cos, concentric[24], concentric[25], concentric[26], concentric[27], ref, accum); - grouped_samples_accum( - cos, concentric[28], concentric[29], concentric[30], concentric[31], ref, accum); - grouped_samples_accum( - cos, concentric[32], concentric[33], concentric[34], concentric[35], ref, accum); - } -#ifdef HIGH_BLUR - if (shadowSampleCount[cascadeID] > 36) { - grouped_samples_accum( - cos, concentric[36], concentric[37], concentric[38], concentric[39], ref, accum); - grouped_samples_accum( - cos, concentric[40], concentric[41], concentric[42], concentric[43], ref, accum); - grouped_samples_accum( - cos, concentric[44], concentric[45], concentric[46], concentric[47], ref, accum); - grouped_samples_accum( - cos, concentric[48], concentric[49], concentric[50], concentric[51], ref, accum); - grouped_samples_accum( - cos, concentric[52], concentric[53], concentric[54], concentric[55], ref, accum); - grouped_samples_accum( - cos, concentric[56], concentric[57], concentric[58], concentric[59], ref, accum); - grouped_samples_accum( - cos, concentric[60], concentric[61], concentric[62], concentric[63], ref, accum); - } - if (shadowSampleCount[cascadeID] > 64) { - grouped_samples_accum( - cos, concentric[64], concentric[65], concentric[66], concentric[67], ref, accum); - grouped_samples_accum( - cos, concentric[68], concentric[69], concentric[70], concentric[71], ref, accum); - grouped_samples_accum( - cos, concentric[72], concentric[73], concentric[74], concentric[75], ref, accum); - grouped_samples_accum( - cos, concentric[76], concentric[77], concentric[78], concentric[79], ref, accum); - grouped_samples_accum( - cos, concentric[80], concentric[81], concentric[82], concentric[83], ref, accum); - grouped_samples_accum( - cos, concentric[84], concentric[85], concentric[86], concentric[87], ref, accum); - grouped_samples_accum( - cos, concentric[88], concentric[89], concentric[90], concentric[91], ref, accum); - grouped_samples_accum( - cos, concentric[92], concentric[93], concentric[94], concentric[95], ref, accum); - grouped_samples_accum( - cos, concentric[96], concentric[97], concentric[98], concentric[99], ref, accum); - } - if (shadowSampleCount[cascadeID] > 100) { - grouped_samples_accum( - cos, concentric[100], concentric[101], concentric[102], concentric[103], ref, accum); - grouped_samples_accum( - cos, concentric[104], concentric[105], concentric[106], concentric[107], ref, accum); - grouped_samples_accum( - cos, concentric[108], concentric[109], concentric[110], concentric[111], ref, accum); - grouped_samples_accum( - cos, concentric[112], concentric[113], concentric[114], concentric[115], ref, accum); - grouped_samples_accum( - cos, concentric[116], concentric[117], concentric[118], concentric[119], ref, accum); - grouped_samples_accum( - cos, concentric[120], concentric[121], concentric[122], concentric[123], ref, accum); - grouped_samples_accum( - cos, concentric[124], concentric[125], concentric[126], concentric[127], ref, accum); - grouped_samples_accum( - cos, concentric[128], concentric[129], concentric[130], concentric[131], ref, accum); - grouped_samples_accum( - cos, concentric[132], concentric[133], concentric[134], concentric[135], ref, accum); - grouped_samples_accum( - cos, concentric[136], concentric[137], concentric[138], concentric[139], ref, accum); - grouped_samples_accum( - cos, concentric[140], concentric[141], concentric[142], concentric[143], ref, accum); - } - if (shadowSampleCount[cascadeID] > 144) { - grouped_samples_accum( - cos, concentric[144], concentric[145], concentric[146], concentric[147], ref, accum); - grouped_samples_accum( - cos, concentric[148], concentric[149], concentric[150], concentric[151], ref, accum); - grouped_samples_accum( - cos, concentric[152], concentric[153], concentric[154], concentric[155], ref, accum); - grouped_samples_accum( - cos, concentric[156], concentric[157], concentric[158], concentric[159], ref, accum); - grouped_samples_accum( - cos, concentric[160], concentric[161], concentric[162], concentric[163], ref, accum); - grouped_samples_accum( - cos, concentric[164], concentric[165], concentric[166], concentric[167], ref, accum); - grouped_samples_accum( - cos, concentric[168], concentric[169], concentric[170], concentric[171], ref, accum); - grouped_samples_accum( - cos, concentric[172], concentric[173], concentric[174], concentric[175], ref, accum); - grouped_samples_accum( - cos, concentric[176], concentric[177], concentric[178], concentric[179], ref, accum); - grouped_samples_accum( - cos, concentric[180], concentric[181], concentric[182], concentric[183], ref, accum); - grouped_samples_accum( - cos, concentric[184], concentric[185], concentric[186], concentric[187], ref, accum); - grouped_samples_accum( - cos, concentric[188], concentric[189], concentric[190], concentric[191], ref, accum); - grouped_samples_accum( - cos, concentric[192], concentric[193], concentric[194], concentric[195], ref, accum); - } - if (shadowSampleCount[cascadeID] > 196) { - grouped_samples_accum( - cos, concentric[196], concentric[197], concentric[198], concentric[199], ref, accum); - grouped_samples_accum( - cos, concentric[200], concentric[201], concentric[202], concentric[203], ref, accum); - grouped_samples_accum( - cos, concentric[204], concentric[205], concentric[206], concentric[207], ref, accum); - grouped_samples_accum( - cos, concentric[208], concentric[209], concentric[210], concentric[211], ref, accum); - grouped_samples_accum( - cos, concentric[212], concentric[213], concentric[114], concentric[215], ref, accum); - grouped_samples_accum( - cos, concentric[216], concentric[217], concentric[218], concentric[219], ref, accum); - grouped_samples_accum( - cos, concentric[220], concentric[221], concentric[222], concentric[223], ref, accum); - grouped_samples_accum( - cos, concentric[224], concentric[225], concentric[226], concentric[227], ref, accum); - grouped_samples_accum( - cos, concentric[228], concentric[229], concentric[230], concentric[231], ref, accum); - grouped_samples_accum( - cos, concentric[232], concentric[233], concentric[234], concentric[235], ref, accum); - grouped_samples_accum( - cos, concentric[236], concentric[237], concentric[238], concentric[239], ref, accum); - grouped_samples_accum( - cos, concentric[240], concentric[241], concentric[242], concentric[243], ref, accum); - grouped_samples_accum( - cos, concentric[244], concentric[245], concentric[246], concentric[247], ref, accum); - grouped_samples_accum( - cos, concentric[248], concentric[249], concentric[250], concentric[251], ref, accum); - grouped_samples_accum( - cos, concentric[252], concentric[253], concentric[254], concentric[255], ref, accum); - } -#endif - -#ifdef ESM - accum.x = dot(vec4(1.0), accum); - accum.x = ln_space_prefilter_finalize(ref, accum.x); - FragColor = accum.xxxx; - -#else /* VSM */ - FragColor = accum.xyxy * shadowInvSampleCount[cascadeID]; -#endif -} |