Workbench: Depth Of Field: Improve noise and Large radius
authorClément Foucault <foucault.clem@gmail.com>
Mon, 28 Jan 2019 17:49:00 +0000 (18:49 +0100)
committerClément Foucault <foucault.clem@gmail.com>
Tue, 29 Jan 2019 14:05:51 +0000 (15:05 +0100)
- Add noise to remove undersampling artifact
- Create 2 mipmaps to the scene color buffer in order to have bigger blurs
- Replace blur2 with a 3x3 median filter that doesn't dilate the highlights
- Use temporal accumulation to remove noise

For some reason all of this exacerbate some bleeding issues happening on
far foreground elements from near foreground elements. The actual problem
was already happening before but was not really noticeable. It needs some
more work to be fixed.

source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
source/blender/draw/engines/workbench/workbench_deferred.c
source/blender/draw/engines/workbench/workbench_effect_dof.c
source/blender/draw/engines/workbench/workbench_private.h

index 8d2cd719c25443a68544b40ff5ba54b2cd0e378e..0185e192f5c14528a0480001388bdd7ce1ed7b5b 100644 (file)
@@ -8,6 +8,7 @@ uniform mat4 ProjectionMatrix;
 uniform vec2 invertedViewportSize;
 uniform vec2 nearFar;
 uniform vec3 dofParams;
+uniform float noiseOffset;
 uniform sampler2D inputCocTex;
 uniform sampler2D maxCocTilesTex;
 uniform sampler2D sceneColorTex;
@@ -15,6 +16,7 @@ uniform sampler2D sceneDepthTex;
 uniform sampler2D backgroundTex;
 uniform sampler2D halfResColorTex;
 uniform sampler2D blurTex;
+uniform sampler2D noiseTex;
 
 #define dof_aperturesize    dofParams.x
 #define dof_distance        dofParams.y
@@ -57,7 +59,6 @@ void main()
        vec4 color3 = texelFetch(sceneColorTex, texel.zy, 0);
        vec4 color4 = texelFetch(sceneColorTex, texel.xw, 0);
 
-       vec3 ofs = vec3(invertedViewportSize.xy, 0.0);
        vec4 depths;
        depths.x = texelFetch(sceneDepthTex, texel.xy, 0).x;
        depths.y = texelFetch(sceneDepthTex, texel.zw, 0).x;
@@ -77,14 +78,60 @@ void main()
        vec4 far_weights  = step(0.0, cocs_far)  * clamp(1.0 - abs(coc_far  - cocs_far),  0.0, 1.0);
 
        /* now write output to weighted buffers. */
-       vec4 w = near_weights + far_weights;
+       /* Take far plane pixels in priority. */
+       vec4 w = any(notEqual(far_weights, vec4(0.0))) ? far_weights : near_weights;
        float tot_weight = dot(w, vec4(1.0));
        halfResColor = weighted_sum(color1, color2, color3, color4, w, tot_weight);
+       halfResColor = clamp(halfResColor, 0.0, 3.0);
 
        normalizedCoc = encode_coc(coc_near, coc_far);
 }
 #endif
 
