Eevee: Improve Transparent BSDF behavior
authorClément Foucault <foucault.clem@gmail.com>
Sun, 11 Aug 2019 23:47:30 +0000 (01:47 +0200)
committerClément Foucault <foucault.clem@gmail.com>
Wed, 14 Aug 2019 11:36:56 +0000 (13:36 +0200)
Alpha blended Transparency is now using dual source blending making it
fully compatible with cycles Transparent BSDF.

Multiply and additive blend mode can be achieved using some nodes and are
going to be removed.

source/blender/draw/engines/eevee/eevee_engine.c
source/blender/draw/engines/eevee/eevee_materials.c
source/blender/draw/engines/eevee/eevee_private.h
source/blender/draw/engines/eevee/eevee_render.c
source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
source/blender/draw/engines/eevee/shaders/default_frag.glsl
source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
source/blender/gpu/intern/gpu_codegen.c
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_subsurface_scattering.c

index b36ad540ef9e5ceffe696575afcc2ba895bc7930..ab4eb7b853296e6fd28a28049bfafaae50f953f4 100644 (file)
@@ -295,7 +295,13 @@ static void eevee_draw_background(void *vedata)
     EEVEE_volumes_resolve(sldata, vedata);
 
     /* Transparent */
+    /* TODO(fclem): should be its own Framebuffer.
+     * This is needed because dualsource blending only works with 1 color buffer. */
+    GPU_framebuffer_texture_attach(fbl->main_color_fb, dtxl->depth, 0, 0);
+    GPU_framebuffer_bind(fbl->main_color_fb);
     DRW_draw_pass(psl->transparent_pass);
+    GPU_framebuffer_bind(fbl->main_fb);
+    GPU_framebuffer_texture_detach(fbl->main_color_fb, dtxl->depth);
 
     /* Post Process */
     DRW_stats_group_start("Post FX");
index 61da9e21cc8fb50c78b721f629bcfe8c25e69b5e..ccc2d6ba02023c4dbc39ec15581f2fe585f00185 100644 (file)
@@ -382,11 +382,6 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp,
   LightCache *lcache = vedata->stl->g_data->light_cache;
   EEVEE_EffectsInfo *effects = vedata->stl->effects;
 
-  if (ssr_id == NULL) {
-    static int no_ssr = -1.0f;
-    ssr_id = &no_ssr;
-  }
-
   DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo);
   DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo);
   DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo);
@@ -394,6 +389,8 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp,
   DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo);
   DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
 
+  DRW_shgroup_uniform_int_copy(shgrp, "outputSssId", 1);
+
   if (use_diffuse || use_glossy || use_refract) {
     DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
     DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeTexture", &sldata->shadow_cube_pool);
@@ -411,7 +408,7 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp,
   }
   if (use_glossy) {
     DRW_shgroup_uniform_texture_ref(shgrp, "probePlanars", &vedata->txl->planar_pool);
-    DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1);
+    DRW_shgroup_uniform_int_copy(shgrp, "outputSsrId", ssr_id ? *ssr_id : 0);
   }
   if (use_refract) {
     DRW_shgroup_uniform_float_copy(
@@ -736,7 +733,6 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
                                             Material *ma,
                                             EEVEE_Data *vedata,
                                             bool use_blend,
-                                            bool use_multiply,
                                             bool use_refract,
                                             bool use_translucency,
                                             int shadow_method)
@@ -746,7 +742,6 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
   int options = VAR_MAT_MESH;
 
   SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND);
-  SET_FLAG_FROM_TEST(options, use_multiply, VAR_MAT_MULT);
   SET_FLAG_FROM_TEST(options, use_refract, VAR_MAT_REFRACT);
   SET_FLAG_FROM_TEST(options, effects->sss_separate_albedo, VAR_MAT_SSSALBED);
   SET_FLAG_FROM_TEST(options, use_translucency, VAR_MAT_TRANSLUC);
@@ -1191,15 +1186,11 @@ static void material_opaque(Material *ma,
     *shgrp_depth_clip = emsg->depth_clip_grp;
 
     /* This will have been created already, just perform a lookup. */
-    *gpumat = (use_gpumat) ? EEVEE_material_mesh_get(scene,
-                                                     ma,
-                                                     vedata,
-                                                     false,
-                                                     false,
-                                                     use_ssrefract,
-                                                     use_translucency,
-                                                     linfo->shadow_method) :
-                             NULL;
+    *gpumat =
+        (use_gpumat) ?
+            EEVEE_material_mesh_get(
+                scene, ma, vedata, false, use_ssrefract, use_translucency, linfo->shadow_method) :
+            NULL;
     *gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get(
                                        scene, ma, (ma->blend_method == MA_BM_HASHED), false) :
                                    NULL;
@@ -1213,7 +1204,7 @@ static void material_opaque(Material *ma,
 
     /* Shading */
     *gpumat = EEVEE_material_mesh_get(
-        scene, ma, vedata, false, false, use_ssrefract, use_translucency, linfo->shadow_method);
+        scene, ma, vedata, false, use_ssrefract, use_translucency, linfo->shadow_method);
 
     eGPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat);
 
