Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2019-01-24 19:28:51 +0300
committerClément Foucault <foucault.clem@gmail.com>2019-01-25 17:02:49 +0300
commit3f6e14e667c4442bcc1f4d1fc795633cc706150f (patch)
treec0501be8f98350b1d5907d7a37b4382f38c1a4b7 /source/blender/draw/engines
parentaae2bf77351103b15e5a97daed7f396a546c001c (diff)
Workbench: Depth Of Field: Initial Commit
The algorithm used is borrowed from : http://tuxedolabs.blogspot.com/2018/05/bokeh-depth-of-field-in-single-pass.html This makes it possible to have a decent blur for foreground over defocused background in one pass only. The algorithm is using a gather approach that is much faster than the scatter approach used in Eevee. This makes it possible to have custom bokeh shapes (not implemented yet) which would be impossible with a separable gaussian technique. The blur is done in 2 steps. The first one define the shape of the bokeh and the second that fill the undersampling. A downsample max-CoC tile texture speed up the gathering process.
Diffstat (limited to 'source/blender/draw/engines')
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl265
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c15
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_dof.c297
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c1
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h35
5 files changed, 610 insertions, 3 deletions
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
new file mode 100644
index 00000000000..08eb22d01c3
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
@@ -0,0 +1,265 @@
+/**
+ * Separable Hexagonal Bokeh Blur by Colin Barré-Brisebois
+ * https://colinbarrebrisebois.com/2017/04/18/hexagonal-bokeh-blur-revisited-part-1-basic-3-pass-version/
+ * Converted and adapted from HLSL to GLSL by Clément Foucault
+ **/
+
+uniform mat4 ProjectionMatrix;
+uniform vec2 invertedViewportSize;
+uniform vec2 nearFar;
+uniform vec3 dofParams;
+uniform sampler2D inputCocTex;
+uniform sampler2D maxCocTilesTex;
+uniform sampler2D sceneColorTex;
+uniform sampler2D sceneDepthTex;
+uniform sampler2D backgroundTex;
+uniform sampler2D halfResColorTex;
+uniform sampler2D blurTex;
+
+#define dof_aperturesize dofParams.x
+#define dof_distance dofParams.y
+#define dof_invsensorsize dofParams.z
+
+#define NUM_SAMPLES 25
+
+#define THRESHOLD 1.0
+#define M_PI 3.1415926535897932 /* pi */
+
+const float GOLDEN_ANGLE = 2.39996323;
+const float MAX_BLUR_SIZE = 20.0;
+const float RAD_SCALE = 2.0; // Smaller = nicer blur, larger = faster
+const float MAX_COC_SIZE = 40.0;
+
+float max_v4(vec4 v) { return max(max(v.x, v.y), max(v.z, v.w)); }
+
+#define weighted_sum(a, b, c, d, e, e_sum) ((a) * e.x + (b) * e.y + (c) * e.z + (d) * e.w) / max(1e-6, e_sum);
+
+#define encode_signed_coc(coc) (((coc) / MAX_COC_SIZE) * 0.5 + 0.5);
+#define decode_signed_coc(coc) (((coc) * 2.0 - 1.0) * MAX_COC_SIZE);
+
+/* divide by sensor size to get the normalized size */
+#define calculate_coc(zdepth) (dof_aperturesize * (dof_distance / zdepth - 1.0) * dof_invsensorsize)
+
+#define linear_depth(z) ((ProjectionMatrix[3][3] == 0.0) \
+ ? (nearFar.x * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y) \
+ : (z * 2.0 - 1.0) * nearFar.y)
+
+vec2 encode_coc(float near, float far) { return vec2(near, far) / MAX_COC_SIZE; }
+float decode_coc(vec2 cocs) { return max(cocs.x, cocs.y) * MAX_COC_SIZE; }
+
+/**
+ * ----------------- STEP 0 ------------------
+ * Coc aware downsample.
+ **/
+#ifdef PREPARE
+
+layout(location = 0) out vec4 backgroundColorCoc;
+layout(location = 1) out vec2 normalizedCoc;
+
+void main()
+{
+ /* Half Res pass */
+ vec2 uv = (floor(gl_FragCoord.xy) * 2.0 + 0.5) * invertedViewportSize;
+
+ ivec4 texel = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
+
+ /* custom downsampling */
+ 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);
+
+ 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;
+ depths.z = texelFetch(sceneDepthTex, texel.zy, 0).x;
+ depths.w = texelFetch(sceneDepthTex, texel.xw, 0).x;
+
+ vec4 zdepths = linear_depth(depths);
+ vec4 cocs_near = calculate_coc(zdepths);
+ vec4 cocs_far = -cocs_near;
+
+ float coc_near = max(max_v4(cocs_near), 0.0);
+ float coc_far = max(max_v4(cocs_far), 0.0);
+
+ /* 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. */
+ // backgroundColorCoc = weighted_sum(color1, color2, color3, color4, cocs_far, coc_far);
+ float tot_weight_near = dot(near_weights, vec4(1.0));
+ float tot_weight_far = dot(far_weights, vec4(1.0));
+ backgroundColorCoc = weighted_sum(color1, color2, color3, color4, near_weights, tot_weight_near);
+ backgroundColorCoc += weighted_sum(color1, color2, color3, color4, far_weights, tot_weight_far);
+ if (tot_weight_near > 0.0 && tot_weight_far > 0.0) {
+ backgroundColorCoc *= 0.5;
+ }
+
+ normalizedCoc = encode_coc(cocs_near.x, cocs_far.x);
+}
+#endif
+
+/**
+ * ----------------- STEP 1 ------------------
+ * Flatten COC buffer using max filter.
+ **/
+#if defined(FLATTEN_VERTICAL) || defined(FLATTEN_HORIZONTAL)
+
+layout(location = 0) out vec2 flattenedCoc;
+
+void main()
+{
+#ifdef FLATTEN_HORIZONTAL
+ ivec2 texel = ivec2(gl_FragCoord.xy) * ivec2(8, 1);
+ vec2 cocs1 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 0)).rg;
+ vec2 cocs2 = texelFetchOffset(inputCocTex, texel, 0, ivec2(1, 0)).rg;
+ vec2 cocs3 = texelFetchOffset(inputCocTex, texel, 0, ivec2(2, 0)).rg;
+ vec2 cocs4 = texelFetchOffset(inputCocTex, texel, 0, ivec2(3, 0)).rg;
+ vec2 cocs5 = texelFetchOffset(inputCocTex, texel, 0, ivec2(4, 0)).rg;
+ vec2 cocs6 = texelFetchOffset(inputCocTex, texel, 0, ivec2(5, 0)).rg;
+ vec2 cocs7 = texelFetchOffset(inputCocTex, texel, 0, ivec2(6, 0)).rg;
+ vec2 cocs8 = texelFetchOffset(inputCocTex, texel, 0, ivec2(7, 0)).rg;
+#else /* FLATTEN_VERTICAL */
+ ivec2 texel = ivec2(gl_FragCoord.xy) * ivec2(1, 8);
+ vec2 cocs1 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 0)).rg;
+ vec2 cocs2 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 1)).rg;
+ vec2 cocs3 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 2)).rg;
+ vec2 cocs4 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 3)).rg;
+ vec2 cocs5 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 4)).rg;
+ vec2 cocs6 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 5)).rg;
+ vec2 cocs7 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 6)).rg;
+ vec2 cocs8 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 7)).rg;
+#endif
+ flattenedCoc = max(max(max(cocs1, cocs2), max(cocs3, cocs4)), max(max(cocs5, cocs6), max(cocs7, cocs8)));
+}
+#endif
+
+/**
+ * ----------------- STEP 1.ax------------------
+ * Dilate COC buffer using min filter.
+ **/
+#if defined(DILATE_VERTICAL) || defined(DILATE_HORIZONTAL)
+
+layout(location = 0) out vec2 dilatedCoc;
+
+void main()
+{
+ vec2 texel_size = 1.0 / vec2(textureSize(inputCocTex, 0));
+ vec2 uv = gl_FragCoord.xy * texel_size;
+#ifdef DILATE_VERTICAL
+ // vec2 cocs1 = texture(inputCocTex, uv + texel_size * vec2(-3, 0)).rg;
+ vec2 cocs2 = texture(inputCocTex, uv + texel_size * vec2(-2, 0)).rg;
+ vec2 cocs3 = texture(inputCocTex, uv + texel_size * vec2(-1, 0)).rg;
+ vec2 cocs4 = texture(inputCocTex, uv + texel_size * vec2( 0, 0)).rg;
+ vec2 cocs5 = texture(inputCocTex, uv + texel_size * vec2( 1, 0)).rg;
+ vec2 cocs6 = texture(inputCocTex, uv + texel_size * vec2( 2, 0)).rg;
+ // vec2 cocs7 = texture(inputCocTex, uv + texel_size * vec2( 3, 0)).rg;
+#else /* DILATE_HORIZONTAL */
+ // vec2 cocs1 = texture(inputCocTex, uv + texel_size * vec2(0, -3)).rg;
+ vec2 cocs2 = texture(inputCocTex, uv + texel_size * vec2(0, -2)).rg;
+ vec2 cocs3 = texture(inputCocTex, uv + texel_size * vec2(0, -1)).rg;
+ vec2 cocs4 = texture(inputCocTex, uv + texel_size * vec2(0, 0)).rg;
+ vec2 cocs5 = texture(inputCocTex, uv + texel_size * vec2(0, 1)).rg;
+ vec2 cocs6 = texture(inputCocTex, uv + texel_size * vec2(0, 2)).rg;
+ // vec2 cocs7 = texture(inputCocTex, uv + texel_size * vec2(0, 3)).rg;
+#endif
+ dilatedCoc = max(max(cocs3, cocs4), max(max(cocs5, cocs6), cocs2));
+ // dilatedCoc = max(max(max(cocs1, cocs2), max(cocs3, cocs4)), max(max(cocs5, cocs6), cocs7));
+}
+#endif
+
+/**
+ * ----------------- STEP 2 ------------------
+ * Blur vertically and diagonally.
+ * Outputs vertical blur and combined blur in MRT
+ **/
+#ifdef BLUR1
+layout(location = 0) out vec4 blurColor;
+
+void main()
+{
+ /* Half Res pass */
+ vec2 uv = gl_FragCoord.xy * invertedViewportSize * 2.0;
+
+ vec2 size = vec2(textureSize(halfResColorTex, 0).xy);
+ ivec2 texel = ivec2(uv * size);
+
+ vec3 color = texelFetch(halfResColorTex, texel, 0).rgb;
+ float coc = decode_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;
+ float radius = RAD_SCALE;
+
+ for (float ang = 0.0; radius < MAX_BLUR_SIZE && radius < max_radius; ang += GOLDEN_ANGLE) {
+ vec2 tc = uv + vec2(cos(ang), sin(ang)) * invertedViewportSize * radius;
+
+ vec3 samp = texture(halfResColorTex, tc).rgb;
+
+ coc = decode_coc(texture(inputCocTex, tc).rg);
+ if (coc > center_coc) {
+ coc = clamp(abs(coc), 0.0, abs(center_coc) * 2.0);
+ }
+
+ float m = smoothstep(radius - 0.5, radius + 0.5, abs(coc));
+ color += mix(color / tot, samp, m);
+ tot += 1.0;
+ radius += RAD_SCALE / radius;
+ }
+
+ blurColor.rgb = color / tot;
+ blurColor.a = 1.0;
+}
+#endif
+
+/**
+ * ----------------- STEP 3 ------------------
+ * Additional 3x3 blur
+ **/
+#ifdef BLUR2
+out vec4 finalColor;
+
+void main()
+{
+ /* Half Res pass */
+ vec2 pixel_size = vec2(1.0, 1.0) / vec2(textureSize(blurTex, 0).xy);
+ vec2 uv = gl_FragCoord.xy * pixel_size.xy;
+ vec2 max_radii = texture(inputCocTex, uv).rg;
+ /* Scale filter */
+ float rad = min(max(max_radii.x, max_radii.y) * MAX_COC_SIZE, 4.0) * 0.25;
+ finalColor = texture(blurTex, uv + pixel_size * vec2(-0.5, -0.5) * rad);
+ finalColor += texture(blurTex, uv + pixel_size * vec2(-0.5, 1.5) * rad);
+ finalColor += texture(blurTex, uv + pixel_size * vec2( 1.5, -0.5) * rad);
+ finalColor += texture(blurTex, uv + pixel_size * vec2( 1.5, 1.5) * rad);
+ finalColor *= 0.25;
+}
+#endif
+
+/**
+ * ----------------- STEP 4 ------------------
+ **/
+#ifdef RESOLVE
+out vec4 finalColor;
+
+void main()
+{
+ /* Fullscreen pass */
+ vec2 pixel_size = 0.5 / vec2(textureSize(halfResColorTex, 0).xy);
+ vec2 uv = gl_FragCoord.xy * pixel_size;
+
+ /* TODO MAKE SURE TO ALIGN SAMPLE POSITION TO AVOID OFFSET IN THE BOKEH */
+ float depth = texelFetch(sceneDepthTex, ivec2(gl_FragCoord.xy), 0).r;
+ float zdepth = linear_depth(depth);
+ float coc = calculate_coc(zdepth);
+
+ finalColor = texture(halfResColorTex, uv);
+ finalColor.a = smoothstep(1.0, 3.0, abs(coc));
+}
+#endif \ No newline at end of file
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index b48e64293fa..d1e32ea42d9 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -343,6 +343,9 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
WORKBENCH_PassList *psl = vedata->psl;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
const DRWContextState *draw_ctx = DRW_context_state_get();
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ View3D *v3d = draw_ctx->v3d;
+ Object *camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL;
if (!stl->g_data) {
/* Alloc transient pointers */
@@ -406,6 +409,8 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
WORKBENCH_PrivateData *wpd = stl->g_data;
workbench_private_data_init(wpd);
+ workbench_dof_engine_init(vedata, camera);
+
{
const float *viewport_size = DRW_viewport_size_get();
const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
@@ -448,7 +453,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
GPU_ATTACHMENT_TEXTURE(dtxl->depth),
GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
});
- GPU_framebuffer_ensure_config(&fbl->volume_fb, {
+ GPU_framebuffer_ensure_config(&fbl->color_only_fb, {
GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
});
@@ -514,6 +519,10 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
workbench_aa_create_pass(vedata, &e_data.color_buffer_tx);
}
+ {
+ workbench_dof_create_pass(vedata, &e_data.composite_buffer_tx);
+ }
+
if (CAVITY_ENABLED(wpd)) {
int state = DRW_STATE_WRITE_COLOR;
GPUShader *shader = workbench_cavity_shader_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd));
@@ -583,6 +592,7 @@ void workbench_deferred_engine_free(void)
workbench_volume_engine_free();
workbench_fxaa_engine_free();
workbench_taa_engine_free();
+ workbench_dof_engine_free();
}
static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp)
@@ -1089,10 +1099,11 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
DRW_draw_pass(psl->background_pass);
if (wpd->volumes_do) {
- GPU_framebuffer_bind(fbl->volume_fb);
+ GPU_framebuffer_bind(fbl->color_only_fb);
DRW_draw_pass(psl->volume_pass);
}
+ workbench_dof_draw_pass(vedata);
workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx);
}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c
new file mode 100644
index 00000000000..85213a7460c
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file workbench_effect_dof.c
+ * \ingroup draw_engine
+ */
+
+#include "workbench_private.h"
+
+#include "BKE_camera.h"
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_camera_types.h"
+
+/* *********** STATIC *********** */
+static struct {
+ struct GPUShader *effect_dof_prepare_sh;
+ struct GPUShader *effect_dof_flatten_v_sh;
+ struct GPUShader *effect_dof_flatten_h_sh;
+ struct GPUShader *effect_dof_dilate_v_sh;
+ struct GPUShader *effect_dof_dilate_h_sh;
+ struct GPUShader *effect_dof_blur1_sh;
+ struct GPUShader *effect_dof_blur2_sh;
+ struct GPUShader *effect_dof_resolve_sh;
+} e_data = {NULL};
+
+/* Shaders */
+extern char datatoc_workbench_effect_dof_frag_glsl[];
+
+/* *********** Functions *********** */
+void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+
+ if (camera == NULL) {
+ wpd->dof_enabled = false;
+ return;
+ }
+
+ if (e_data.effect_dof_prepare_sh == NULL) {
+ e_data.effect_dof_prepare_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define PREPARE\n");
+
+ e_data.effect_dof_flatten_v_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define FLATTEN_VERTICAL\n");
+
+ e_data.effect_dof_flatten_h_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define FLATTEN_HORIZONTAL\n");
+
+ e_data.effect_dof_dilate_v_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define DILATE_VERTICAL\n");
+
+ e_data.effect_dof_dilate_h_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define DILATE_HORIZONTAL\n");
+
+ e_data.effect_dof_blur1_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define BLUR1\n");
+
+ e_data.effect_dof_blur2_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define BLUR2\n");
+
+ e_data.effect_dof_resolve_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define RESOLVE\n");
+ }
+
+ const float *full_size = DRW_viewport_size_get();
+ int size[2] = {full_size[0] / 2, full_size[1] / 2};
+ /* NOTE: We Ceil here in order to not miss any edge texel if using a NPO2 texture. */
+ int shrink_h_size[2] = {ceilf(size[0] / 8.0f), size[1]};
+ int shrink_w_size[2] = {shrink_h_size[0], ceilf(size[1] / 8.0f)};
+
+ wpd->half_res_col_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_R11F_G11F_B10F, &draw_engine_workbench_solid);
+ 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);
+ 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);
+ wpd->coc_tiles_tx[1] = DRW_texture_pool_query_2D(shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid);
+
+ 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_framebuffer_ensure_config(&fbl->dof_coc_tile_h_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->coc_temp_tx),
+ });
+ GPU_framebuffer_ensure_config(&fbl->dof_coc_tile_v_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->coc_tiles_tx[0]),
+ });
+ GPU_framebuffer_ensure_config(&fbl->dof_coc_dilate_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->coc_tiles_tx[1]),
+ });
+ GPU_framebuffer_ensure_config(&fbl->dof_blur1_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->dof_blur_tx),
+ });
+ GPU_framebuffer_ensure_config(&fbl->dof_blur2_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->half_res_col_tx),
+ });
+
+ {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ Camera *cam = (Camera *)camera->data;
+
+ /* Parameters */
+ /* TODO UI Options */
+ float fstop = cam->gpu_dof.fstop;
+ float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
+ float focus_dist = BKE_camera_object_dof_distance(camera);
+ float focal_len = cam->lens;
+
+ /* TODO(fclem) deduplicate with eevee */
+
+ /* this is factor that converts to the scene scale. focal length and sensor are expressed in mm
+ * unit.scale_length is how many meters per blender unit we have. We want to convert to blender units though
+ * because the shader reads coordinates in world space, which is in blender units.
+ * Note however that focus_distance is already in blender units and shall not be scaled here (see T48157). */
+ float scale = (scene_eval->unit.system) ? scene_eval->unit.scale_length : 1.0f;
+ float scale_camera = 0.001f / scale;
+ /* we want radius here for the aperture number */
+ float aperture = 0.5f * scale_camera * focal_len / fstop;
+ float focal_len_scaled = scale_camera * focal_len;
+ float sensor_scaled = scale_camera * sensor;
+
+ if (rv3d != NULL) {
+ sensor_scaled *= rv3d->viewcamtexcofac[0];
+ }
+
+ wpd->dof_aperturesize = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled));
+ wpd->dof_distance = -focus_dist;
+ wpd->dof_invsensorsize = full_size[0] / sensor_scaled;
+
+ wpd->dof_near_far[0] = -cam->clipsta;
+ wpd->dof_near_far[1] = -cam->clipend;
+ }
+
+ wpd->dof_enabled = true;
+}
+
+void workbench_dof_create_pass(WORKBENCH_Data *vedata, GPUTexture **dof_input)
+{
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+
+ if (!wpd->dof_enabled) {
+ return;
+ }
+
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ psl->dof_down_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);
+ psl->dof_dilate_v_ps = DRW_pass_create("DoF Dilate Coc V", DRW_STATE_WRITE_COLOR);
+ psl->dof_blur1_ps = DRW_pass_create("DoF Blur 1", DRW_STATE_WRITE_COLOR);
+ psl->dof_blur2_ps = DRW_pass_create("DoF Blur 2", DRW_STATE_WRITE_COLOR);
+ psl->dof_resolve_ps = DRW_pass_create("DoF Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
+
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_prepare_sh, psl->dof_down_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "sceneColorTex", dof_input);
+ 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);
+ 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_flatten_h_sh, psl->dof_flatten_h_ps);
+ DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_halfres_tx);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_v_sh, psl->dof_flatten_v_ps);
+ DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_temp_tx);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_v_sh, psl->dof_dilate_v_ps);
+ DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[0]);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_h_sh, psl->dof_dilate_h_ps);
+ DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[1]);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur1_sh, psl->dof_blur1_ps);
+ DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_halfres_tx);
+ DRW_shgroup_uniform_texture(grp, "maxCocTilesTex", wpd->coc_tiles_tx[0]);
+ DRW_shgroup_uniform_texture(grp, "halfResColorTex", wpd->half_res_col_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_blur2_sh, psl->dof_blur2_ps);
+ DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->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, "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);
+ DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+}
+
+void workbench_dof_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.effect_dof_prepare_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);
+ DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_h_sh);
+ DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur1_sh);
+ DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur2_sh);
+ DRW_SHADER_FREE_SAFE(e_data.effect_dof_resolve_sh);
+}
+
+void workbench_dof_draw_pass(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+
+ if (!wpd->dof_enabled) {
+ return;
+ }
+
+ GPU_framebuffer_bind(fbl->dof_downsample_fb);
+ DRW_draw_pass(psl->dof_down_ps);
+
+ GPU_framebuffer_bind(fbl->dof_coc_tile_h_fb);
+ DRW_draw_pass(psl->dof_flatten_h_ps);
+
+ GPU_framebuffer_bind(fbl->dof_coc_tile_v_fb);
+ DRW_draw_pass(psl->dof_flatten_v_ps);
+
+ GPU_framebuffer_bind(fbl->dof_coc_dilate_fb);
+ DRW_draw_pass(psl->dof_dilate_v_ps);
+
+ GPU_framebuffer_bind(fbl->dof_coc_tile_v_fb);
+ DRW_draw_pass(psl->dof_dilate_h_ps);
+
+ GPU_framebuffer_bind(fbl->dof_blur1_fb);
+ DRW_draw_pass(psl->dof_blur1_ps);
+
+ GPU_framebuffer_bind(fbl->dof_blur2_fb);
+ DRW_draw_pass(psl->dof_blur2_ps);
+
+ GPU_framebuffer_bind(fbl->color_only_fb);
+ DRW_draw_pass(psl->dof_resolve_ps);
+}
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
index ead9d51aaac..b353f96d18d 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -430,6 +430,7 @@ void workbench_forward_engine_free()
workbench_volume_engine_free();
workbench_fxaa_engine_free();
workbench_taa_engine_free();
+ workbench_dof_engine_free();
}
void workbench_forward_cache_init(WORKBENCH_Data *UNUSED(vedata))
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index bbcae7f81d4..62622b56805 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -92,7 +92,14 @@ typedef struct WORKBENCH_FramebufferList {
struct GPUFrameBuffer *effect_fb;
struct GPUFrameBuffer *effect_taa_fb;
struct GPUFrameBuffer *depth_buffer_fb;
- struct GPUFrameBuffer *volume_fb;
+ struct GPUFrameBuffer *color_only_fb;
+
+ struct GPUFrameBuffer *dof_downsample_fb;
+ struct GPUFrameBuffer *dof_coc_tile_h_fb;
+ struct GPUFrameBuffer *dof_coc_tile_v_fb;
+ struct GPUFrameBuffer *dof_coc_dilate_fb;
+ struct GPUFrameBuffer *dof_blur1_fb;
+ struct GPUFrameBuffer *dof_blur2_fb;
/* Forward render buffers */
struct GPUFrameBuffer *object_outline_fb;
@@ -129,6 +136,14 @@ typedef struct WORKBENCH_PassList {
struct DRWPass *background_pass_clip;
struct DRWPass *ghost_resolve_pass;
struct DRWPass *effect_aa_pass;
+ struct DRWPass *dof_down_ps;
+ struct DRWPass *dof_flatten_v_ps;
+ struct DRWPass *dof_flatten_h_ps;
+ struct DRWPass *dof_dilate_h_ps;
+ struct DRWPass *dof_dilate_v_ps;
+ struct DRWPass *dof_blur1_ps;
+ struct DRWPass *dof_blur2_ps;
+ struct DRWPass *dof_resolve_ps;
struct DRWPass *volume_pass;
/* forward rendering */
@@ -218,6 +233,18 @@ typedef struct WORKBENCH_PrivateData {
float ssao_params[4];
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];
+ float dof_aperturesize;
+ float dof_distance;
+ float dof_invsensorsize;
+ float dof_near_far[2];
+ bool dof_enabled;
+
/* Color Management */
bool use_color_view_settings;
} WORKBENCH_PrivateData; /* Transient data */
@@ -302,6 +329,12 @@ void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata);
void workbench_taa_view_updated(WORKBENCH_Data *vedata);
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_draw_pass(WORKBENCH_Data *vedata);
+
/* workbench_materials.c */
int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, Image *ima, Object *ob);
void workbench_material_get_image_and_mat(Object *ob, int mat_nr, Image **r_image, int *r_interp, Material **r_mat);