+/**
+ * ----------------- STEP 0.5 ------------------
+ * Custom Coc aware downsampling. Quater res pass.
+ **/
+#ifdef DOWNSAMPLE
+
+layout(location = 0) out vec4 outColor;
+layout(location = 1) out vec2 outCocs;
+
+void main()
+{
+       ivec4 texel = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
+
+       vec4 color1 = texelFetch(sceneColorTex, texel.xy, 0);
+       vec4 color2 = texelFetch(sceneColorTex, texel.zw, 0);
+       vec4 color3 = texelFetch(sceneColorTex, texel.zy, 0);
+       vec4 color4 = texelFetch(sceneColorTex, texel.xw, 0);
+
+       vec4 depths;
+       vec2 cocs1 = texelFetch(inputCocTex, texel.xy, 0).rg;
+       vec2 cocs2 = texelFetch(inputCocTex, texel.zw, 0).rg;
+       vec2 cocs3 = texelFetch(inputCocTex, texel.zy, 0).rg;
+       vec2 cocs4 = texelFetch(inputCocTex, texel.xw, 0).rg;
+
+       vec4 cocs_near = vec4(cocs1.r, cocs2.r, cocs3.r, cocs4.r) * MAX_COC_SIZE;
+       vec4 cocs_far  = vec4(cocs1.g, cocs2.g, cocs3.g, cocs4.g) * MAX_COC_SIZE;
+
+       float coc_near = max_v4(cocs_near);
+       float coc_far  = max_v4(cocs_far);
+
+       /* now we need to write the near-far fields premultiplied by the coc
+        * also use bilateral weighting by each coc values to avoid bleeding. */
+       vec4 near_weights = step(0.0, cocs_near) * clamp(1.0 - abs(coc_near - cocs_near), 0.0, 1.0);
+       vec4 far_weights  = step(0.0, cocs_far)  * clamp(1.0 - abs(coc_far  - cocs_far),  0.0, 1.0);
+
+       /* now write output to weighted buffers. */
+       vec4 w = any(notEqual(far_weights, vec4(0.0))) ? far_weights : near_weights;
+       float tot_weight = dot(w, vec4(1.0));
+       outColor = weighted_sum(color1, color2, color3, color4, w, tot_weight);
+
+       outCocs = encode_coc(coc_near, coc_far);
+}
+#endif
+
 /**
  * ----------------- STEP 1 ------------------
  * Flatten COC buffer using max filter.
@@ -168,42 +215,17 @@ layout(std140) uniform dofSamplesBlock {
        vec4 samples[NUM_SAMPLES];
 };
 
-#if 0 /* Spilar sampling. Better but slower */
-void main()
+vec2 get_random_vector(float offset)
 {
-       /* Half Res pass */
-       vec2 uv = gl_FragCoord.xy * invertedViewportSize * 2.0;
-
-       vec2 size = vec2(textureSize(halfResColorTex, 0).xy);
-       ivec2 texel = ivec2(uv * size);
-
-       vec4 color = texelFetch(halfResColorTex, texel, 0);
-       float coc = decode_signed_coc(texelFetch(inputCocTex, texel, 0).rg);
-
-       /* TODO Ensure alignement */
-       vec2 max_radii = texture(maxCocTilesTex, (0.5 + floor(gl_FragCoord.xy / 8.0)) / vec2(textureSize(maxCocTilesTex, 0))).rg;
-       float max_radius = decode_coc(max_radii);
-
-       float center_coc = coc;
-       float tot = 1.0;
-
-       for (int i = 0; i < NUM_SAMPLES; ++i) {
-               vec2 tc = uv + samples[i].xy * invertedViewportSize * max_radius;
-
-               vec4 samp = texture(halfResColorTex, tc);
-               coc = decode_signed_coc(texture(inputCocTex, tc).rg);
-               if (coc > center_coc) {
-                       coc = clamp(abs(coc), 0.0, abs(center_coc) * 2.0);
-               }
-               float radius = max_radius * float(i + 1) / float(NUM_SAMPLES);
-               float m = smoothstep(radius - 0.5, radius + 0.5, abs(coc));
-               color += mix(color / tot, samp, m);
-               tot += 1.0;
-       }
-
-       blurColor = color / tot;
+       /* Interlieved gradient noise by Jorge Jimenez
+        * http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare */
+       float ign = fract(offset + 52.9829189 * fract(0.06711056 * gl_FragCoord.x + 0.00583715 * gl_FragCoord.y));
+       float bn = texelFetch(noiseTex, ivec2(gl_FragCoord.xy) % 64, 0).a;
+       float ang = M_PI * 2.0 * fract(bn + offset);
+       return vec2(cos(ang), sin(ang)) * sqrt(ign);
+       // return noise.rg * sqrt(ign);
 }
