Workbench: Separate depth of field shaders

Workbench shaders uses one fragment shaders, but uses different
resources based on the step of the effect. This failed in vulkan as all
defined resources should be found. This PR separates the steps in its
own fragment shader and adds sampler binding per step.

- Removed the max coc input texture as it wasn't used.
- Removed the background texture as it wasn't used.
- Renumbered the resources.

Pull Request: https://projects.blender.org/blender/blender/pulls/131606
This commit is contained in:
Jeroen Bakker 2024-12-09 16:01:41 +01:00
parent c3f012b719
commit cf0db73571
10 changed files with 398 additions and 410 deletions

View file

@ -509,7 +509,12 @@ set(GLSL_SRC
engines/workbench/shaders/workbench_common_lib.glsl
engines/workbench/shaders/workbench_composite_frag.glsl
engines/workbench/shaders/workbench_curvature_lib.glsl
engines/workbench/shaders/workbench_effect_dof_frag.glsl
engines/workbench/shaders/workbench_effect_dof_prepare_frag.glsl
engines/workbench/shaders/workbench_effect_dof_downsample_frag.glsl
engines/workbench/shaders/workbench_effect_dof_blur1_frag.glsl
engines/workbench/shaders/workbench_effect_dof_blur2_frag.glsl
engines/workbench/shaders/workbench_effect_dof_resolve_frag.glsl
engines/workbench/shaders/workbench_effect_dof_lib.glsl
engines/workbench/shaders/workbench_effect_outline_frag.glsl
engines/workbench/shaders/workbench_effect_smaa_frag.glsl
engines/workbench/shaders/workbench_effect_smaa_vert.glsl

View file

@ -34,7 +34,11 @@ set(SRC_GLSL_VERT
set(SRC_GLSL_FRAG
workbench_composite_frag.glsl
workbench_effect_dof_frag.glsl
workbench_effect_dof_prepare_frag.glsl
workbench_effect_dof_downsample_frag.glsl
workbench_effect_dof_blur1_frag.glsl
workbench_effect_dof_blur2_frag.glsl
workbench_effect_dof_resolve_frag.glsl
workbench_effect_outline_frag.glsl
workbench_effect_smaa_frag.glsl
workbench_effect_taa_frag.glsl
@ -53,6 +57,7 @@ set(SRC_GLSL_COMP
)
set(SRC_GLSL_LIB
workbench_effect_dof_lib.glsl
workbench_cavity_lib.glsl
workbench_common_lib.glsl
workbench_curvature_lib.glsl

View file

@ -21,61 +21,74 @@
#include "gpu_shader_create_info.hh"
/*
* NOTE: Keep the sampler bind points consistent between the steps.
*
* SAMPLER(0, FLOAT_2D, inputCocTex)
* SAMPLER(1, FLOAT_2D, sceneColorTex)
* SAMPLER(2, FLOAT_2D, sceneDepthTex)
* SAMPLER(3, FLOAT_2D, halfResColorTex)
* SAMPLER(4, FLOAT_2D, blurTex)
* SAMPLER(5, FLOAT_2D, noiseTex)
*/
GPU_SHADER_CREATE_INFO(workbench_effect_dof)
/* TODO(fclem): Split resources per stage. */
SAMPLER(0, FLOAT_2D, inputCocTex)
SAMPLER(1, FLOAT_2D, maxCocTilesTex)
SAMPLER(2, FLOAT_2D, sceneColorTex)
SAMPLER(3, FLOAT_2D, sceneDepthTex)
SAMPLER(4, FLOAT_2D, backgroundTex)
SAMPLER(5, FLOAT_2D, halfResColorTex)
SAMPLER(6, FLOAT_2D, blurTex)
SAMPLER(7, FLOAT_2D, noiseTex)
PUSH_CONSTANT(VEC2, invertedViewportSize)
PUSH_CONSTANT(VEC2, nearFar)
PUSH_CONSTANT(VEC3, dofParams)
PUSH_CONSTANT(FLOAT, noiseOffset)
FRAGMENT_SOURCE("workbench_effect_dof_frag.glsl")
ADDITIONAL_INFO(draw_fullscreen)
ADDITIONAL_INFO(draw_view)
GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(workbench_effect_dof_prepare)
DEFINE("PREPARE")
SAMPLER(1, FLOAT_2D, sceneColorTex)
SAMPLER(2, FLOAT_2D, sceneDepthTex)
FRAGMENT_OUT(0, VEC4, halfResColor)
FRAGMENT_OUT(1, VEC2, normalizedCoc)
FRAGMENT_SOURCE("workbench_effect_dof_prepare_frag.glsl")
ADDITIONAL_INFO(workbench_effect_dof)
DO_STATIC_COMPILATION()
GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(workbench_effect_dof_downsample)
DEFINE("DOWNSAMPLE")
SAMPLER(0, FLOAT_2D, inputCocTex)
SAMPLER(1, FLOAT_2D, sceneColorTex)
FRAGMENT_OUT(0, VEC4, outColor)
FRAGMENT_OUT(1, VEC2, outCocs)
FRAGMENT_SOURCE("workbench_effect_dof_downsample_frag.glsl")
ADDITIONAL_INFO(workbench_effect_dof)
DO_STATIC_COMPILATION()
GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(workbench_effect_dof_blur1)
DEFINE("BLUR1")
DEFINE_VALUE("NUM_SAMPLES", "49")
SAMPLER(0, FLOAT_2D, inputCocTex)
SAMPLER(3, FLOAT_2D, halfResColorTex)
SAMPLER(5, FLOAT_2D, noiseTex)
UNIFORM_BUF(1, vec4, samples[49])
FRAGMENT_OUT(0, VEC4, blurColor)
FRAGMENT_SOURCE("workbench_effect_dof_blur1_frag.glsl")
ADDITIONAL_INFO(workbench_effect_dof)
DO_STATIC_COMPILATION()
GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(workbench_effect_dof_blur2)
DEFINE("BLUR2")
SAMPLER(0, FLOAT_2D, inputCocTex)
SAMPLER(4, FLOAT_2D, blurTex)
FRAGMENT_OUT(0, VEC4, finalColor)
FRAGMENT_SOURCE("workbench_effect_dof_blur2_frag.glsl")
ADDITIONAL_INFO(workbench_effect_dof)
DO_STATIC_COMPILATION()
GPU_SHADER_CREATE_END()
GPU_SHADER_CREATE_INFO(workbench_effect_dof_resolve)
DEFINE("RESOLVE")
SAMPLER(1, FLOAT_2D, sceneColorTex)
SAMPLER(2, FLOAT_2D, sceneDepthTex)
SAMPLER(3, FLOAT_2D, halfResColorTex)
FRAGMENT_OUT_DUAL(0, VEC4, finalColorAdd, SRC_0)
FRAGMENT_OUT_DUAL(0, VEC4, finalColorMul, SRC_1)
FRAGMENT_SOURCE("workbench_effect_dof_resolve_frag.glsl")
ADDITIONAL_INFO(workbench_effect_dof)
DO_STATIC_COMPILATION()
GPU_SHADER_CREATE_END()

View file

@ -0,0 +1,72 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/**
* 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
*/
#include "infos/workbench_effect_dof_info.hh"
#include "draw_view_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
#include "workbench_effect_dof_lib.glsl"
FRAGMENT_SHADER_CREATE_INFO(workbench_effect_dof_blur1)
/**
* ----------------- STEP 2 ------------------
* Blur vertically and diagonally.
* Outputs vertical blur and combined blur in MRT
*/
vec2 get_random_vector(float offset)
{
/* Interleaved gradient noise by Jorge Jimenez
* http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare */
float ign = fract(offset +
52.9829189 * fract(0.06711056 * gl_FragCoord.x + 0.00583715 * gl_FragCoord.y));
float bn = texelFetch(noiseTex, ivec2(gl_FragCoord.xy) % 64, 0).a;
float ang = M_PI * 2.0 * fract(bn + offset);
return vec2(cos(ang), sin(ang)) * sqrt(ign);
// return noise.rg * sqrt(ign);
}
void main()
{
vec2 uv = gl_FragCoord.xy * invertedViewportSize * 2.0;
vec2 size = vec2(textureSize(halfResColorTex, 0).xy);
ivec2 texel = ivec2(uv * size);
vec4 color = vec4(0.0);
float tot = 0.0;
float coc = dof_decode_coc(texelFetch(inputCocTex, texel, 0).rg);
float max_radius = coc;
vec2 noise = get_random_vector(noiseOffset) * 0.2 * clamp(max_radius * 0.2 - 4.0, 0.0, 1.0);
for (int i = 0; i < NUM_SAMPLES; i++) {
vec2 tc = uv + (noise + samples[i].xy) * invertedViewportSize * max_radius;
/* decode_signed_coc return biggest coc. */
coc = abs(dof_decode_signed_coc(texture(inputCocTex, tc).rg));
float lod = log2(clamp((coc + min(coc, max_radius)) * 0.5 - 21.0, 0.0, 16.0) * 0.25);
vec4 samp = textureLod(halfResColorTex, tc, lod);
float radius = samples[i].z * max_radius;
float weight = abs(coc) * smoothstep(radius - 0.5, radius + 0.5, abs(coc));
color += samp * weight;
tot += weight;
}
if (tot > 0.0) {
blurColor = color / tot;
}
else {
blurColor = textureLod(halfResColorTex, uv, 0.0);
}
}

View file

@ -0,0 +1,95 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/**
* 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
*/
#include "infos/workbench_effect_dof_info.hh"
#include "draw_view_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
#include "workbench_effect_dof_lib.glsl"
FRAGMENT_SHADER_CREATE_INFO(workbench_effect_dof_blur2)
/**
* ----------------- STEP 3 ------------------
* 3x3 Median Filter
* Morgan McGuire and Kyle Whitson
* http://graphics.cs.williams.edu
*
* SPDX-License-Identifier: BSD-2-Clause
* Copyright 2006 Morgan McGuire and Williams College, All rights reserved.
*/
void main()
{
/* Half Res pass */
vec2 pixel_size = 1.0 / vec2(textureSize(blurTex, 0).xy);
vec2 uv = gl_FragCoord.xy * pixel_size.xy;
float coc = dof_decode_coc(texture(inputCocTex, uv).rg);
/* Only use this filter if coc is > 9.0
* since this filter is not weighted by CoC
* and can bleed a bit. */
float rad = clamp(coc - 9.0, 0.0, 1.0);
#define vec vec4
#define toVec(x) x.rgba
#define s2(a, b) \
temp = a; \
a = min(a, b); \
b = max(temp, b);
#define mn3(a, b, c) \
s2(a, b); \
s2(a, c);
#define mx3(a, b, c) \
s2(b, c); \
s2(a, c);
#define mnmx3(a, b, c) \
mx3(a, b, c); \
s2(a, b); /* 3 exchanges */
#define mnmx4(a, b, c, d) \
s2(a, b); \
s2(c, d); \
s2(a, c); \
s2(b, d); /* 4 exchanges */
#define mnmx5(a, b, c, d, e) \
s2(a, b); \
s2(c, d); \
mn3(a, c, e); \
mx3(b, d, e); /* 6 exchanges */
#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 */
vec v[9];
/* Add the pixels which make up our window to the pixel array. */
for (int dX = -1; dX <= 1; dX++) {
for (int dY = -1; dY <= 1; dY++) {
vec2 offset = vec2(float(dX), float(dY));
/* 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 pixel array. This will fill the pixel array, with the top left pixel of
* the window at pixel[0] and the bottom right pixel of the window at pixel[N-1]. */
v[(dX + 1) * 3 + (dY + 1)] = toVec(texture(blurTex, uv + offset * pixel_size * rad));
}
}
vec temp;
/* Starting with a subset of size 6, remove the min and max each time */
mnmx6(v[0], v[1], v[2], v[3], v[4], v[5]);
mnmx5(v[1], v[2], v[3], v[4], v[6]);
mnmx4(v[2], v[3], v[4], v[7]);
mnmx3(v[3], v[4], v[8]);
toVec(finalColor) = v[4];
}

View file

@ -0,0 +1,58 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/**
* 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
*/
#include "infos/workbench_effect_dof_info.hh"
#include "draw_view_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
#include "workbench_effect_dof_lib.glsl"
FRAGMENT_SHADER_CREATE_INFO(workbench_effect_dof_downsample)
/**
* ----------------- STEP 0.5 ------------------
* Custom COC aware down-sampling. Quarter res pass.
*/
void main()
{
vec4 texel = vec4(gl_FragCoord.xyxy) * 2.0 + vec4(0.0, 0.0, 1.0, 1.0);
texel = (texel - 0.5) / vec4(textureSize(sceneColorTex, 0).xyxy);
/* Using texelFetch can bypass the mip range setting on some platform.
* Using texture LOD fixes this issue. Note that we need to disable filtering to get the right
* texel values. */
vec4 color1 = textureLod(sceneColorTex, texel.xy, 0.0);
vec4 color2 = textureLod(sceneColorTex, texel.zw, 0.0);
vec4 color3 = textureLod(sceneColorTex, texel.zy, 0.0);
vec4 color4 = textureLod(sceneColorTex, texel.xw, 0.0);
vec2 cocs1 = textureLod(inputCocTex, texel.xy, 0.0).rg;
vec2 cocs2 = textureLod(inputCocTex, texel.zw, 0.0).rg;
vec2 cocs3 = textureLod(inputCocTex, texel.zy, 0.0).rg;
vec2 cocs4 = textureLod(inputCocTex, texel.xw, 0.0).rg;
vec4 cocs_near = vec4(cocs1.r, cocs2.r, cocs3.r, cocs4.r) * MAX_COC_SIZE;
vec4 cocs_far = vec4(cocs1.g, cocs2.g, cocs3.g, cocs4.g) * MAX_COC_SIZE;
float coc_near = reduce_max(cocs_near);
float coc_far = reduce_max(cocs_far);
/* 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. */
vec4 w = any(notEqual(far_weights, vec4(0.0))) ? far_weights : near_weights;
outColor = weighted_sum(color1, color2, color3, color4, w);
outCocs = dof_encode_coc(coc_near, coc_far);
}

View file

@ -1,393 +0,0 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/**
* 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
*/
#include "infos/workbench_effect_dof_info.hh"
#include "draw_view_lib.glsl"
#include "gpu_shader_math_vector_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
FRAGMENT_SHADER_CREATE_INFO(workbench_effect_dof)
#define dof_aperturesize dofParams.x
#define dof_distance dofParams.y
#define dof_invsensorsize dofParams.z
/* 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) \
((drw_view.winmat[3][3] == 0.0) ? \
(nearFar.x * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y) : \
(z * 2.0 - 1.0) * nearFar.y)
#define MAX_COC_SIZE 100.0
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;
}
float decode_signed_coc(vec2 cocs)
{
return ((cocs.x > cocs.y) ? cocs.x : -cocs.y) * MAX_COC_SIZE;
}
/**
* ----------------- STEP 0 ------------------
* Custom COC aware down-sampling. Half res pass.
*/
#ifdef PREPARE
FRAGMENT_SHADER_CREATE_INFO(workbench_effect_dof_prepare)
void main_prepare()
{
ivec4 texel = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
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);
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(reduce_max(cocs_near), 0.0);
float coc_far = max(reduce_max(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. */
/* Take far plane pixels in priority. */
vec4 w = any(notEqual(far_weights, vec4(0.0))) ? far_weights : near_weights;
halfResColor = weighted_sum(color1, color2, color3, color4, w);
halfResColor = clamp(halfResColor, 0.0, 3.0);
normalizedCoc = encode_coc(coc_near, coc_far);
}
#endif
/**
* ----------------- STEP 0.5 ------------------
* Custom COC aware down-sampling. Quarter res pass.
*/
#ifdef DOWNSAMPLE
FRAGMENT_SHADER_CREATE_INFO(workbench_effect_dof_downsample)
void main_downsample()
{
vec4 texel = vec4(gl_FragCoord.xyxy) * 2.0 + vec4(0.0, 0.0, 1.0, 1.0);
texel = (texel - 0.5) / vec4(textureSize(sceneColorTex, 0).xyxy);
/* Using texelFetch can bypass the mip range setting on some platform.
* Using texture LOD fixes this issue. Note that we need to disable filtering to get the right
* texel values. */
vec4 color1 = textureLod(sceneColorTex, texel.xy, 0.0);
vec4 color2 = textureLod(sceneColorTex, texel.zw, 0.0);
vec4 color3 = textureLod(sceneColorTex, texel.zy, 0.0);
vec4 color4 = textureLod(sceneColorTex, texel.xw, 0.0);
vec2 cocs1 = textureLod(inputCocTex, texel.xy, 0.0).rg;
vec2 cocs2 = textureLod(inputCocTex, texel.zw, 0.0).rg;
vec2 cocs3 = textureLod(inputCocTex, texel.zy, 0.0).rg;
vec2 cocs4 = textureLod(inputCocTex, texel.xw, 0.0).rg;
vec4 cocs_near = vec4(cocs1.r, cocs2.r, cocs3.r, cocs4.r) * MAX_COC_SIZE;
vec4 cocs_far = vec4(cocs1.g, cocs2.g, cocs3.g, cocs4.g) * MAX_COC_SIZE;
float coc_near = reduce_max(cocs_near);
float coc_far = reduce_max(cocs_far);
/* 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. */
vec4 w = any(notEqual(far_weights, vec4(0.0))) ? far_weights : near_weights;
outColor = weighted_sum(color1, color2, color3, color4, w);
outCocs = encode_coc(coc_near, coc_far);
}
#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
FRAGMENT_SHADER_CREATE_INFO(workbench_effect_dof_blur1)
vec2 get_random_vector(float offset)
{
/* Interleaved gradient noise by Jorge Jimenez
* http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare */
float ign = fract(offset +
52.9829189 * fract(0.06711056 * gl_FragCoord.x + 0.00583715 * gl_FragCoord.y));
float bn = texelFetch(noiseTex, ivec2(gl_FragCoord.xy) % 64, 0).a;
float ang = M_PI * 2.0 * fract(bn + offset);
return vec2(cos(ang), sin(ang)) * sqrt(ign);
// return noise.rg * sqrt(ign);
}
void main_blur1()
{
vec2 uv = gl_FragCoord.xy * invertedViewportSize * 2.0;
vec2 size = vec2(textureSize(halfResColorTex, 0).xy);
ivec2 texel = ivec2(uv * size);
vec4 color = vec4(0.0);
float tot = 0.0;
float coc = decode_coc(texelFetch(inputCocTex, texel, 0).rg);
float max_radius = coc;
vec2 noise = get_random_vector(noiseOffset) * 0.2 * clamp(max_radius * 0.2 - 4.0, 0.0, 1.0);
for (int i = 0; i < NUM_SAMPLES; i++) {
vec2 tc = uv + (noise + samples[i].xy) * invertedViewportSize * max_radius;
/* decode_signed_coc return biggest coc. */
coc = abs(decode_signed_coc(texture(inputCocTex, tc).rg));
float lod = log2(clamp((coc + min(coc, max_radius)) * 0.5 - 21.0, 0.0, 16.0) * 0.25);
vec4 samp = textureLod(halfResColorTex, tc, lod);
float radius = samples[i].z * max_radius;
float weight = abs(coc) * smoothstep(radius - 0.5, radius + 0.5, abs(coc));
color += samp * weight;
tot += weight;
}
if (tot > 0.0) {
blurColor = color / tot;
}
else {
blurColor = textureLod(halfResColorTex, uv, 0.0);
}
}
#endif
/**
* ----------------- STEP 3 ------------------
* 3x3 Median Filter
* Morgan McGuire and Kyle Whitson
* http://graphics.cs.williams.edu
*
* SPDX-License-Identifier: BSD-2-Clause
* Copyright 2006 Morgan McGuire and Williams College, All rights reserved.
*/
#ifdef BLUR2
FRAGMENT_SHADER_CREATE_INFO(workbench_effect_dof_blur2)
void main_blur2()
{
/* Half Res pass */
vec2 pixel_size = 1.0 / vec2(textureSize(blurTex, 0).xy);
vec2 uv = gl_FragCoord.xy * pixel_size.xy;
float coc = decode_coc(texture(inputCocTex, uv).rg);
/* Only use this filter if coc is > 9.0
* since this filter is not weighted by CoC
* and can bleed a bit. */
float rad = clamp(coc - 9.0, 0.0, 1.0);
# define vec vec4
# define toVec(x) x.rgba
# define s2(a, b) \
temp = a; \
a = min(a, b); \
b = max(temp, b);
# define mn3(a, b, c) \
s2(a, b); \
s2(a, c);
# define mx3(a, b, c) \
s2(b, c); \
s2(a, c);
# define mnmx3(a, b, c) \
mx3(a, b, c); \
s2(a, b); /* 3 exchanges */
# define mnmx4(a, b, c, d) \
s2(a, b); \
s2(c, d); \
s2(a, c); \
s2(b, d); /* 4 exchanges */
# define mnmx5(a, b, c, d, e) \
s2(a, b); \
s2(c, d); \
mn3(a, c, e); \
mx3(b, d, e); /* 6 exchanges */
# 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 */
vec v[9];
/* Add the pixels which make up our window to the pixel array. */
for (int dX = -1; dX <= 1; dX++) {
for (int dY = -1; dY <= 1; dY++) {
vec2 offset = vec2(float(dX), float(dY));
/* 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 pixel array. This will fill the pixel array, with the top left pixel of
* the window at pixel[0] and the bottom right pixel of the window at pixel[N-1]. */
v[(dX + 1) * 3 + (dY + 1)] = toVec(texture(blurTex, uv + offset * pixel_size * rad));
}
}
vec temp;
/* Starting with a subset of size 6, remove the min and max each time */
mnmx6(v[0], v[1], v[2], v[3], v[4], v[5]);
mnmx5(v[1], v[2], v[3], v[4], v[6]);
mnmx4(v[2], v[3], v[4], v[7]);
mnmx3(v[3], v[4], v[8]);
toVec(finalColor) = v[4];
}
#endif
/**
* ----------------- STEP 4 ------------------
*/
#ifdef RESOLVE
FRAGMENT_SHADER_CREATE_INFO(workbench_effect_dof_resolve)
void main_resolve()
{
/* Full-screen 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);
float blend = smoothstep(1.0, 3.0, abs(coc));
finalColorAdd = texture(halfResColorTex, uv) * blend;
finalColorMul = vec4(1.0 - blend);
}
#endif
void main()
{
#ifdef PREPARE
main_prepare();
#endif
#ifdef DOWNSAMPLE
main_downsample();
#endif
#ifdef BLUR1
main_blur1();
#endif
#ifdef BLUR2
main_blur2();
#endif
#ifdef RESOLVE
main_resolve();
#endif
}

View file

@ -0,0 +1,38 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/**
* 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
*/
#include "gpu_shader_math_vector_lib.glsl"
#define dof_aperturesize dofParams.x
#define dof_distance dofParams.y
#define dof_invsensorsize dofParams.z
/* divide by sensor size to get the normalized size */
#define dof_calculate_coc(zdepth) \
(dof_aperturesize * (dof_distance / zdepth - 1.0) * dof_invsensorsize)
#define dof_linear_depth(z) \
((drw_view.winmat[3][3] == 0.0) ? \
(nearFar.x * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y) : \
(z * 2.0 - 1.0) * nearFar.y)
#define MAX_COC_SIZE 100.0
vec2 dof_encode_coc(float near, float far)
{
return vec2(near, far) / MAX_COC_SIZE;
}
float dof_decode_coc(vec2 cocs)
{
return max(cocs.x, cocs.y) * MAX_COC_SIZE;
}
float dof_decode_signed_coc(vec2 cocs)
{
return ((cocs.x > cocs.y) ? cocs.x : -cocs.y) * MAX_COC_SIZE;
}

View file

@ -0,0 +1,58 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/**
* 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
*/
#include "infos/workbench_effect_dof_info.hh"
#include "draw_view_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
#include "workbench_effect_dof_lib.glsl"
FRAGMENT_SHADER_CREATE_INFO(workbench_effect_dof_prepare)
/**
* ----------------- STEP 0 ------------------
* Custom COC aware down-sampling. Half res pass.
*/
void main()
{
ivec4 texel = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
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);
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 = dof_linear_depth(depths);
vec4 cocs_near = dof_calculate_coc(zdepths);
vec4 cocs_far = -cocs_near;
float coc_near = max(reduce_max(cocs_near), 0.0);
float coc_far = max(reduce_max(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. */
/* Take far plane pixels in priority. */
vec4 w = any(notEqual(far_weights, vec4(0.0))) ? far_weights : near_weights;
halfResColor = weighted_sum(color1, color2, color3, color4, w);
halfResColor = clamp(halfResColor, 0.0, 3.0);
normalizedCoc = dof_encode_coc(coc_near, coc_far);
}

View file

@ -0,0 +1,37 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/**
* 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
*/
#include "infos/workbench_effect_dof_info.hh"
#include "draw_view_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
#include "workbench_effect_dof_lib.glsl"
/**
* ----------------- STEP 4 ------------------
*/
FRAGMENT_SHADER_CREATE_INFO(workbench_effect_dof_resolve)
void main()
{
/* Full-screen 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 = dof_linear_depth(depth);
float coc = dof_calculate_coc(zdepth);
float blend = smoothstep(1.0, 3.0, abs(coc));
finalColorAdd = texture(halfResColorTex, uv) * blend;
finalColorMul = vec4(1.0 - blend);
}