Eevee: Fix Missing alpha when rendering with DOF
authorClément Foucault <foucault.clem@gmail.com>
Mon, 15 Oct 2018 14:04:33 +0000 (16:04 +0200)
committerClément Foucault <foucault.clem@gmail.com>
Mon, 15 Oct 2018 14:04:50 +0000 (16:04 +0200)
NOTE: There is a float imprecision near the focus plane
due to the current technique used for DOF. This makes the alpha channel
transparent on nearly in focus objects even when they should not.
This artifact should be fixed when the DOF will use scatter as gather for
low brightness areas.

Fix T57042 : Eevee does not render alpha when DOF is turned on

source/blender/draw/engines/eevee/eevee_depth_of_field.c
source/blender/draw/engines/eevee/eevee_private.h
source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl
source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl

index e51fb2fd1d76ee3596a3506ba61019fa1264c5e9..c36e8601d25b3eddeca5025a8d0ca868eb1d9e66 100644 (file)
 
 static struct {
        /* Depth Of Field */
-       struct GPUShader *dof_downsample_sh;
-       struct GPUShader *dof_scatter_sh;
-       struct GPUShader *dof_resolve_sh;
+       struct GPUShader *dof_downsample_sh[2];
+       struct GPUShader *dof_scatter_sh[2];
+       struct GPUShader *dof_resolve_sh[2];
 } e_data = {NULL}; /* Engine data */
 
 extern char datatoc_effect_dof_vert_glsl[];
 extern char datatoc_effect_dof_frag_glsl[];
 
-static void eevee_create_shader_depth_of_field(void)
+static void eevee_create_shader_depth_of_field(const bool use_alpha)
 {
-       e_data.dof_downsample_sh = DRW_shader_create_fullscreen(
-               datatoc_effect_dof_frag_glsl, "#define STEP_DOWNSAMPLE\n");
-       e_data.dof_scatter_sh = DRW_shader_create(
+       e_data.dof_downsample_sh[use_alpha] = DRW_shader_create_fullscreen(
+               datatoc_effect_dof_frag_glsl, use_alpha ?
+                                             "#define USE_ALPHA_DOF\n"
+                                             "#define STEP_DOWNSAMPLE\n" :
+                                             "#define STEP_DOWNSAMPLE\n");
+       e_data.dof_scatter_sh[use_alpha] = DRW_shader_create(
                datatoc_effect_dof_vert_glsl, NULL,
-               datatoc_effect_dof_frag_glsl, "#define STEP_SCATTER\n");
-       e_data.dof_resolve_sh = DRW_shader_create_fullscreen(
-               datatoc_effect_dof_frag_glsl, "#define STEP_RESOLVE\n");
+               datatoc_effect_dof_frag_glsl, use_alpha ?
+                                             "#define USE_ALPHA_DOF\n"
+                                             "#define STEP_SCATTER\n" :
+                                             "#define STEP_SCATTER\n");
+       e_data.dof_resolve_sh[use_alpha] = DRW_shader_create_fullscreen(
+               datatoc_effect_dof_frag_glsl, use_alpha ?
+                                             "#define USE_ALPHA_DOF\n"
+                                             "#define STEP_RESOLVE\n" :
+                                             "#define STEP_RESOLVE\n");
 }
 
 int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, Object *camera)