@@ -1286,7 +1277,7 @@ static void material_opaque(Material *ma,
 
     switch (status_mat_surface) {
       case GPU_MAT_SUCCESS: {
-        static int no_ssr = -1;
+        static int no_ssr = 0;
         static int first_ssr = 1;
         int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_ssrefract) ?
                           &first_ssr :
@@ -1426,22 +1417,16 @@ static void material_transparent(Material *ma,
     static float half = 0.5f;
 
     /* Shading */
-    *gpumat = EEVEE_material_mesh_get(scene,
-                                      ma,
-                                      vedata,
-                                      true,
-                                      (ma->blend_method == MA_BM_MULTIPLY),
-                                      use_ssrefract,
-                                      false,
-                                      linfo->shadow_method);
+    *gpumat = EEVEE_material_mesh_get(
+        scene, ma, vedata, true, use_ssrefract, false, linfo->shadow_method);
 
     switch (GPU_material_status(*gpumat)) {
       case GPU_MAT_SUCCESS: {
         static int ssr_id = -1; /* TODO transparent SSR */
-        bool use_blend = (ma->blend_method & MA_BM_BLEND) != 0;
 
         *shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass);
 
+        bool use_blend = true;
         bool use_diffuse = GPU_material_flag_get(*gpumat, GPU_MATFLAG_DIFFUSE);
         bool use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY);
         bool use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT);
@@ -1487,7 +1472,7 @@ static void material_transparent(Material *ma,
 
   DRWState all_state = (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_CULL_BACK |
                         DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL |
-                        DRW_STATE_BLEND_ALPHA | DRW_STATE_BLEND_ADD | DRW_STATE_BLEND_MUL);
+                        DRW_STATE_BLEND_CUSTOM);
 
   DRWState cur_state = DRW_STATE_WRITE_COLOR;
   cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL;
@@ -1495,13 +1480,9 @@ static void material_transparent(Material *ma,
 
   switch (ma->blend_method) {
     case MA_BM_ADD:
-      cur_state |= DRW_STATE_BLEND_ADD;
-      break;
     case MA_BM_MULTIPLY:
-      cur_state |= DRW_STATE_BLEND_MUL;
-      break;
     case MA_BM_BLEND:
-      cur_state |= DRW_STATE_BLEND_ALPHA;
+      cur_state |= DRW_STATE_BLEND_CUSTOM;
       break;
     default:
       BLI_assert(0);
index 8aeddc723163b9cf9c6578363860681fd40b119f..27edd44075bd9ce82fd48fde5c88679eae7cb14b 100644 (file)
@@ -897,7 +897,6 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
                                             Material *ma,
                                             EEVEE_Data *vedata,
                                             bool use_blend,
-                                            bool use_multiply,
                                             bool use_refract,
                                             bool use_translucency,
                                             int shadow_method);
index ebd13ef1cf53e41192fc0ee85b86f4cb91e126d5..f840fa23bd2612e60f50dda1d0160d7312086cb4 100644 (file)
@@ -628,7 +628,11 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
     /* Mist output */
     EEVEE_mist_output_accumulate(sldata, vedata);
     /* Transparent */
+    GPU_framebuffer_texture_attach(fbl->main_color_fb, dtxl->depth, 0, 0);
+    GPU_framebuffer_bind(fbl->main_color_fb);
     DRW_draw_pass(psl->transparent_pass);
+    GPU_framebuffer_bind(fbl->main_fb);
+    GPU_framebuffer_texture_detach(fbl->main_color_fb, dtxl->depth);
     /* Result Z */
     eevee_render_result_z(rl, viewname, rect, vedata, sldata);
     /* Post Process */
index 274269846bc9e10c679f1c24b587f30262c37c69..412fa47dbec45608332d933530fca8a13532d6db 100644 (file)
@@ -164,6 +164,19 @@ float sum(vec4 v)
   return dot(vec4(1.0), v);
 }
 
+float avg(vec2 v)
+{
+  return dot(vec2(1.0 / 2.0), v);
+}
+float avg(vec3 v)
+{
+  return dot(vec3(1.0 / 3.0), v);
+}
+float avg(vec4 v)
+{
+  return dot(vec4(1.0 / 4.0), v);
+}
+
 float saturate(float a)
 {
   return clamp(a, 0.0, 1.0);
@@ -716,6 +729,7 @@ float cone_cosine(float r)
 }
 
 /* --------- Closure ---------- */
+
 #ifdef VOLUMETRICS
 
 struct Closure {
@@ -725,6 +739,8 @@ struct Closure {
   float anisotropy;
 };
 
+Closure nodetree_exec(void); /* Prototype */
+
 #  define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), vec3(0.0), 0.0)
 
 Closure closure_mix(Closure cl1, Closure cl2, float fac)
@@ -758,7 +774,7 @@ Closure closure_emission(vec3 rgb)
 
 struct Closure {
   vec3 radiance;
-  float opacity;
+  vec3 transmittance;
 #  ifdef USE_SSS
   vec4 sss_data;
 #    ifdef USE_SSS_ALBEDO
@@ -767,110 +783,113 @@ struct Closure {
 #  endif
   vec4 ssr_data;
   vec2 ssr_normal;
-  int ssr_id;
+  int flag;
 };
 
-/* This is hacking ssr_id to tag transparent bsdf */
-#  define TRANSPARENT_CLOSURE_FLAG -2
-#  define REFRACT_CLOSURE_FLAG -3
-#  define NO_SSR -999
+Closure nodetree_exec(void); /* Prototype */
+
+#  define FLAG_TEST(flag, val) (((flag) & (val)) != 0)
+
+#  define CLOSURE_SSR_FLAG 1
+#  define CLOSURE_SSS_FLAG 2
 
 #  ifdef USE_SSS
 #    ifdef USE_SSS_ALBEDO
 #      define CLOSURE_DEFAULT \
-        Closure(vec3(0.0), 1.0, vec4(0.0), vec3(0.0), vec4(0.0), vec2(0.0), -1)
+        Closure(vec3(0.0), vec3(0.0), vec4(0.0), vec3(0.0), vec4(0.0), vec2(0.0), 0)
 #    else
-#      define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec4(0.0), vec2(0.0), -1)
+#      define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), vec4(0.0), vec4(0.0), vec2(0.0), 0)
 #    endif
 #  else
-#    define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec2(0.0), -1)
+#    define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), vec4(0.0), vec2(0.0), 0)
 #  endif
 
-uniform int outputSsrId;
+uniform int outputSsrId = 1;
+uniform int outputSssId = 1;
 
-Closure closure_mix(Closure cl1, Closure cl2, float fac)
+void closure_load_ssr_data(
+    vec3 ssr_spec, float roughness, vec3 N, vec3 viewVec, int ssr_id, inout Closure cl)
 {
-  Closure cl;
+  /* Still encode to avoid artifacts in the SSR pass. */
+  vec3 vN = normalize(mat3(ViewMatrix) * N);
+  cl.ssr_normal = normal_encode(vN, viewVec);
+
+  if (ssr_id == outputSsrId) {
+    cl.ssr_data = vec4(ssr_spec, roughness);
+    cl.flag |= CLOSURE_SSR_FLAG;
+  }
+}
 
-  if (cl1.ssr_id == TRANSPARENT_CLOSURE_FLAG) {
-    cl.ssr_normal = cl2.ssr_normal;
-    cl.ssr_data = cl2.ssr_data;
-    cl.ssr_id = cl2.ssr_id;
 #  ifdef USE_SSS
-    cl1.sss_data = cl2.sss_data;
+void closure_load_sss_data(float radius,
+                           vec3 sss_radiance,
 #    ifdef USE_SSS_ALBEDO
-    cl1.sss_albedo = cl2.sss_albedo;
+                           vec3 sss_albedo,
 #    endif
-#  endif
-  }
-  else if (cl2.ssr_id == TRANSPARENT_CLOSURE_FLAG) {
-    cl.ssr_normal = cl1.ssr_normal;
-    cl.ssr_data = cl1.ssr_data;
-    cl.ssr_id = cl1.ssr_id;
-#  ifdef USE_SSS
-    cl2.sss_data = cl1.sss_data;
+                           int sss_id,
+                           inout Closure cl)
+{
+  if (sss_id == outputSssId) {
+    cl.sss_data = vec4(sss_radiance, radius);
 #    ifdef USE_SSS_ALBEDO
-    cl2.sss_albedo = cl1.sss_albedo;
+    cl.sss_albedo = sss_albedo;
 #    endif
-#  endif
-  }
-  else if (cl1.ssr_id == outputSsrId) {
-    /* When mixing SSR don't blend roughness.
-     *
-     * It makes no sense to mix them really, so we take either one of them and
-     * tone down its specularity (ssr_data.xyz) while keeping its roughness (ssr_data.w).
-     */
-    cl.ssr_data = mix(cl1.ssr_data.xyzw, vec4(vec3(0.0), cl1.ssr_data.w), fac);
-    cl.ssr_normal = cl1.ssr_normal;
-    cl.ssr_id = cl1.ssr_id;
+    cl.flag |= CLOSURE_SSS_FLAG;
   }
   else {
-    cl.ssr_data = mix(vec4(vec3(0.0), cl2.ssr_data.w), cl2.ssr_data.xyzw, fac);
-    cl.ssr_normal = cl2.ssr_normal;
-    cl.ssr_id = cl2.ssr_id;
+    cl.radiance += sss_radiance;
+#    ifdef USE_SSS_ALBEDO
+    cl.radiance += sss_radiance * sss_albedo;
+#    endif
   }
+}
+#  endif
 
-  cl.opacity = mix(cl1.opacity, cl2.opacity, fac);
-  cl.radiance = mix(cl1.radiance * cl1.opacity, cl2.radiance * cl2.opacity, fac);
-  cl.radiance /= max(1e-8, cl.opacity);
+Closure closure_mix(Closure cl1, Closure cl2, float fac)
+{
+  Closure cl;
+  cl.transmittance = mix(cl1.transmittance, cl2.transmittance, fac);
+  cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
+  cl.flag = cl1.flag | cl2.flag;
+  cl.ssr_data = mix(cl1.ssr_data, cl2.ssr_data, fac);
+  bool use_cl1_ssr = FLAG_TEST(cl1.flag, CLOSURE_SSR_FLAG);
+  /* When mixing SSR don't blend roughness and normals but only specular (ssr_data.xyz).*/
+  cl.ssr_data.w = (use_cl1_ssr) ? cl1.ssr_data.w : cl2.ssr_data.w;
+  cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
 
 #  ifdef USE_SSS
-  /* Apply Mix on input */
-  cl1.sss_data.rgb *= 1.0 - fac;
-  cl2.sss_data.rgb *= fac;
-
-  /* Select biggest radius. */
-  bool use_cl1 = (cl1.sss_data.a > cl2.sss_data.a);
-  cl.sss_data = (use_cl1) ? cl1.sss_data : cl2.sss_data;
-
+  cl.sss_data = mix(cl1.sss_data, cl2.sss_data, fac);
+  bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
+  /* It also does not make sense to mix SSS radius or albedo. */
+  cl.sss_data.w = (use_cl1_sss) ? cl1.sss_data.w : cl2.sss_data.w;
 #    ifdef USE_SSS_ALBEDO
-  /* TODO Find a solution to this. Dither? */
-  cl.sss_albedo = (use_cl1) ? cl1.sss_albedo : cl2.sss_albedo;
-  /* Add radiance that was supposed to be filtered but was rejected. */
-  cl.radiance += (use_cl1) ? cl2.sss_data.rgb * cl2.sss_albedo : cl1.sss_data.rgb * cl1.sss_albedo;
-#    else
-  /* Add radiance that was supposed to be filtered but was rejected. */
-  cl.radiance += (use_cl1) ? cl2.sss_data.rgb : cl1.sss_data.rgb;
+  cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo;
 #    endif
 #  endif
-
   return cl;
 }
 
 Closure closure_add(Closure cl1, Closure cl2)
 {
-  Closure cl = (cl1.ssr_id == outputSsrId) ? cl1 : cl2;
+  Closure cl;
+  cl.transmittance = cl1.transmittance + cl2.transmittance;
   cl.radiance = cl1.radiance + cl2.radiance;
+  cl.flag = cl1.flag | cl2.flag;
+  cl.ssr_data = cl1.ssr_data + cl2.ssr_data;
+  bool use_cl1_ssr = FLAG_TEST(cl1.flag, CLOSURE_SSR_FLAG);
+  /* When mixing SSR don't blend roughness and normals.*/
+  cl.ssr_data.w = (use_cl1_ssr) ? cl1.ssr_data.w : cl2.ssr_data.w;
+  cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
+
 #  ifdef USE_SSS
-  cl.sss_data = (cl1.sss_data.a > 0.0) ? cl1.sss_data : cl2.sss_data;
-  /* Add radiance that was supposed to be filtered but was rejected. */
-  cl.radiance += (cl1.sss_data.a > 0.0) ? cl2.sss_data.rgb : cl1.sss_data.rgb;
+  cl.sss_data = cl1.sss_data + cl2.sss_data;
+  bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
+  /* It also does not make sense to mix SSS radius or albedo. */
+  cl.sss_data.w = (use_cl1_sss) ? cl1.sss_data.w : cl2.sss_data.w;
 #    ifdef USE_SSS_ALBEDO
-  /* TODO Find a solution to this. Dither? */
-  cl.sss_albedo = (cl1.sss_data.a > 0.0) ? cl1.sss_albedo : cl2.sss_albedo;
+  cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo;
 #    endif
 #  endif
-  cl.opacity = saturate(cl1.opacity + cl2.opacity);
   return cl;
 }
 
@@ -883,19 +902,23 @@ Closure closure_emission(vec3 rgb)
 
 /* Breaking this across multiple lines causes issues for some older GLSL compilers. */
 /* clang-format off */
-#  if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER) && !defined(USE_MULTIPLY)
+#  if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER)
 /* clang-format on */
-layout(location = 0) out vec4 fragColor;
-layout(location = 1) out vec4 ssrNormals;
+#    ifndef USE_ALPHA_BLEND
+layout(location = 0) out vec4 outRadiance;
+layout(location = 1) out vec2 ssrNormals;
 layout(location = 2) out vec4 ssrData;
-#    ifdef USE_SSS
+#      ifdef USE_SSS
 layout(location = 3) out vec4 sssData;
-#      ifdef USE_SSS_ALBEDO
+#        ifdef USE_SSS_ALBEDO
 layout(location = 4) out vec4 sssAlbedo;
-#      endif /* USE_SSS_ALBEDO */
-#    endif   /* USE_SSS */
-
-Closure nodetree_exec(void); /* Prototype */
+#        endif
+#      endif
+#    else  /* USE_ALPHA_BLEND */
+/* Use dual source blending to be able to make a whole range of effects. */
+layout(location = 0, index = 0) out vec4 outRadiance;
+layout(location = 0, index = 1) out vec4 outTransmittance;
+#    endif /* USE_ALPHA_BLEND */
 
 #    if defined(USE_ALPHA_BLEND)
 /* Prototype because this file is included before volumetric_lib.glsl */
@@ -909,27 +932,24 @@ void volumetric_resolve(vec2 frag_uvs,
 void main()
 {
   Closure cl = nodetree_exec();
-#    ifndef USE_ALPHA_BLEND
-  /* Prevent alpha hash material writing into alpha channel. */
-  cl.opacity = 1.0;
-#    endif
 
-#    if defined(USE_ALPHA_BLEND)
+#    ifdef USE_ALPHA_BLEND
   vec2 uvs = gl_FragCoord.xy * volCoordScale.zw;
-  vec3 transmittance, scattering;
-  volumetric_resolve(uvs, gl_FragCoord.z, transmittance, scattering);
-  fragColor.rgb = cl.radiance * transmittance + scattering;
-  fragColor.a = cl.opacity;
-#    else
-  fragColor = vec4(cl.radiance, cl.opacity);
-#    endif
+  vec3 vol_transmit, vol_scatter;
+  volumetric_resolve(uvs, gl_FragCoord.z, vol_transmit, vol_scatter);
 
-  ssrNormals = cl.ssr_normal.xyyy;
+  float transmit = saturate(avg(cl.transmittance));
+  outRadiance = vec4(cl.radiance * vol_transmit + vol_scatter, (1.0 - transmit));
+  outTransmittance = vec4(cl.transmittance, transmit);
+#    else
+  outRadiance = vec4(cl.radiance, 1.0);
+  ssrNormals = cl.ssr_normal;
   ssrData = cl.ssr_data;
-#    ifdef USE_SSS
+#      ifdef USE_SSS
   sssData = cl.sss_data;
-#      ifdef USE_SSS_ALBEDO
+#        ifdef USE_SSS_ALBEDO
   sssAlbedo = cl.sss_albedo.rgbb;
+#        endif
 #      endif
 #    endif
 
@@ -945,9 +965,9 @@ void main()
 #      endif
 
 #      ifdef USE_SSS_ALBEDO
-  fragColor.rgb += cl.sss_data.rgb * cl.sss_albedo.rgb * fac;
+  outRadiance.rgb += cl.sss_data.rgb * cl.sss_albedo.rgb * fac;
 #      else
-  fragColor.rgb += cl.sss_data.rgb * fac;
+  outRadiance.rgb += cl.sss_data.rgb * fac;
 #      endif
 #    endif
 }
@@ -955,18 +975,3 @@ void main()
 #  endif /* MESH_SHADER && !SHADOW_SHADER */
 
 #endif /* VOLUMETRICS */
-
-Closure nodetree_exec(void); /* Prototype */
-
-/* TODO find a better place */
-#ifdef USE_MULTIPLY
-
-out vec4 fragColor;
-
-#  define NODETREE_EXEC
-void main()
-{
-  Closure cl = nodetree_exec();
-  fragColor = vec4(mix(vec3(1.0), cl.radiance, cl.opacity), 1.0);
-}
-#endif
index 64a1c725a6b47f9ada48a1441901e290d7ec2e32..561f1335cb8c8d835050c94148b3864fab849090 100644 (file)
@@ -33,15 +33,13 @@ Closure nodetree_exec(void)
   vec3 out_diff, out_spec, ssr_spec;
   eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, out_diff, out_spec, ssr_spec);
 
-  Closure result = Closure(out_spec + out_diff * albedo,
-                           1.0,
-                           vec4(ssr_spec, roughness),
-                           normal_encode(vN, viewCameraVec),
-                           0);
+  Closure cl = CLOSURE_DEFAULT;
+  cl.radiance = out_spec + out_diff * albedo;
+  closure_load_ssr_data(ssr_spec, roughness, N, viewCameraVec, 0, cl);
 
 #ifdef LOOKDEV
   gl_FragDepth = 0.0;
 #endif
 
-  return result;
+  return cl;
 }
index e7b31b94f816c41d22bf86bf6e2d49fb71bbd623..dea6bc020ec0ca8e380bb32694fb8e37003216a8 100644 (file)
@@ -71,14 +71,16 @@ void main()
 
   Closure cl = nodetree_exec();
 
+  float opacity = saturate(1.0 - avg(cl.transmittance));
+
 #  if defined(USE_ALPHA_HASH)
   /* Hashed Alpha Testing */
-  if (cl.opacity < hashed_alpha_threshold(worldPosition)) {
+  if (opacity < hashed_alpha_threshold(worldPosition)) {
     discard;
   }
 #  elif defined(USE_ALPHA_CLIP)
   /* Alpha clip */
-  if (cl.opacity <= alphaThreshold) {
+  if (opacity <= alphaThreshold) {
     discard;
   }
 #  endif
index 51b73c93c86517cf2de53c9ca6657dcea8b31c59..6d9fda1c695d58679dba89243d3a40a36b34dcf4 100644 (file)
@@ -934,7 +934,7 @@ static char *code_generate_fragment(GPUMaterial *material,
   BLI_dynstr_append(ds, "void main()\n");
   BLI_dynstr_append(ds, "{\n");
   BLI_dynstr_append(ds, "\tClosure cl = nodetree_exec();\n");
-  BLI_dynstr_append(ds, "\tfragColor = vec4(cl.radiance, cl.opacity);\n");
+  BLI_dynstr_append(ds, "\tfragColor = vec4(cl.radiance, saturate(avg(cl.transmittance)));\n");
   BLI_dynstr_append(ds, "}\n");
   BLI_dynstr_append(ds, "#endif\n\n");
 
index 83d008c344132361add0b9bb8cef7eb1412a8f33..798d19b6b9df1ec91abcbafd93341c520b369100 100644 (file)
@@ -1239,10 +1239,9 @@ vec3 principled_sheen(float NV, vec3 basecol_tint, float sheen_tint)
 void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
 {
   N = normalize(N);
-  vec3 vN = mat3(ViewMatrix) * N;
   result = CLOSURE_DEFAULT;
-  result.ssr_normal = normal_encode(vN, viewCameraVec);
   eevee_closure_diffuse(N, color.rgb, 1.0, result.radiance);
+  closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
   result.radiance *= color.rgb;
 }
 
@@ -1254,9 +1253,7 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Clo
   vec3 vN = mat3(ViewMatrix) * N;
   result = CLOSURE_DEFAULT;
   result.radiance = out_spec * color.rgb;
-  result.ssr_data = vec4(ssr_spec * color.rgb, roughness);
-  result.ssr_normal = normal_encode(vN, viewCameraVec);
-  result.ssr_id = int(ssr_id);
+  closure_load_ssr_data(ssr_spec * color.rgb, roughness, N, viewCameraVec, int(ssr_id), result);
 }
 
 void node_bsdf_anisotropic(vec4 color,
@@ -1285,9 +1282,8 @@ void node_bsdf_glass(
   vec3 vN = mat3(ViewMatrix) * N;
   result = CLOSURE_DEFAULT;
   result.radiance = mix(out_refr, out_spec, fresnel);
-  result.ssr_data = vec4(ssr_spec * color.rgb * fresnel, roughness);
-  result.ssr_normal = normal_encode(vN, viewCameraVec);
-  result.ssr_id = int(ssr_id);
+  closure_load_ssr_data(
+      ssr_spec * color.rgb * fresnel, roughness, N, viewCameraVec, int(ssr_id), result);
 }
 
 void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result)
@@ -1352,7 +1348,7 @@ void node_bsdf_principled(vec4 base_color,
 
   vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
 
-  float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0)) * subsurface;
+  float sss_scalef = avg(sss_scale) * subsurface;
   eevee_closure_principled(N,
                            mixed_ss_base_color,
                            f0,
@@ -1376,28 +1372,34 @@ void node_bsdf_principled(vec4 base_color,
                                           vec3(1.0); /* Simulate 2 transmission event */
   out_refr *= refr_color * (1.0 - fresnel) * transmission;
 
-  vec3 vN = mat3(ViewMatrix) * N;
   result = CLOSURE_DEFAULT;
   result.radiance = out_spec + out_refr;
   result.radiance += out_diff * out_sheen; /* Coarse approx. */
+
+  closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+
+  vec3 sss_radiance = (out_diff + out_trans) * alpha;
 #  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;
+  result.radiance += sss_radiance * mixed_ss_base_color * (1.0 - transmission);
+#  else
 #    ifdef USE_SSS_ALBEDO
-  result.sss_albedo.rgb = mixed_ss_base_color;
+  vec3 sss_albedo = mixed_ss_base_color;
 #    else
-  result.sss_data.rgb *= mixed_ss_base_color;
+  sss_radiance *= mixed_ss_base_color;
 #    endif
-  result.sss_data.rgb *= (1.0 - transmission);
-#  endif
+  sss_radiance *= (1.0 - transmission);
+  closure_load_sss_data(sss_scalef,
+                        sss_radiance,
+#    ifdef USE_SSS_ALBEDO
+                        sss_albedo,
+#    endif
+                        int(sss_id),
+                        result);
+#  endif /* USE_SSS */
+
   result.radiance += emission.rgb;
-  result.opacity = alpha;
+  result.radiance *= alpha;
+  result.transmittance = vec3(1.0 - alpha);
 }
 
 void node_bsdf_principled_dielectric(vec4 base_color,
@@ -1443,14 +1445,12 @@ void node_bsdf_principled_dielectric(vec4 base_color,
   eevee_closure_default(
       N, diffuse, f0, vec3(1.0), int(ssr_id), roughness, 1.0, out_diff, out_spec, ssr_spec);
 
-  vec3 vN = mat3(ViewMatrix) * N;
   result = CLOSURE_DEFAULT;
   result.radiance = out_spec + out_diff * (diffuse + out_sheen);
-  result.ssr_data = vec4(ssr_spec, roughness);
-  result.ssr_normal = normal_encode(vN, viewCameraVec);
-  result.ssr_id = int(ssr_id);
+  closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
   result.radiance += emission.rgb;
-  result.opacity = alpha;
+  result.radiance *= alpha;
+  result.transmittance = vec3(1.0 - alpha);
 }
 
 void node_bsdf_principled_metallic(vec4 base_color,
@@ -1488,14 +1488,12 @@ void node_bsdf_principled_metallic(vec4 base_color,
 
   eevee_closure_glossy(N, base_color.rgb, f90, int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
 
-  vec3 vN = 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);
+  closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
   result.radiance += emission.rgb;
-  result.opacity = alpha;
+  result.radiance *= alpha;
+  result.transmittance = vec3(1.0 - alpha);
 }
 
 void node_bsdf_principled_clearcoat(vec4 base_color,
@@ -1543,14 +1541,12 @@ void node_bsdf_principled_clearcoat(vec4 base_color,
                           out_spec,
                           ssr_spec);
 
-  vec3 vN = 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);
+  closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
   result.radiance += emission.rgb;
-  result.opacity = alpha;
+  result.radiance *= alpha;
+  result.transmittance = vec3(1.0 - alpha);
 }
 
 void node_bsdf_principled_subsurface(vec4 base_color,
@@ -1591,7 +1587,7 @@ void node_bsdf_principled_subsurface(vec4 base_color,
 
   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;
+  float sss_scalef = avg(sss_scale) * subsurface;
 
   float NV = dot(N, cameraVec);
   vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
@@ -1611,26 +1607,33 @@ void node_bsdf_principled_subsurface(vec4 base_color,
                      out_spec,
                      ssr_spec);
 
-  vec3 vN = 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);
-#  ifdef USE_SSS
-  result.sss_data.a = sss_scalef;
-  result.sss_data.rgb = out_diff + out_trans;
+  closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
+
+  vec3 sss_radiance = (out_diff + out_trans) * alpha;
+#  ifndef USE_SSS
+  result.radiance += sss_radiance * mixed_ss_base_color * (1.0 - transmission);
+#  else
 #    ifdef USE_SSS_ALBEDO
-  result.sss_albedo.rgb = mixed_ss_base_color;
+  vec3 sss_albedo = mixed_ss_base_color;
 #    else
-  result.sss_data.rgb *= mixed_ss_base_color;
+  sss_radiance *= mixed_ss_base_color;
 #    endif
-#  else
-  result.radiance += (out_diff + out_trans) * mixed_ss_base_color;
-#  endif
+  sss_radiance *= (1.0 - transmission);
+  closure_load_sss_data(sss_scalef,
+                        sss_radiance,
+#    ifdef USE_SSS_ALBEDO
+                        sss_albedo,
+#    endif
+                        int(sss_id),
+                        result);
+#  endif /* USE_SSS */
+
   result.radiance += out_diff * out_sheen;
   result.radiance += emission.rgb;
-  result.opacity = alpha;
+  result.radiance *= alpha;
+  result.transmittance = vec3(1.0 - alpha);
 }
 
 void node_bsdf_principled_glass(vec4 base_color,
@@ -1680,14 +1683,12 @@ void node_bsdf_principled_glass(vec4 base_color,
   out_spec *= spec_col;
   ssr_spec *= spec_col * fresnel;
 
-  vec3 vN = 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);
+  closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
   result.radiance += emission.rgb;
-  result.opacity = alpha;
+  result.radiance *= alpha;
+  result.transmittance = vec3(1.0 - alpha);
 }
 
 void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
@@ -1697,11 +1698,9 @@ void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
 
 void node_bsdf_transparent(vec4 color, out Closure result)
 {
-  /* this isn't right */
   result = CLOSURE_DEFAULT;
   result.radiance = vec3(0.0);
-  result.opacity = clamp(1.0 - dot(color.rgb, vec3(0.3333334)), 0.0, 1.0);
-  result.ssr_id = TRANSPARENT_CLOSURE_FLAG;
+  result.transmittance = abs(color.rgb);
 }
 
 void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result)
@@ -1723,19 +1722,25 @@ void node_subsurface_scattering(vec4 color,
   vec3 out_diff, out_trans;
   vec3 vN = mat3(ViewMatrix) * N;
   result = CLOSURE_DEFAULT;
-  result.ssr_data = vec4(0.0);
-  result.ssr_normal = normal_encode(vN, viewCameraVec);
-  result.ssr_id = -1;
-  result.sss_data.a = scale;
+  closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
+
   eevee_closure_subsurface(N, color.rgb, 1.0, scale, out_diff, out_trans);
-  result.sss_data.rgb = out_diff + out_trans;
+
+  vec3 sss_radiance = out_diff + out_trans;
 #    ifdef USE_SSS_ALBEDO
   /* Not perfect for texture_blur not exactly 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);
+  vec3 sss_albedo = mix(color.rgb, vec3(1.0), texture_blur);
+  sss_radiance *= mix(vec3(1.0), color.rgb, texture_blur);
 #    else
-  result.sss_data.rgb *= color.rgb;
+  sss_radiance *= color.rgb;
 #    endif
+  closure_load_sss_data(scale,
+                        sss_radiance,
+#    ifdef USE_SSS_ALBEDO
+                        sss_albedo,
+#    endif
+                        int(sss_id),
+                        result);
 #  else
   node_bsdf_diffuse(color, 0.0, N, result);
 #  endif
@@ -1751,7 +1756,6 @@ void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Cl
   result = CLOSURE_DEFAULT;
   result.ssr_normal = normal_encode(vN, viewCameraVec);
   result.radiance = out_refr * color.rgb;
-  result.ssr_id = REFRACT_CLOSURE_FLAG;
 }
 
 void node_ambient_occlusion(
@@ -1852,7 +1856,7 @@ void node_background(vec4 color, float strength, out Closure result)
   color *= strength;
   result = CLOSURE_DEFAULT;
   result.radiance = color.rgb;
-  result.opacity = color.a;
+  result.transmittance = vec3(0.0);
 #else
   result = CLOSURE_DEFAULT;
 #endif
@@ -2034,7 +2038,7 @@ void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outv
 #endif
   outvec = texture(tex, cos).aaa;
   outcol = vec4(outvec, 1.0);
-  outf = dot(vec3(1.0 / 3.0), outvec);
+  outf = avg(outvec);
 }
 
 uniform vec3 volumeColor = vec3(1.0);
@@ -2055,7 +2059,7 @@ void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec
 
   outvec = value.rgb * volumeColor;
   outcol = vec4(outvec, 1.0);
-  outf = dot(vec3(1.0 / 3.0), outvec);
+  outf = avg(outvec);
 }
 
 void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
@@ -2089,7 +2093,7 @@ void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
 {
   outcol = vec4(attr, 1.0);
   outvec = attr;
-  outf = dot(vec3(1.0 / 3.0), attr);
+  outf = avg(attr);
 }
 
 void node_uvmap(vec3 attr_uv, out vec3 outvec)
@@ -3502,7 +3506,7 @@ void node_output_world(Closure surface, Closure volume, out Closure result)
 {
 #ifndef VOLUMETRICS
   result.radiance = surface.radiance * backgroundAlpha;
-  result.opacity = backgroundAlpha;
+  result.transmittance = vec3(0.0);
 #else
   result = volume;
 #endif /* VOLUMETRICS */
@@ -3549,6 +3553,8 @@ 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,
@@ -3564,19 +3570,19 @@ void node_eevee_specular(vec4 diffuse,
                                   out_spec,
                                   ssr_spec);
 
-  vec3 vN = normalize(mat3(ViewMatrix) * normal);
+  float alpha = 1.0 - transp;
   result = CLOSURE_DEFAULT;
   result.radiance = out_diff * diffuse.rgb + out_spec + emissive.rgb;
-  result.opacity = 1.0 - transp;
-  result.ssr_data = vec4(ssr_spec, roughness);
-  result.ssr_normal = normal_encode(vN, viewCameraVec);
-  result.ssr_id = int(ssr_id);
+  result.radiance *= alpha;
+  result.transmittance = vec3(transp);
+
+  closure_load_ssr_data(ssr_spec * alpha, roughness, normal, viewCameraVec, int(ssr_id), result);
 }
 
 void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha)
 {
   vec4 spec_accum = vec4(0.0);
-  if (ssrToggle && cl.ssr_id == outputSsrId) {
+  if (ssrToggle && FLAG_TEST(cl.flag, CLOSURE_SSR_FLAG)) {
     vec3 V = cameraVec;
     vec3 vN = normal_decode(cl.ssr_normal, viewCameraVec);
     vec3 N = transform_direction(ViewMatrixInverse, vN);
@@ -3585,7 +3591,7 @@ void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha)
     fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
   }
 
-  outalpha = cl.opacity;
+  outalpha = avg(cl.transmittance);
   outcol = vec4((spec_accum.rgb * cl.ssr_data.rgb) + cl.radiance, 1.0);
 
 #  ifdef USE_SSS
index 741e792da87d2a896c5ac6c7df6af88656969828..595ddf27d0ab2aafcfa2845f8e8dd3286ddca697 100644 (file)
@@ -132,8 +132,13 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
              &in[21].link);
   }
 
+  bool use_diffuse = socket_not_one(4) && socket_not_one(15);
+  bool use_subsurf = socket_not_zero(1) && use_diffuse && node->sss_id > 0;
+  bool use_refract = socket_not_one(4) && socket_not_zero(15);
+  bool use_clear = socket_not_zero(12);
+
   /* SSS Profile */
-  if (node->sss_id == 1) {
+  if (use_subsurf) {
     static short profile = SHD_SUBSURFACE_BURLEY;
     bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
     bNodeSocketValueRGBA *socket_data = socket->default_value;
@@ -148,11 +153,6 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
     GPU_link(mat, "set_rgb_one", &sss_scale);
   }
 
-  bool use_diffuse = socket_not_one(4) && socket_not_one(15);
-  bool use_subsurf = socket_not_zero(1) && use_diffuse && node->sss_id == 1;
-  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;
index 21e07ece7b9989b8a68dab54cf54c6c1bacd13ce..9a0a132b3118df4869b4232e1c690c28cc37f7dc 100644 (file)
@@ -63,7 +63,7 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
 
   GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS);
 
-  if (node->sss_id == 1) {
+  if (node->sss_id > 0) {
     bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
     bNodeSocketValueRGBA *socket_data = socket->default_value;
     bNodeSocket *socket_sharp = BLI_findlink(&node->original->inputs, 3);