-#else
+
 void main()
 {
        vec2 uv = gl_FragCoord.xy * invertedViewportSize * 2.0;
@@ -216,15 +238,18 @@ void main()
 
        float coc = decode_coc(texelFetch(inputCocTex, texel, 0).rg);
        float max_radius = coc;
+       vec2 noise = get_random_vector(noiseOffset) * 0.2 * clamp(max_radius * 0.2 - 4.0, 0.0, 1.0);
        for (int i = 0; i < NUM_SAMPLES; ++i) {
-               vec2 tc = uv + samples[i].xy * invertedViewportSize * max_radius;
+               vec2 tc = uv + (noise + samples[i].xy) * invertedViewportSize * max_radius;
 
-               vec4 samp = texture(halfResColorTex, tc);
+               /* decode_signed_coc return biggest coc. */
+               coc = abs(decode_signed_coc(texture(inputCocTex, tc).rg));
 
-               coc = decode_coc(texture(inputCocTex, tc).rg);
+               float lod = log2(clamp((coc + min(coc, max_radius)) * 0.5 - 21.0, 0.0, 16.0) * 0.25);
+               vec4 samp = textureLod(halfResColorTex, tc, lod);
 
                float radius = samples[i].z * max_radius;
-               float weight = coc * smoothstep(radius - 0.5, radius + 0.5, coc);
+               float weight = abs(coc) * smoothstep(radius - 0.5, radius + 0.5, abs(coc));
 
                color += samp * weight;
                tot += weight;
@@ -233,11 +258,38 @@ void main()
        blurColor = color / tot;
 }
 #endif
-#endif
 
 /**
  * ----------------- STEP 3 ------------------
- * Additional 3x3 blur
+ * 3x3 Median Filter
+ * Morgan McGuire and Kyle Whitson
+ * http://graphics.cs.williams.edu
+ *
+ *
+ * Copyright (c) Morgan McGuire and Williams College, 2006
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  **/
 #ifdef BLUR2
 out vec4 finalColor;
@@ -252,18 +304,42 @@ void main()
         * since this filter is not weighted by CoC
         * and can bleed a bit. */
        float rad = clamp(coc - 9.0, 0.0, 1.0);
-       rad *= 1.5; /* If not, it's a gaussian filter. */
-       finalColor  = texture(blurTex, uv + pixel_size * vec2(-1.0, -1.0) * rad);
-       finalColor += texture(blurTex, uv + pixel_size * vec2(-1.0,  0.0) * rad);
-       finalColor += texture(blurTex, uv + pixel_size * vec2(-1.0,  1.0) * rad);
-       finalColor += texture(blurTex, uv + pixel_size * vec2( 0.0, -1.0) * rad);
-       finalColor += texture(blurTex, uv + pixel_size * vec2( 0.0,  0.0) * rad);
-       finalColor += texture(blurTex, uv + pixel_size * vec2( 0.0,  1.0) * rad);
-       finalColor += texture(blurTex, uv + pixel_size * vec2( 1.0, -1.0) * rad);
-       finalColor += texture(blurTex, uv + pixel_size * vec2( 1.0,  0.0) * rad);
-       finalColor += texture(blurTex, uv + pixel_size * vec2( 1.0,  1.0) * rad);
-       finalColor *= 1.0 / 9.0;
+
+#define vec vec4
+#define toVec(x) x.rgba
+
+#define s2(a, b)                               temp = a; a = min(a, b); b = max(temp, b);
+#define mn3(a, b, c)                   s2(a, b); s2(a, c);
+#define mx3(a, b, c)                   s2(b, c); s2(a, c);
+
+#define mnmx3(a, b, c)                 mx3(a, b, c); s2(a, b);                                   // 3 exchanges
+#define mnmx4(a, b, c, d)              s2(a, b); s2(c, d); s2(a, c); s2(b, d);                   // 4 exchanges
+#define mnmx5(a, b, c, d, e)   s2(a, b); s2(c, d); mn3(a, c, e); mx3(b, d, e);           // 6 exchanges
+#define mnmx6(a, b, c, d, e, f) s2(a, d); s2(b, e); s2(c, f); mn3(a, b, c); mx3(d, e, f); // 7 exchanges
+
+       vec v[9];
+
+       /* Add the pixels which make up our window to the pixel array. */
+       for(int dX = -1; dX <= 1; ++dX) {
+               for(int dY = -1; dY <= 1; ++dY) {
+                       vec2 offset = vec2(float(dX), float(dY));
+                       /* If a pixel in the window is located at (x+dX, y+dY), put it at index (dX + R)(2R + 1) + (dY + R) of the
+                        * pixel array. This will fill the pixel array, with the top left pixel of the window at pixel[0] and the
+                        * bottom right pixel of the window at pixel[N-1]. */
+                       v[(dX + 1) * 3 + (dY + 1)] = toVec(texture(blurTex, uv + offset * pixel_size * rad));
+               }
+       }
+
+       vec temp;
+
+       /* Starting with a subset of size 6, remove the min and max each time */
+       mnmx6(v[0], v[1], v[2], v[3], v[4], v[5]);
+       mnmx5(v[1], v[2], v[3], v[4], v[6]);
+       mnmx4(v[2], v[3], v[4], v[7]);
+       mnmx3(v[3], v[4], v[8]);
+       toVec(finalColor) = v[4];
 }
