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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
/* amount of offset to move one pixel left-right.
* In second pass some dimensions are zero to control verical/horizontal convolution */
uniform vec2 invrendertargetdim;
// color buffer
uniform sampler2D colorbuffer;
//blurred color buffer for DOF effect
uniform sampler2D blurredcolorbuffer;
// slightly blurred buffer
uniform sampler2D mblurredcolorbuffer;
// depth buffer
uniform sampler2D depthbuffer;
// this includes focal distance in x and aperture size in y
uniform vec4 dof_params;
// viewvectors for reconstruction of world space
uniform vec4 viewvecs[3];
// coordinates on framebuffer in normalized (0.0-1.0) uv space
in vec4 uvcoordsvar;
/* color texture coordinates, offset by a small amount */
in vec2 color_uv1;
in vec2 color_uv2;
in vec2 depth_uv1;
in vec2 depth_uv2;
in vec2 depth_uv3;
in vec2 depth_uv4;
out vec4 FragColor;
#define texture2D texture
float calculate_far_coc(in float zdepth)
{
float coc = dof_params.x * max(1.0 - dof_params.y / zdepth, 0.0);
/* multiply by 1.0 / sensor size to get the normalized size */
return coc * dof_params.z;
}
/* near coc only! when distance is nearer than focus plane first term is bigger than one */
vec4 calculate_near_coc(in vec4 zdepth)
{
vec4 coc = dof_params.x * max(vec4(dof_params.y) / zdepth - vec4(1.0), vec4(0.0));
/* multiply by 1.0 / sensor size to get the normalized size */
return coc * dof_params.z;
}
/* first pass blurs the color buffer heavily and gets the near coc only.
* There are many texture accesses here but they are done on a
* lower resolution image so overall bandwidth is not a concern */
void first_pass()
{
vec4 depth;
vec4 zdepth;
vec4 coc;
float final_coc;
/* amount to add to uvs so that they move one row further */
vec2 offset_row[3];
offset_row[0] = vec2(0.0, invrendertargetdim.y);
offset_row[1] = 2.0 * offset_row[0];
offset_row[2] = 3.0 * offset_row[0];
/* heavily blur the image */
vec4 color = texture2D(colorbuffer, color_uv1);
color += texture2D(colorbuffer, color_uv1 + offset_row[1]);
color += texture2D(colorbuffer, color_uv2);
color += texture2D(colorbuffer, color_uv2 + offset_row[1]);
color /= 4.0;
depth.r = texture2D(depthbuffer, depth_uv1).r;
depth.g = texture2D(depthbuffer, depth_uv2).r;
depth.b = texture2D(depthbuffer, depth_uv3).r;
depth.a = texture2D(depthbuffer, depth_uv4).r;
zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
coc = calculate_near_coc(zdepth);
depth.r = texture2D(depthbuffer, depth_uv1 + offset_row[0]).r;
depth.g = texture2D(depthbuffer, depth_uv2 + offset_row[0]).r;
depth.b = texture2D(depthbuffer, depth_uv3 + offset_row[0]).r;
depth.a = texture2D(depthbuffer, depth_uv4 + offset_row[0]).r;
zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
coc = max(calculate_near_coc(zdepth), coc);
depth.r = texture2D(depthbuffer, depth_uv1 + offset_row[1]).r;
depth.g = texture2D(depthbuffer, depth_uv2 + offset_row[1]).r;
depth.b = texture2D(depthbuffer, depth_uv3 + offset_row[1]).r;
depth.a = texture2D(depthbuffer, depth_uv4 + offset_row[1]).r;
zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
coc = max(calculate_near_coc(zdepth), coc);
depth.r = texture2D(depthbuffer, depth_uv1 + offset_row[2]).r;
depth.g = texture2D(depthbuffer, depth_uv2 + offset_row[2]).r;
depth.b = texture2D(depthbuffer, depth_uv3 + offset_row[2]).r;
depth.a = texture2D(depthbuffer, depth_uv4 + offset_row[2]).r;
zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
coc = max(calculate_near_coc(zdepth), coc);
final_coc = max(max(coc.x, coc.y), max(coc.z, coc.w));
FragColor = vec4(color.rgb, final_coc);
}
/* second pass, gaussian blur the downsampled image */
void second_pass()
{
vec4 depth = vec4(texture2D(depthbuffer, uvcoordsvar.xy).r);
/* clever sampling to sample 2 pixels at once. Of course it's not real gaussian sampling this way */
vec4 color = texture2D(colorbuffer, uvcoordsvar.xy) * 0.3125;
color += texture2D(colorbuffer, uvcoordsvar.xy + invrendertargetdim) * 0.234375;
color += texture2D(colorbuffer, uvcoordsvar.xy + 2.5 * invrendertargetdim) * 0.09375;
color += texture2D(colorbuffer, uvcoordsvar.xy + 4.5 * invrendertargetdim) * 0.015625;
color += texture2D(colorbuffer, uvcoordsvar.xy - invrendertargetdim) * 0.234375;
color += texture2D(colorbuffer, uvcoordsvar.xy - 2.5 * invrendertargetdim) * 0.09375;
color += texture2D(colorbuffer, uvcoordsvar.xy - 4.5 * invrendertargetdim) * 0.015625;
FragColor = color;
}
/* third pass, calculate the final coc from blurred and unblurred images */
void third_pass()
{
vec4 color = texture2D(colorbuffer, uvcoordsvar.xy);
vec4 color_blurred = texture2D(blurredcolorbuffer, uvcoordsvar.xy);
float coc = 2.0 * max(color_blurred.a, color.a); -color.a;
FragColor = vec4(color.rgb, coc);
}
/* fourth pass, blur the final coc once to get rid of discontinuities */
void fourth_pass()
{
vec4 color = texture2D(colorbuffer, uvcoordsvar.xz);
color += texture2D(colorbuffer, uvcoordsvar.yz);
color += texture2D(colorbuffer, uvcoordsvar.xw);
color += texture2D(colorbuffer, uvcoordsvar.yw);
FragColor = color / 4.0;
}
vec4 small_sample_blur(in sampler2D colorbuffer, in vec2 uv, in vec4 color)
{
float weight = 1.0 / 17.0;
vec4 result = weight * color;
weight *= 4.0;
result += weight * texture2D(colorbuffer, uv + color_uv1.xy);
result += weight * texture2D(colorbuffer, uv - color_uv1.xy);
result += weight * texture2D(colorbuffer, uv + color_uv1.yx);
result += weight * texture2D(colorbuffer, uv - color_uv1.yx);
return result;
}
/* fourth pass, just visualize the third pass contents */
void fifth_pass()
{
vec4 factors;
vec4 color_orig = texture2D(colorbuffer, uvcoordsvar.xy);
vec4 highblurred = texture2D(blurredcolorbuffer, uvcoordsvar.xy);
vec4 mediumblurred = texture2D(mblurredcolorbuffer, uvcoordsvar.xy);
vec4 smallblurred = small_sample_blur(colorbuffer, uvcoordsvar.xy, color_orig);
float depth = texture2D(depthbuffer, uvcoordsvar.xy).r;
float zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), vec4(depth)).r;
float coc_far = clamp(calculate_far_coc(zdepth), 0.0, 1.0);
/* calculate final coc here */
float coc = max(max(coc_far, mediumblurred.a), 0.0);
float width = 2.5;
float radius = 0.2;
factors.x = 1.0 - clamp(width * coc, 0.0, 1.0);
factors.y = 1.0 - clamp(abs(width * (coc - 2.0 * radius)), 0.0, 1.0);
factors.z = 1.0 - clamp(abs(width * (coc - 3.0 * radius)), 0.0, 1.0);
factors.w = 1.0 - clamp(abs(width * (coc - 4.0 * radius)), 0.0, 1.0);
/* blend! */
vec4 color = factors.x * color_orig + factors.y * smallblurred + factors.z * mediumblurred + factors.w * highblurred;
color /= dot(factors, vec4(1.0));
/* using original color is not correct, but use that for now because alpha of
* blurred buffers uses CoC instead */
FragColor = vec4(color.rgb, color_orig.a);
}
void main()
{
#ifdef FIRST_PASS
first_pass();
#elif defined(SECOND_PASS)
second_pass();
#elif defined(THIRD_PASS)
third_pass();
#elif defined(FOURTH_PASS)
fourth_pass();
#elif defined(FIFTH_PASS)
fifth_pass();
#endif
}
|