@@ -86,9 +95,10 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
 
        if (scene_eval->eevee.flag & SCE_EEVEE_DOF_ENABLED) {
                RegionView3D *rv3d = draw_ctx->rv3d;
+               const bool use_alpha = !DRW_state_draw_background();
 
-               if (!e_data.dof_downsample_sh) {
-                       eevee_create_shader_depth_of_field();
+               if (!e_data.dof_downsample_sh[use_alpha]) {
+                       eevee_create_shader_depth_of_field(use_alpha);
                }
 
                if (camera) {
@@ -101,9 +111,11 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
 
                        int buffer_size[2] = {(int)viewport_size[0] / 2, (int)viewport_size[1] / 2};
 
-                       effects->dof_down_near = DRW_texture_pool_query_2D(buffer_size[0], buffer_size[1], GPU_R11F_G11F_B10F,
+                       GPUTextureFormat down_format = DRW_state_draw_background() ? GPU_R11F_G11F_B10F : GPU_RGBA16F;
+
+                       effects->dof_down_near = DRW_texture_pool_query_2D(buffer_size[0], buffer_size[1], down_format,
                                                                           &draw_engine_eevee_type);
-                       effects->dof_down_far =  DRW_texture_pool_query_2D(buffer_size[0], buffer_size[1], GPU_R11F_G11F_B10F,
+                       effects->dof_down_far =  DRW_texture_pool_query_2D(buffer_size[0], buffer_size[1], down_format,
                                                                           &draw_engine_eevee_type);
                        effects->dof_coc =       DRW_texture_pool_query_2D(buffer_size[0], buffer_size[1], GPU_RG16F,
                                                                           &draw_engine_eevee_type);
@@ -120,11 +132,18 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
 
                        effects->dof_blur = DRW_texture_pool_query_2D(buffer_size[0] * 2, buffer_size[1], fb_format,
                                                                      &draw_engine_eevee_type);
+
                        GPU_framebuffer_ensure_config(&fbl->dof_scatter_fb, {
                                GPU_ATTACHMENT_NONE,
                                GPU_ATTACHMENT_TEXTURE(effects->dof_blur),
                        });
 
+                       if (!DRW_state_draw_background()) {
+                               effects->dof_blur_alpha = DRW_texture_pool_query_2D(buffer_size[0] * 2, buffer_size[1], GPU_R32F,
+                                                                                   &draw_engine_eevee_type);
+                               GPU_framebuffer_texture_attach(fbl->dof_scatter_fb, effects->dof_blur_alpha, 1, 0);
+                       }
+
                        /* Parameters */
                        /* TODO UI Options */
                        float fstop = cam->gpu_dof.fstop;
@@ -193,10 +212,11 @@ void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_
                 **/
                DRWShadingGroup *grp;
                struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+               const bool use_alpha = !DRW_state_draw_background();
 
                psl->dof_down = DRW_pass_create("DoF Downsample", DRW_STATE_WRITE_COLOR);
 
-               grp = DRW_shgroup_create(e_data.dof_downsample_sh, psl->dof_down);
+               grp = DRW_shgroup_create(e_data.dof_downsample_sh[use_alpha], psl->dof_down);
                DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer);
                DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
                DRW_shgroup_uniform_vec2(grp, "nearFar", effects->dof_near_far, 1);
@@ -209,8 +229,7 @@ void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_
                 * by the vertex shader 0.4ms against 6ms with instancing */
                const float *viewport_size = DRW_viewport_size_get();
                const int sprite_len = ((int)viewport_size[0] / 2) * ((int)viewport_size[1] / 2); /* brackets matters */
-               grp = DRW_shgroup_empty_tri_batch_create(e_data.dof_scatter_sh, psl->dof_scatter, sprite_len);
-
+               grp = DRW_shgroup_empty_tri_batch_create(e_data.dof_scatter_sh[use_alpha], psl->dof_scatter, sprite_len);
                DRW_shgroup_uniform_texture_ref(grp, "nearBuffer", &effects->dof_down_near);
                DRW_shgroup_uniform_texture_ref(grp, "farBuffer", &effects->dof_down_far);
                DRW_shgroup_uniform_texture_ref(grp, "cocBuffer", &effects->dof_coc);
@@ -218,13 +237,17 @@ void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_
 
                psl->dof_resolve = DRW_pass_create("DoF Resolve", DRW_STATE_WRITE_COLOR);
 
-               grp = DRW_shgroup_create(e_data.dof_resolve_sh, psl->dof_resolve);
+               grp = DRW_shgroup_create(e_data.dof_resolve_sh[use_alpha], psl->dof_resolve);
                DRW_shgroup_uniform_texture_ref(grp, "scatterBuffer", &effects->dof_blur);
                DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer);
                DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
                DRW_shgroup_uniform_vec2(grp, "nearFar", effects->dof_near_far, 1);
                DRW_shgroup_uniform_vec3(grp, "dofParams", effects->dof_params, 1);
                DRW_shgroup_call_add(grp, quad, NULL);
+
+               if (use_alpha) {
+                       DRW_shgroup_uniform_texture_ref(grp, "scatterAlphaBuffer", &effects->dof_blur_alpha);
+               }
        }
 }
 
@@ -258,7 +281,9 @@ void EEVEE_depth_of_field_draw(EEVEE_Data *vedata)
 
 void EEVEE_depth_of_field_free(void)
 {
-       DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh);
-       DRW_SHADER_FREE_SAFE(e_data.dof_scatter_sh);
-       DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh);
+       for (int i = 0; i < 2; ++i) {
+               DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh[i]);
+               DRW_SHADER_FREE_SAFE(e_data.dof_scatter_sh[i]);
+               DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh[i]);
+       }
 }