+
 #endif
 
 /**
index 0e8981ed4a1a482fa97d68790b72aa276cd23d79..2e42159599843d253cc770d57fc3ff9797c56ee7 100644 (file)
@@ -305,7 +305,7 @@ static float *create_disk_samples(int num_samples, int num_iterations)
 
 static struct GPUTexture *create_jitter_texture(int num_samples)
 {
-       float jitter[64 * 64][3];
+       float jitter[64 * 64][4];
        const float num_samples_inv = 1.0f / num_samples;
 
        for (int i = 0; i < 64 * 64; i++) {
@@ -317,11 +317,12 @@ static struct GPUTexture *create_jitter_texture(int num_samples)
                float bn = blue_noise[i][1] - 0.5f;
                CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */
                jitter[i][2] = bn * num_samples_inv;
+               jitter[i][3] = blue_noise[i][1];
        }
 
        UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral);
 
-       return DRW_texture_create_2D(64, 64, GPU_RGB16F, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]);
+       return DRW_texture_create_2D(64, 64, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]);
 }
 /* Functions */
 
@@ -524,7 +525,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
        }
 
        {
-               workbench_dof_create_pass(vedata, &e_data.composite_buffer_tx);
+               workbench_dof_create_pass(vedata, &e_data.composite_buffer_tx, e_data.jitter_tx);
        }
 
        if (CAVITY_ENABLED(wpd)) {
index ec8c184eac5f68970b55fd9e9726af9140ec76b8..85bb5ba05229530d5184ce13ab47e0d12dca2a8f 100644 (file)
@@ -33,6 +33,7 @@
 /* *********** STATIC *********** */
 static struct {
        struct GPUShader *effect_dof_prepare_sh;
+       struct GPUShader *effect_dof_downsample_sh;
        struct GPUShader *effect_dof_flatten_v_sh;
        struct GPUShader *effect_dof_flatten_h_sh;
        struct GPUShader *effect_dof_dilate_v_sh;
@@ -130,6 +131,7 @@ static void workbench_dof_setup_samples(
 
 void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
 {
+       WORKBENCH_TextureList *txl = vedata->txl;
        WORKBENCH_StorageList *stl = vedata->stl;
        WORKBENCH_PrivateData *wpd = stl->g_data;
        WORKBENCH_FramebufferList *fbl = vedata->fbl;
@@ -146,6 +148,10 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
                        datatoc_workbench_effect_dof_frag_glsl,
                        "#define PREPARE\n");
 
+               e_data.effect_dof_downsample_sh = DRW_shader_create_fullscreen(
+                       datatoc_workbench_effect_dof_frag_glsl,
+                       "#define DOWNSAMPLE\n");
+
                e_data.effect_dof_flatten_v_sh = DRW_shader_create_fullscreen(
                        datatoc_workbench_effect_dof_frag_glsl,
                        "#define FLATTEN_VERTICAL\n");
@@ -183,9 +189,9 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
        int shrink_w_size[2] = {shrink_h_size[0], ceilf(size[1] / 8.0f)};
 #endif
 
-       wpd->half_res_col_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_R11F_G11F_B10F, &draw_engine_workbench_solid);
+       DRW_texture_ensure_2D(&txl->dof_source_tx, size[0], size[1], GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
+       DRW_texture_ensure_2D(&txl->coc_halfres_tx, size[0], size[1], GPU_RG8, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
        wpd->dof_blur_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_R11F_G11F_B10F, &draw_engine_workbench_solid);
-       wpd->coc_halfres_tx  = DRW_texture_pool_query_2D(size[0], size[1], GPU_RG8, &draw_engine_workbench_solid);
 #if 0
        wpd->coc_temp_tx     = DRW_texture_pool_query_2D(shrink_h_size[0], shrink_h_size[1], GPU_RG8, &draw_engine_workbench_solid);
        wpd->coc_tiles_tx[0] = DRW_texture_pool_query_2D(shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid);
@@ -194,8 +200,8 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
 
        GPU_framebuffer_ensure_config(&fbl->dof_downsample_fb, {
                GPU_ATTACHMENT_NONE,
-               GPU_ATTACHMENT_TEXTURE(wpd->half_res_col_tx),
-               GPU_ATTACHMENT_TEXTURE(wpd->coc_halfres_tx),
+               GPU_ATTACHMENT_TEXTURE(txl->dof_source_tx),
+               GPU_ATTACHMENT_TEXTURE(txl->coc_halfres_tx),
        });
 #if 0
        GPU_framebuffer_ensure_config(&fbl->dof_coc_tile_h_fb, {
@@ -217,7 +223,7 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
        });
        GPU_framebuffer_ensure_config(&fbl->dof_blur2_fb, {
                GPU_ATTACHMENT_NONE,
-               GPU_ATTACHMENT_TEXTURE(wpd->half_res_col_tx),
+               GPU_ATTACHMENT_TEXTURE(txl->dof_source_tx),
        });
 
        {
@@ -276,9 +282,10 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
        wpd->dof_enabled = true;
 }
 
-void workbench_dof_create_pass(WORKBENCH_Data *vedata, GPUTexture **dof_input)
+void workbench_dof_create_pass(WORKBENCH_Data *vedata, GPUTexture **dof_input, GPUTexture *noise_tex)
 {
        WORKBENCH_PassList *psl = vedata->psl;
+       WORKBENCH_TextureList *txl = vedata->txl;
        WORKBENCH_StorageList *stl = vedata->stl;
        WORKBENCH_PrivateData *wpd = stl->g_data;
        struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
@@ -290,6 +297,7 @@ void workbench_dof_create_pass(WORKBENCH_Data *vedata, GPUTexture **dof_input)
        DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
 
        psl->dof_down_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
+       psl->dof_down2_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
        psl->dof_flatten_h_ps = DRW_pass_create("DoF Flatten Coc H", DRW_STATE_WRITE_COLOR);
        psl->dof_flatten_v_ps = DRW_pass_create("DoF Flatten Coc V", DRW_STATE_WRITE_COLOR);
        psl->dof_dilate_h_ps = DRW_pass_create("DoF Dilate Coc H", DRW_STATE_WRITE_COLOR);
@@ -307,10 +315,17 @@ void workbench_dof_create_pass(WORKBENCH_Data *vedata, GPUTexture **dof_input)
                DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1);
                DRW_shgroup_call_add(grp, quad, NULL);
        }
+
+       {
+               DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_downsample_sh, psl->dof_down2_ps);
+               DRW_shgroup_uniform_texture(grp, "sceneColorTex", txl->dof_source_tx);
+               DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
+               DRW_shgroup_call_add(grp, quad, NULL);
+       }
 #if 0
        {
                DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_h_sh, psl->dof_flatten_h_ps);
-               DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_halfres_tx);
+               DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
                DRW_shgroup_call_add(grp, quad, NULL);
        }
        {
@@ -330,23 +345,26 @@ void workbench_dof_create_pass(WORKBENCH_Data *vedata, GPUTexture **dof_input)
        }
 #endif
        {
+               float offset = stl->effects->jitter_index / (float)workbench_taa_calculate_num_iterations(vedata);
                DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur1_sh, psl->dof_blur1_ps);
                DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->dof_ubo);
