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/workbench/shaders/workbench_effect_dof_frag.glsl
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/workbench/shaders/workbench_effect_dof_frag.glsl')
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl265
1 files changed, 265 insertions, 0 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