index 35a1211ba4a11e449fc66f63e58fc3deb85191cc..c5d184e1a840a6af3a530b538421ba569c48e5ed 100644 (file)
@@ -578,6 +578,7 @@ typedef struct EEVEE_EffectsInfo {
        struct GPUTexture *dof_down_far;
        struct GPUTexture *dof_coc;
        struct GPUTexture *dof_blur;
+       struct GPUTexture *dof_blur_alpha;
        /* Other */
        float prev_persmat[4][4];
        /* Bloom */
index d816d72c1e393430dffe72122e0c7d8041d7aafe..27517ebd86e1ac0b3ecf1d0525ae124166da70a5 100644 (file)
@@ -77,6 +77,14 @@ void main(void)
        vec4 near_weights = step(THRESHOLD, coc_near) * clamp(1.0 - abs(cocData.x - coc_near), 0.0, 1.0);
        vec4 far_weights  = step(THRESHOLD, coc_far)  * clamp(1.0 - abs(cocData.y - coc_far),  0.0, 1.0);
 
+#  ifdef USE_ALPHA_DOF
+       /* Premult */
+       color1.rgb *= color1.a;
+       color2.rgb *= color2.a;
+       color3.rgb *= color3.a;
+       color4.rgb *= color4.a;
+#  endif
+
        /* now write output to weighted buffers. */
        nearColor = weighted_sum(color1, color2, color3, color4, near_weights);
        farColor = weighted_sum(color1, color2, color3, color4, far_weights);
@@ -85,12 +93,16 @@ void main(void)
 #elif defined(STEP_SCATTER)
 
 flat in vec4 color;
+flat in float weight;
 flat in float smoothFac;
 flat in ivec2 edge;
 /* coordinate used for calculating radius */
 in vec2 particlecoord;
 
-out vec4 fragColor;
+layout(location = 0) out vec4 fragColor;
+#  ifdef USE_ALPHA_DOF
+layout(location = 1) out float fragAlpha;
+#  endif
 
 /* accumulate color in the near/far blur buffers */
 void main(void)
@@ -130,9 +142,14 @@ void main(void)
 
        /* Smooth the edges a bit. This effectively reduce the bokeh shape
         * but does fade out the undersampling artifacts. */
-       if (smoothFac < 1.0) {
-               fragColor *= smoothstep(1.0, smoothFac, dist);
-       }
+       float shape = smoothstep(1.0, min(0.999, smoothFac), dist);
+
+       fragColor *= shape;
+
+#  ifdef USE_ALPHA_DOF
+       fragAlpha = fragColor.a;
+       fragColor.a = weight * shape;
+#  endif
 }
 
 #elif defined(STEP_RESOLVE)
@@ -140,6 +157,7 @@ void main(void)
 #define MERGE_THRESHOLD 4.0
 
 uniform sampler2D scatterBuffer;
+uniform sampler2D scatterAlphaBuffer;
 
 in vec4 uvcoordsvar;
 out vec4 fragColor;
@@ -203,9 +221,21 @@ void main(void)
        float far_w = far_col.a;
        float near_w = near_col.a;
        float focus_w = 1.0 - smoothstep(1.0, MERGE_THRESHOLD, abs(coc_signed));
+       float inv_weight_sum = 1.0 / (near_w + focus_w + far_w);
+
        focus_col *= focus_w; /* Premul */
 
-       fragColor = (far_col + near_col + focus_col) / (near_w + focus_w + far_w);
+#  ifdef USE_ALPHA_DOF
+       near_col.a = upsample_filter(scatterAlphaBuffer, near_uv, texelSize).r;
+       far_col.a = upsample_filter(scatterAlphaBuffer, far_uv, texelSize).r;
+#  endif
+
+       fragColor = (far_col + near_col + focus_col) * inv_weight_sum;
+
+#  ifdef USE_ALPHA_DOF
+       /* Unpremult */
+       fragColor.rgb /= (fragColor.a > 0.0) ? fragColor.a : 1.0;
+#  endif
 }
 
 #endif
index ec8b474b4318de2cf43ce56a19f3446d7225e0db..92fd36f684a59fab75f141f917bde9ee1669f20e 100644 (file)
@@ -10,6 +10,7 @@ uniform sampler2D farBuffer;
 uniform sampler2D cocBuffer;
 
 flat out vec4 color;
+flat out float weight;
 flat out float smoothFac;
 flat out ivec2 edge;
 out vec2 particlecoord;
@@ -49,8 +50,8 @@ void main()
                /* find the area the pixel will cover and divide the color by it */
                /* HACK: 4.0 out of nowhere (I suppose it's 4 pixels footprint for coc 0?)
                 * Makes near in focus more closer to 1.0 alpha. */
-               color.a = 4.0 / (coc * coc * M_PI);
-               color.rgb *= color.a;
+               weight = 4.0 / (coc * coc * M_PI);
+               color *= weight;
 
                /* Compute edge to discard fragment that does not belong to the other layer. */
                edge.x = (is_near) ? 1 : -1;