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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2020-09-19 01:06:45 +0300
committerClément Foucault <foucault.clem@gmail.com>2020-09-19 01:09:51 +0300
commit6f3c279d9e7082b963f3ca758f6ba0561c4bcc9c (patch)
tree1ea2b44e57e192dd9a23223d605d1244734bff9e
parentaa2e978bd8b47dbc06826698b07d850cdd499568 (diff)
EEVEE: Add support for GGX Multi-scatter
Based on http://jcgt.org/published/0008/01/03/ This is a simple trick that does *not* have a huge performance impact but does work pretty well. It just modifies the Fresnel term to account for the multibounce energy loss (coloration). However this makes the shader variations count double. To avoid this we use a uniform and pass the multiscatter use flag inside the sign of f90. This is a bit hacky but avoids many code duplication. This uses the simplification proposed by McAuley in A Journey Through Implementing Multiscattering BRDFs and Area Lights This does not handle area light differently than the IBL case but that's already an issue in current implementation. This is related to T68460. Reviewed By: brecht Differential Revision: https://developer.blender.org/D8912
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl42
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl58
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c3
8 files changed, 102 insertions, 45 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
index deedde64194..3560ae62a84 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -74,34 +74,36 @@ vec3 F_color_blend(float eta, float fresnel, vec3 f0_color)
return mix(f0_color, vec3(1.0), fac);
}
-/* Fresnel */
-vec3 F_schlick(vec3 f0, float cos_theta)
-{
- float fac = 1.0 - cos_theta;
- float fac2 = fac * fac;
- fac = fac2 * fac2 * fac;
-
- /* Unreal specular matching : if specular color is below 2% intensity,
- * (using green channel for intensity) treat as shadowning */
- return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * fac + (1.0 - fac) * f0;
-}
-
-/* Fresnel approximation for LTC area lights (not MRP) */
-vec3 F_area(vec3 f0, vec3 f90, vec2 lut)
+/* Fresnel split-sum approximation. */
+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 * f90 + lut.x * f0;
+ return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * lut.y * abs(f90) + lut.x * f0;
}
-/* Fresnel approximation for IBL */
-vec3 F_ibl(vec3 f0, vec3 f90, vec2 lut)
+/* Multi-scattering brdf approximation from :
+ * "A Multiple-Scattering Microfacet Model for Real-Time Image-based Lighting"
+ * by Carmelo J. Fdez-Agüera. */
+vec3 F_brdf_multi_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 * f90 + lut.x * f0;
+ vec3 FssEss = F_brdf_single_scatter(f0, f90, lut);
+ /* Hack to avoid many more shader variations. */
+ if (f90.g < 0.0) {
+ return FssEss;
+ }
+
+ float Ess = lut.x + lut.y;
+ float Ems = 1.0 - Ess;
+ vec3 Favg = f0 + (1.0 - f0) / 21.0;
+ vec3 Fms = FssEss * Favg / (1.0 - (1.0 - Ess) * Favg);
+ /* We don't do anything special for diffuse surfaces because the principle bsdf
+ * does not care about energy conservation of the specular layer for dielectrics. */
+ 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_lit_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl
index bf33caf9854..613b48ff9b8 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl
@@ -250,12 +250,12 @@ void CLOSURE_NAME(vec3 N
# ifdef CLOSURE_GLOSSY
vec2 brdf_lut_lights = texture(utilTex, vec3(lut_uv, 1.0)).ba;
- out_spec *= F_area(f0, f90, brdf_lut_lights.xy);
+ 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_area(vec3(0.04), vec3(1.0), brdf_lut_lights_clear.xy);
+ out_spec_clear *= F_brdf(vec3(0.04), vec3(1.0), brdf_lut_lights_clear.xy);
out_spec += out_spec_clear * C_intensity;
# endif
@@ -449,7 +449,7 @@ void CLOSURE_NAME(vec3 N
/* This factor is outputted to be used by SSR in order
* to match the intensity of the regular reflections. */
- ssr_spec = F_ibl(f0, f90, brdf_lut);
+ 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 */
@@ -470,7 +470,7 @@ void CLOSURE_NAME(vec3 N
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_ibl(vec3(0.04), vec3(1.0), C_brdf_lut) *
+ 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;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl
index e1137d9d0e7..8131958313b 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl
@@ -5,11 +5,12 @@ void node_bsdf_anisotropic(vec4 color,
float rotation,
vec3 N,
vec3 T,
+ float use_multiscatter,
out Closure result)
{
- node_bsdf_glossy(color, roughness, N, -1, result);
+ node_bsdf_glossy(color, roughness, N, -1, use_multiscatter, result);
}
#else
/* Stub anisotropic because it is not compatible with volumetrics. */
-# define node_bsdf_anisotropic(a, b, c, d, e, f, g) (g = CLOSURE_DEFAULT)
+# define node_bsdf_anisotropic(a, b, c, d, e, f, g, result) (result = CLOSURE_DEFAULT)
#endif
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 5ea22f3e0b4..36675cf720d 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
@@ -1,10 +1,18 @@
#ifndef VOLUMETRICS
-void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Closure result)
+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), vec3(1.0), int(ssr_id), roughness, 1.0, true, 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;
result = CLOSURE_DEFAULT;
result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec) * color.rgb;
@@ -12,5 +20,5 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Clo
}
#else
/* Stub glossy because it is not compatible with volumetrics. */
-# define node_bsdf_glossy(a, b, c, d, e) (e = CLOSURE_DEFAULT)
+# define node_bsdf_glossy(a, b, c, d, e, result) (result = CLOSURE_DEFAULT)
#endif
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 f7803155934..3fc40fd88e5 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
@@ -60,6 +60,7 @@ void node_bsdf_principled(vec4 base_color,
vec3 CN,
vec3 T,
vec3 I,
+ float use_multiscatter,
float ssr_id,
float sss_id,
vec3 sss_scale,
@@ -107,7 +108,9 @@ void node_bsdf_principled(vec4 base_color,
eevee_closure_principled(N,
mixed_ss_base_color,
f0,
- f90,
+ /* 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,
@@ -168,6 +171,7 @@ void node_bsdf_principled_dielectric(vec4 base_color,
vec3 CN,
vec3 T,
vec3 I,
+ float use_multiscatter,
float ssr_id,
float sss_id,
vec3 sss_scale,
@@ -188,8 +192,19 @@ void node_bsdf_principled_dielectric(vec4 base_color,
float NV = dot(N, cameraVec);
principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color);
- eevee_closure_default(
- N, diffuse, f0, f90, int(ssr_id), roughness, 1.0, true, out_diff, out_spec, ssr_spec);
+ 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);
result = CLOSURE_DEFAULT;
result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec);
@@ -226,6 +241,7 @@ void node_bsdf_principled_metallic(vec4 base_color,
vec3 CN,
vec3 T,
vec3 I,
+ float use_multiscatter,
float ssr_id,
float sss_id,
vec3 sss_scale,
@@ -236,8 +252,17 @@ void node_bsdf_principled_metallic(vec4 base_color,
vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
- eevee_closure_glossy(
- N, base_color.rgb, f90, int(ssr_id), roughness, 1.0, true, out_spec, ssr_spec);
+ 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);
result = CLOSURE_DEFAULT;
result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec);
@@ -272,6 +297,7 @@ void node_bsdf_principled_clearcoat(vec4 base_color,
vec3 CN,
vec3 T,
vec3 I,
+ float use_multiscatter,
float ssr_id,
float sss_id,
vec3 sss_scale,
@@ -284,7 +310,9 @@ void node_bsdf_principled_clearcoat(vec4 base_color,
eevee_closure_clearcoat(N,
base_color.rgb,
- f90,
+ /* 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,
@@ -331,6 +359,7 @@ void node_bsdf_principled_subsurface(vec4 base_color,
vec3 CN,
vec3 T,
vec3 I,
+ float use_multiscatter,
float ssr_id,
float sss_id,
vec3 sss_scale,
@@ -357,7 +386,9 @@ void node_bsdf_principled_subsurface(vec4 base_color,
eevee_closure_skin(N,
mixed_ss_base_color,
f0,
- f90,
+ /* 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,
@@ -405,6 +436,7 @@ void node_bsdf_principled_glass(vec4 base_color,
vec3 CN,
vec3 T,
vec3 I,
+ float use_multiscatter,
float ssr_id,
float sss_id,
vec3 sss_scale,
@@ -450,11 +482,11 @@ void node_bsdf_principled_glass(vec4 base_color,
#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, 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, 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, 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, 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, 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, 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, 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)
/* clang-format on */
#endif
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
index b0e17ed7716..7ce085d2c82 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
@@ -53,7 +53,10 @@ static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat,
GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY);
- return GPU_stack_link(mat, node, "node_bsdf_anisotropic", in, out);
+ float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
+
+ return GPU_stack_link(
+ mat, node, "node_bsdf_anisotropic", in, out, GPU_constant(&use_multi_scatter));
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
index 2bbd260fe0e..13b1b21c7fc 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
@@ -54,7 +54,15 @@ static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat,
GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY);
- return GPU_stack_link(mat, node, "node_bsdf_glossy", in, out, GPU_constant(&node->ssr_id));
+ float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
+
+ return GPU_stack_link(mat,
+ node,
+ "node_bsdf_glossy",
+ in,
+ out,
+ GPU_constant(&use_multi_scatter),
+ GPU_constant(&node->ssr_id));
}
/* node type definition */
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 ccc5198832a..b9f0e793a61 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
@@ -172,6 +172,8 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
flag |= GPU_MATFLAG_SSS;
}
+ 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,
@@ -180,6 +182,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
in,
out,
GPU_builtin(GPU_VIEW_POSITION),
+ GPU_constant(&use_multi_scatter),
GPU_constant(&node->ssr_id),
GPU_constant(&node->sss_id),
sss_scale);