-               DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_halfres_tx);
-               DRW_shgroup_uniform_texture(grp, "halfResColorTex", wpd->half_res_col_tx);
+               DRW_shgroup_uniform_texture(grp, "noiseTex", noise_tex);
+               DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
+               DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx);
                DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
+               DRW_shgroup_uniform_float_copy(grp, "noiseOffset", offset);
                DRW_shgroup_call_add(grp, quad, NULL);
        }
        {
                DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur2_sh, psl->dof_blur2_ps);
-               DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_halfres_tx);
+               DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
                DRW_shgroup_uniform_texture(grp, "blurTex", wpd->dof_blur_tx);
                DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
                DRW_shgroup_call_add(grp, quad, NULL);
        }
        {
                DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_resolve_sh, psl->dof_resolve_ps);
-               DRW_shgroup_uniform_texture(grp, "halfResColorTex", wpd->half_res_col_tx);
+               DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx);
                DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth);
                DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
                DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1);
@@ -358,6 +376,7 @@ void workbench_dof_create_pass(WORKBENCH_Data *vedata, GPUTexture **dof_input)
 void workbench_dof_engine_free(void)
 {
        DRW_SHADER_FREE_SAFE(e_data.effect_dof_prepare_sh);
+       DRW_SHADER_FREE_SAFE(e_data.effect_dof_downsample_sh);
        DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_v_sh);
        DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_h_sh);
        DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_v_sh);
