[Bf-blender-cvs] [6f3c279d9e7] master: EEVEE: Add support for GGX Multi-scatter

Clément Foucault noreply at git.blender.org
Sat Sep 19 00:10:08 CEST 2020


Commit: 6f3c279d9e7082b963f3ca758f6ba0561c4bcc9c
Author: Clément Foucault
Date:   Sat Sep 19 00:06:45 2020 +0200
Branches: master
https://developer.blender.org/rB6f3c279d9e7082b963f3ca758f6ba0561c4bcc9c

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

===================================================================

M	source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
M	source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl
M	source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl
M	source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
M	source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
M	source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
M	source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
M	source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c

===================================================================

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 in

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list