Eevee: Use "constant folding" for the principle shader
authorClément Foucault <foucault.clem@gmail.com>
Wed, 8 Aug 2018 16:34:25 +0000 (18:34 +0200)
committerClément Foucault <foucault.clem@gmail.com>
Wed, 8 Aug 2018 19:27:26 +0000 (21:27 +0200)
This is more like a static optimisation when some parameters are set to 1.0
or 0.0. In theses case we use a more optimized version of the node.

This also revisit the transmission parameter behaviour to make it closer to
cycles.

source/blender/draw/engines/eevee/eevee_materials.c
source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
source/blender/gpu/GPU_material.h
source/blender/gpu/shaders/gpu_shader_material.glsl
source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
source/blender/nodes/shader/nodes/node_shader_eevee_specular.c

index 769ac11736d8a8493c945646dcb2e2a97e42644a..cd6b5db5b565bd01d0d676cf4ed166d51e076177 100644 (file)
@@ -405,7 +405,7 @@ static void add_standard_uniforms(
                DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1);
        }
 
-       if (use_ssrefraction) {
+       if (use_refract || use_ssrefraction) {
                BLI_assert(refract_depth != NULL);
                DRW_shgroup_uniform_float(shgrp, "refractionDepth", refract_depth, 1);
                DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->refract_color);
@@ -563,6 +563,8 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E
                        datatoc_lit_surface_frag_glsl,
                        datatoc_lit_surface_frag_glsl,
                        datatoc_lit_surface_frag_glsl,
+                       datatoc_lit_surface_frag_glsl,
+                       datatoc_lit_surface_frag_glsl,
                        datatoc_volumetric_lib_glsl);
 
                e_data.volume_shader_lib = BLI_string_joinN(
index 8b232bf14a423c280dff234c90a6d3e2d7584dc2..286f00783d9fd4576f0de55e75a57583bcb11193 100644 (file)
@@ -548,6 +548,14 @@ float F_eta(float eta, float cos_theta)
        return result;
 }
 
