0185e192f5c14528a0480001388bdd7ce1ed7b5b
[blender.git] / source / blender / draw / engines / workbench / shaders / workbench_effect_dof_frag.glsl
1 /**
2  * Separable Hexagonal Bokeh Blur by Colin Barré-Brisebois
3  * https://colinbarrebrisebois.com/2017/04/18/hexagonal-bokeh-blur-revisited-part-1-basic-3-pass-version/
4  * Converted and adapted from HLSL to GLSL by Clément Foucault
5  **/
6
7 uniform mat4 ProjectionMatrix;
8 uniform vec2 invertedViewportSize;
9 uniform vec2 nearFar;
10 uniform vec3 dofParams;
11 uniform float noiseOffset;
12 uniform sampler2D inputCocTex;
13 uniform sampler2D maxCocTilesTex;
14 uniform sampler2D sceneColorTex;
15 uniform sampler2D sceneDepthTex;
16 uniform sampler2D backgroundTex;
17 uniform sampler2D halfResColorTex;
18 uniform sampler2D blurTex;
19 uniform sampler2D noiseTex;
20
21 #define dof_aperturesize    dofParams.x
22 #define dof_distance        dofParams.y
23 #define dof_invsensorsize   dofParams.z
24
25 #define M_PI       3.1415926535897932        /* pi */
26
27 float max_v4(vec4 v) { return max(max(v.x, v.y), max(v.z, v.w)); }
28
29 #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);
30
31 /* divide by sensor size to get the normalized size */
32 #define calculate_coc(zdepth) (dof_aperturesize * (dof_distance / zdepth - 1.0) * dof_invsensorsize)
33
34 #define linear_depth(z) ((ProjectionMatrix[3][3] == 0.0) \
35                 ? (nearFar.x  * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y) \
36                 : (z * 2.0 - 1.0) * nearFar.y)
37
38
39 const float MAX_COC_SIZE = 100.0;
40 vec2 encode_coc(float near, float far) { return vec2(near, far) / MAX_COC_SIZE; }
41 float decode_coc(vec2 cocs) { return max(cocs.x, cocs.y) * MAX_COC_SIZE; }
42 float decode_signed_coc(vec2 cocs) { return ((cocs.x > cocs.y) ? cocs.x : -cocs.y) * MAX_COC_SIZE; }
43
44 /**
45  * ----------------- STEP 0 ------------------
46  * Custom Coc aware downsampling. Half res pass.
47  **/
48 #ifdef PREPARE
49
50 layout(location = 0) out vec4 halfResColor;
51 layout(location = 1) out vec2 normalizedCoc;
52
53 void main()
54 {
55         ivec4 texel = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
56
57         vec4 color1 = texelFetch(sceneColorTex, texel.xy, 0);
58         vec4 color2 = texelFetch(sceneColorTex, texel.zw, 0);
59         vec4 color3 = texelFetch(sceneColorTex, texel.zy, 0);
60         vec4 color4 = texelFetch(sceneColorTex, texel.xw, 0);
61
62         vec4 depths;
63         depths.x = texelFetch(sceneDepthTex, texel.xy, 0).x;
64         depths.y = texelFetch(sceneDepthTex, texel.zw, 0).x;
65         depths.z = texelFetch(sceneDepthTex, texel.zy, 0).x;
66         depths.w = texelFetch(sceneDepthTex, texel.xw, 0).x;
67
68         vec4 zdepths = linear_depth(depths);
69         vec4 cocs_near = calculate_coc(zdepths);
70         vec4 cocs_far = -cocs_near;
71
72         float coc_near = max(max_v4(cocs_near), 0.0);
73         float coc_far  = max(max_v4(cocs_far), 0.0);
74
75         /* now we need to write the near-far fields premultiplied by the coc
76          * also use bilateral weighting by each coc values to avoid bleeding. */
77         vec4 near_weights = step(0.0, cocs_near) * clamp(1.0 - abs(coc_near - cocs_near), 0.0, 1.0);
78         vec4 far_weights  = step(0.0, cocs_far)  * clamp(1.0 - abs(coc_far  - cocs_far),  0.0, 1.0);
79
80         /* now write output to weighted buffers. */
81         /* Take far plane pixels in priority. */
82         vec4 w = any(notEqual(far_weights, vec4(0.0))) ? far_weights : near_weights;
83         float tot_weight = dot(w, vec4(1.0));
84         halfResColor = weighted_sum(color1, color2, color3, color4, w, tot_weight);
85         halfResColor = clamp(halfResColor, 0.0, 3.0);
86
87         normalizedCoc = encode_coc(coc_near, coc_far);
88 }
89 #endif
90
91 /**
92  * ----------------- STEP 0.5 ------------------
93  * Custom Coc aware downsampling. Quater res pass.
94  **/
95 #ifdef DOWNSAMPLE
96
97 layout(location = 0) out vec4 outColor;
98 layout(location = 1) out vec2 outCocs;
99
100 void main()
101 {
102         ivec4 texel = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
103
104         vec4 color1 = texelFetch(sceneColorTex, texel.xy, 0);
105         vec4 color2 = texelFetch(sceneColorTex, texel.zw, 0);
106         vec4 color3 = texelFetch(sceneColorTex, texel.zy, 0);
107         vec4 color4 = texelFetch(sceneColorTex, texel.xw, 0);
108
109         vec4 depths;
110         vec2 cocs1 = texelFetch(inputCocTex, texel.xy, 0).rg;
111         vec2 cocs2 = texelFetch(inputCocTex, texel.zw, 0).rg;
112         vec2 cocs3 = texelFetch(inputCocTex, texel.zy, 0).rg;
113         vec2 cocs4 = texelFetch(inputCocTex, texel.xw, 0).rg;
114
115         vec4 cocs_near = vec4(cocs1.r, cocs2.r, cocs3.r, cocs4.r) * MAX_COC_SIZE;
116         vec4 cocs_far  = vec4(cocs1.g, cocs2.g, cocs3.g, cocs4.g) * MAX_COC_SIZE;
117
118         float coc_near = max_v4(cocs_near);
119         float coc_far  = max_v4(cocs_far);
120
121         /* now we need to write the near-far fields premultiplied by the coc
122          * also use bilateral weighting by each coc values to avoid bleeding. */
123         vec4 near_weights = step(0.0, cocs_near) * clamp(1.0 - abs(coc_near - cocs_near), 0.0, 1.0);
124         vec4 far_weights  = step(0.0, cocs_far)  * clamp(1.0 - abs(coc_far  - cocs_far),  0.0, 1.0);
125
126         /* now write output to weighted buffers. */
127         vec4 w = any(notEqual(far_weights, vec4(0.0))) ? far_weights : near_weights;
128         float tot_weight = dot(w, vec4(1.0));
129         outColor = weighted_sum(color1, color2, color3, color4, w, tot_weight);
130
131         outCocs = encode_coc(coc_near, coc_far);
132 }
133 #endif
134
135 /**
136  * ----------------- STEP 1 ------------------
137  * Flatten COC buffer using max filter.
138  **/
139 #if defined(FLATTEN_VERTICAL) || defined(FLATTEN_HORIZONTAL)
140
141 layout(location = 0) out vec2 flattenedCoc;
142
143 void main()
144 {
145 #ifdef FLATTEN_HORIZONTAL
146         ivec2 texel = ivec2(gl_FragCoord.xy) * ivec2(8, 1);
147         vec2 cocs1 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 0)).rg;
148         vec2 cocs2 = texelFetchOffset(inputCocTex, texel, 0, ivec2(1, 0)).rg;
149         vec2 cocs3 = texelFetchOffset(inputCocTex, texel, 0, ivec2(2, 0)).rg;
150         vec2 cocs4 = texelFetchOffset(inputCocTex, texel, 0, ivec2(3, 0)).rg;
151         vec2 cocs5 = texelFetchOffset(inputCocTex, texel, 0, ivec2(4, 0)).rg;
152         vec2 cocs6 = texelFetchOffset(inputCocTex, texel, 0, ivec2(5, 0)).rg;
153         vec2 cocs7 = texelFetchOffset(inputCocTex, texel, 0, ivec2(6, 0)).rg;
154         vec2 cocs8 = texelFetchOffset(inputCocTex, texel, 0, ivec2(7, 0)).rg;
155 #else /* FLATTEN_VERTICAL */
156         ivec2 texel = ivec2(gl_FragCoord.xy) * ivec2(1, 8);
157         vec2 cocs1 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 0)).rg;
158         vec2 cocs2 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 1)).rg;
159         vec2 cocs3 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 2)).rg;
160         vec2 cocs4 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 3)).rg;
161         vec2 cocs5 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 4)).rg;
162         vec2 cocs6 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 5)).rg;
163         vec2 cocs7 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 6)).rg;
164         vec2 cocs8 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 7)).rg;
165 #endif
166         flattenedCoc = max(max(max(cocs1, cocs2), max(cocs3, cocs4)), max(max(cocs5, cocs6), max(cocs7, cocs8)));
167 }
168 #endif
169
170 /**
171  * ----------------- STEP 1.ax------------------
172  * Dilate COC buffer using min filter.
173  **/
174 #if defined(DILATE_VERTICAL) || defined(DILATE_HORIZONTAL)
175
176 layout(location = 0) out vec2 dilatedCoc;
177
178 void main()
179 {
180         vec2 texel_size = 1.0 / vec2(textureSize(inputCocTex, 0));
181         vec2 uv = gl_FragCoord.xy * texel_size;
182 #ifdef DILATE_VERTICAL
183         vec2 cocs1 = texture(inputCocTex, uv + texel_size * vec2(-3, 0)).rg;
184         vec2 cocs2 = texture(inputCocTex, uv + texel_size * vec2(-2, 0)).rg;
185         vec2 cocs3 = texture(inputCocTex, uv + texel_size * vec2(-1, 0)).rg;
186         vec2 cocs4 = texture(inputCocTex, uv + texel_size * vec2( 0, 0)).rg;
187         vec2 cocs5 = texture(inputCocTex, uv + texel_size * vec2( 1, 0)).rg;
188         vec2 cocs6 = texture(inputCocTex, uv + texel_size * vec2( 2, 0)).rg;
189         vec2 cocs7 = texture(inputCocTex, uv + texel_size * vec2( 3, 0)).rg;
190 #else /* DILATE_HORIZONTAL */
191         vec2 cocs1 = texture(inputCocTex, uv + texel_size * vec2(0, -3)).rg;
192         vec2 cocs2 = texture(inputCocTex, uv + texel_size * vec2(0, -2)).rg;
193         vec2 cocs3 = texture(inputCocTex, uv + texel_size * vec2(0, -1)).rg;
194         vec2 cocs4 = texture(inputCocTex, uv + texel_size * vec2(0,  0)).rg;
195         vec2 cocs5 = texture(inputCocTex, uv + texel_size * vec2(0,  1)).rg;
196         vec2 cocs6 = texture(inputCocTex, uv + texel_size * vec2(0,  2)).rg;
197         vec2 cocs7 = texture(inputCocTex, uv + texel_size * vec2(0,  3)).rg;
198 #endif
199         // dilatedCoc = max(max(cocs3, cocs4), max(max(cocs5, cocs6), cocs2));
200         dilatedCoc = max(max(max(cocs1, cocs2), max(cocs3, cocs4)), max(max(cocs5, cocs6), cocs7));
201 }
202 #endif
203
204 /**
205  * ----------------- STEP 2 ------------------
206  * Blur vertically and diagonally.
207  * Outputs vertical blur and combined blur in MRT
208  **/
209 #ifdef BLUR1
210 layout(location = 0) out vec4 blurColor;
211
212 #define NUM_SAMPLES 49
213
214 layout(std140) uniform dofSamplesBlock {
215         vec4 samples[NUM_SAMPLES];
216 };
217
218 vec2 get_random_vector(float offset)
219 {
220         /* Interlieved gradient noise by Jorge Jimenez
221          * http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare */
222         float ign = fract(offset + 52.9829189 * fract(0.06711056 * gl_FragCoord.x + 0.00583715 * gl_FragCoord.y));
223         float bn = texelFetch(noiseTex, ivec2(gl_FragCoord.xy) % 64, 0).a;
224         float ang = M_PI * 2.0 * fract(bn + offset);
225         return vec2(cos(ang), sin(ang)) * sqrt(ign);
226         // return noise.rg * sqrt(ign);
227 }
228
229 void main()
230 {
231         vec2 uv = gl_FragCoord.xy * invertedViewportSize * 2.0;
232
233         vec2 size = vec2(textureSize(halfResColorTex, 0).xy);
234         ivec2 texel = ivec2(uv * size);
235
236         vec4 color = vec4(0.0);
237         float tot = 1e-4;
238
239         float coc = decode_coc(texelFetch(inputCocTex, texel, 0).rg);
240         float max_radius = coc;
241         vec2 noise = get_random_vector(noiseOffset) * 0.2 * clamp(max_radius * 0.2 - 4.0, 0.0, 1.0);
242         for (int i = 0; i < NUM_SAMPLES; ++i) {
243                 vec2 tc = uv + (noise + samples[i].xy) * invertedViewportSize * max_radius;
244
245                 /* decode_signed_coc return biggest coc. */
246                 coc = abs(decode_signed_coc(texture(inputCocTex, tc).rg));
247
248                 float lod = log2(clamp((coc + min(coc, max_radius)) * 0.5 - 21.0, 0.0, 16.0) * 0.25);
249                 vec4 samp = textureLod(halfResColorTex, tc, lod);
250
251                 float radius = samples[i].z * max_radius;
252                 float weight = abs(coc) * smoothstep(radius - 0.5, radius + 0.5, abs(coc));
253
254                 color += samp * weight;
255                 tot += weight;
256         }
257
258         blurColor = color / tot;
259 }
260 #endif
261
262 /**
263  * ----------------- STEP 3 ------------------
264  * 3x3 Median Filter
265  * Morgan McGuire and Kyle Whitson
266  * http://graphics.cs.williams.edu
267  *
268  *
269  * Copyright (c) Morgan McGuire and Williams College, 2006
270  * All rights reserved.
271  * Redistribution and use in source and binary forms, with or without
272  * modification, are permitted provided that the following conditions are
273  * met:
274  *
275  * Redistributions of source code must retain the above copyright notice,
276  * this list of conditions and the following disclaimer.
277  *
278  * Redistributions in binary form must reproduce the above copyright
279  * notice, this list of conditions and the following disclaimer in the
280  * documentation and/or other materials provided with the distribution.
281  *
282  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
283  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
284  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
285  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
286  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
287  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
288  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
289  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
290  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
291  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
292  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
293  **/
294 #ifdef BLUR2
295 out vec4 finalColor;
296
297 void main()
298 {
299         /* Half Res pass */
300         vec2 pixel_size = 1.0 / vec2(textureSize(blurTex, 0).xy);
301         vec2 uv = gl_FragCoord.xy * pixel_size.xy; 
302         float coc = decode_coc(texture(inputCocTex, uv).rg);
303         /* Only use this filter if coc is > 9.0
304          * since this filter is not weighted by CoC
305          * and can bleed a bit. */
306         float rad = clamp(coc - 9.0, 0.0, 1.0);
307
308 #define vec vec4
309 #define toVec(x) x.rgba
310
311 #define s2(a, b)                                temp = a; a = min(a, b); b = max(temp, b);
312 #define mn3(a, b, c)                    s2(a, b); s2(a, c);
313 #define mx3(a, b, c)                    s2(b, c); s2(a, c);
314
315 #define mnmx3(a, b, c)                  mx3(a, b, c); s2(a, b);                                   // 3 exchanges
316 #define mnmx4(a, b, c, d)               s2(a, b); s2(c, d); s2(a, c); s2(b, d);                   // 4 exchanges
317 #define mnmx5(a, b, c, d, e)    s2(a, b); s2(c, d); mn3(a, c, e); mx3(b, d, e);           // 6 exchanges
318 #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
319
320         vec v[9];
321
322         /* Add the pixels which make up our window to the pixel array. */
323         for(int dX = -1; dX <= 1; ++dX) {
324                 for(int dY = -1; dY <= 1; ++dY) {
325                         vec2 offset = vec2(float(dX), float(dY));
326                         /* 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
327                          * pixel array. This will fill the pixel array, with the top left pixel of the window at pixel[0] and the
328                          * bottom right pixel of the window at pixel[N-1]. */
329                         v[(dX + 1) * 3 + (dY + 1)] = toVec(texture(blurTex, uv + offset * pixel_size * rad));
330                 }
331         }
332
333         vec temp;
334
335         /* Starting with a subset of size 6, remove the min and max each time */
336         mnmx6(v[0], v[1], v[2], v[3], v[4], v[5]);
337         mnmx5(v[1], v[2], v[3], v[4], v[6]);
338         mnmx4(v[2], v[3], v[4], v[7]);
339         mnmx3(v[3], v[4], v[8]);
340         toVec(finalColor) = v[4];
341 }
342
343 #endif
344
345 /**
346  * ----------------- STEP 4 ------------------
347  **/
348 #ifdef RESOLVE
349 out vec4 finalColor;
350
351 void main()
352 {
353         /* Fullscreen pass */
354         vec2 pixel_size = 0.5 / vec2(textureSize(halfResColorTex, 0).xy);
355         vec2 uv = gl_FragCoord.xy * pixel_size;
356
357         /* TODO MAKE SURE TO ALIGN SAMPLE POSITION TO AVOID OFFSET IN THE BOKEH */
358         float depth = texelFetch(sceneDepthTex, ivec2(gl_FragCoord.xy), 0).r;
359         float zdepth = linear_depth(depth);
360         float coc = calculate_coc(zdepth);
361
362         finalColor = texture(halfResColorTex, uv);
363         finalColor.a = smoothstep(1.0, 3.0, abs(coc));
364 }
365 #endif