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