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:
-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
-rw-r--r--source/blender/gpu/intern/gpu_material_library.c4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl23
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl82
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl53
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl37
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl574
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl29
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl32
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl16
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c46
33 files changed, 1303 insertions, 1270 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;
+}
+
/** \} */
/* ---------------------------------------------------------------------- */
diff --git a/source/blender/gpu/intern/gpu_material_library.c b/source/blender/gpu/intern/gpu_material_library.c
index 496988c4ba9..64cd375d466 100644
--- a/source/blender/gpu/intern/gpu_material_library.c
+++ b/source/blender/gpu/intern/gpu_material_library.c
@@ -755,6 +755,10 @@ static void gpu_parse_material_library(GHash *hash, GPUMaterialLibrary *library)
/* get parameters */
while (*code && *code != ')') {
+ if (BLI_str_startswith(code, "const ")) {
+ code = gpu_str_skip_token(code, NULL, 0);
+ }
+
/* test if it's an input or output */
qual = FUNCTION_QUAL_IN;
if (BLI_str_startswith(code, "out ")) {
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
index eea8d19efce..d718cc3f4fe 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
@@ -4,7 +4,7 @@ void node_ambient_occlusion(
{
vec3 bent_normal;
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
- result_ao = occlusion_compute(normalize(normal), viewPosition, 1.0, rand, bent_normal);
+ result_ao = occlusion_compute(normalize(normal), viewPosition, rand, bent_normal);
result_color = result_ao * color;
}
#else
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
index d7b6143d2a1..01a16e194ca 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
@@ -1,12 +1,27 @@
#ifndef VOLUMETRICS
+
+CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_diffuse, Diffuse)
+
void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
{
- N = normalize(N);
+ CLOSURE_VARS_DECLARE_1(Diffuse);
+
+ in_Diffuse_0.N = N; /* Normalized during eval. */
+ in_Diffuse_0.albedo = color.rgb;
+
+ CLOSURE_EVAL_FUNCTION_1(node_bsdf_diffuse, Diffuse);
+
result = CLOSURE_DEFAULT;
- eevee_closure_diffuse(N, color.rgb, 1.0, true, result.radiance);
- result.radiance = render_pass_diffuse_mask(color.rgb, result.radiance * color.rgb);
- closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
+
+ out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1.0), out_Diffuse_0.radiance);
+ out_Diffuse_0.radiance *= color.rgb;
+
+ result.radiance = out_Diffuse_0.radiance;
+
+ /* TODO(fclem) Try to not use this. */
+ closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result);
}
+
#else
/* Stub diffuse because it is not compatible with volumetrics. */
# define node_bsdf_diffuse(a, b, c, d) (d = CLOSURE_DEFAULT)
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
index 443bab7529b..429c4ed41ac 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
@@ -1,4 +1,7 @@
#ifndef VOLUMETRICS
+
+CLOSURE_EVAL_FUNCTION_DECLARE_3(node_eevee_specular, Diffuse, Glossy, Glossy)
+
void node_eevee_specular(vec4 diffuse,
vec4 specular,
float roughness,
@@ -12,34 +15,63 @@ void node_eevee_specular(vec4 diffuse,
float ssr_id,
out Closure result)
{
- normal = normalize(normal);
-
- vec3 out_diff, out_spec, ssr_spec;
- eevee_closure_default_clearcoat(normal,
- diffuse.rgb,
- specular.rgb,
- vec3(1.0),
- int(ssr_id),
- roughness,
- clearcoat_normal,
- clearcoat * 0.25,
- clearcoat_roughness,
- occlusion,
- true,
- out_diff,
- out_spec,
- ssr_spec);
-
- float alpha = 1.0 - transp;
+ CLOSURE_VARS_DECLARE_3(Diffuse, Glossy, Glossy);
+
+ in_common.occlusion = occlusion;
+
+ in_Diffuse_0.N = normal; /* Normalized during eval. */
+ in_Diffuse_0.albedo = diffuse.rgb;
+
+ in_Glossy_1.N = normal; /* Normalized during eval. */
+ in_Glossy_1.roughness = roughness;
+
+ in_Glossy_2.N = clearcoat_normal; /* Normalized during eval. */
+ in_Glossy_2.roughness = clearcoat_roughness;
+
+ CLOSURE_EVAL_FUNCTION_3(node_eevee_specular, Diffuse, Glossy, Glossy);
+
result = CLOSURE_DEFAULT;
- result.radiance = render_pass_diffuse_mask(diffuse.rgb, out_diff * diffuse.rgb);
- result.radiance += render_pass_glossy_mask(vec3(1.0), out_spec);
- result.radiance += render_pass_emission_mask(emissive.rgb);
- result.radiance *= alpha;
- result.transmittance = vec3(transp);
- closure_load_ssr_data(ssr_spec * alpha, roughness, normal, viewCameraVec, int(ssr_id), result);
+ {
+ /* Diffuse. */
+ out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1), out_Diffuse_0.radiance);
+ out_Diffuse_0.radiance *= in_Diffuse_0.albedo;
+ result += out_Diffuse_0.radiance;
+ }
+ {
+ /* Glossy. */
+ float NV = dot(in_Glossy_1.N, cameraVec);
+ vec2 split_sum = brdf_lut(NV, in_Glossy_1.roughness);
+ vec3 brdf = F_brdf_single_scatter(specular.rgb, vec3(1.0), split_sum);
+
+ out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id);
+ out_Glossy_1.radiance *= brdf;
+ out_Glossy_1.radiance = render_pass_glossy_mask(spec_color, out_Glossy_1.radiance);
+ closure_load_ssr_data(
+ out_Glossy_1.radiance, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result);
+ }
+ {
+ /* Clearcoat. */
+ float NV = dot(in_Glossy_2.N, cameraVec);
+ vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness);
+ vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum);
+
+ out_Glossy_2.radiance *= brdf * clearcoat * 0.25;
+ out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance);
+ result.radiance += out_Glossy_2.radiance;
+ }
+ {
+ /* Emission. */
+ vec3 out_emission_radiance = render_pass_emission_mask(emission.rgb);
+ result.radiance += out_emission_radiance;
+ }
+
+ float trans = 1.0 - trans;
+ result.transmittance = vec3(trans);
+ result.radiance *= alpha;
+ result.ssr_data.rgb *= alpha;
}
+
#else
/* Stub specular because it is not compatible with volumetrics. */
# define node_eevee_specular(a, b, c, d, e, f, g, h, i, j, k, result) (result = CLOSURE_DEFAULT)
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl
index c328b4800bc..ba02ae6d886 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl
@@ -1,4 +1,7 @@
#ifndef VOLUMETRICS
+
+CLOSURE_EVAL_FUNCTION_DECLARE_2(node_bsdf_glass, Glossy, Refraction)
+
void node_bsdf_glass(vec4 color,
float roughness,
float ior,
@@ -7,32 +10,38 @@ void node_bsdf_glass(vec4 color,
float ssr_id,
out Closure result)
{
- N = normalize(N);
- vec3 out_spec, out_refr, ssr_spec;
- vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb :
- color.rgb; /* Simulate 2 transmission event */
- eevee_closure_glass(N,
- vec3(1.0),
- /* HACK: Pass the multiscatter flag as the sign to not add closure
- * variations or increase register usage. */
- (use_multiscatter != 0.0) ? vec3(1.0) : -vec3(1.0),
- int(ssr_id),
- roughness,
- 1.0,
- ior,
- true,
- out_spec,
- out_refr,
- ssr_spec);
- float fresnel = F_eta(ior, dot(N, cameraVec));
- vec3 vN = mat3(ViewMatrix) * N;
+ CLOSURE_VARS_DECLARE_2(Glossy, Refraction);
+
+ in_Glossy_0.N = N; /* Normalized during eval. */
+ in_Glossy_0.roughness = roughness;
+
+ in_Refraction_1.N = N; /* Normalized during eval. */
+ in_Refraction_1.roughness = roughness;
+ in_Refraction_1.ior = ior;
+
+ CLOSURE_EVAL_FUNCTION_2(node_bsdf_glass, Glossy, Refraction);
+
result = CLOSURE_DEFAULT;
- result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color) * (1.0 - fresnel);
- result.radiance += render_pass_glossy_mask(color.rgb, out_spec * color.rgb) * fresnel;
+ float fresnel = F_eta(in_Refraction_1.ior, dot(in_Glossy_0.N, cameraVec));
+
+ vec2 split_sum = brdf_lut(dot(in_Glossy_0.N, cameraVec), in_Glossy_0.roughness);
+ vec3 brdf = (use_multiscatter != 0.0) ? F_brdf_multi_scatter(vec3(1.0), vec3(1.0), split_sum) :
+ F_brdf_single_scatter(vec3(1.0), vec3(1.0), split_sum);
+ out_Glossy_0.radiance = closure_mask_ssr_radiance(out_Glossy_0.radiance, ssr_id);
+ out_Glossy_0.radiance *= brdf;
+ out_Glossy_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Glossy_0.radiance);
+ out_Glossy_0.radiance *= color.rgb * fresnel;
closure_load_ssr_data(
- ssr_spec * color.rgb * fresnel, roughness, N, viewCameraVec, int(ssr_id), result);
+ out_Glossy_0.radiance, in_Glossy_0.roughness, in_Glossy_0.N, ssr_id, result);
+
+ out_Refraction_1.radiance = render_pass_glossy_mask(vec3(1.0), out_Refraction_1.radiance);
+ out_Refraction_1.radiance *= color.rgb * (1.0 - fresnel);
+ /* Simulate 2nd absorption event. */
+ out_Refraction_1.radiance *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0);
+ result.radiance += out_Refraction_1.radiance;
}
+
#else
/* Stub glass because it is not compatible with volumetrics. */
# define node_bsdf_glass(a, b, c, d, e, f, result) (result = CLOSURE_DEFAULT)
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
index 36675cf720d..ca7c3749597 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
@@ -1,23 +1,32 @@
#ifndef VOLUMETRICS
+
+CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_glossy, Glossy)
+
void node_bsdf_glossy(
vec4 color, float roughness, vec3 N, float use_multiscatter, float ssr_id, out Closure result)
{
- N = normalize(N);
- vec3 out_spec, ssr_spec;
- eevee_closure_glossy(N,
- vec3(1.0),
- use_multiscatter != 0.0 ? vec3(1.0) : vec3(-1.0), /* HACK */
- int(ssr_id),
- roughness,
- 1.0,
- true,
- out_spec,
- ssr_spec);
- vec3 vN = mat3(ViewMatrix) * N;
+ bool do_ssr = (ssrToggle && int(ssr_id) == outputSsrId);
+
+ CLOSURE_VARS_DECLARE_1(Glossy);
+
+ in_Glossy_0.N = N; /* Normalized during eval. */
+ in_Glossy_0.roughness = roughness;
+
+ CLOSURE_EVAL_FUNCTION_1(node_bsdf_glossy, Glossy);
+
result = CLOSURE_DEFAULT;
- result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec) * color.rgb;
- closure_load_ssr_data(ssr_spec * color.rgb, roughness, N, viewCameraVec, int(ssr_id), result);
+
+ vec2 split_sum = brdf_lut(dot(in_Glossy_0.N, cameraVec), in_Glossy_0.roughness);
+ vec3 brdf = (use_multiscatter != 0.0) ? F_brdf_multi_scatter(vec3(1.0), vec3(1.0), split_sum) :
+ F_brdf_single_scatter(vec3(1.0), vec3(1.0), split_sum);
+ out_Glossy_0.radiance = closure_mask_ssr_radiance(out_Glossy_0.radiance, ssr_id);
+ out_Glossy_0.radiance *= brdf;
+ out_Glossy_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Glossy_0.radiance);
+ out_Glossy_0.radiance *= color.rgb;
+ closure_load_ssr_data(
+ out_Glossy_0.radiance, in_Glossy_0.roughness, in_Glossy_0.N, ssr_id, result);
}
+
#else
/* Stub glossy because it is not compatible with volumetrics. */
# define node_bsdf_glossy(a, b, c, d, e, result) (result = CLOSURE_DEFAULT)
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
index 3bd578e1ffc..15958dcf65e 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
@@ -1,41 +1,20 @@
#ifndef VOLUMETRICS
vec3 tint_from_color(vec3 color)
{
- float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
- return (lum > 0) ? color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
+ float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
+ return (lum > 0.0) ? color / lum : vec3(0.0); /* normalize lum. to isolate hue+sat */
}
-void convert_metallic_to_specular_tinted(vec3 basecol,
- vec3 basecol_tint,
- float metallic,
- float specular_fac,
- float specular_tint,
- out vec3 diffuse,
- out vec3 f0)
-{
- vec3 tmp_col = mix(vec3(1.0), basecol_tint, specular_tint);
- f0 = mix((0.08 * specular_fac) * tmp_col, basecol, metallic);
- diffuse = basecol * (1.0 - metallic);
-}
-
-/* Output sheen is to be multiplied by sheen_color. */
-void principled_sheen(float NV,
- vec3 basecol_tint,
- float sheen,
- float sheen_tint,
- out float out_sheen,
- out vec3 sheen_color)
+float principled_sheen(float NV)
{
float f = 1.0 - NV;
- /* Temporary fix for T59784. Normal map seems to contain NaNs for tangent space normal maps,
- * therefore we need to clamp value. */
- f = clamp(f, 0.0, 1.0);
/* Empirical approximation (manual curve fitting). Can be refined. */
- out_sheen = f * f * f * 0.077 + f * 0.01 + 0.00026;
-
- sheen_color = sheen * mix(vec3(1.0), basecol_tint, sheen_tint);
+ float sheen = f * f * f * 0.077 + f * 0.01 + 0.00026;
+ return sheen;
}
+CLOSURE_EVAL_FUNCTION_DECLARE_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction)
+
void node_bsdf_principled(vec4 base_color,
float subsurface,
vec3 subsurface_radius,
@@ -59,434 +38,163 @@ void node_bsdf_principled(vec4 base_color,
vec3 N,
vec3 CN,
vec3 T,
- vec3 I,
- float use_multiscatter,
+ const float do_diffuse,
+ const float do_clearcoat,
+ const float do_refraction,
+ const float do_multiscatter,
float ssr_id,
float sss_id,
vec3 sss_scale,
out Closure result)
{
- N = normalize(N);
- ior = max(ior, 1e-5);
- metallic = saturate(metallic);
- transmission = saturate(transmission);
- float m_transmission = 1.0 - transmission;
-
- float dielectric = 1.0 - metallic;
- transmission *= dielectric;
- sheen *= dielectric;
- subsurface_color *= dielectric;
-
- vec3 diffuse, f0, out_diff, out_spec, out_refr, ssr_spec, sheen_color;
- float out_sheen;
- vec3 ctint = tint_from_color(base_color.rgb);
- convert_metallic_to_specular_tinted(
- base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
-
- float NV = dot(N, cameraVec);
- principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color);
-
- vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic);
-
- /* Far from being accurate, but 2 glossy evaluation is too expensive.
- * Most noticeable difference is at grazing angles since the bsdf lut
- * f0 color interpolation is done on top of this interpolation. */
- vec3 f0_glass = mix(vec3(1.0), base_color.rgb, specular_tint);
- float fresnel = F_eta(ior, NV);
- vec3 spec_col = F_color_blend(ior, fresnel, f0_glass) * fresnel;
- f0 = mix(f0, spec_col, transmission);
- f90 = mix(f90, spec_col, transmission);
-
- /* Really poor approximation but needed to workaround issues with renderpasses. */
- spec_col = mix(vec3(1.0), spec_col, transmission);
/* Match cycles. */
- spec_col += float(clearcoat > 1e-5);
-
- vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
-
- float sss_scalef = avg(sss_scale) * subsurface;
- eevee_closure_principled(N,
- mixed_ss_base_color,
- f0,
- /* HACK: Pass the multiscatter flag as the sign to not add closure
- * variations or increase register usage. */
- (use_multiscatter != 0.0) ? f90 : -f90,
- int(ssr_id),
- roughness,
- CN,
- clearcoat * 0.25,
- clearcoat_roughness,
- 1.0,
- sss_scalef,
- ior,
- true,
- out_diff,
- out_spec,
- out_refr,
- ssr_spec);
-
- vec3 refr_color = base_color.rgb;
- refr_color *= (refractionDepth > 0.0) ? refr_color :
- vec3(1.0); /* Simulate 2 transmission event */
- refr_color *= saturate(1.0 - fresnel) * transmission;
-
- sheen_color *= m_transmission;
- mixed_ss_base_color *= m_transmission;
-
- result = CLOSURE_DEFAULT;
- result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color);
- result.radiance += render_pass_glossy_mask(spec_col, out_spec);
- /* Coarse approx. */
- result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color);
- result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
- result.radiance *= alpha;
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
-
- mixed_ss_base_color *= alpha;
- closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
- result.transmittance = vec3(1.0 - alpha);
-}
-
-void node_bsdf_principled_dielectric(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float emission_strength,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float use_multiscatter,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- N = normalize(N);
metallic = saturate(metallic);
- float dielectric = 1.0 - metallic;
-
- vec3 diffuse, f0, out_diff, out_spec, ssr_spec, sheen_color;
- float out_sheen;
- vec3 ctint = tint_from_color(base_color.rgb);
- convert_metallic_to_specular_tinted(
- base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
-
- vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic);
-
- float NV = dot(N, cameraVec);
- principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color);
-
- eevee_closure_default(N,
- diffuse,
- f0,
- /* HACK: Pass the multiscatter flag as the sign to not add closure
- * variations or increase register usage. */
- (use_multiscatter != 0.0) ? f90 : -f90,
- int(ssr_id),
- roughness,
- 1.0,
- true,
- out_diff,
- out_spec,
- ssr_spec);
+ transmission = saturate(transmission);
+ float diffuse_weight = (1.0 - transmission) * (1.0 - metallic);
+ transmission *= (1.0 - metallic);
+ float specular_weight = (1.0 - transmission);
+ clearcoat = max(clearcoat, 0.0);
+ transmission_roughness = 1.0 - (1.0 - roughness) * (1.0 - transmission_roughness);
- result = CLOSURE_DEFAULT;
- result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec);
- result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color);
- result.radiance += render_pass_diffuse_mask(diffuse, out_diff * diffuse);
- result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
- result.radiance *= alpha;
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+ CLOSURE_VARS_DECLARE_4(Diffuse, Glossy, Glossy, Refraction);
- result.transmittance = vec3(1.0 - alpha);
-}
+ in_Diffuse_0.N = N; /* Normalized during eval. */
+ in_Diffuse_0.albedo = mix(base_color.rgb, subsurface_color.rgb, subsurface);
-void node_bsdf_principled_metallic(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float emission_strength,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float use_multiscatter,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- N = normalize(N);
- vec3 out_spec, ssr_spec;
-
- vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
-
- eevee_closure_glossy(N,
- base_color.rgb,
- /* HACK: Pass the multiscatter flag as the sign to not add closure
- * variations or increase register usage. */
- (use_multiscatter != 0.0) ? f90 : -f90,
- int(ssr_id),
- roughness,
- 1.0,
- true,
- out_spec,
- ssr_spec);
+ in_Glossy_1.N = N; /* Normalized during eval. */
+ in_Glossy_1.roughness = roughness;
- result = CLOSURE_DEFAULT;
- result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec);
- result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
- result.radiance *= alpha;
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+ in_Glossy_2.N = CN; /* Normalized during eval. */
+ in_Glossy_2.roughness = clearcoat_roughness;
- result.transmittance = vec3(1.0 - alpha);
-}
+ in_Refraction_3.N = N; /* Normalized during eval. */
+ in_Refraction_3.roughness = do_multiscatter != 0.0 ? roughness : transmission_roughness;
+ in_Refraction_3.ior = ior;
+
-void node_bsdf_principled_clearcoat(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float emission_strength,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float use_multiscatter,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- vec3 out_spec, ssr_spec;
- N = normalize(N);
-
- vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
-
- eevee_closure_clearcoat(N,
- base_color.rgb,
- /* HACK: Pass the multiscatter flag as the sign to not add closure
- * variations or increase register usage. */
- (use_multiscatter != 0.0) ? f90 : -f90,
- int(ssr_id),
- roughness,
- CN,
- clearcoat * 0.25,
- clearcoat_roughness,
- 1.0,
- true,
- out_spec,
- ssr_spec);
- /* Match cycles. */
- float spec_col = 1.0 + float(clearcoat > 1e-5);
+ CLOSURE_EVAL_FUNCTION_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction);
result = CLOSURE_DEFAULT;
- result.radiance = render_pass_glossy_mask(vec3(spec_col), out_spec);
- result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
- result.radiance *= alpha;
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+ /* This will tag the whole eval for optimisation. */
+ if (do_diffuse == 0.0) {
+ out_Diffuse_0.radiance = vec3(0);
+ }
+ if (do_clearcoat == 0.0) {
+ out_Glossy_2.radiance = vec3(0);
+ }
+ if (do_refraction == 0.0) {
+ out_Refraction_3.radiance = vec3(0);
+ }
+
+ /* Glossy_1 will always be evaluated. */
+ float NV = dot(in_Glossy_1.N, cameraVec);
+
+ vec3 base_color_tint = tint_from_color(base_color.rgb);
+
+ /* TODO(fclem) This isn't good for rough glass using multiscatter (since the fresnel is applied
+ * on each microfacet in cycles). */
+ float fresnel = F_eta(in_Refraction_3.ior, NV);
+
+ {
+ /* Glossy reflections.
+ * Separate Glass reflections and main specular reflections to match Cycles renderpasses. */
+ out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id);
+
+ vec2 split_sum = brdf_lut(NV, roughness);
+
+ vec3 glossy_radiance_final = vec3(0.0);
+ if (transmission > 1e-5) {
+ /* Glass Reflection: Reuse radiance from Glossy1. */
+ vec3 out_glass_refl_radiance = out_Glossy_1.radiance;
+
+ /* Poor approximation since we baked the LUT using a fixed IOR. */
+ vec3 f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
+ vec3 f90 = vec3(1);
+
+ vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
+ F_brdf_single_scatter(f0, f90, split_sum);
+
+ out_glass_refl_radiance *= brdf;
+ out_glass_refl_radiance = render_pass_glossy_mask(vec3(1), out_glass_refl_radiance);
+ out_glass_refl_radiance *= fresnel * transmission;
+ glossy_radiance_final += out_glass_refl_radiance;
+ }
+ if (specular_weight > 1e-5) {
+ vec3 dielectric_f0_color = mix(vec3(1.0), base_color_tint, specular_tint);
+ vec3 metallic_f0_color = base_color.rgb;
+ vec3 f0 = mix((0.08 * specular) * dielectric_f0_color, metallic_f0_color, metallic);
+ /* Cycles does this blending using the microfacet fresnel factor. However, our fresnel
+ * is already baked inside the split sum LUT. We approximate using by modifying the
+ * changing the f90 color directly in a non linear fashion. */
+ vec3 f90 = mix(f0, vec3(1), fast_sqrt(specular));
+
+ vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
+ F_brdf_single_scatter(f0, f90, split_sum);
+
+ out_Glossy_1.radiance *= brdf;
+ out_Glossy_1.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_1.radiance);
+ out_Glossy_1.radiance *= specular_weight;
+ glossy_radiance_final += out_Glossy_1.radiance;
+ }
+
+ closure_load_ssr_data(
+ glossy_radiance_final, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result);
+ }
+
+ if (diffuse_weight > 1e-5) {
+ /* Mask over all diffuse radiance. */
+ out_Diffuse_0.radiance *= diffuse_weight;
+
+ /* Sheen Coarse approximation: We reuse the diffuse radiance and just scale it. */
+ vec3 sheen_color = mix(vec3(1), base_color_tint, sheen_tint);
+ vec3 out_sheen_radiance = out_Diffuse_0.radiance * principled_sheen(NV);
+ out_sheen_radiance = render_pass_diffuse_mask(vec3(1), out_sheen_radiance);
+ out_sheen_radiance *= sheen * sheen_color;
+ result.radiance += out_sheen_radiance;
+
+ /* Diffuse / Subsurface. */
+ float scale = avg(sss_scale) * subsurface;
+ closure_load_sss_data(scale, out_Diffuse_0.radiance, in_Diffuse_0.albedo, int(sss_id), result);
+ }
+
+ if (transmission > 1e-5) {
+ /* TODO(fclem) This could be going to a transmission render pass instead. */
+ out_Refraction_3.radiance = render_pass_glossy_mask(vec3(1), out_Refraction_3.radiance);
+ out_Refraction_3.radiance *= base_color.rgb;
+ /* Simulate 2nd transmission event. */
+ out_Refraction_3.radiance *= (refractionDepth > 0.0) ? base_color.rgb : vec3(1);
+ out_Refraction_3.radiance *= (1.0 - fresnel) * transmission;
+ result.radiance += out_Refraction_3.radiance;
+ }
+
+ if (clearcoat > 1e-5) {
+ float NV = dot(in_Glossy_2.N, cameraVec);
+ vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness);
+ vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum);
+
+ out_Glossy_2.radiance *= brdf * clearcoat * 0.25;
+ out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance);
+ result.radiance += out_Glossy_2.radiance;
+ }
+
+ {
+ vec3 out_emission_radiance = render_pass_emission_mask(emission.rgb);
+ out_emission_radiance *= emission_strength;
+ result.radiance += out_emission_radiance;
+ }
result.transmittance = vec3(1.0 - alpha);
-}
-
-void node_bsdf_principled_subsurface(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float emission_strength,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float use_multiscatter,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- metallic = saturate(metallic);
- N = normalize(N);
-
- vec3 diffuse, f0, out_diff, out_spec, ssr_spec, sheen_color;
- float out_sheen;
- vec3 ctint = tint_from_color(base_color.rgb);
- convert_metallic_to_specular_tinted(
- base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
-
- subsurface_color = subsurface_color * (1.0 - metallic);
- vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
- float sss_scalef = avg(sss_scale) * subsurface;
-
- float NV = dot(N, cameraVec);
- principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color);
-
- vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
-
- eevee_closure_skin(N,
- mixed_ss_base_color,
- f0,
- /* HACK: Pass the multiscatter flag as the sign to not add closure variations
- * or increase register usage. */
- (use_multiscatter != 0.0) ? f90 : -f90,
- int(ssr_id),
- roughness,
- 1.0,
- sss_scalef,
- true,
- out_diff,
- out_spec,
- ssr_spec);
-
- result = CLOSURE_DEFAULT;
- result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec);
- result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color);
- result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
result.radiance *= alpha;
-
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
-
- mixed_ss_base_color *= alpha;
- closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
-
- result.transmittance = vec3(1.0 - alpha);
+ result.ssr_data.rgb *= alpha;
+# ifdef USE_SSS
+ result.sss_irradiance *= alpha;
+# endif
}
-void node_bsdf_principled_glass(vec4 base_color,
- float subsurface,
- vec3 subsurface_radius,
- vec4 subsurface_color,
- float metallic,
- float specular,
- float specular_tint,
- float roughness,
- float anisotropic,
- float anisotropic_rotation,
- float sheen,
- float sheen_tint,
- float clearcoat,
- float clearcoat_roughness,
- float ior,
- float transmission,
- float transmission_roughness,
- vec4 emission,
- float emission_strength,
- float alpha,
- vec3 N,
- vec3 CN,
- vec3 T,
- vec3 I,
- float use_multiscatter,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
- out Closure result)
-{
- ior = max(ior, 1e-5);
- N = normalize(N);
-
- vec3 f0, out_spec, out_refr, ssr_spec;
- f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
-
- eevee_closure_glass(N,
- vec3(1.0),
- vec3((use_multiscatter != 0.0) ? 1.0 : -1.0),
- int(ssr_id),
- roughness,
- 1.0,
- ior,
- true,
- out_spec,
- out_refr,
- ssr_spec);
-
- vec3 refr_color = base_color.rgb;
- refr_color *= (refractionDepth > 0.0) ? refr_color :
- vec3(1.0); /* Simulate 2 transmission events */
-
- float fresnel = F_eta(ior, dot(N, cameraVec));
- vec3 spec_col = F_color_blend(ior, fresnel, f0);
- spec_col *= fresnel;
- refr_color *= (1.0 - fresnel);
-
- ssr_spec *= spec_col;
-
- result = CLOSURE_DEFAULT;
- result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color);
- result.radiance += render_pass_glossy_mask(spec_col, out_spec * spec_col);
- result.radiance += render_pass_emission_mask(emission.rgb * emission_strength);
- result.radiance *= alpha;
- closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
- result.transmittance = vec3(1.0 - alpha);
-}
#else
/* clang-format off */
/* Stub principled because it is not compatible with volumetrics. */
-# define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
-# define node_bsdf_principled_dielectric(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
-# define node_bsdf_principled_metallic(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
-# define node_bsdf_principled_clearcoat(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
-# define node_bsdf_principled_subsurface(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
-# define node_bsdf_principled_glass(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT)
+# define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, cc, dd, result) (result = CLOSURE_DEFAULT)
/* clang-format on */
#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
index cd043020a7f..db820efa42e 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
@@ -1,15 +1,30 @@
#ifndef VOLUMETRICS
+
+CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_refraction, Refraction)
+
void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
{
- N = normalize(N);
- vec3 out_refr;
- color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */
- eevee_closure_refraction(N, roughness, ior, true, out_refr);
- vec3 vN = mat3(ViewMatrix) * N;
+ CLOSURE_VARS_DECLARE_1(Refraction);
+
+ in_Refraction_0.N = N; /* Normalized during eval. */
+ in_Refraction_0.roughness = roughness;
+ in_Refraction_0.ior = ior;
+
+ CLOSURE_EVAL_FUNCTION_1(node_bsdf_refraction, Refraction);
+
result = CLOSURE_DEFAULT;
- result.ssr_normal = normal_encode(vN, viewCameraVec);
- result.radiance = render_pass_glossy_mask(color.rgb, out_refr * color.rgb);
+
+ out_Refraction_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Refraction_0.radiance);
+ out_Refraction_0.radiance *= color.rgb;
+ /* Simulate 2nd absorption event. */
+ out_Refraction_0.radiance *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0);
+
+ result.radiance = out_Refraction_0.radiance;
+
+ /* TODO(fclem) Try to not use this. */
+ result.ssr_normal = normal_encode(mat3(ViewMatrix) * in_Refraction_0.N, viewCameraVec);
}
+
#else
/* Stub refraction because it is not compatible with volumetrics. */
# define node_bsdf_refraction(a, b, c, d, e) (e = CLOSURE_DEFAULT)
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
index c13b55513da..5a68f802659 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
@@ -1,4 +1,7 @@
#ifndef VOLUMETRICS
+
+CLOSURE_EVAL_FUNCTION_DECLARE_1(node_subsurface_scattering, Diffuse)
+
void node_subsurface_scattering(vec4 color,
float scale,
vec3 radius,
@@ -8,20 +11,29 @@ void node_subsurface_scattering(vec4 color,
float sss_id,
out Closure result)
{
- N = normalize(N);
- vec3 out_diff;
- vec3 vN = mat3(ViewMatrix) * N;
+ CLOSURE_VARS_DECLARE_1(Diffuse);
+
+ in_Diffuse_0.N = N; /* Normalized during eval. */
+ in_Diffuse_0.albedo = color.rgb;
+
+ CLOSURE_EVAL_FUNCTION_1(node_subsurface_scattering, Diffuse);
+
result = CLOSURE_DEFAULT;
- closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
- eevee_closure_subsurface(N, color.rgb, 1.0, scale, true, out_diff);
+ /* Not perfect for texture_blur values between 0.0 and 1.0.
+ * Interpolate between separated color and color applied on irradiance. */
+ float one_minus_texture_blur = 1.0 - texture_blur;
+ vec3 sss_albedo = color.rgb * texture_blur + one_minus_texture_blur;
+ vec3 radiance_tint = color.rgb * one_minus_texture_blur + texture_blur;
+ /* Consider output radiance as irradiance. */
+ out_Diffuse_0.radiance *= radiance_tint;
+
+ closure_load_sss_data(scale, out_Diffuse_0.radiance, sss_albedo, int(sss_id), result);
- /* Not perfect for texture_blur not exactly equal to 0.0 or 1.0. */
- vec3 sss_albedo = mix(color.rgb, vec3(1.0), texture_blur);
- out_diff *= mix(vec3(1.0), color.rgb, texture_blur);
- result.radiance = render_pass_sss_mask(sss_albedo);
- closure_load_sss_data(scale, out_diff, sss_albedo, int(sss_id), result);
+ /* TODO(fclem) Try to not use this. */
+ closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result);
}
+
#else
/* Stub subsurface scattering because it is not compatible with volumetrics. */
# define node_subsurface_scattering(a, b, c, d, e, f, g, h) (h = CLOSURE_DEFAULT)
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl
index 79bfd9b24bb..80bd3941b22 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl
@@ -1,12 +1,20 @@
#ifndef VOLUMETRICS
+
+CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_translucent, Translucent)
+
void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
{
- N = normalize(N);
+ CLOSURE_VARS_DECLARE_1(Translucent);
+
+ in_Translucent_0.N = -N; /* Normalized during eval. */
+
+ CLOSURE_EVAL_FUNCTION_1(node_bsdf_translucent, Translucent);
+
result = CLOSURE_DEFAULT;
- eevee_closure_diffuse(-N, color.rgb, 1.0, false, result.radiance);
- closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
- result.radiance = render_pass_diffuse_mask(color.rgb, result.radiance * color.rgb);
+ closure_load_ssr_data(vec3(0.0), 0.0, -in_Translucent_0.N, -1.0, result);
+ result.radiance = render_pass_diffuse_mask(color.rgb, out_Translucent_0.radiance * color.rgb);
}
+
#else
/* Stub translucent because it is not compatible with volumetrics. */
# define node_bsdf_translucent(a, b, c) (c = CLOSURE_DEFAULT)
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
index b9f0e793a61..f601f3e9fd0 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
@@ -134,54 +134,32 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
GPU_link(mat, "set_rgb_one", &sss_scale);
}
- /* Due to the manual effort done per config, we only optimize the most common permutations. */
- char *node_name;
- uint flag = 0;
- if (!use_subsurf && use_diffuse && !use_refract && !use_clear) {
- static char name[] = "node_bsdf_principled_dielectric";
- node_name = name;
- flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY;
+ uint flag = GPU_MATFLAG_GLOSSY;
+ if (use_diffuse) {
+ flag |= GPU_MATFLAG_DIFFUSE;
}
- else if (!use_subsurf && !use_diffuse && !use_refract && !use_clear) {
- static char name[] = "node_bsdf_principled_metallic";
- node_name = name;
- flag = GPU_MATFLAG_GLOSSY;
+ if (use_refract) {
+ flag |= GPU_MATFLAG_REFRACT;
}
- else if (!use_subsurf && !use_diffuse && !use_refract && use_clear) {
- static char name[] = "node_bsdf_principled_clearcoat";
- node_name = name;
- flag = GPU_MATFLAG_GLOSSY;
- }
- else if (use_subsurf && use_diffuse && !use_refract && !use_clear) {
- static char name[] = "node_bsdf_principled_subsurface";
- node_name = name;
- flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY;
- }
- else if (!use_subsurf && !use_diffuse && use_refract && !use_clear && !socket_not_zero(4)) {
- static char name[] = "node_bsdf_principled_glass";
- node_name = name;
- flag = GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT;
- }
- else {
- static char name[] = "node_bsdf_principled";
- node_name = name;
- flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT;
- }
-
if (use_subsurf) {
flag |= GPU_MATFLAG_SSS;
}
+ float f_use_diffuse = use_diffuse ? 1.0f : 0.0f;
+ float f_use_clearcoat = use_clear ? 1.0f : 0.0f;
+ float f_use_refraction = use_refract ? 1.0f : 0.0f;
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
GPU_material_flag_set(mat, flag);
return GPU_stack_link(mat,
node,
- node_name,
+ "node_bsdf_principled",
in,
out,
- GPU_builtin(GPU_VIEW_POSITION),
+ GPU_constant(&f_use_diffuse),
+ GPU_constant(&f_use_clearcoat),
+ GPU_constant(&f_use_refraction),
GPU_constant(&use_multi_scatter),
GPU_constant(&node->ssr_id),
GPU_constant(&node->sss_id),