+/* Fresnel color blend base on fresnel factor */
+vec3 F_color_blend(float eta, float fresnel, vec3 f0_color)
+{
+       float f0 = F_eta(eta, 1.0);
+       float fac = saturate((fresnel - f0) / max(1e-8, 1.0 - f0));
+       return mix(f0_color, vec3(1.0), fac);
+}
+
 /* Fresnel */
 vec3 F_schlick(vec3 f0, float cos_theta)
 {
index 22194c22f392d60b7b61e548a862aad2aad9fe1e..c2e45ebb87963b626ce6e81d1899a483a8914879 100644 (file)
@@ -54,6 +54,13 @@ uniform int hairThicknessRes = 1;
        #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
@@ -67,6 +74,14 @@ uniform int hairThicknessRes = 1;
        #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
index cc1150b6d77e52b10207187be6f77cc76f61b53b..9dcf308a414db06bbaa82b87baf8add67afbc183 100644 (file)
@@ -128,6 +128,7 @@ typedef enum GPUMatFlag {
        GPU_MATFLAG_DIFFUSE       = (1 << 0),
        GPU_MATFLAG_GLOSSY        = (1 << 1),
        GPU_MATFLAG_REFRACT       = (1 << 2),
+       GPU_MATFLAG_SSS           = (1 << 3),
 } GPUMatFlag;
 
 typedef enum GPUBlendMode {
index 808d2f736593e8e5fbfb9f498a7066e1eaa860ea..c9564a21d1508fd883b607963f14d9d27c141def 100644 (file)
@@ -1069,11 +1069,11 @@ void convert_metallic_to_specular_tinted(
         vec3 basecol, float metallic, float specular_fac, float specular_tint,
         out vec3 diffuse, out vec3 f0)
 {
-       vec3 dielectric = vec3(0.034) * specular_fac * 2.0;
        float lum = dot(basecol, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
        vec3 tint = lum > 0 ? basecol / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
-       f0 = mix(dielectric * mix(vec3(1.0), tint, specular_tint), basecol, metallic);
-       diffuse = mix(basecol, vec3(0.0), metallic);
+       vec3 tmp_col = mix(vec3(1.0), tint, specular_tint);
+       f0 = mix((0.08 * specular_fac) * tmp_col, basecol, metallic);
+       diffuse = basecol * (1.0 - metallic);
 }
 
 #ifndef VOLUMETRICS
@@ -1126,52 +1126,142 @@ void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure r
        node_bsdf_diffuse(color, 0.0, N, result);
 }
 
-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, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
-       float sss_id, vec3 sss_scale, out Closure result)
+void node_bsdf_principled(
+        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, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
+        float sss_id, vec3 sss_scale, out Closure result)
 {
+       ior = max(ior, 1e-5);
        metallic = saturate(metallic);
        transmission = saturate(transmission);
+       float dielectric = 1.0 - metallic;
+       transmission *= dielectric;
+       subsurface_color *= dielectric;
 
        vec3 diffuse, f0, out_diff, out_spec, out_trans, out_refr, ssr_spec;
        convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
 
-       transmission *= 1.0 - metallic;
-       subsurface *= 1.0 - metallic;
-
-       clearcoat *= 0.25;
-       clearcoat *= 1.0 - transmission;
+       /* 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, dot(N, cameraVec));
+       vec3 spec_col = F_color_blend(ior, fresnel, f0_glass) * fresnel;
+       f0 = mix(f0, spec_col, transmission);
 
        vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
 
-#ifdef USE_SSS
-       diffuse = vec3(0.0);
-#else
-       diffuse = mixed_ss_base_color;
-#endif
-
-       f0 = mix(f0, vec3(1.0), transmission);
-
        float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0)) * subsurface;
        eevee_closure_principled(N, mixed_ss_base_color, f0, int(ssr_id), roughness,
-                                CN, clearcoat, clearcoat_roughness, 1.0, sss_scalef, ior,
+                                CN, clearcoat * 0.25, clearcoat_roughness, 1.0, sss_scalef, ior,
                                 out_diff, out_trans, 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 */
+       out_refr *= refr_color * (1.0 - fresnel) * transmission;
 
-       float fresnel = F_eta(ior, dot(N, cameraVec));
-       vec3 refr_spec_color = base_color.rgb * fresnel;
-       /* This bit maybe innacurate. */
-       out_refr = out_refr * refr_color * (1.0 - fresnel) + out_spec * refr_spec_color;
+       vec3 vN = normalize(mat3(ViewMatrix) * N);
+       result = CLOSURE_DEFAULT;
+       result.radiance = out_spec + out_refr;
+#ifndef USE_SSS
+       result.radiance += (out_diff + out_trans) * mixed_ss_base_color *  (1.0 - transmission);
+#endif
+       result.ssr_data = vec4(ssr_spec, roughness);
+       result.ssr_normal = normal_encode(vN, viewCameraVec);
+       result.ssr_id = int(ssr_id);
+#ifdef USE_SSS
+       result.sss_data.a = sss_scalef;
+       result.sss_data.rgb = out_diff + out_trans;
+#  ifdef USE_SSS_ALBEDO
+       result.sss_albedo.rgb = mixed_ss_base_color;
+#  else
+       result.sss_data.rgb *= mixed_ss_base_color;
+#  endif
+       result.sss_data.rgb *= (1.0 - transmission);
+#endif
+}
+
+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, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
+        float sss_id, vec3 sss_scale, out Closure result)
+{
+       metallic = saturate(metallic);
+       float dielectric = 1.0 - metallic;
+
+       vec3 diffuse, f0, out_diff, out_spec, ssr_spec;
+       convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
 
-       ssr_spec = mix(ssr_spec, refr_spec_color, transmission);
+       eevee_closure_default(N, diffuse, f0, int(ssr_id), roughness, 1.0, out_diff, out_spec, ssr_spec);
 
        vec3 vN = normalize(mat3(ViewMatrix) * N);
        result = CLOSURE_DEFAULT;
        result.radiance = out_spec + out_diff * diffuse;
-       result.radiance = mix(result.radiance, out_refr, transmission);
+       result.ssr_data = vec4(ssr_spec, roughness);
+       result.ssr_normal = normal_encode(vN, viewCameraVec);
+       result.ssr_id = int(ssr_id);
+}
+
+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, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
+        float sss_id, vec3 sss_scale, out Closure result)
+{
+       vec3 out_spec, ssr_spec;
+
+       eevee_closure_glossy(N, base_color.rgb, int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
+
+       vec3 vN = normalize(mat3(ViewMatrix) * N);
+       result = CLOSURE_DEFAULT;
+       result.radiance = out_spec;
+       result.ssr_data = vec4(ssr_spec, roughness);
+       result.ssr_normal = normal_encode(vN, viewCameraVec);
+       result.ssr_id = int(ssr_id);
+}
+
+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, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
+        float sss_id, vec3 sss_scale, out Closure result)
+{
+       vec3 out_spec, ssr_spec;
+
+       eevee_closure_clearcoat(N, base_color.rgb, int(ssr_id), roughness, CN, clearcoat * 0.25, clearcoat_roughness,
+                               1.0, out_spec, ssr_spec);
+
+       vec3 vN = normalize(mat3(ViewMatrix) * N);
+       result = CLOSURE_DEFAULT;
+       result.radiance = out_spec;
+       result.ssr_data = vec4(ssr_spec, roughness);
+       result.ssr_normal = normal_encode(vN, viewCameraVec);
+       result.ssr_id = int(ssr_id);
+}
+
+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, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
+        float sss_id, vec3 sss_scale, out Closure result)
+{
+       metallic = saturate(metallic);
+
+       vec3 diffuse, f0, out_diff, out_spec, out_trans, ssr_spec;
+       convert_metallic_to_specular_tinted(base_color.rgb, 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 = dot(sss_scale, vec3(1.0 / 3.0)) * subsurface;
+
+       eevee_closure_skin(N, mixed_ss_base_color, f0, int(ssr_id), roughness, 1.0, sss_scalef,
+                          out_diff, out_trans, out_spec, ssr_spec);
+
+       vec3 vN = normalize(mat3(ViewMatrix) * N);
+       result = CLOSURE_DEFAULT;
+       result.radiance = out_spec;
        result.ssr_data = vec4(ssr_spec, roughness);
        result.ssr_normal = normal_encode(vN, viewCameraVec);
        result.ssr_id = int(ssr_id);
@@ -1183,10 +1273,41 @@ void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subs
 #  else
        result.sss_data.rgb *= mixed_ss_base_color;
 #  endif
-       result.sss_data.rgb *= (1.0 - transmission);
+#else
+       result.radiance += (out_diff + out_trans) * mixed_ss_base_color;
 #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, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
+        float sss_id, vec3 sss_scale, out Closure result)
+{
+       ior = max(ior, 1e-5);
+
+       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), int(ssr_id), roughness, 1.0, ior, 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 */
+       out_refr *= refr_color;
+
+       float fresnel = F_eta(ior, dot(N, cameraVec));
+       vec3 spec_col = F_color_blend(ior, fresnel, f0);
+       out_spec *= spec_col;
+       ssr_spec *= spec_col * fresnel;
+
+       vec3 vN = normalize(mat3(ViewMatrix) * N);
+       result = CLOSURE_DEFAULT;
+       result.radiance = mix(out_refr, out_spec, fresnel);
+       result.ssr_data = vec4(ssr_spec, roughness);
+       result.ssr_normal = normal_encode(vN, viewCameraVec);
+       result.ssr_id = int(ssr_id);
+}
+
 void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
 {
        node_bsdf_diffuse(color, 0.0, -N, result);
@@ -1220,13 +1341,13 @@ void node_subsurface_scattering(
        result.sss_data.a = scale;
        eevee_closure_subsurface(N, color.rgb, 1.0, scale, out_diff, out_trans);
        result.sss_data.rgb = out_diff + out_trans;
-#ifdef USE_SSS_ALBEDO
+#  ifdef USE_SSS_ALBEDO
        /* Not perfect for texture_blur not exaclty equal to 0.0 or 1.0. */
        result.sss_albedo.rgb = mix(color.rgb, vec3(1.0), texture_blur);
        result.sss_data.rgb *= mix(vec3(1.0), color.rgb, texture_blur);
-#else
+#  else
        result.sss_data.rgb *= color.rgb;
-#endif
+#  endif
 #else
        node_bsdf_diffuse(color, 0.0, N, result);
 #endif
index 831ac1c98da55314fa92eae58d5cb448436b551b..370dcdcc2eae49f1d6751b89a38ed69f9c1f4863 100644 (file)
@@ -64,22 +64,12 @@ static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node)
        node->custom2 = SHD_SUBSURFACE_BURLEY;
 }
 