@@ -367,6 +386,12 @@ void workbench_dof_engine_free(void)
        DRW_SHADER_FREE_SAFE(e_data.effect_dof_resolve_sh);
 }
 
+static void workbench_dof_downsample_level(void *userData, int UNUSED(level))
+{
+       WORKBENCH_PassList *psl = (WORKBENCH_PassList *)userData;
+       DRW_draw_pass(psl->dof_down2_ps);
+}
+
 void workbench_dof_draw_pass(WORKBENCH_Data *vedata)
 {
        WORKBENCH_FramebufferList *fbl = vedata->fbl;
@@ -383,6 +408,8 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata)
        GPU_framebuffer_bind(fbl->dof_downsample_fb);
        DRW_draw_pass(psl->dof_down_ps);
 
+       GPU_framebuffer_recursive_downsample(fbl->dof_downsample_fb, 2, workbench_dof_downsample_level, psl);
+
 #if 0
        GPU_framebuffer_bind(fbl->dof_coc_tile_h_fb);
        DRW_draw_pass(psl->dof_flatten_h_ps);
index ef1143705873d74ef97b33a755793a6293423d20..35cd957171159aeb29d75dbe128c8dc6cad3fde8 100644 (file)
@@ -108,6 +108,8 @@ typedef struct WORKBENCH_FramebufferList {
 } WORKBENCH_FramebufferList;
 
 typedef struct WORKBENCH_TextureList {
+       struct GPUTexture *dof_source_tx;
+       struct GPUTexture *coc_halfres_tx;
        struct GPUTexture *history_buffer_tx;
        struct GPUTexture *depth_buffer_tx;
 } WORKBENCH_TextureList;
@@ -138,6 +140,7 @@ typedef struct WORKBENCH_PassList {
        struct DRWPass *ghost_resolve_pass;
        struct DRWPass *effect_aa_pass;
        struct DRWPass *dof_down_ps;
+       struct DRWPass *dof_down2_ps;
        struct DRWPass *dof_flatten_v_ps;
        struct DRWPass *dof_flatten_h_ps;
        struct DRWPass *dof_dilate_h_ps;
@@ -235,9 +238,7 @@ typedef struct WORKBENCH_PrivateData {
        float ssao_settings[4];
 
        /* Dof */
-       struct GPUTexture *half_res_col_tx;
        struct GPUTexture *dof_blur_tx;
-       struct GPUTexture *coc_halfres_tx;
        struct GPUTexture *coc_temp_tx;
        struct GPUTexture *coc_tiles_tx[2];
        struct GPUUniformBuffer *dof_ubo;
@@ -337,7 +338,7 @@ int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata);
 /* workbench_effect_dof.c */
 void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera);
 void workbench_dof_engine_free(void);
-void workbench_dof_create_pass(WORKBENCH_Data *vedata, GPUTexture **dof_input);
+void workbench_dof_create_pass(WORKBENCH_Data *vedata, GPUTexture **dof_input, GPUTexture *noise_tex);
 void workbench_dof_draw_pass(WORKBENCH_Data *vedata);
 
 /* workbench_materials.c */