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-02-13 20:43:09 +0300
committerClément Foucault <foucault.clem@gmail.com>2021-02-13 20:43:09 +0300
commit7f7e6830991bf66e285fb54cdbae6c6618ed7afa (patch)
treeaccbf8b2f2ab68452ee8e2dfa58bf2477abe6294 /source/blender/draw
parent40aadd894016f6ad6a1cde3d60b63ba47a72ec6c (diff)
EEVEE: Refactor closure_lit_lib.glsl
This refactor was needed for some reasons: - closure_lit_lib.glsl was unreadable and could not be easily extended to use new features. - It was generating ~5K LOC for any shader. Slowing down compilation. - Some calculations were incorrect and BSDF/Closure code had lots of workaround/hacks. What this refactor does: - Add some macros to define the light object loops / eval. - Clear separation between each closures which now have separate files. Each closure implements the eval functions. - Make principled BSDF a bit more correct in some cases (specular coloring, mix between glass and opaque). - The BSDF term are applied outside of the eval function and on the whole lighting (was separated for lights before). - Make light iteration last to avoid carrying more data than needed. - Makes sure that all inputs are within correct ranges before evaluating the closures (use `safe_normalize` on normals). - Making each BSDF isolated means that we might carry duplicated data (normals for instance) but this should be optimized by compilers. - Makes Translucent BSDF its own closure type to avoid having to disable raytraced shadows using hacks. - Separate transmission roughness is now working on Principled BSDF. - Makes principled shader variations using constants. Removing a lot of duplicated code. This needed `const` keyword detection in `gpu_material_library.c`. - SSR/SSS masking and data loading is a bit more consistent and defined outside of closure eval. The loading functions will act as accumulator if the lighting is not to be separated. - SSR pass now do a full deferred lighting evaluation, including lights, in order to avoid interference with the closure eval code. However, it seems that the cost of having a global SSR toggle uniform is making the surface shader more expensive (which is already the case, by the way). - Principle fully black specular tint now returns black instead of white. - This fixed some artifact issue on my AMD computer on normal surfaces (which might have been some uninitialized variables). - This touched the Ambient Occlusion because it needs to be evaluated for each closure. But to avoid the cost of this, we use another approach to just pass the result of the occlusion on interpolated normals and modify it using the bent normal for each Closure. This tends to reduce shadowing. I'm still looking into improving this but this is out of the scope of this patch. - Performance might be a bit worse with this patch since it is more oriented towards code modularity. But not by a lot. Render tests needs to be updated after this. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D10390 # Conflicts: # source/blender/draw/engines/eevee/eevee_shaders.c # source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl # source/blender/draw/intern/shaders/common_math_lib.glsl
Diffstat (limited to 'source/blender/draw')
-rw-r--r--source/blender/draw/CMakeLists.txt8
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c7
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c32
-rw-r--r--source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl27
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl19
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl85
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl136
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl316
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl128
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl71
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl545
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl (renamed from source/blender/draw/engines/eevee/shaders/closure_lib.glsl)26
-rw-r--r--source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl13
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl143
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/lights_lib.glsl61
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_frag.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_frag.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_lib.glsl12
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_math_lib.glsl10
22 files changed, 959 insertions, 716 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index e52e30a6c44..8abd353d36d 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -197,7 +197,6 @@ set(LIB
data_to_c_simple(engines/eevee/shaders/ambient_occlusion_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/background_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/closure_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/common_uniforms_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/common_utiltex_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lights_lib.glsl SRC)
@@ -215,7 +214,12 @@ data_to_c_simple(engines/eevee/shaders/lightprobe_grid_fill_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lookdev_world_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/closure_lit_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/closure_eval_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/closure_eval_diffuse_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/closure_eval_glossy_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/closure_eval_refraction_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/closure_eval_translucent_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/closure_type_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_bloom_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_dof_bokeh_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_dof_dilate_tiles_frag.glsl SRC)
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
index 1465c9dd84c..db5c86dc5e1 100644
--- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -191,6 +191,12 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_shgroup_uniform_texture_ref(grp, "hitBuffer", &effects->ssr_hit_output);
DRW_shgroup_uniform_texture_ref(grp, "pdfBuffer", &effects->ssr_pdf_output);
DRW_shgroup_uniform_texture_ref(grp, "prevColorBuffer", &txl->color_double_buffer);
+ DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
+ DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
+ DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
@@ -198,7 +204,6 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1);
if ((effects->enabled_effects & EFFECT_GTAO) != 0) {
- DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
}
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index ec058afd58e..64efca83915 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -149,7 +149,6 @@ static struct {
struct GPUShader *volumetric_accum_sh;
/* Shader strings */
- char *closure_lit_lib;
char *surface_lit_frag;
char *surface_prepass_frag;
char *surface_geom_barycentric;
@@ -191,7 +190,7 @@ extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_bsdf_lut_frag_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
extern char datatoc_btdf_lut_frag_glsl[];
-extern char datatoc_closure_lib_glsl[];
+extern char datatoc_closure_type_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_common_utiltex_lib_glsl[];
extern char datatoc_cryptomatte_frag_glsl[];
@@ -241,7 +240,11 @@ extern char datatoc_lightprobe_planar_downsample_geom_glsl[];
extern char datatoc_lightprobe_planar_downsample_vert_glsl[];
extern char datatoc_lightprobe_vert_glsl[];
extern char datatoc_lights_lib_glsl[];
-extern char datatoc_closure_lit_lib_glsl[];
+extern char datatoc_closure_eval_lib_glsl[];
+extern char datatoc_closure_eval_diffuse_lib_glsl[];
+extern char datatoc_closure_eval_glossy_lib_glsl[];
+extern char datatoc_closure_eval_refraction_lib_glsl[];
+extern char datatoc_closure_eval_translucent_lib_glsl[];
extern char datatoc_ltc_lib_glsl[];
extern char datatoc_object_motion_frag_glsl[];
extern char datatoc_object_motion_vert_glsl[];
@@ -296,24 +299,14 @@ static void eevee_shader_library_ensure(void)
DRW_SHADER_LIB_ADD(e_data.lib, lights_lib);
DRW_SHADER_LIB_ADD(e_data.lib, surface_lib);
DRW_SHADER_LIB_ADD(e_data.lib, volumetric_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, closure_lib);
DRW_SHADER_LIB_ADD(e_data.lib, ssr_lib);
DRW_SHADER_LIB_ADD(e_data.lib, effect_dof_lib);
-
- /* Add one for each Closure */
- e_data.closure_lit_lib = BLI_string_joinN(datatoc_closure_lit_lib_glsl,
- datatoc_closure_lit_lib_glsl,
- datatoc_closure_lit_lib_glsl,
- datatoc_closure_lit_lib_glsl,
- datatoc_closure_lit_lib_glsl,
- datatoc_closure_lit_lib_glsl,
- datatoc_closure_lit_lib_glsl,
- datatoc_closure_lit_lib_glsl,
- datatoc_closure_lit_lib_glsl,
- datatoc_closure_lit_lib_glsl,
- datatoc_closure_lit_lib_glsl);
-
- DRW_shader_library_add_file(e_data.lib, e_data.closure_lit_lib, "closure_lit_lib.glsl");
+ DRW_SHADER_LIB_ADD(e_data.lib, closure_type_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_diffuse_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_glossy_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_translucent_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_refraction_lib);
e_data.surface_lit_frag = DRW_shader_library_create_shader_string(e_data.lib,
datatoc_surface_frag_glsl);
@@ -1545,7 +1538,6 @@ struct GPUMaterial *EEVEE_material_get(
void EEVEE_shaders_free(void)
{
- MEM_SAFE_FREE(e_data.closure_lit_lib);
MEM_SAFE_FREE(e_data.surface_prepass_frag);
MEM_SAFE_FREE(e_data.surface_lit_frag);
MEM_SAFE_FREE(e_data.surface_geom_barycentric);
diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
index 2f6f8327f58..7c0ae3881d7 100644
--- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
@@ -191,15 +191,15 @@ void gtao_deferred(
dirs.xy = get_ao_dir(noise.x * 0.5);
dirs.zw = get_ao_dir(noise.x * 0.5 + 0.5);
- bent_normal = normal * 1e-8;
- visibility = 1e-8;
+ bent_normal = vec3(0.0);
+ visibility = 0.0;
horizons = unpack_horizons(horizons);
integrate_slice(normal, dirs.xy, horizons.xy, visibility, bent_normal);
integrate_slice(normal, dirs.zw, horizons.zw, visibility, bent_normal);
- bent_normal = normalize(bent_normal / visibility);
+ bent_normal = safe_normalize(bent_normal);
visibility *= 0.5; /* We integrated 2 slices. */
}
@@ -240,13 +240,24 @@ float gtao_multibounce(float visibility, vec3 albedo)
return max(x, ((x * a + b) * x + c) * x);
}
+float diffuse_occlusion(vec3 N, vec3 vis_cone_dir, float vis_cone_aperture_cos, vec3 albedo)
+{
+ if ((int(aoSettings) & USE_AO) == 0) {
+ return 1.0;
+ }
+ /* If the shading normal is orthogonal to the geometric normal, it should be half lit. */
+ float horizon_fac = saturate(dot(N, vis_cone_dir) * 0.5 + 0.5);
+ float ao = vis_cone_aperture_cos * horizon_fac;
+ return gtao_multibounce(ao, albedo);
+}
+
float specular_occlusion(float NV, float AO, float roughness)
{
return saturate(pow(NV + AO, roughness) - 1.0 + AO);
}
/* Use the right occlusion */
-float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out vec3 bent_normal)
+float occlusion_compute(vec3 N, vec3 vpos, vec4 rand, out vec3 bent_normal)
{
#ifndef USE_REFRACTION
if ((int(aoSettings) & USE_AO) != 0) {
@@ -263,10 +274,6 @@ float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out
visibility = max(1e-3, visibility);
if ((int(aoSettings) & USE_BENT_NORMAL) != 0) {
- /* The bent normal will show the facet look of the mesh. Try to minimize this. */
- float mix_fac = visibility * visibility * visibility;
- bent_normal = normalize(mix(bent_normal, vnor, mix_fac));
-
bent_normal = transform_direction(ViewMatrixInverse, bent_normal);
}
else {
@@ -276,10 +283,10 @@ float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out
/* Scale by user factor */
visibility = pow(visibility, aoFactor);
- return min(visibility, user_occlusion);
+ return visibility;
}
#endif
bent_normal = N;
- return user_occlusion;
+ return 1.0;
}
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 3560ae62a84..f050cf3a08a 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -1,6 +1,15 @@
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+vec3 diffuse_dominant_dir(vec3 N, vec3 vis_cone_dir, float vis_cone_aperture_cos)
+{
+ /* TODO(fclem) revisit this. bent too much towards vis_cone_dir. */
+ vis_cone_aperture_cos *= sqr(vis_cone_aperture_cos);
+
+ N = mix(vis_cone_dir, N, vis_cone_aperture_cos);
+ return normalize(N);
+}
+
vec3 specular_dominant_dir(vec3 N, vec3 V, float roughness)
{
vec3 R = -reflect(V, N);
@@ -79,7 +88,7 @@ vec3 F_brdf_single_scatter(vec3 f0, vec3 f90, vec2 lut)
{
/* Unreal specular matching : if specular color is below 2% intensity,
* treat as shadowning */
- return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * lut.y * abs(f90) + lut.x * f0;
+ return lut.y * f90 + lut.x * f0;
}
/* Multi-scattering brdf approximation from :
@@ -87,11 +96,7 @@ vec3 F_brdf_single_scatter(vec3 f0, vec3 f90, vec2 lut)
* by Carmelo J. Fdez-Agüera. */
vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
{
- vec3 FssEss = F_brdf_single_scatter(f0, f90, lut);
- /* Hack to avoid many more shader variations. */
- if (f90.g < 0.0) {
- return FssEss;
- }
+ vec3 FssEss = lut.y * f90 + lut.x * f0;
float Ess = lut.x + lut.y;
float Ems = 1.0 - Ess;
@@ -102,8 +107,6 @@ vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
return FssEss + Fms * Ems;
}
-#define F_brdf(f0, f90, lut) F_brdf_multi_scatter(f0, f90, lut)
-
/* GGX */
float D_ggx_opti(float NH, float a2)
{
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
new file mode 100644
index 00000000000..1e65d3ccb87
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl
@@ -0,0 +1,85 @@
+#pragma BLENDER_REQUIRE(lights_lib.glsl)
+#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
+#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
+
+struct ClosureInputDiffuse {
+ vec3 N; /** Shading normal. */
+ vec3 albedo; /** Used for multibounce GTAO approximation. Not applied to final radiance. */
+};
+
+#define CLOSURE_INPUT_Diffuse_DEFAULT ClosureInputDiffuse(vec3(0.0), vec3(0.0))
+
+struct ClosureEvalDiffuse {
+ vec3 probe_sampling_dir; /** Direction to sample probes from. */
+ float ambient_occlusion; /** Final occlusion for distant lighting. */
+};
+
+/* Stubs. */
+#define ClosureOutputDiffuse ClosureOutput
+#define closure_Diffuse_planar_eval(cl_in, cl_eval, cl_common, data, cl_out)
+#define closure_Diffuse_cubemap_eval(cl_in, cl_eval, cl_common, data, cl_out)
+
+ClosureEvalDiffuse closure_Diffuse_eval_init(inout ClosureInputDiffuse cl_in,
+ ClosureEvalCommon cl_common,
+ out ClosureOutputDiffuse cl_out)
+{
+ cl_in.N = safe_normalize(cl_in.N);
+ cl_out.radiance = vec3(0.0);
+
+ ClosureEvalDiffuse cl_eval;
+ cl_eval.ambient_occlusion = diffuse_occlusion(
+ cl_in.N, cl_common.bent_normal, cl_common.occlusion, cl_in.albedo);
+ cl_eval.probe_sampling_dir = diffuse_dominant_dir(
+ cl_in.N, cl_common.bent_normal, cl_common.occlusion);
+ return cl_eval;
+}
+
+void closure_Diffuse_light_eval(ClosureInputDiffuse cl_in,
+ ClosureEvalDiffuse cl_eval,
+ ClosureEvalCommon cl_common,
+ ClosureLightData light,
+ inout ClosureOutputDiffuse cl_out)
+{
+ 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);
+}
+
+void closure_Diffuse_grid_eval(ClosureInputDiffuse cl_in,
+ ClosureEvalDiffuse cl_eval,
+ ClosureEvalCommon cl_common,
+ ClosureGridData grid,
+ inout ClosureOutputDiffuse cl_out)
+{
+ vec3 probe_radiance = probe_evaluate_grid(
+ grid.data, cl_common.P, cl_eval.probe_sampling_dir, grid.local_pos);
+ cl_out.radiance += grid.attenuation * probe_radiance;
+}
+
+void closure_Diffuse_indirect_end(ClosureInputDiffuse cl_in,
+ ClosureEvalDiffuse cl_eval,
+ ClosureEvalCommon cl_common,
+ inout ClosureOutputDiffuse cl_out)
+{
+ /* If not enough light has been accumulated from probes, use the world specular cubemap
+ * to fill the remaining energy needed. */
+ if (cl_common.diffuse_accum > 0.0) {
+ vec3 probe_radiance = probe_evaluate_world_diff(cl_eval.probe_sampling_dir);
+ cl_out.radiance += cl_common.diffuse_accum * probe_radiance;
+ }
+ /* Apply occlusion on radiance before the light loop. */
+ cl_out.radiance *= cl_eval.ambient_occlusion;
+}
+
+void closure_Diffuse_eval_end(ClosureInputDiffuse cl_in,
+ ClosureEvalDiffuse cl_eval,
+ ClosureEvalCommon cl_common,
+ inout ClosureOutputDiffuse cl_out)
+{
+#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
+ /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
+ cl_out.radiance = vec3(0.0);
+ return;
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
new file mode 100644
index 00000000000..9d539ec5a48
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
@@ -0,0 +1,136 @@
+
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(lights_lib.glsl)
+#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
+#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
+
+struct ClosureInputGlossy {
+ vec3 N; /** Shading normal. */
+ float roughness; /** Input roughness, not squared. */
+};
+
+#define CLOSURE_INPUT_Glossy_DEFAULT ClosureInputGlossy(vec3(0.0), 0.0)
+
+struct ClosureEvalGlossy {
+ vec4 ltc_mat; /** LTC matrix values. */
+ float ltc_brdf_scale; /** LTC BRDF scaling. */
+ vec3 probe_sampling_dir; /** Direction to sample probes from. */
+ float spec_occlusion; /** Specular Occlusion. */
+ vec3 raytrace_radiance; /** Raytrace reflection to be accumulated after occlusion. */
+};
+
+/* Stubs. */
+#define ClosureOutputGlossy ClosureOutput
+#define closure_Glossy_grid_eval(cl_in, cl_eval, cl_common, data, cl_out)
+
+#ifdef STEP_RESOLVE /* SSR */
+/* Prototype. */
+void raytrace_resolve(ClosureInputGlossy cl_in,
+ inout ClosureEvalGlossy cl_eval,
+ inout ClosureEvalCommon cl_common,
+ inout ClosureOutputGlossy cl_out);
+#endif
+
+ClosureEvalGlossy closure_Glossy_eval_init(inout ClosureInputGlossy cl_in,
+ inout ClosureEvalCommon cl_common,
+ out ClosureOutputGlossy cl_out)
+{
+ cl_in.N = safe_normalize(cl_in.N);
+ cl_in.roughness = clamp(cl_in.roughness, 1e-8, 0.9999);
+ cl_out.radiance = vec3(0.0);
+
+ float NV = dot(cl_in.N, cl_common.V);
+ vec2 lut_uv = lut_coords_ltc(NV, cl_in.roughness);
+
+ ClosureEvalGlossy cl_eval;
+ cl_eval.ltc_mat = texture(utilTex, vec3(lut_uv, LTC_MAT_LAYER));
+ cl_eval.probe_sampling_dir = specular_dominant_dir(cl_in.N, cl_common.V, sqr(cl_in.roughness));
+ cl_eval.spec_occlusion = specular_occlusion(NV, cl_common.occlusion, cl_in.roughness);
+ cl_eval.raytrace_radiance = vec3(0.0);
+
+#ifdef STEP_RESOLVE /* SSR */
+ raytrace_resolve(cl_in, cl_eval, cl_common, cl_out);
+#endif
+
+ /* The brdf split sum LUT is applied after the radiance accumulation.
+ * Correct the LTC so that its energy is constant. */
+ /* TODO(fclem) Optimize this so that only one scale factor is stored. */
+ vec4 ltc_brdf = texture(utilTex, vec3(lut_uv, LTC_BRDF_LAYER)).barg;
+ vec2 split_sum_brdf = ltc_brdf.zw;
+ cl_eval.ltc_brdf_scale = (ltc_brdf.x + ltc_brdf.y) / (split_sum_brdf.x + split_sum_brdf.y);
+ return cl_eval;
+}
+
+void closure_Glossy_light_eval(ClosureInputGlossy cl_in,
+ ClosureEvalGlossy cl_eval,
+ ClosureEvalCommon cl_common,
+ ClosureLightData light,
+ inout ClosureOutputGlossy cl_out)
+{
+ float radiance = light_specular(light.data, cl_eval.ltc_mat, cl_in.N, cl_common.V, light.L);
+ radiance *= cl_eval.ltc_brdf_scale;
+ cl_out.radiance += light.data.l_color *
+ (light.data.l_spec * light.vis * light.contact_shadow * radiance);
+}
+
+void closure_Glossy_planar_eval(ClosureInputGlossy cl_in,
+ ClosureEvalGlossy cl_eval,
+ inout ClosureEvalCommon cl_common,
+ ClosurePlanarData planar,
+ inout ClosureOutputGlossy cl_out)
+{
+#ifndef STEP_RESOLVE /* SSR already evaluates planar reflections. */
+ vec3 probe_radiance = probe_evaluate_planar(
+ planar.id, planar.data, cl_common.P, cl_in.N, cl_common.V, cl_in.roughness);
+ cl_out.radiance += planar.attenuation * probe_radiance;
+#else
+ /* HACK: Fix an issue with planar reflections still being counted inside the specular
+ * accumulator. This only works because we only use one Glossy closure in the resolve pass. */
+ cl_common.specular_accum += planar.attenuation;
+#endif
+}
+
+void closure_Glossy_cubemap_eval(ClosureInputGlossy cl_in,
+ ClosureEvalGlossy cl_eval,
+ ClosureEvalCommon cl_common,
+ ClosureCubemapData cube,
+ inout ClosureOutputGlossy cl_out)
+{
+ vec3 probe_radiance = probe_evaluate_cube(
+ cube.id, cl_common.P, cl_eval.probe_sampling_dir, cl_in.roughness);
+ cl_out.radiance += cube.attenuation * probe_radiance;
+}
+
+void closure_Glossy_indirect_end(ClosureInputGlossy cl_in,
+ ClosureEvalGlossy cl_eval,
+ ClosureEvalCommon cl_common,
+ inout ClosureOutputGlossy cl_out)
+{
+ /* If not enough light has been accumulated from probes, use the world specular cubemap
+ * to fill the remaining energy needed. */
+ if (specToggle && cl_common.specular_accum > 0.0) {
+ vec3 probe_radiance = probe_evaluate_world_spec(cl_eval.probe_sampling_dir, cl_in.roughness);
+ cl_out.radiance += cl_common.specular_accum * probe_radiance;
+ }
+
+ /* Apply occlusion on distant lighting. */
+ cl_out.radiance *= cl_eval.spec_occlusion;
+ /* Apply Raytrace reflections after occlusion since they are direct, local reflections. */
+ cl_out.radiance += cl_eval.raytrace_radiance;
+}
+
+void closure_Glossy_eval_end(ClosureInputGlossy cl_in,
+ ClosureEvalGlossy cl_eval,
+ ClosureEvalCommon cl_common,
+ inout ClosureOutputGlossy cl_out)
+{
+#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
+ /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
+ cl_out.radiance = vec3(0.0);
+ return;
+#endif
+
+ if (!specToggle) {
+ cl_out.radiance = vec3(0.0);
+ }
+}
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
new file mode 100644
index 00000000000..b1bb5f96f5c
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
@@ -0,0 +1,316 @@
+
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(lights_lib.glsl)
+#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
+
+/**
+ * Extensive use of Macros to be able to change the maximum amount of evaluated closure easily.
+ * NOTE: GLSL does not support variadic macros.
+ *
+ * Example
+ * // Declare the cl_eval function
+ * CLOSURE_EVAL_FUNCTION_DECLARE_3(name, Diffuse, Glossy, Refraction);
+ * // Declare the inputs & outputs
+ * CLOSURE_VARS_DECLARE(Diffuse, Glossy, Refraction);
+ * // Specify inputs
+ * in_Diffuse_0.N = N;
+ * ...
+ * // Call the cl_eval function
+ * CLOSURE_EVAL_FUNCTION_3(name, Diffuse, Glossy, Refraction);
+ * // Get the cl_out
+ * closure.radiance = out_Diffuse_0.radiance + out_Glossy_1.radiance + out_Refraction_2.radiance;
+ **/
+
+#define CLOSURE_VARS_DECLARE(t0, t1, t2, t3) \
+ ClosureInputCommon in_common = CLOSURE_INPUT_COMMON_DEFAULT; \
+ ClosureInput##t0 in_##t0##_0 = CLOSURE_INPUT_##t0##_DEFAULT; \
+ ClosureInput##t1 in_##t1##_1 = CLOSURE_INPUT_##t1##_DEFAULT; \
+ ClosureInput##t2 in_##t2##_2 = CLOSURE_INPUT_##t2##_DEFAULT; \
+ ClosureInput##t3 in_##t3##_3 = CLOSURE_INPUT_##t3##_DEFAULT; \
+ ClosureOutput##t0 out_##t0##_0; \
+ ClosureOutput##t1 out_##t1##_1; \
+ ClosureOutput##t2 out_##t2##_2; \
+ ClosureOutput##t3 out_##t3##_3;
+
+#define CLOSURE_EVAL_DECLARE(t0, t1, t2, t3) \
+ ClosureEvalCommon cl_common = closure_Common_eval_init(in_common); \
+ ClosureEval##t0 eval_##t0##_0 = closure_##t0##_eval_init(in_##t0##_0, cl_common, out_##t0##_0); \
+ ClosureEval##t1 eval_##t1##_1 = closure_##t1##_eval_init(in_##t1##_1, cl_common, out_##t1##_1); \
+ ClosureEval##t2 eval_##t2##_2 = closure_##t2##_eval_init(in_##t2##_2, cl_common, out_##t2##_2); \
+ ClosureEval##t3 eval_##t3##_3 = closure_##t3##_eval_init(in_##t3##_3, cl_common, out_##t3##_3);
+
+#define CLOSURE_META_SUBROUTINE(subroutine, t0, t1, t2, t3) \
+ closure_##t0##_##subroutine(in_##t0##_0, eval_##t0##_0, cl_common, out_##t0##_0); \
+ closure_##t1##_##subroutine(in_##t1##_1, eval_##t1##_1, cl_common, out_##t1##_1); \
+ closure_##t2##_##subroutine(in_##t2##_2, eval_##t2##_2, cl_common, out_##t2##_2); \
+ closure_##t3##_##subroutine(in_##t3##_3, eval_##t3##_3, cl_common, out_##t3##_3);
+
+#define CLOSURE_META_SUBROUTINE_DATA(subroutine, sub_data, t0, t1, t2, t3) \
+ closure_##t0##_##subroutine(in_##t0##_0, eval_##t0##_0, cl_common, sub_data, out_##t0##_0); \
+ closure_##t1##_##subroutine(in_##t1##_1, eval_##t1##_1, cl_common, sub_data, out_##t1##_1); \
+ closure_##t2##_##subroutine(in_##t2##_2, eval_##t2##_2, cl_common, sub_data, out_##t2##_2); \
+ closure_##t3##_##subroutine(in_##t3##_3, eval_##t3##_3, cl_common, sub_data, out_##t3##_3);
+
+/* Inputs are inout so that callers can get the final inputs used for evaluation. */
+#define CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3) \
+ void closure_##name##_eval(ClosureInputCommon in_common, \
+ inout ClosureInput##t0 in_##t0##_0, \
+ inout ClosureInput##t1 in_##t1##_1, \
+ inout ClosureInput##t2 in_##t2##_2, \
+ inout ClosureInput##t3 in_##t3##_3, \
+ out ClosureOutput##t0 out_##t0##_0, \
+ out ClosureOutput##t1 out_##t1##_1, \
+ out ClosureOutput##t2 out_##t2##_2, \
+ out ClosureOutput##t3 out_##t3##_3) \
+ { \
+ CLOSURE_EVAL_DECLARE(t0, t1, t2, t3); \
+\
+ for (int i = 0; cl_common.specular_accum > 0.0 && i < prbNumPlanar && i < MAX_PLANAR; i++) { \
+ ClosurePlanarData planar = closure_planar_eval_init(i, cl_common); \
+ if (planar.attenuation > 1e-8) { \
+ CLOSURE_META_SUBROUTINE_DATA(planar_eval, planar, t0, t1, t2, t3); \
+ } \
+ } \
+\
+ /* Starts at 1 because 0 is world cubemap. */ \
+ for (int i = 1; cl_common.specular_accum > 0.0 && i < prbNumRenderCube && i < MAX_PROBE; \
+ i++) { \
+ ClosureCubemapData cube = closure_cubemap_eval_init(i, cl_common); \
+ if (cube.attenuation > 1e-8) { \
+ CLOSURE_META_SUBROUTINE_DATA(cubemap_eval, cube, t0, t1, t2, t3); \
+ } \
+ } \
+\
+ /* Starts at 1 because 0 is world irradiance. */ \
+ for (int i = 1; cl_common.diffuse_accum > 0.0 && i < prbNumRenderGrid && i < MAX_GRID; i++) { \
+ ClosureGridData grid = closure_grid_eval_init(i, cl_common); \
+ if (grid.attenuation > 1e-8) { \
+ CLOSURE_META_SUBROUTINE_DATA(grid_eval, grid, t0, t1, t2, t3); \
+ } \
+ } \
+\
+ CLOSURE_META_SUBROUTINE(indirect_end, t0, t1, t2, t3); \
+\
+ for (int i = 0; i < laNumLight && i < MAX_LIGHT; i++) { \
+ ClosureLightData light = closure_light_eval_init(cl_common, i); \
+ if (light.vis > 1e-8) { \
+ CLOSURE_META_SUBROUTINE_DATA(light_eval, light, t0, t1, t2, t3); \
+ } \
+ } \
+\
+ CLOSURE_META_SUBROUTINE(eval_end, t0, t1, t2, t3); \
+ }
+
+#define CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, t3) \
+ closure_##name##_eval(in_common, \
+ in_##t0##_0, \
+ in_##t1##_1, \
+ in_##t2##_2, \
+ in_##t3##_3, \
+ out_##t0##_0, \
+ out_##t1##_1, \
+ out_##t2##_2, \
+ out_##t3##_3)
+
+#define CLOSURE_EVAL_FUNCTION_DECLARE_1(name, t0) \
+ CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, Dummy, Dummy, Dummy)
+#define CLOSURE_EVAL_FUNCTION_DECLARE_2(name, t0, t1) \
+ CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, Dummy, Dummy)
+#define CLOSURE_EVAL_FUNCTION_DECLARE_3(name, t0, t1, t2) \
+ CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, Dummy)
+#define CLOSURE_EVAL_FUNCTION_DECLARE_4(name, t0, t1, t2, t3) \
+ CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3)
+
+#define CLOSURE_VARS_DECLARE_1(t0) CLOSURE_VARS_DECLARE(t0, Dummy, Dummy, Dummy)
+#define CLOSURE_VARS_DECLARE_2(t0, t1) CLOSURE_VARS_DECLARE(t0, t1, Dummy, Dummy)
+#define CLOSURE_VARS_DECLARE_3(t0, t1, t2) CLOSURE_VARS_DECLARE(t0, t1, t2, Dummy)
+#define CLOSURE_VARS_DECLARE_4(t0, t1, t2, t3) CLOSURE_VARS_DECLARE(t0, t1, t2, t3)
+
+#define CLOSURE_EVAL_FUNCTION_1(name, t0) CLOSURE_EVAL_FUNCTION(name, t0, Dummy, Dummy, Dummy)
+#define CLOSURE_EVAL_FUNCTION_2(name, t0, t1) CLOSURE_EVAL_FUNCTION(name, t0, t1, Dummy, Dummy)
+#define CLOSURE_EVAL_FUNCTION_3(name, t0, t1, t2) CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, Dummy)
+#define CLOSURE_EVAL_FUNCTION_4(name, t0, t1, t2, t3) CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, t3)
+
+/* -------------------------------------------------------------------- */
+/** \name Dummy Closure
+ *
+ * Dummy closure type that will be optimized out by the compiler.
+ * \{ */
+
+#define ClosureInputDummy ClosureOutput
+#define ClosureOutputDummy ClosureOutput
+#define ClosureEvalDummy ClosureOutput
+#define CLOSURE_EVAL_DUMMY ClosureOutput(vec3(0))
+#define CLOSURE_INPUT_Dummy_DEFAULT CLOSURE_EVAL_DUMMY
+#define closure_Dummy_eval_init(cl_in, cl_common, cl_out) CLOSURE_EVAL_DUMMY
+#define closure_Dummy_planar_eval(cl_in, cl_eval, cl_common, data, cl_out)
+#define closure_Dummy_cubemap_eval(cl_in, cl_eval, cl_common, data, cl_out)
+#define closure_Dummy_grid_eval(cl_in, cl_eval, cl_common, data, cl_out)
+#define closure_Dummy_indirect_end(cl_in, cl_eval, cl_common, cl_out)
+#define closure_Dummy_light_eval(cl_in, cl_eval, cl_common, data, cl_out)
+#define closure_Dummy_eval_end(cl_in, cl_eval, cl_common, cl_out)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Common cl_eval data
+ *
+ * Eval data not dependant on input parameters. All might not be used but unused ones
+ * will be optimized out.
+ * \{ */
+
+struct ClosureInputCommon {
+ /** Custom occlusion value set by the user. */
+ float occlusion;
+};
+
+#define CLOSURE_INPUT_COMMON_DEFAULT ClosureInputCommon(1.0)
+
+struct ClosureEvalCommon {
+ /** View vector. */
+ vec3 V;
+ /** Surface position. */
+ vec3 P;
+ /** Normal vector, always facing camera. */
+ vec3 N;
+ /** Normal vector, always facing camera. (viewspace) */
+ vec3 vN;
+ /** Surface position. (viewspace) */
+ vec3 vP;
+ /** Geometric normal, always facing camera. (viewspace) */
+ vec3 vNg;
+ /** Random numbers. 3 random sequences. zw is a random point on a circle. */
+ vec4 rand;
+ /** Final occlusion factor. Mix of the user occlusion and SSAO. */
+ float occlusion;
+ /** Least occluded direction in the hemisphere. */
+ vec3 bent_normal;
+
+ /** Specular probe accumulator. Shared between planar and cubemap probe. */
+ float specular_accum;
+ /** Diffuse probe accumulator. */
+ float diffuse_accum;
+ /** Viewspace depth to start raytracing from. */
+ float tracing_depth;
+};
+
+/* Common cl_out struct used by most closures. */
+struct ClosureOutput {
+ vec3 radiance;
+};
+
+ClosureEvalCommon closure_Common_eval_init(ClosureInputCommon cl_in)
+{
+ ClosureEvalCommon cl_eval;
+ cl_eval.rand = texelfetch_noise_tex(gl_FragCoord.xy);
+ cl_eval.V = cameraVec;
+ cl_eval.P = worldPosition;
+ cl_eval.N = safe_normalize(gl_FrontFacing ? worldNormal : -worldNormal);
+ cl_eval.vN = safe_normalize(gl_FrontFacing ? viewNormal : -viewNormal);
+ cl_eval.vP = viewPosition;
+ cl_eval.vNg = safe_normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
+ /* TODO(fclem) See if we can avoid this complicated setup. */
+ cl_eval.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) */
+ cl_eval.tracing_depth -= mix(2.4e-7, 4.8e-7, gl_FragCoord.z);
+ /* Convert to view Z. */
+ cl_eval.tracing_depth = get_view_z_from_depth(cl_eval.tracing_depth);
+
+ /* TODO(fclem) Do occlusion evaluation per Closure using shading normal. */
+ cl_eval.occlusion = min(
+ cl_in.occlusion,
+ occlusion_compute(cl_eval.N, cl_eval.vP, cl_eval.rand, cl_eval.bent_normal));
+
+ cl_eval.specular_accum = 1.0;
+ cl_eval.diffuse_accum = 1.0;
+ return cl_eval;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop data
+ *
+ * Loop datas are conveniently packed into struct to make it future proof.
+ * \{ */
+
+struct ClosureLightData {
+ LightData data; /** Light Data. */
+ vec4 L; /** Non-Normalized Light Vector (surface to light) with length in W component. */
+ float vis; /** Light visibility. */
+ float contact_shadow; /** Result of contact shadow tracing. */
+};
+
+ClosureLightData closure_light_eval_init(ClosureEvalCommon cl_common, int light_id)
+{
+ ClosureLightData light;
+ light.data = lights_data[light_id];
+
+ light.L.xyz = light.data.l_position - cl_common.P;
+ light.L.w = length(light.L.xyz);
+
+ light.vis = light_visibility(light.data, cl_common.P, light.L);
+ light.contact_shadow = light_contact_shadows(light.data,
+ cl_common.P,
+ cl_common.vP,
+ cl_common.tracing_depth,
+ cl_common.vNg,
+ cl_common.rand.x,
+ light.vis);
+
+ return light;
+}
+
+struct ClosureCubemapData {
+ int id; /** Probe id. */
+ float attenuation; /** Attenuation. */
+};
+
+ClosureCubemapData closure_cubemap_eval_init(int cube_id, inout ClosureEvalCommon cl_common)
+{
+ ClosureCubemapData cube;
+ cube.id = cube_id;
+ cube.attenuation = probe_attenuation_cube(cube_id, cl_common.P);
+ cube.attenuation = min(cube.attenuation, cl_common.specular_accum);
+ cl_common.specular_accum -= cube.attenuation;
+ return cube;
+}
+
+struct ClosurePlanarData {
+ int id; /** Probe id. */
+ PlanarData data; /** planars_data[id]. */
+ float attenuation; /** Attenuation. */
+};
+
+ClosurePlanarData closure_planar_eval_init(int planar_id, inout ClosureEvalCommon cl_common)
+{
+ ClosurePlanarData planar;
+ planar.id = planar_id;
+ planar.data = planars_data[planar_id];
+ planar.attenuation = probe_attenuation_planar(planar.data, cl_common.P, cl_common.N, 0.0);
+ planar.attenuation = min(planar.attenuation, cl_common.specular_accum);
+ cl_common.specular_accum -= planar.attenuation;
+ return planar;
+}
+
+struct ClosureGridData {
+ int id; /** Grid id. */
+ GridData data; /** grids_data[id] */
+ float attenuation; /** Attenuation. */
+ vec3 local_pos; /** Local position inside the grid. */
+};
+
+ClosureGridData closure_grid_eval_init(int id, inout ClosureEvalCommon cl_common)
+{
+ ClosureGridData grid;
+ grid.id = id;
+ grid.data = grids_data[id];
+ grid.attenuation = probe_attenuation_grid(grid.data, cl_common.P, grid.local_pos);
+ grid.attenuation = min(grid.attenuation, cl_common.diffuse_accum);
+ cl_common.diffuse_accum -= grid.attenuation;
+ return grid;
+}
+
+/** \} */
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl
new file mode 100644
index 00000000000..9011eea07c4
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl
@@ -0,0 +1,128 @@
+
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(lights_lib.glsl)
+#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
+#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
+#pragma BLENDER_REQUIRE(ssr_lib.glsl)
+
+struct ClosureInputRefraction {
+ vec3 N; /** Shading normal. */
+ float roughness; /** Input roughness, not squared. */
+ float ior; /** Index of refraction ratio. */
+};
+
+#define CLOSURE_INPUT_Refraction_DEFAULT ClosureInputRefraction(vec3(0.0), 0.0, 0.0)
+
+struct ClosureEvalRefraction {
+ vec3 P; /** LTC matrix values. */
+ vec3 ltc_brdf; /** LTC BRDF values. */
+ vec3 probe_sampling_dir; /** Direction to sample probes from. */
+ float probes_weight; /** Factor to apply to probe radiance. */
+};
+
+/* Stubs. */
+#define ClosureOutputRefraction ClosureOutput
+#define closure_Refraction_grid_eval(cl_in, cl_eval, cl_common, data, cl_out)
+
+ClosureEvalRefraction closure_Refraction_eval_init(inout ClosureInputRefraction cl_in,
+ ClosureEvalCommon cl_common,
+ out ClosureOutputRefraction cl_out)
+{
+ cl_in.N = safe_normalize(cl_in.N);
+ cl_in.roughness = clamp(cl_in.roughness, 1e-8, 0.9999);
+ cl_in.ior = max(cl_in.ior, 1e-5);
+ cl_out.radiance = vec3(0.0);
+
+ ClosureEvalRefraction cl_eval;
+ vec3 cl_V;
+ float eval_ior;
+ /* Refract the view vector using the depth heuristic.
+ * Then later Refract a second time the already refracted
+ * ray using the inverse ior. */
+ if (refractionDepth > 0.0) {
+ eval_ior = 1.0 / cl_in.ior;
+ cl_V = -refract(-cl_common.V, cl_in.N, eval_ior);
+ vec3 plane_pos = cl_common.P - cl_in.N * refractionDepth;
+ cl_eval.P = line_plane_intersect(cl_common.P, cl_V, plane_pos, cl_in.N);
+ }
+ else {
+ eval_ior = cl_in.ior;
+ cl_V = cl_common.V;
+ cl_eval.P = cl_common.P;
+ }
+
+ cl_eval.probe_sampling_dir = refraction_dominant_dir(cl_in.N, cl_V, cl_in.roughness, eval_ior);
+ cl_eval.probes_weight = 1.0;
+
+#ifdef USE_REFRACTION
+ if (ssrefractToggle && cl_in.roughness < ssrMaxRoughness + 0.2) {
+ /* Find approximated position of the 2nd refraction event. */
+ vec3 vP = (refractionDepth > 0.0) ? transform_point(ViewMatrix, cl_eval.P) : cl_common.vP;
+ vec4 ssr_output = screen_space_refraction(
+ vP, cl_in.N, cl_V, eval_ior, sqr(cl_in.roughness), cl_common.rand);
+ ssr_output.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, cl_in.roughness);
+ cl_out.radiance += ssr_output.rgb * ssr_output.a;
+ cl_eval.probes_weight -= ssr_output.a;
+ }
+#endif
+ return cl_eval;
+}
+
+void closure_Refraction_light_eval(ClosureInputRefraction cl_in,
+ ClosureEvalRefraction cl_eval,
+ ClosureEvalCommon cl_common,
+ ClosureLightData light,
+ inout ClosureOutputRefraction cl_out)
+{
+ /* Not implemented yet. */
+}
+
+void closure_Refraction_planar_eval(ClosureInputRefraction cl_in,
+ ClosureEvalRefraction cl_eval,
+ ClosureEvalCommon cl_common,
+ ClosurePlanarData planar,
+ inout ClosureOutputRefraction cl_out)
+{
+ /* Not implemented yet. */
+}
+
+void closure_Refraction_cubemap_eval(ClosureInputRefraction cl_in,
+ ClosureEvalRefraction cl_eval,
+ ClosureEvalCommon cl_common,
+ ClosureCubemapData cube,
+ inout ClosureOutputRefraction cl_out)
+{
+ vec3 probe_radiance = probe_evaluate_cube(
+ cube.id, cl_eval.P, cl_eval.probe_sampling_dir, sqr(cl_in.roughness));
+ cl_out.radiance += (cube.attenuation * cl_eval.probes_weight) * probe_radiance;
+}
+
+void closure_Refraction_indirect_end(ClosureInputRefraction cl_in,
+ ClosureEvalRefraction cl_eval,
+ ClosureEvalCommon cl_common,
+ inout ClosureOutputRefraction cl_out)
+{
+ /* If not enough light has been accumulated from probes, use the world specular cubemap
+ * to fill the remaining energy needed. */
+ if (specToggle && cl_common.specular_accum > 0.0) {
+ vec3 probe_radiance = probe_evaluate_world_spec(cl_eval.probe_sampling_dir,
+ sqr(cl_in.roughness));
+ cl_out.radiance += (cl_common.specular_accum * cl_eval.probes_weight) * probe_radiance;
+ }
+}
+
+void closure_Refraction_eval_end(ClosureInputRefraction cl_in,
+ ClosureEvalRefraction cl_eval,
+ ClosureEvalCommon cl_common,
+ inout ClosureOutputRefraction cl_out)
+{
+#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
+ /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
+ cl_out.radiance = vec3(0.0);
+ return;
+#endif
+
+ if (!specToggle) {
+ cl_out.radiance = vec3(0.0);
+ }
+}
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
new file mode 100644
index 00000000000..66c467af29b
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl
@@ -0,0 +1,71 @@
+
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(lights_lib.glsl)
+#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
+#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
+
+struct ClosureInputTranslucent {
+ vec3 N; /** Shading normal. */
+};
+
+#define CLOSURE_INPUT_Translucent_DEFAULT ClosureInputTranslucent(vec3(0.0))
+
+/* Stubs. */
+#define ClosureEvalTranslucent ClosureEvalDummy
+#define ClosureOutputTranslucent ClosureOutput
+#define closure_Translucent_planar_eval(cl_in, cl_eval, cl_common, data, cl_out)
+#define closure_Translucent_cubemap_eval(cl_in, cl_eval, cl_common, data, cl_out)
+
+ClosureEvalTranslucent closure_Translucent_eval_init(inout ClosureInputTranslucent cl_in,
+ ClosureEvalCommon cl_common,
+ out ClosureOutputTranslucent cl_out)
+{
+ cl_in.N = safe_normalize(cl_in.N);
+ cl_out.radiance = vec3(0.0);
+ return CLOSURE_EVAL_DUMMY;
+}
+
+void closure_Translucent_light_eval(ClosureInputTranslucent cl_in,
+ ClosureEvalTranslucent cl_eval,
+ ClosureEvalCommon cl_common,
+ ClosureLightData light,
+ 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);
+}
+
+void closure_Translucent_grid_eval(ClosureInputTranslucent cl_in,
+ ClosureEvalTranslucent cl_eval,
+ ClosureEvalCommon cl_common,
+ ClosureGridData grid,
+ inout ClosureOutputTranslucent cl_out)
+{
+ vec3 probe_radiance = probe_evaluate_grid(grid.data, cl_common.P, cl_in.N, grid.local_pos);
+ cl_out.radiance += grid.attenuation * probe_radiance;
+}
+
+void closure_Translucent_indirect_end(ClosureInputTranslucent cl_in,
+ ClosureEvalTranslucent cl_eval,
+ ClosureEvalCommon cl_common,
+ inout ClosureOutputTranslucent cl_out)
+{
+ /* If not enough light has been accumulated from probes, use the world specular cubemap
+ * to fill the remaining energy needed. */
+ if (cl_common.diffuse_accum > 0.0) {
+ vec3 probe_radiance = probe_evaluate_world_diff(cl_in.N);
+ cl_out.radiance += cl_common.diffuse_accum * probe_radiance;
+ }
+}
+
+void closure_Translucent_eval_end(ClosureInputTranslucent cl_in,
+ ClosureEvalTranslucent cl_eval,
+ ClosureEvalCommon cl_common,
+ inout ClosureOutputTranslucent cl_out)
+{
+#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
+ /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
+ cl_out.radiance = vec3(0.0);
+ return;
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl
deleted file mode 100644
index 30ce60f3ec0..00000000000
--- a/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl
+++ /dev/null
@@ -1,545 +0,0 @@
-
-#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
-#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
-#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
-#pragma BLENDER_REQUIRE(ssr_lib.glsl)
-
-/**
- * AUTO CONFIG
- * We include the file multiple times each time with a different configuration.
- * This leads to a lot of deadcode. Better idea would be to only generate the one needed.
- */
-#if !defined(SURFACE_DEFAULT)
-# define SURFACE_DEFAULT
-# define CLOSURE_NAME eevee_closure_default
-# define CLOSURE_DIFFUSE
-# define CLOSURE_GLOSSY
-#endif /* SURFACE_DEFAULT */
-
-#if !defined(SURFACE_DEFAULT_CLEARCOAT) && !defined(CLOSURE_NAME)
-# define SURFACE_DEFAULT_CLEARCOAT
-# define CLOSURE_NAME eevee_closure_default_clearcoat
-# define CLOSURE_DIFFUSE
-# define CLOSURE_GLOSSY
-# define CLOSURE_CLEARCOAT
-#endif /* SURFACE_DEFAULT_CLEARCOAT */
-
-#if !defined(SURFACE_PRINCIPLED) && !defined(CLOSURE_NAME)
-# define SURFACE_PRINCIPLED
-# define CLOSURE_NAME eevee_closure_principled
-# define CLOSURE_DIFFUSE
-# define CLOSURE_GLOSSY
-# define CLOSURE_CLEARCOAT
-# define CLOSURE_REFRACTION
-# define CLOSURE_SUBSURFACE
-#endif /* SURFACE_PRINCIPLED */
-
-#if !defined(SURFACE_CLEARCOAT) && !defined(CLOSURE_NAME)
-# define SURFACE_CLEARCOAT
-# define CLOSURE_NAME eevee_closure_clearcoat
-# define CLOSURE_GLOSSY
-# define CLOSURE_CLEARCOAT
-#endif /* SURFACE_CLEARCOAT */
-
-#if !defined(SURFACE_DIFFUSE) && !defined(CLOSURE_NAME)
-# define SURFACE_DIFFUSE
-# define CLOSURE_NAME eevee_closure_diffuse
-# define CLOSURE_DIFFUSE
-#endif /* SURFACE_DIFFUSE */
-
-#if !defined(SURFACE_SUBSURFACE) && !defined(CLOSURE_NAME)
-# define SURFACE_SUBSURFACE
-# define CLOSURE_NAME eevee_closure_subsurface
-# define CLOSURE_DIFFUSE
-# define CLOSURE_SUBSURFACE
-#endif /* SURFACE_SUBSURFACE */
-
-#if !defined(SURFACE_SKIN) && !defined(CLOSURE_NAME)
-# define SURFACE_SKIN
-# define CLOSURE_NAME eevee_closure_skin
-# define CLOSURE_DIFFUSE
-# define CLOSURE_SUBSURFACE
-# define CLOSURE_GLOSSY
-#endif /* SURFACE_SKIN */
-
-#if !defined(SURFACE_GLOSSY) && !defined(CLOSURE_NAME)
-# define SURFACE_GLOSSY
-# define CLOSURE_NAME eevee_closure_glossy
-# define CLOSURE_GLOSSY
-#endif /* SURFACE_GLOSSY */
-
-#if !defined(SURFACE_REFRACT) && !defined(CLOSURE_NAME)
-# define SURFACE_REFRACT
-# define CLOSURE_NAME eevee_closure_refraction
-# define CLOSURE_REFRACTION
-#endif /* SURFACE_REFRACT */
-
-#if !defined(SURFACE_GLASS) && !defined(CLOSURE_NAME)
-# define SURFACE_GLASS
-# define CLOSURE_NAME eevee_closure_glass
-# define CLOSURE_GLOSSY
-# define CLOSURE_REFRACTION
-#endif /* SURFACE_GLASS */
-
-/* Safety : CLOSURE_CLEARCOAT implies CLOSURE_GLOSSY */
-#ifdef CLOSURE_CLEARCOAT
-# ifndef CLOSURE_GLOSSY
-# define CLOSURE_GLOSSY
-# endif
-#endif /* CLOSURE_CLEARCOAT */
-
-void CLOSURE_NAME(vec3 N
-#ifdef CLOSURE_DIFFUSE
- ,
- vec3 albedo
-#endif
-#ifdef CLOSURE_GLOSSY
- ,
- vec3 f0,
- vec3 f90,
- int ssr_id
-#endif
-#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION)
- ,
- float roughness
-#endif
-#ifdef CLOSURE_CLEARCOAT
- ,
- vec3 C_N,
- float C_intensity,
- float C_roughness
-#endif
-#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE)
- ,
- float ao
-#endif
-#ifdef CLOSURE_SUBSURFACE
- ,
- float sss_scale
-#endif
-#ifdef CLOSURE_REFRACTION
- ,
- float ior
-#endif
- ,
- const bool use_contact_shadows
-#ifdef CLOSURE_DIFFUSE
- ,
- out vec3 out_diff
-#endif
-#ifdef CLOSURE_GLOSSY
- ,
- out vec3 out_spec
-#endif
-#ifdef CLOSURE_REFRACTION
- ,
- out vec3 out_refr
-#endif
-#ifdef CLOSURE_GLOSSY
- ,
- out vec3 ssr_spec
-#endif
-)
-{
-#ifdef CLOSURE_DIFFUSE
- out_diff = vec3(0.0);
-#endif
-
-#ifdef CLOSURE_GLOSSY
- out_spec = vec3(0.0);
-#endif
-
-#ifdef CLOSURE_REFRACTION
- out_refr = vec3(0.0);
-#endif
-
-#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
- /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
- return;
-#else
-
- /* Zero length vectors cause issues, see: T51979. */
- float len = length(N);
- if (isnan(len)) {
- return;
- }
- N /= len;
-
-# ifdef CLOSURE_CLEARCOAT
- len = length(C_N);
- if (isnan(len)) {
- return;
- }
- C_N /= len;
-# endif
-
-# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION)
- roughness = clamp(roughness, 1e-8, 0.9999);
- float roughnessSquared = roughness * roughness;
-# endif
-
-# ifdef CLOSURE_CLEARCOAT
- C_roughness = clamp(C_roughness, 1e-8, 0.9999);
- float C_roughnessSquared = C_roughness * C_roughness;
-# endif
-
- vec3 V = cameraVec;
-
- vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
-
- /* ---------------------------------------------------------------- */
- /* -------------------- SCENE LIGHTS LIGHTING --------------------- */
- /* ---------------------------------------------------------------- */
-
-# ifdef CLOSURE_GLOSSY
- vec2 lut_uv = lut_coords_ltc(dot(N, V), roughness);
- vec4 ltc_mat = texture(utilTex, vec3(lut_uv, 0.0)).rgba;
-# endif
-
-# ifdef CLOSURE_CLEARCOAT
- vec2 lut_uv_clear = lut_coords_ltc(dot(C_N, V), C_roughness);
- vec4 ltc_mat_clear = texture(utilTex, vec3(lut_uv_clear, 0.0)).rgba;
- 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];
-
- vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */
- l_vector.xyz = ld.l_position - worldPosition;
- l_vector.w = length(l_vector.xyz);
-
- 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;
- }
-
- vec3 l_color_vis = ld.l_color * l_vis;
-
-# ifdef CLOSURE_DIFFUSE
- out_diff += l_color_vis * light_diffuse(ld, N, V, l_vector);
-# endif
-
-# ifdef CLOSURE_GLOSSY
- out_spec += l_color_vis * light_specular(ld, ltc_mat, N, V, l_vector) * ld.l_spec;
-# endif
-
-# ifdef CLOSURE_CLEARCOAT
- out_spec_clear += l_color_vis * light_specular(ld, ltc_mat_clear, C_N, V, l_vector) *
- ld.l_spec;
-# endif
- }
-
-# ifdef CLOSURE_GLOSSY
- vec2 brdf_lut_lights = texture(utilTex, vec3(lut_uv, 1.0)).ba;
- out_spec *= F_brdf(f0, f90, brdf_lut_lights.xy);
-# endif
-
-# ifdef CLOSURE_CLEARCOAT
- vec2 brdf_lut_lights_clear = texture(utilTex, vec3(lut_uv_clear, 1.0)).ba;
- out_spec_clear *= F_brdf(vec3(0.04), vec3(1.0), brdf_lut_lights_clear.xy);
- out_spec += out_spec_clear * C_intensity;
-# endif
-
- /* ---------------------------------------------------------------- */
- /* ---------------- SPECULAR ENVIRONMENT LIGHTING ----------------- */
- /* ---------------------------------------------------------------- */
-
- /* Accumulate incoming light from all sources until accumulator is full. Then apply Occlusion and
- * BRDF. */
-# ifdef CLOSURE_GLOSSY
- vec4 spec_accum = vec4(0.0);
-# endif
-
-# ifdef CLOSURE_CLEARCOAT
- vec4 C_spec_accum = vec4(0.0);
-# endif
-
-# ifdef CLOSURE_REFRACTION
- vec4 refr_accum = vec4(0.0);
-# endif
-
-# ifdef CLOSURE_GLOSSY
- /* ---------------------------- */
- /* Planar Reflections */
- /* ---------------------------- */
-
- for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar && spec_accum.a < 0.999; i++) {
- PlanarData pd = planars_data[i];
-
- /* Fade on geometric normal. */
- float fade = probe_attenuation_planar(
- pd, worldPosition, (gl_FrontFacing) ? worldNormal : -worldNormal, roughness);
-
- if (fade > 0.0) {
- if (!(ssrToggle && ssr_id == outputSsrId)) {
- vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, roughness, fade);
- accumulate_light(spec, fade, spec_accum);
- }
-
-# ifdef CLOSURE_CLEARCOAT
- vec3 C_spec = probe_evaluate_planar(float(i), pd, worldPosition, C_N, V, C_roughness, fade);
- accumulate_light(C_spec, fade, C_spec_accum);
-# endif
- }
- }
-# endif
-
-# ifdef CLOSURE_GLOSSY
- vec3 spec_dir = specular_dominant_dir(N, V, roughnessSquared);
-# endif
-
-# ifdef CLOSURE_CLEARCOAT
- vec3 C_spec_dir = specular_dominant_dir(C_N, V, C_roughnessSquared);
-# endif
-
-# ifdef CLOSURE_REFRACTION
- /* Refract the view vector using the depth heuristic.
- * Then later Refract a second time the already refracted
- * ray using the inverse ior. */
- float final_ior = (refractionDepth > 0.0) ? 1.0 / ior : ior;
- vec3 refr_V = (refractionDepth > 0.0) ? -refract(-V, N, final_ior) : V;
- vec3 refr_pos = (refractionDepth > 0.0) ?
- line_plane_intersect(
- worldPosition, refr_V, worldPosition - N * refractionDepth, N) :
- worldPosition;
- vec3 refr_dir = refraction_dominant_dir(N, refr_V, roughness, final_ior);
-# endif
-
-# ifdef CLOSURE_REFRACTION
-/* ---------------------------- */
-/* Screen Space Refraction */
-/* ---------------------------- */
-# ifdef USE_REFRACTION
- if (ssrefractToggle && roughness < ssrMaxRoughness + 0.2) {
- /* Find approximated position of the 2nd refraction event. */
- vec3 refr_vpos = (refractionDepth > 0.0) ? transform_point(ViewMatrix, refr_pos) :
- viewPosition;
- vec4 trans = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand);
- trans.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
- accumulate_light(trans.rgb, trans.a, refr_accum);
- }
-# endif
-
-# endif
-
- /* ---------------------------- */
- /* Specular probes */
- /* ---------------------------- */
-# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION)
-
-# if defined(CLOSURE_GLOSSY) && defined(CLOSURE_REFRACTION)
-# define GLASS_ACCUM 1
-# define ACCUM min(refr_accum.a, spec_accum.a)
-# elif defined(CLOSURE_REFRACTION)
-# define GLASS_ACCUM 0
-# define ACCUM refr_accum.a
-# else
-# define GLASS_ACCUM 0
-# define ACCUM spec_accum.a
-# endif
-
- /* Starts at 1 because 0 is world probe */
- for (int i = 1; ACCUM < 0.999 && i < prbNumRenderCube && i < MAX_PROBE; i++) {
- float fade = probe_attenuation_cube(i, worldPosition);
-
- if (fade > 0.0) {
-
-# if GLASS_ACCUM
- if (spec_accum.a < 0.999) {
-# endif
-# ifdef CLOSURE_GLOSSY
- if (!(ssrToggle && ssr_id == outputSsrId)) {
- vec3 spec = probe_evaluate_cube(i, worldPosition, spec_dir, roughness);
- accumulate_light(spec, fade, spec_accum);
- }
-# endif
-
-# ifdef CLOSURE_CLEARCOAT
- vec3 C_spec = probe_evaluate_cube(i, worldPosition, C_spec_dir, C_roughness);
- accumulate_light(C_spec, fade, C_spec_accum);
-# endif
-# if GLASS_ACCUM
- }
-# endif
-
-# if GLASS_ACCUM
- if (refr_accum.a < 0.999) {
-# endif
-# ifdef CLOSURE_REFRACTION
- vec3 trans = probe_evaluate_cube(i, refr_pos, refr_dir, roughnessSquared);
- accumulate_light(trans, fade, refr_accum);
-# endif
-# if GLASS_ACCUM
- }
-# endif
- }
- }
-
-# undef GLASS_ACCUM
-# undef ACCUM
-
-/* ---------------------------- */
-/* World Probe */
-/* ---------------------------- */
-# ifdef CLOSURE_GLOSSY
- if (spec_accum.a < 0.999) {
- if (!(ssrToggle && ssr_id == outputSsrId)) {
- vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
- accumulate_light(spec, 1.0, spec_accum);
- }
-
-# ifdef CLOSURE_CLEARCOAT
- vec3 C_spec = probe_evaluate_world_spec(C_spec_dir, C_roughness);
- accumulate_light(C_spec, 1.0, C_spec_accum);
-# endif
- }
-# endif
-
-# ifdef CLOSURE_REFRACTION
- if (refr_accum.a < 0.999) {
- vec3 trans = probe_evaluate_world_spec(refr_dir, roughnessSquared);
- accumulate_light(trans, 1.0, refr_accum);
- }
-# endif
-# endif /* Specular probes */
-
- /* ---------------------------- */
- /* Ambient Occlusion */
- /* ---------------------------- */
-# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE)
- if (!use_contact_shadows) {
- /* HACK: Fix for translucent BSDF. (see T65631) */
- N = -N;
- }
- vec3 bent_normal;
- float final_ao = occlusion_compute(N, viewPosition, ao, rand, bent_normal);
- if (!use_contact_shadows) {
- N = -N;
- /* Bypass bent normal. */
- bent_normal = N;
- }
-# endif
-
- /* ---------------------------- */
- /* Specular Output */
- /* ---------------------------- */
- float NV = dot(N, V);
-# ifdef CLOSURE_GLOSSY
- vec2 uv = lut_coords(NV, roughness);
- vec2 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rg;
-
- /* This factor is outputted to be used by SSR in order
- * to match the intensity of the regular reflections. */
- ssr_spec = F_brdf(f0, f90, brdf_lut);
- float spec_occlu = specular_occlusion(NV, final_ao, roughness);
-
- /* The SSR pass recompute the occlusion to not apply it to the SSR */
- if (ssrToggle && ssr_id == outputSsrId) {
- spec_occlu = 1.0;
- }
-
- out_spec += spec_accum.rgb * ssr_spec * spec_occlu;
-# endif
-
-# ifdef CLOSURE_REFRACTION
- float btdf = get_btdf_lut(NV, roughness, ior);
-
- out_refr += refr_accum.rgb * btdf;
-
- /* Global toggle for lightprobe baking. */
- out_refr *= float(specToggle);
-# endif
-
-# ifdef CLOSURE_CLEARCOAT
- NV = dot(C_N, V);
- vec2 C_uv = lut_coords(NV, C_roughness);
- vec2 C_brdf_lut = texture(utilTex, vec3(C_uv, 1.0)).rg;
- vec3 C_fresnel = F_brdf(vec3(0.04), vec3(1.0), C_brdf_lut) *
- specular_occlusion(NV, final_ao, C_roughness);
-
- out_spec += C_spec_accum.rgb * C_fresnel * C_intensity;
-# endif
-
-# ifdef CLOSURE_GLOSSY
- /* Global toggle for lightprobe baking. */
- out_spec *= float(specToggle);
-# endif
-
- /* ---------------------------------------------------------------- */
- /* ---------------- DIFFUSE ENVIRONMENT LIGHTING ------------------ */
- /* ---------------------------------------------------------------- */
-
- /* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */
-# ifdef CLOSURE_DIFFUSE
- vec4 diff_accum = vec4(0.0);
-
- /* ---------------------------- */
- /* Irradiance Grids */
- /* ---------------------------- */
- /* Start at 1 because 0 is world irradiance */
- for (int i = 1; i < MAX_GRID && i < prbNumRenderGrid && diff_accum.a < 0.999; i++) {
- GridData gd = grids_data[i];
-
- vec3 localpos;
- float fade = probe_attenuation_grid(gd, grids_data[i].localmat, worldPosition, localpos);
-
- if (fade > 0.0) {
- vec3 diff = probe_evaluate_grid(gd, worldPosition, bent_normal, localpos);
- accumulate_light(diff, fade, diff_accum);
- }
- }
-
- /* ---------------------------- */
- /* World Diffuse */
- /* ---------------------------- */
- if (diff_accum.a < 0.999 && prbNumRenderGrid > 0) {
- vec3 diff = probe_evaluate_world_diff(bent_normal);
- accumulate_light(diff, 1.0, diff_accum);
- }
-
- out_diff += diff_accum.rgb * gtao_multibounce(final_ao, albedo);
-# endif
-#endif
-}
-
-/* Cleanup for next configuration */
-#undef CLOSURE_NAME
-
-#ifdef CLOSURE_DIFFUSE
-# undef CLOSURE_DIFFUSE
-#endif
-
-#ifdef CLOSURE_GLOSSY
-# undef CLOSURE_GLOSSY
-#endif
-
-#ifdef CLOSURE_CLEARCOAT
-# undef CLOSURE_CLEARCOAT
-#endif
-
-#ifdef CLOSURE_REFRACTION
-# undef CLOSURE_REFRACTION
-#endif
-
-#ifdef CLOSURE_SUBSURFACE
-# undef CLOSURE_SUBSURFACE
-#endif
diff --git a/source/blender/draw/engines/eevee/shaders/closure_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
index b56a186ab3f..9ca25ef240f 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
@@ -147,17 +147,27 @@ Closure closure_emission(vec3 rgb)
#ifndef VOLUMETRICS
+/* Let radiance passthrough or replace it to get the BRDF and color
+ * to applied to the SSR result. */
+vec3 closure_mask_ssr_radiance(vec3 radiance, float ssr_id)
+{
+ return (ssrToggle && int(ssr_id) == outputSsrId) ? vec3(1.0) : radiance;
+}
+
void closure_load_ssr_data(
- vec3 ssr_spec, float roughness, vec3 N, vec3 viewVec, int ssr_id, inout Closure cl)
+ vec3 ssr_radiance, float roughness, vec3 N, float ssr_id, inout Closure cl)
{
/* Still encode to avoid artifacts in the SSR pass. */
vec3 vN = normalize(mat3(ViewMatrix) * N);
- cl.ssr_normal = normal_encode(vN, viewVec);
+ cl.ssr_normal = normal_encode(vN, viewCameraVec);
- if (ssr_id == outputSsrId) {
- cl.ssr_data = vec4(ssr_spec, roughness);
+ if (ssrToggle && int(ssr_id) == outputSsrId) {
+ cl.ssr_data = vec4(ssr_radiance, roughness);
cl.flag |= CLOSURE_SSR_FLAG;
}
+ else {
+ cl.radiance += ssr_radiance;
+ }
}
void closure_load_sss_data(
@@ -169,13 +179,11 @@ void closure_load_sss_data(
cl.sss_radius = radius;
cl.sss_albedo = sss_albedo;
cl.flag |= CLOSURE_SSS_FLAG;
- cl.radiance += render_pass_diffuse_mask(sss_albedo, vec3(0));
+ /* Irradiance will be convolved by SSSS pass. Do not add to radiance. */
+ sss_irradiance = vec3(0);
}
- else
# endif
- {
- cl.radiance += render_pass_diffuse_mask(sss_albedo, sss_irradiance * sss_albedo);
- }
+ cl.radiance += render_pass_diffuse_mask(vec3(1), sss_irradiance) * sss_albedo;
}
#endif
diff --git a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl
index 427657b19b7..7b1a0b263c0 100644
--- a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl
@@ -12,6 +12,13 @@ uniform sampler2DArray utilTex;
#define LUT_SIZE 64
+#define LTC_MAT_LAYER 0
+#define LTC_BRDF_LAYER 1
+#define BRDF_LUT_LAYER 1
+#define NOISE_LAYER 2
+#define LTC_DISK_LAYER 3 /* UNUSED */
+/* Layers 4 to 20 are for BTDF Lut. */
+
/**
* Reminder: The 4 noise values are based of 3 uncorrelated blue noises:
* x : Uniformly distributed value [0..1] (noise 1).
@@ -23,6 +30,7 @@ uniform sampler2DArray utilTex;
/* Return texture coordinates to sample Surface LUT */
vec2 lut_coords(float cosTheta, float roughness)
{
+ /* TODO(fclem) Ugly Acos here. Get rid ot this. Should use same mapping as lut_coords_ltc. */
float theta = acos(cosTheta);
vec2 coords = vec2(roughness, theta / M_PI_2);
@@ -38,6 +46,11 @@ vec2 lut_coords_ltc(float cosTheta, float roughness)
return coords * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
}
+vec2 brdf_lut(float cosTheta, float roughness)
+{
+ return textureLod(utilTex, vec3(lut_coords(cosTheta, roughness), BRDF_LUT_LAYER), 0.0).rg;
+}
+
float get_btdf_lut(float NV, float roughness, float ior)
{
const vec3 lut_scale_bias_texel_size = vec3((LUT_SIZE - 1.0), 0.5, 1.5) / LUT_SIZE;
diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
index d50a4eaea3c..b49cd987a6e 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
@@ -2,6 +2,8 @@
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
#pragma BLENDER_REQUIRE(raytrace_lib.glsl)
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
#pragma BLENDER_REQUIRE(ssr_lib.glsl)
@@ -170,7 +172,7 @@ void main()
/* Importance sampling bias */
rand.x = mix(rand.x, 0.0, ssrBrdfBias);
- vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
+ vec3 W = transform_point(ViewMatrixInverse, viewPosition);
vec3 wN = transform_direction(ViewMatrixInverse, N);
vec3 T, B;
@@ -180,12 +182,12 @@ void main()
for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
PlanarData pd = planars_data[i];
- float fade = probe_attenuation_planar(pd, worldPosition, wN, 0.0);
+ float fade = probe_attenuation_planar(pd, W, wN, 0.0);
if (fade > 0.5) {
/* Find view vector / reflection plane intersection. */
/* TODO optimize, use view space for all. */
- vec3 tracePosition = line_plane_intersect(worldPosition, cameraVec, pd.pl_plane_eq);
+ vec3 tracePosition = line_plane_intersect(W, cameraVec, pd.pl_plane_eq);
tracePosition = transform_point(ViewMatrix, tracePosition);
vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal);
@@ -213,6 +215,8 @@ uniform sampler2D pdfBuffer;
uniform int neighborOffset;
+in vec4 uvcoordsvar;
+
const ivec2 neighbors[32] = ivec2[32](ivec2(0, 0),
ivec2(1, 1),
ivec2(-2, 0),
@@ -298,7 +302,7 @@ float get_sample_depth(vec2 hit_co, bool is_planar, float planar_index)
vec3 get_hit_vector(vec3 hit_pos,
PlanarData pd,
- vec3 worldPosition,
+ vec3 P,
vec3 N,
vec3 V,
bool is_planar,
@@ -309,7 +313,7 @@ vec3 get_hit_vector(vec3 hit_pos,
if (is_planar) {
/* Reflect back the hit position to have it in non-reflected world space */
- vec3 trace_pos = line_plane_intersect(worldPosition, V, pd.pl_plane_eq);
+ vec3 trace_pos = line_plane_intersect(P, V, pd.pl_plane_eq);
hit_vec = hit_pos - trace_pos;
hit_vec = reflect(hit_vec, pd.pl_normal);
/* Modify here so mip texel alignment is correct. */
@@ -317,8 +321,8 @@ vec3 get_hit_vector(vec3 hit_pos,
}
else {
/* Find hit position in previous frame. */
- hit_co = get_reprojected_reflection(hit_pos, worldPosition, N);
- hit_vec = hit_pos - worldPosition;
+ hit_co = get_reprojected_reflection(hit_pos, P, N);
+ hit_vec = hit_pos - P;
}
mask = screen_border_mask(hit_co);
@@ -339,7 +343,7 @@ vec4 get_ssr_samples(vec4 hit_pdf,
ivec4 hit_data[2],
PlanarData pd,
float planar_index,
- vec3 worldPosition,
+ vec3 P,
vec3 N,
vec3 V,
float roughnessSquared,
@@ -379,14 +383,10 @@ vec4 get_ssr_samples(vec4 hit_pdf,
/* Get actual hit vector and hit coordinate (from last frame). */
vec4 mask = vec4(1.0);
- hit_pos[0] = get_hit_vector(
- hit_pos[0], pd, worldPosition, N, V, is_planar.x, hit_co[0].xy, mask.x);
- hit_pos[1] = get_hit_vector(
- hit_pos[1], pd, worldPosition, N, V, is_planar.y, hit_co[0].zw, mask.y);
- hit_pos[2] = get_hit_vector(
- hit_pos[2], pd, worldPosition, N, V, is_planar.z, hit_co[1].xy, mask.z);
- hit_pos[3] = get_hit_vector(
- hit_pos[3], pd, worldPosition, N, V, is_planar.w, hit_co[1].zw, mask.w);
+ hit_pos[0] = get_hit_vector(hit_pos[0], pd, P, N, V, is_planar.x, hit_co[0].xy, mask.x);
+ hit_pos[1] = get_hit_vector(hit_pos[1], pd, P, N, V, is_planar.y, hit_co[0].zw, mask.y);
+ hit_pos[2] = get_hit_vector(hit_pos[2], pd, P, N, V, is_planar.z, hit_co[1].xy, mask.z);
+ hit_pos[3] = get_hit_vector(hit_pos[3], pd, P, N, V, is_planar.w, hit_co[1].zw, mask.w);
vec4 hit_dist;
hit_dist.x = length(hit_pos[0]);
@@ -476,47 +476,30 @@ vec4 get_ssr_samples(vec4 hit_pdf,
return accum;
}
-void main()
+void raytrace_resolve(ClosureInputGlossy cl_in,
+ inout ClosureEvalGlossy cl_eval,
+ inout ClosureEvalCommon cl_common,
+ inout ClosureOutputGlossy cl_out)
{
- ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
# ifdef FULLRES
- ivec2 halfres_texel = fullres_texel;
+ ivec2 texel = ivec2(gl_FragCoord.xy);
# else
- ivec2 halfres_texel = ivec2(gl_FragCoord.xy / 2.0);
+ ivec2 texel = ivec2(gl_FragCoord.xy / 2.0);
# endif
- vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0));
-
- float depth = textureLod(depthBuffer, uvs, 0.0).r;
-
- /* Early out */
- if (depth == 1.0) {
- discard;
- }
-
/* Using world space */
- vec3 viewPosition = get_view_space_from_depth(uvs, depth); /* Needed for viewCameraVec */
- vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
- vec3 V = cameraVec;
- vec3 vN = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, viewCameraVec);
- vec3 N = transform_direction(ViewMatrixInverse, vN);
- vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
+ vec3 V = cl_common.V;
+ vec3 N = cl_in.N;
+ vec3 P = cl_common.P;
- /* Early out */
- if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) {
- discard;
- }
-
- float roughness = speccol_roughness.a;
- float roughnessSquared = max(1e-3, roughness * roughness);
-
- vec4 spec_accum = vec4(0.0);
+ float roughness = cl_in.roughness;
+ float roughnessSquared = max(1e-3, sqr(roughness));
/* Resolve SSR */
float cone_cos = cone_cosine(roughnessSquared);
float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos;
cone_tan *= mix(saturate(dot(N, -V) * 2.0), 1.0, roughness); /* Elongation fit */
- vec2 source_uvs = project_point(pastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5;
+ vec2 source_uvs = project_point(pastViewProjectionMatrix, P).xy * 0.5 + 0.5;
vec4 ssr_accum = vec4(0.0);
float weight_acc = 0.0;
@@ -525,16 +508,16 @@ void main()
/* TODO optimize with textureGather */
/* Doing these fetches early to hide latency. */
vec4 hit_pdf;
- hit_pdf.x = texelFetch(pdfBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).r;
- hit_pdf.y = texelFetch(pdfBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).r;
- hit_pdf.z = texelFetch(pdfBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).r;
- hit_pdf.w = texelFetch(pdfBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).r;
+ hit_pdf.x = texelFetch(pdfBuffer, texel + neighbors[0 + neighborOffset], 0).r;
+ hit_pdf.y = texelFetch(pdfBuffer, texel + neighbors[1 + neighborOffset], 0).r;
+ hit_pdf.z = texelFetch(pdfBuffer, texel + neighbors[2 + neighborOffset], 0).r;
+ hit_pdf.w = texelFetch(pdfBuffer, texel + neighbors[3 + neighborOffset], 0).r;
ivec4 hit_data[2];
- hit_data[0].xy = texelFetch(hitBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).rg;
- hit_data[0].zw = texelFetch(hitBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).rg;
- hit_data[1].xy = texelFetch(hitBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).rg;
- hit_data[1].zw = texelFetch(hitBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).rg;
+ hit_data[0].xy = texelFetch(hitBuffer, texel + neighbors[0 + neighborOffset], 0).rg;
+ hit_data[0].zw = texelFetch(hitBuffer, texel + neighbors[1 + neighborOffset], 0).rg;
+ hit_data[1].xy = texelFetch(hitBuffer, texel + neighbors[2 + neighborOffset], 0).rg;
+ hit_data[1].zw = texelFetch(hitBuffer, texel + neighbors[3 + neighborOffset], 0).rg;
/* Find Planar Reflections affecting this pixel */
PlanarData pd;
@@ -542,7 +525,7 @@ void main()
for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) {
pd = planars_data[i];
- float fade = probe_attenuation_planar(pd, worldPosition, N, 0.0);
+ float fade = probe_attenuation_planar(pd, P, N, 0.0);
if (fade > 0.5) {
planar_index = float(i);
@@ -554,7 +537,7 @@ void main()
hit_data,
pd,
planar_index,
- worldPosition,
+ P,
N,
V,
roughnessSquared,
@@ -564,19 +547,51 @@ void main()
}
/* Compute SSR contribution */
- if (weight_acc > 0.0) {
- ssr_accum /= weight_acc;
- /* fade between 0.5 and 1.0 roughness */
- ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
- accumulate_light(ssr_accum.rgb, ssr_accum.a, spec_accum);
+ ssr_accum *= (weight_acc == 0.0) ? 0.0 : (1.0 / weight_acc);
+ /* fade between 0.5 and 1.0 roughness */
+ ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
+
+ cl_eval.raytrace_radiance = ssr_accum.rgb * ssr_accum.a;
+ cl_common.specular_accum -= ssr_accum.a;
+}
+
+CLOSURE_EVAL_FUNCTION_DECLARE_1(ssr_resolve, Glossy)
+
+void main()
+{
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+ float depth = texelFetch(depthBuffer, texel, 0).r;
+
+ if (depth == 1.0) {
+ discard;
}
- /* If SSR contribution is not 1.0, blend with cubemaps */
- if (spec_accum.a < 1.0) {
- fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
+ vec4 speccol_roughness = texelFetch(specroughBuffer, texel, 0).rgba;
+ vec3 brdf = speccol_roughness.rgb;
+ float roughness = speccol_roughness.a;
+
+ if (max_v3(brdf) <= 0.0) {
+ discard;
}
- fragColor = vec4(spec_accum.rgb * speccol_roughness.rgb, 1.0);
+ viewPosition = get_view_space_from_depth(uvcoordsvar.xy, depth);
+ worldPosition = transform_point(ViewMatrixInverse, viewPosition);
+
+ vec2 normal_encoded = texelFetch(normalBuffer, texel, 0).rg;
+ viewNormal = normal_decode(normal_encoded, viewCameraVec);
+ worldNormal = transform_direction(ViewMatrixInverse, viewNormal);
+
+ CLOSURE_VARS_DECLARE_1(Glossy);
+
+ in_Glossy_0.N = worldNormal;
+ in_Glossy_0.roughness = roughness;
+
+ /* Do a full deferred evaluation of the glossy BSDF. The only difference is that we inject the
+ * SSR resolve before the cubemap iter. BRDF term is already computed during main pass and is
+ * passed as specular color. */
+ CLOSURE_EVAL_FUNCTION_1(ssr_resolve, Glossy);
+
+ fragColor = vec4(out_Glossy_0.radiance * brdf, 1.0);
}
#endif
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
index a2e25b83532..fe4f3dcaa2f 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
@@ -137,9 +137,9 @@ float probe_attenuation_planar(PlanarData pd, vec3 W, vec3 N, float roughness)
return fac;
}
-float probe_attenuation_grid(GridData gd, mat4 localmat, vec3 W, out vec3 localpos)
+float probe_attenuation_grid(GridData gd, vec3 W, out vec3 localpos)
{
- localpos = transform_point(localmat, W);
+ localpos = transform_point(gd.localmat, W);
vec3 pos_to_edge = max(vec3(0.0), abs(localpos) - 1.0);
float fade = length(pos_to_edge);
return saturate(-fade * gd.g_atten_scale + gd.g_atten_bias);
@@ -183,8 +183,7 @@ vec3 probe_evaluate_world_spec(vec3 R, float roughness)
return textureLod_cubemapArray(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax).rgb;
}
-vec3 probe_evaluate_planar(
- float id, PlanarData pd, vec3 W, vec3 N, vec3 V, float roughness, inout float fade)
+vec3 probe_evaluate_planar(int id, PlanarData pd, vec3 W, vec3 N, vec3 V, float roughness)
{
/* Find view vector / reflection plane intersection. */
vec3 point_on_plane = line_plane_intersect(W, V, pd.pl_plane_eq);
@@ -226,7 +225,7 @@ void fallback_cubemap(vec3 N,
#ifdef SSR_AO
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
vec3 bent_normal;
- float final_ao = occlusion_compute(N, viewPosition, 1.0, rand, bent_normal);
+ float final_ao = occlusion_compute(N, viewPosition, rand, bent_normal);
final_ao = specular_occlusion(dot(N, V), final_ao, roughness);
#else
const float final_ao = 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 949e4d8f04f..b0845057a43 100644
--- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl
@@ -252,32 +252,29 @@ float light_attenuation(LightData ld, vec4 l_vector)
return vis;
}
-float light_shadowing(LightData ld,
- vec3 W,
-#ifndef VOLUMETRICS
- vec3 viewPosition,
- float tracing_depth,
- vec3 true_normal,
- float rand_x,
- const bool use_contact_shadows,
-#endif
- float vis)
+float light_shadowing(LightData ld, vec3 W, float vis)
{
#if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW)
- /* shadowing */
if (ld.l_shadowid >= 0.0 && vis > 0.001) {
-
if (ld.l_type == SUN) {
vis *= sample_cascade_shadow(int(ld.l_shadowid), W);
}
else {
vis *= sample_cube_shadow(int(ld.l_shadowid), W);
}
+ }
+#endif
+ return vis;
+}
-# ifndef VOLUMETRICS
+#ifndef VOLUMETRICS
+float light_contact_shadows(
+ LightData ld, vec3 P, vec3 vP, float tracing_depth, vec3 vNg, float rand_x, float vis)
+{
+ if (ld.l_shadowid >= 0.0 && vis > 0.001) {
ShadowData sd = shadows_data[int(ld.l_shadowid)];
/* Only compute if not already in shadow. */
- if (use_contact_shadows && sd.sh_contact_dist > 0.0 && vis > 1e-8) {
+ if (sd.sh_contact_dist > 0.0) {
/* Contact Shadows. */
vec3 ray_ori, ray_dir;
float trace_distance;
@@ -287,54 +284,34 @@ float light_shadowing(LightData ld,
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;
+ ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - P;
float len = length(ray_dir);
trace_distance = min(sd.sh_contact_dist, len);
ray_dir *= trace_distance / len;
}
ray_dir = transform_direction(ViewMatrix, ray_dir);
- ray_ori = vec3(viewPosition.xy, tracing_depth) + true_normal * sd.sh_contact_offset;
+ ray_ori = vec3(vP.xy, tracing_depth) + vNg * sd.sh_contact_offset;
vec3 hit_pos = raycast(
-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 hit_dist = distance(vP, hit_pos);
float dist_ratio = hit_dist / trace_distance;
- return vis * saturate(dist_ratio * 3.0 - 2.0);
+ return saturate(dist_ratio * 3.0 - 2.0);
}
}
-# endif /* VOLUMETRICS */
}
-#endif
-
- return vis;
+ return 1.0;
}
+#endif /* VOLUMETRICS */
-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 light_visibility(LightData ld, vec3 W, vec4 l_vector)
{
float l_atten = light_attenuation(ld, l_vector);
- return light_shadowing(ld,
- W,
-#ifndef VOLUMETRICS
- viewPosition,
- tracing_depth,
- true_normal,
- rand_x,
- use_contact_shadows,
-#endif
- l_atten);
+ return light_shadowing(ld, W, l_atten);
}
float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector)
diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
index 34999076f9c..fd08dfda060 100644
--- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
@@ -5,8 +5,12 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_lit_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_diffuse_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_refraction_lib.glsl)
#pragma BLENDER_REQUIRE(surface_lib.glsl)
#ifdef USE_ALPHA_HASH
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl
index e0b9d4a60db..19eecdb5b79 100644
--- a/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl
@@ -39,7 +39,7 @@ void main()
vec3 viewPosition = get_view_space_from_depth(uvs, depth);
vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
- vec3 true_normal = normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
+ vec3 true_normal = safe_normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) {
LightData ld = lights_data[i];
@@ -48,8 +48,10 @@ void main()
l_vector.xyz = ld.l_position - worldPosition;
l_vector.w = length(l_vector.xyz);
- float l_vis = light_shadowing(
- ld, worldPosition, viewPosition, tracing_depth, true_normal, rand.x, true, 1.0);
+ float l_vis = light_shadowing(ld, worldPosition, 1.0);
+
+ l_vis *= light_contact_shadows(
+ ld, worldPosition, viewPosition, tracing_depth, true_normal, rand.x, 1.0);
accum_light += l_vis;
}
diff --git a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
index d0297c8cb7f..62930b9944a 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
@@ -3,8 +3,13 @@
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_lit_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_diffuse_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_refraction_lib.glsl)
+
#pragma BLENDER_REQUIRE(surface_lib.glsl)
#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
index b93a3a23eff..e80dc1761f0 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
@@ -13,7 +13,15 @@ uniform float refractionDepth;
vec3 worldNormal; \
vec3 viewNormal;
-#ifdef GPU_GEOMETRY_SHADER
+#if defined(STEP_RESOLVE) || defined(STEP_RAYTRACE)
+/* SSR will set these global variables itself.
+ * Also make false positive compiler warnings disapear by setting values. */
+vec3 worldPosition = vec3(0);
+vec3 viewPosition = vec3(0);
+vec3 worldNormal = vec3(0);
+vec3 viewNormal = vec3(0);
+
+#elif defined(GPU_GEOMETRY_SHADER)
in ShaderStageInterface{SURFACE_INTERFACE} dataIn[];
out ShaderStageInterface{SURFACE_INTERFACE} dataOut;
@@ -24,7 +32,7 @@ out ShaderStageInterface{SURFACE_INTERFACE} dataOut;
dataOut.worldNormal = dataIn[vert].worldNormal; \
dataOut.viewNormal = dataIn[vert].viewNormal;
-#else
+#else /* GPU_VERTEX_SHADER || GPU_FRAGMENT_SHADER*/
IN_OUT ShaderStageInterface{SURFACE_INTERFACE};
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
index bac69ab0355..25661a0d731 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
@@ -1,6 +1,6 @@
#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
/* Based on Frosbite Unified Volumetric.
* https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl
index 9cb1723346d..0213ba2622b 100644
--- a/source/blender/draw/intern/shaders/common_math_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_math_lib.glsl
@@ -96,6 +96,7 @@ float len_squared(vec2 a) { return dot(a, a); }
#define weighted_sum(val0, val1, val2, val3, weights) ((val0 * weights[0] + val1 * weights[1] + val2 * weights[2] + val3 * weights[3]) * safe_rcp(sum(weights)));
#define weighted_sum_array(val, weights) ((val[0] * weights[0] + val[1] * weights[1] + val[2] * weights[2] + val[3] * weights[3]) * safe_rcp(sum(weights)));
+
/* clang-format on */
#define saturate(a) clamp(a, 0.0, 1.0)
@@ -112,6 +113,15 @@ float distance_squared(vec3 a, vec3 b)
return dot(a, a);
}
+vec3 safe_normalize(vec3 v)
+{
+ float len = length(v);
+ if (isnan(len) || len == 0.0) {
+ return vec3(1.0, 0.0, 0.0);
+ }
+ return v / len;
+}
+
/** \} */
/* ---------------------------------------------------------------------- */