1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
vec4 load_input(ivec2 texel)
{
vec4 color;
if (extend_bounds) {
/* If bounds are extended, then we treat the input as padded by a radius amount of pixels. So
* we load the input with an offset by the radius amount and fallback to a transparent color if
* it is out of bounds. */
color = texture_load(input_tx, texel - radius, vec4(0.0));
}
else {
color = texture_load(input_tx, texel);
}
return color;
}
/* Given the texel in the range [-radius, radius] in both axis, load the appropriate weight from
* the weights texture, where the texel (0, 0) is considered the center of weights texture. */
vec4 load_weight(ivec2 texel)
{
/* Add the radius to transform the texel into the range [0, radius * 2], then divide by the upper
* bound plus one to transform the texel into the normalized range [0, 1] needed to sample the
* weights sampler. Finally, also add 0.5 to sample at the center of the pixels. */
return texture(weights_tx, (texel + vec2(radius + 0.5)) / (radius * 2 + 1));
}
void main()
{
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
/* The mask input is treated as a boolean. If it is zero, then no blurring happens for this
* pixel. Otherwise, the pixel is blurred normally and the mask value is irrelevant. */
float mask = texture_load(mask_tx, texel).x;
if (mask == 0.0) {
imageStore(output_img, texel, texture_load(input_tx, texel));
return;
}
/* Go over the window of the given radius and accumulate the colors multiplied by their
* respective weights as well as the weights themselves. */
vec4 accumulated_color = vec4(0.0);
vec4 accumulated_weight = vec4(0.0);
for (int y = -radius; y <= radius; y++) {
for (int x = -radius; x <= radius; x++) {
vec4 weight = load_weight(ivec2(x, y));
accumulated_color += load_input(texel + ivec2(x, y)) * weight;
accumulated_weight += weight;
}
}
imageStore(output_img, texel, safe_divide(accumulated_color, accumulated_weight));
}
|