210 lines
6.9 KiB
GLSL
210 lines
6.9 KiB
GLSL
/* 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;
|
|
|
|
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 = texture(colorbuffer, color_uv1);
|
|
color += texture(colorbuffer, color_uv1 + offset_row[1]);
|
|
color += texture(colorbuffer, color_uv2);
|
|
color += texture(colorbuffer, color_uv2 + offset_row[1]);
|
|
color /= 4.0;
|
|
|
|
depth.r = texture(depthbuffer, depth_uv1).r;
|
|
depth.g = texture(depthbuffer, depth_uv2).r;
|
|
depth.b = texture(depthbuffer, depth_uv3).r;
|
|
depth.a = texture(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 = texture(depthbuffer, depth_uv1 + offset_row[0]).r;
|
|
depth.g = texture(depthbuffer, depth_uv2 + offset_row[0]).r;
|
|
depth.b = texture(depthbuffer, depth_uv3 + offset_row[0]).r;
|
|
depth.a = texture(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 = texture(depthbuffer, depth_uv1 + offset_row[1]).r;
|
|
depth.g = texture(depthbuffer, depth_uv2 + offset_row[1]).r;
|
|
depth.b = texture(depthbuffer, depth_uv3 + offset_row[1]).r;
|
|
depth.a = texture(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 = texture(depthbuffer, depth_uv1 + offset_row[2]).r;
|
|
depth.g = texture(depthbuffer, depth_uv2 + offset_row[2]).r;
|
|
depth.b = texture(depthbuffer, depth_uv3 + offset_row[2]).r;
|
|
depth.a = texture(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(texture(depthbuffer, uvcoordsvar.xy).r);
|
|
|
|
/* clever sampling to sample 2 pixels at once. Of course it's not real gaussian sampling this way */
|
|
vec4 color = texture(colorbuffer, uvcoordsvar.xy) * 0.3125;
|
|
color += texture(colorbuffer, uvcoordsvar.xy + invrendertargetdim) * 0.234375;
|
|
color += texture(colorbuffer, uvcoordsvar.xy + 2.5 * invrendertargetdim) * 0.09375;
|
|
color += texture(colorbuffer, uvcoordsvar.xy + 4.5 * invrendertargetdim) * 0.015625;
|
|
color += texture(colorbuffer, uvcoordsvar.xy - invrendertargetdim) * 0.234375;
|
|
color += texture(colorbuffer, uvcoordsvar.xy - 2.5 * invrendertargetdim) * 0.09375;
|
|
color += texture(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 = texture(colorbuffer, uvcoordsvar.xy);
|
|
vec4 color_blurred = texture(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 = texture(colorbuffer, uvcoordsvar.xz);
|
|
color += texture(colorbuffer, uvcoordsvar.yz);
|
|
color += texture(colorbuffer, uvcoordsvar.xw);
|
|
color += texture(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 * texture(colorbuffer, uv + color_uv1.xy);
|
|
result += weight * texture(colorbuffer, uv - color_uv1.xy);
|
|
result += weight * texture(colorbuffer, uv + color_uv1.yx);
|
|
result += weight * texture(colorbuffer, uv - color_uv1.yx);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/* fourth pass, just visualize the third pass contents */
|
|
void fifth_pass()
|
|
{
|
|
vec4 factors;
|
|
vec4 color_orig = texture(colorbuffer, uvcoordsvar.xy);
|
|
vec4 highblurred = texture(blurredcolorbuffer, uvcoordsvar.xy);
|
|
vec4 mediumblurred = texture(mblurredcolorbuffer, uvcoordsvar.xy);
|
|
vec4 smallblurred = small_sample_blur(colorbuffer, uvcoordsvar.xy, color_orig);
|
|
float depth = texture(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
|
|
}
|