[Bf-blender-cvs] [3f6e14e667c] master: Workbench: Depth Of Field: Initial Commit

Clément Foucault noreply at git.blender.org
Fri Jan 25 15:13:36 CET 2019


Commit: 3f6e14e667c4442bcc1f4d1fc795633cc706150f
Author: Clément Foucault
Date:   Thu Jan 24 17:28:51 2019 +0100
Branches: master
https://developer.blender.org/rB3f6e14e667c4442bcc1f4d1fc795633cc706150f

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.

===================================================================

M	source/blender/draw/CMakeLists.txt
A	source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
M	source/blender/draw/engines/workbench/workbench_deferred.c
A	source/blender/draw/engines/workbench/workbench_effect_dof.c
M	source/blender/draw/engines/workbench/workbench_forward.c
M	source/blender/draw/engines/workbench/workbench_private.h

===================================================================

diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index cf41b3b3e28..20be15b3102 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -115,6 +115,7 @@ set(SRC
 	engines/workbench/workbench_data.c
 	engines/workbench/workbench_deferred.c
 	engines/workbench/workbench_effect_aa.c
+	engines/workbench/workbench_effect_dof.c
 	engines/workbench/workbench_effect_fxaa.c
 	engines/workbench/workbench_effect_taa.c
 	engines/workbench/workbench_engine.c
@@ -227,6 +228,7 @@ data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC)
 data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC)
 data_to_c_simple(engines/workbench/shaders/workbench_deferred_composite_frag.glsl SRC)
 data_to_c_simple(engines/workbench/shaders/workbench_deferred_background_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_effect_dof_frag.glsl SRC)
 data_to_c_simple(engines/workbench/shaders/workbench_effect_fxaa_frag.glsl SRC)
 data_to_c_simple(engines/workbench/shaders/workbench_effect_taa_frag.glsl SRC)
 data_to_c_simple(engines/workbench/shaders/workbench_forward_composite_frag.glsl SRC)
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 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list