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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
/* clang-format off */
#[vertex]
#version 450
#VERSION_DEFINES
#include "blur_raster_inc.glsl"
layout(location = 0) out vec2 uv_interp;
/* clang-format on */
void main() {
vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
uv_interp = base_arr[gl_VertexIndex];
gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
}
/* clang-format off */
#[fragment]
#version 450
#VERSION_DEFINES
#include "blur_raster_inc.glsl"
layout(location = 0) in vec2 uv_interp;
/* clang-format on */
layout(set = 0, binding = 0) uniform sampler2D source_color;
#ifdef GLOW_USE_AUTO_EXPOSURE
layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
#endif
layout(location = 0) out vec4 frag_color;
void main() {
// We do not apply our color scale for our mobile renderer here, we'll leave our colors at half brightness and apply scale in the tonemap raster.
#ifdef MODE_MIPMAP
vec2 pix_size = blur.pixel_size;
vec4 color = texture(source_color, uv_interp + vec2(-0.5, -0.5) * pix_size);
color += texture(source_color, uv_interp + vec2(0.5, -0.5) * pix_size);
color += texture(source_color, uv_interp + vec2(0.5, 0.5) * pix_size);
color += texture(source_color, uv_interp + vec2(-0.5, 0.5) * pix_size);
frag_color = color / 4.0;
#endif
#ifdef MODE_GAUSSIAN_BLUR
// For Gaussian Blur we use 13 taps in a single pass instead of 12 taps over 2 passes.
// This minimizes the number of times we change framebuffers which is very important for mobile.
// Source: http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
vec4 A = texture(source_color, uv_interp + blur.pixel_size * vec2(-1.0, -1.0));
vec4 B = texture(source_color, uv_interp + blur.pixel_size * vec2(0.0, -1.0));
vec4 C = texture(source_color, uv_interp + blur.pixel_size * vec2(1.0, -1.0));
vec4 D = texture(source_color, uv_interp + blur.pixel_size * vec2(-0.5, -0.5));
vec4 E = texture(source_color, uv_interp + blur.pixel_size * vec2(0.5, -0.5));
vec4 F = texture(source_color, uv_interp + blur.pixel_size * vec2(-1.0, 0.0));
vec4 G = texture(source_color, uv_interp);
vec4 H = texture(source_color, uv_interp + blur.pixel_size * vec2(1.0, 0.0));
vec4 I = texture(source_color, uv_interp + blur.pixel_size * vec2(-0.5, 0.5));
vec4 J = texture(source_color, uv_interp + blur.pixel_size * vec2(0.5, 0.5));
vec4 K = texture(source_color, uv_interp + blur.pixel_size * vec2(-1.0, 1.0));
vec4 L = texture(source_color, uv_interp + blur.pixel_size * vec2(0.0, 1.0));
vec4 M = texture(source_color, uv_interp + blur.pixel_size * vec2(1.0, 1.0));
float base_weight = 0.5 / 4.0;
float lesser_weight = 0.125 / 4.0;
frag_color = (D + E + I + J) * base_weight;
frag_color += (A + B + G + F) * lesser_weight;
frag_color += (B + C + H + G) * lesser_weight;
frag_color += (F + G + L + K) * lesser_weight;
frag_color += (G + H + M + L) * lesser_weight;
#endif
#ifdef MODE_GAUSSIAN_GLOW
//Glow uses larger sigma 1 for a more rounded blur effect
#define GLOW_ADD(m_ofs, m_mult) \
{ \
vec2 ofs = uv_interp + m_ofs * pix_size; \
vec4 c = texture(source_color, ofs) * m_mult; \
if (any(lessThan(ofs, vec2(0.0))) || any(greaterThan(ofs, vec2(1.0)))) { \
c *= 0.0; \
} \
color += c; \
}
if (bool(blur.flags & FLAG_HORIZONTAL)) {
vec2 pix_size = blur.pixel_size;
pix_size *= 0.5; //reading from larger buffer, so use more samples
vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.174938;
GLOW_ADD(vec2(1.0, 0.0), 0.165569);
GLOW_ADD(vec2(2.0, 0.0), 0.140367);
GLOW_ADD(vec2(3.0, 0.0), 0.106595);
GLOW_ADD(vec2(-1.0, 0.0), 0.165569);
GLOW_ADD(vec2(-2.0, 0.0), 0.140367);
GLOW_ADD(vec2(-3.0, 0.0), 0.106595);
// only do this in the horizontal pass, if we also do this in the vertical pass we're doubling up.
color *= blur.glow_strength;
frag_color = color;
} else {
vec2 pix_size = blur.pixel_size;
vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.288713;
GLOW_ADD(vec2(0.0, 1.0), 0.233062);
GLOW_ADD(vec2(0.0, 2.0), 0.122581);
GLOW_ADD(vec2(0.0, -1.0), 0.233062);
GLOW_ADD(vec2(0.0, -2.0), 0.122581);
frag_color = color;
}
#undef GLOW_ADD
if (bool(blur.flags & FLAG_GLOW_FIRST_PASS)) {
// In the first pass bring back to correct color range else we're applying the wrong threshold
// in subsequent passes we can use it as is as we'd just be undoing it right after.
frag_color *= blur.luminance_multiplier;
#ifdef GLOW_USE_AUTO_EXPOSURE
frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / blur.glow_auto_exposure_scale;
#endif
frag_color *= blur.glow_exposure;
float luminance = max(frag_color.r, max(frag_color.g, frag_color.b));
float feedback = max(smoothstep(blur.glow_hdr_threshold, blur.glow_hdr_threshold + blur.glow_hdr_scale, luminance), blur.glow_bloom);
frag_color = min(frag_color * feedback, vec4(blur.glow_luminance_cap)) / blur.luminance_multiplier;
}
#endif // MODE_GAUSSIAN_GLOW
#ifdef MODE_COPY
vec4 color = textureLod(source_color, uv_interp, 0.0);
frag_color = color;
#endif
}
|