godot/servers/rendering/rasterizer_rd/shaders/bokeh_dof.glsl
Rémi Verschelde 0be6d925dc Style: clang-format: Disable KeepEmptyLinesAtTheStartOfBlocks
Which means that reduz' beloved style which we all became used to
will now be changed automatically to remove the first empty line.

This makes us lean closer to 1TBS (the one true brace style) instead
of hybridating it with some Allman-inspired spacing.

There's still the case of braces around single-statement blocks that
needs to be addressed (but clang-format can't help with that, but
clang-tidy may if we agree about it).

Part of #33027.
2020-05-14 16:54:55 +02:00

254 lines
6.1 KiB
GLSL

/* clang-format off */
[compute]
#version 450
VERSION_DEFINES
#define BLOCK_SIZE 8
layout(local_size_x = BLOCK_SIZE, local_size_y = BLOCK_SIZE, local_size_z = 1) in;
/* clang-format on */
#ifdef MODE_GEN_BLUR_SIZE
layout(rgba16f, set = 0, binding = 0) uniform restrict image2D color_image;
layout(set = 1, binding = 0) uniform sampler2D source_depth;
#endif
#if defined(MODE_BOKEH_BOX) || defined(MODE_BOKEH_HEXAGONAL) || defined(MODE_BOKEH_CIRCULAR)
layout(set = 1, binding = 0) uniform sampler2D color_texture;
layout(rgba16f, set = 0, binding = 0) uniform restrict writeonly image2D bokeh_image;
#endif
#ifdef MODE_COMPOSITE_BOKEH
layout(rgba16f, set = 0, binding = 0) uniform restrict image2D color_image;
layout(set = 1, binding = 0) uniform sampler2D source_bokeh;
#endif
// based on https://www.shadertoy.com/view/Xd3GDl
layout(push_constant, binding = 1, std430) uniform Params {
ivec2 size;
float z_far;
float z_near;
bool orthogonal;
float blur_size;
float blur_scale;
int blur_steps;
bool blur_near_active;
float blur_near_begin;
float blur_near_end;
bool blur_far_active;
float blur_far_begin;
float blur_far_end;
bool second_pass;
bool half_size;
bool use_jitter;
float jitter_seed;
uint pad[2];
}
params;
//used to work around downsampling filter
#define DEPTH_GAP 0.0
#ifdef MODE_GEN_BLUR_SIZE
float get_depth_at_pos(vec2 uv) {
float depth = textureLod(source_depth, uv, 0.0).x;
if (params.orthogonal) {
depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0;
} else {
depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near));
}
return depth;
}
float get_blur_size(float depth) {
if (params.blur_near_active && depth < params.blur_near_begin) {
return -(1.0 - smoothstep(params.blur_near_end, params.blur_near_begin, depth)) * params.blur_size - DEPTH_GAP; //near blur is negative
}
if (params.blur_far_active && depth > params.blur_far_begin) {
return smoothstep(params.blur_far_begin, params.blur_far_end, depth) * params.blur_size + DEPTH_GAP;
}
return 0.0;
}
#endif
const float GOLDEN_ANGLE = 2.39996323;
//note: uniform pdf rand [0;1[
float hash12n(vec2 p) {
p = fract(p * vec2(5.3987, 5.4421));
p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
return fract(p.x * p.y * 95.4307);
}
#if defined(MODE_BOKEH_BOX) || defined(MODE_BOKEH_HEXAGONAL)
vec4 weighted_filter_dir(vec2 dir, vec2 uv, vec2 pixel_size) {
dir *= pixel_size;
vec4 color = texture(color_texture, uv);
vec4 accum = color;
float total = 1.0;
float blur_scale = params.blur_size / float(params.blur_steps);
if (params.use_jitter) {
uv += dir * (hash12n(uv + params.jitter_seed) - 0.5);
}
for (int i = -params.blur_steps; i <= params.blur_steps; i++) {
if (i == 0) {
continue;
}
float radius = float(i) * blur_scale;
vec2 suv = uv + dir * radius;
radius = abs(radius);
vec4 sample_color = texture(color_texture, suv);
float limit;
if (sample_color.a < color.a) {
limit = abs(sample_color.a);
} else {
limit = abs(color.a);
}
limit -= DEPTH_GAP;
float m = smoothstep(radius - 0.5, radius + 0.5, limit);
accum += mix(color, sample_color, m);
total += 1.0;
}
return accum / total;
}
#endif
void main() {
ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
if (any(greaterThan(pos, params.size))) { //too large, do nothing
return;
}
vec2 pixel_size = 1.0 / vec2(params.size);
vec2 uv = vec2(pos) / vec2(params.size);
#ifdef MODE_GEN_BLUR_SIZE
uv += pixel_size * 0.5;
//precompute size in alpha channel
float depth = get_depth_at_pos(uv);
float size = get_blur_size(depth);
vec4 color = imageLoad(color_image, pos);
color.a = size;
imageStore(color_image, pos, color);
#endif
#ifdef MODE_BOKEH_BOX
//pixel_size*=0.5; //resolution is doubled
if (params.second_pass || !params.half_size) {
uv += pixel_size * 0.5; //half pixel to read centers
} else {
uv += pixel_size * 0.25; //half pixel to read centers from full res
}
vec2 dir = (params.second_pass ? vec2(0.0, 1.0) : vec2(1.0, 0.0));
vec4 color = weighted_filter_dir(dir, uv, pixel_size);
imageStore(bokeh_image, pos, color);
#endif
#ifdef MODE_BOKEH_HEXAGONAL
//pixel_size*=0.5; //resolution is doubled
if (params.second_pass || !params.half_size) {
uv += pixel_size * 0.5; //half pixel to read centers
} else {
uv += pixel_size * 0.25; //half pixel to read centers from full res
}
vec2 dir = (params.second_pass ? normalize(vec2(1.0, 0.577350269189626)) : vec2(0.0, 1.0));
vec4 color = weighted_filter_dir(dir, uv, pixel_size);
if (params.second_pass) {
dir = normalize(vec2(-1.0, 0.577350269189626));
vec4 color2 = weighted_filter_dir(dir, uv, pixel_size);
color.rgb = min(color.rgb, color2.rgb);
color.a = (color.a + color2.a) * 0.5;
}
imageStore(bokeh_image, pos, color);
#endif
#ifdef MODE_BOKEH_CIRCULAR
if (params.half_size) {
pixel_size *= 0.5; //resolution is doubled
}
uv += pixel_size * 0.5; //half pixel to read centers
vec4 color = texture(color_texture, uv);
float accum = 1.0;
float radius = params.blur_scale;
for (float ang = 0.0; radius < params.blur_size; ang += GOLDEN_ANGLE) {
vec2 suv = uv + vec2(cos(ang), sin(ang)) * pixel_size * radius;
vec4 sample_color = texture(color_texture, suv);
float sample_size = abs(sample_color.a);
if (sample_color.a > color.a) {
sample_size = clamp(sample_size, 0.0, abs(color.a) * 2.0);
}
float m = smoothstep(radius - 0.5, radius + 0.5, sample_size);
color += mix(color / accum, sample_color, m);
accum += 1.0;
radius += params.blur_scale / radius;
}
color /= accum;
imageStore(bokeh_image, pos, color);
#endif
#ifdef MODE_COMPOSITE_BOKEH
uv += pixel_size * 0.5;
vec4 color = imageLoad(color_image, pos);
vec4 bokeh = texture(source_bokeh, uv);
float mix_amount;
if (bokeh.a < color.a) {
mix_amount = min(1.0, max(0.0, max(abs(color.a), abs(bokeh.a)) - DEPTH_GAP));
} else {
mix_amount = min(1.0, max(0.0, abs(color.a) - DEPTH_GAP));
}
color.rgb = mix(color.rgb, bokeh.rgb, mix_amount); //blend between hires and lowres
color.a = 0; //reset alpha
imageStore(color_image, pos, color);
#endif
}