+#define socket_not_zero(sock) (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) > 1e-5f))
+#define socket_not_one(sock)  (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) < 1.0f - 1e-5f))
+
 static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
 {
        GPUNodeLink *sss_scale;
-#if 0 /* Old 2.7 glsl viewport */
-       // normal
-       if (!in[17].link)
-               in[17].link = GPU_builtin(GPU_VIEW_NORMAL);
-       else
-               GPU_link(mat, "direction_transform_m4v3", in[17].link, GPU_builtin(GPU_VIEW_MATRIX), &in[17].link);
-
-       // clearcoat normal
-       if (!in[18].link)
-               in[18].link = GPU_builtin(GPU_VIEW_NORMAL);
-       else
-               GPU_link(mat, "direction_transform_m4v3", in[18].link, GPU_builtin(GPU_VIEW_MATRIX), &in[18].link);
-#endif
 
        /* Normals */
        if (!in[17].link) {
@@ -117,9 +107,48 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *node, bNodeE
                GPU_link(mat, "set_rgb", GPU_uniform((float *)one), &sss_scale);
        }
 
-       GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT);
+       bool use_diffuse = socket_not_one(4) && socket_not_one(15);
+       bool use_subsurf = socket_not_zero(1) && use_diffuse;
+       bool use_refract = socket_not_one(4) && socket_not_zero(15);
+       bool use_clear = socket_not_zero(12);
+
+       /* 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;
+       }
+       else if (!use_subsurf && !use_diffuse && !use_refract && !use_clear) {
+               static char name[] = "node_bsdf_principled_metallic";
+               node_name = name;
+               flag = GPU_MATFLAG_GLOSSY;
+       }
+       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_SSS | 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_SSS | GPU_MATFLAG_REFRACT;
+       }
+
+       GPU_material_flag_set(mat, flag);
 
-       return GPU_stack_link(mat, node, "node_bsdf_principled_clearcoat", in, out, GPU_builtin(GPU_VIEW_POSITION),
+       return GPU_stack_link(mat, node, node_name, in, out, GPU_builtin(GPU_VIEW_POSITION),
                              GPU_uniform(&node->ssr_id), GPU_uniform(&node->sss_id), sss_scale);
 }
 
index e05b0be1e626be5749392b3816bf0b6299a64acd..6583dd0cec36c0eb23b7bd82a638fd9b1e5a18a3 100644 (file)
@@ -67,6 +67,8 @@ static int node_shader_gpu_eevee_specular(GPUMaterial *mat, bNode *node, bNodeEx
                GPU_link(mat, "set_value", GPU_uniform(&one), &in[9].link);
        }
 
+       GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY);
+
        return GPU_stack_link(mat, node, "node_eevee_specular", in, out, GPU_uniform(&node->ssr_id));
 }