255 lines
7.2 KiB
GLSL
255 lines
7.2 KiB
GLSL
|
|
uniform mat4 ProjectionMatrix;
|
|
|
|
uniform sampler2D colorBuffer;
|
|
uniform sampler2D depthBuffer;
|
|
|
|
uniform vec2 dofParams;
|
|
uniform bool unpremult;
|
|
|
|
#define dof_mul dofParams.x /* distance * aperturesize * invsensorsize */
|
|
#define dof_bias dofParams.y /* aperturesize * invsensorsize */
|
|
|
|
uniform vec4 bokehParams[2];
|
|
|
|
#define bokeh_rotation bokehParams[0].x
|
|
#define bokeh_ratio bokehParams[0].y
|
|
#define bokeh_maxsize bokehParams[0].z
|
|
#define bokeh_sides \
|
|
bokehParams[1] /* Polygon Bokeh shape number of sides (with precomputed vars) */
|
|
|
|
uniform vec2 nearFar; /* Near & far view depths values */
|
|
|
|
#define M_PI 3.1415926535897932384626433832795
|
|
#define M_2PI 6.2831853071795864769252868
|
|
|
|
/* -------------- Utils ------------- */
|
|
|
|
/* divide by sensor size to get the normalized size */
|
|
#define calculate_coc(zdepth) (dof_mul / zdepth - dof_bias)
|
|
|
|
#define linear_depth(z) \
|
|
((ProjectionMatrix[3][3] == 0.0) ? \
|
|
(nearFar.x * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y) : \
|
|
z * (nearFar.y - nearFar.x) + nearFar.x) /* Only true for camera view! */
|
|
|
|
#define weighted_sum(a, b, c, d, e) \
|
|
(a * e.x + b * e.y + c * e.z + d * e.w) / max(1e-6, dot(e, vec4(1.0)));
|
|
|
|
float max_v4(vec4 v)
|
|
{
|
|
return max(max(v.x, v.y), max(v.z, v.w));
|
|
}
|
|
|
|
#define THRESHOLD 1.0
|
|
|
|
#ifdef STEP_DOWNSAMPLE
|
|
|
|
layout(location = 0) out vec4 nearColor;
|
|
layout(location = 1) out vec4 farColor;
|
|
layout(location = 2) out vec2 cocData;
|
|
|
|
/* Downsample the color buffer to half resolution.
|
|
* Weight color samples by
|
|
* Compute maximum CoC for near and far blur. */
|
|
void main(void)
|
|
{
|
|
ivec4 uvs = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
|
|
|
|
/* custom downsampling */
|
|
vec4 color1 = texelFetch(colorBuffer, uvs.xy, 0);
|
|
vec4 color2 = texelFetch(colorBuffer, uvs.zw, 0);
|
|
vec4 color3 = texelFetch(colorBuffer, uvs.zy, 0);
|
|
vec4 color4 = texelFetch(colorBuffer, uvs.xw, 0);
|
|
|
|
/* Leverage SIMD by combining 4 depth samples into a vec4 */
|
|
vec4 depth;
|
|
depth.r = texelFetch(depthBuffer, uvs.xy, 0).r;
|
|
depth.g = texelFetch(depthBuffer, uvs.zw, 0).r;
|
|
depth.b = texelFetch(depthBuffer, uvs.zy, 0).r;
|
|
depth.a = texelFetch(depthBuffer, uvs.xw, 0).r;
|
|
|
|
vec4 zdepth = linear_depth(depth);
|
|
|
|
/* Compute signed CoC for each depth samples */
|
|
vec4 coc_near = calculate_coc(zdepth);
|
|
vec4 coc_far = -coc_near;
|
|
|
|
cocData.x = max(max_v4(coc_near), 0.0);
|
|
cocData.y = max(max_v4(coc_far), 0.0);
|
|
|
|
/* now we need to write the near-far fields premultiplied by the coc
|
|
* also use bilateral weighting by each coc values to avoid bleeding. */
|
|
vec4 near_weights = step(THRESHOLD, coc_near) * clamp(1.0 - abs(cocData.x - coc_near), 0.0, 1.0);
|
|
vec4 far_weights = step(THRESHOLD, coc_far) * clamp(1.0 - abs(cocData.y - coc_far), 0.0, 1.0);
|
|
|
|
# ifdef USE_ALPHA_DOF
|
|
/* Premult */
|
|
color1.rgb *= color1.a;
|
|
color2.rgb *= color2.a;
|
|
color3.rgb *= color3.a;
|
|
color4.rgb *= color4.a;
|
|
# endif
|
|
|
|
/* now write output to weighted buffers. */
|
|
nearColor = weighted_sum(color1, color2, color3, color4, near_weights);
|
|
farColor = weighted_sum(color1, color2, color3, color4, far_weights);
|
|
}
|
|
|
|
#elif defined(STEP_SCATTER)
|
|
|
|
flat in vec4 color;
|
|
flat in float weight;
|
|
flat in float smoothFac;
|
|
flat in ivec2 edge;
|
|
/* coordinate used for calculating radius */
|
|
in vec2 particlecoord;
|
|
|
|
layout(location = 0) out vec4 fragColor;
|
|
# ifdef USE_ALPHA_DOF
|
|
layout(location = 1) out float fragAlpha;
|
|
# endif
|
|
|
|
/* accumulate color in the near/far blur buffers */
|
|
void main(void)
|
|
{
|
|
/* Discard to avoid bleeding onto the next layer */
|
|
if (int(gl_FragCoord.x) * edge.x + edge.y > 0) {
|
|
discard;
|
|
}
|
|
|
|
/* Circle Dof */
|
|
float dist = length(particlecoord);
|
|
|
|
/* Outside of bokeh shape */
|
|
if (dist > 1.0) {
|
|
discard;
|
|
}
|
|
|
|
/* Regular Polygon Dof */
|
|
if (bokeh_sides.x > 0.0) {
|
|
/* Circle parametrization */
|
|
float theta = atan(particlecoord.y, particlecoord.x) + bokeh_rotation;
|
|
|
|
/* Optimized version of :
|
|
* float denom = theta - (M_2PI / bokeh_sides) * floor((bokeh_sides * theta + M_PI) / M_2PI);
|
|
* float r = cos(M_PI / bokeh_sides) / cos(denom); */
|
|
float denom = theta - bokeh_sides.y * floor(bokeh_sides.z * theta + 0.5);
|
|
float r = bokeh_sides.w / cos(denom);
|
|
|
|
/* Divide circle radial coord by the shape radius for angle theta.
|
|
* Giving us the new linear radius to the shape edge. */
|
|
dist /= r;
|
|
|
|
/* Outside of bokeh shape */
|
|
if (dist > 1.0) {
|
|
discard;
|
|
}
|
|
}
|
|
|
|
fragColor = color;
|
|
|
|
/* Smooth the edges a bit. This effectively reduce the bokeh shape
|
|
* but does fade out the undersampling artifacts. */
|
|
float shape = smoothstep(1.0, min(0.999, smoothFac), dist);
|
|
|
|
fragColor *= shape;
|
|
|
|
# ifdef USE_ALPHA_DOF
|
|
fragAlpha = fragColor.a;
|
|
fragColor.a = weight * shape;
|
|
# endif
|
|
}
|
|
|
|
#elif defined(STEP_RESOLVE)
|
|
|
|
# define MERGE_THRESHOLD 4.0
|
|
|
|
uniform sampler2D scatterBuffer;
|
|
uniform sampler2D scatterAlphaBuffer;
|
|
|
|
in vec4 uvcoordsvar;
|
|
out vec4 fragColor;
|
|
|
|
vec4 upsample_filter(sampler2D tex, vec2 uv, vec2 texelSize)
|
|
{
|
|
/* TODO FIXME: Clamp the sample position
|
|
* depending on the layer to avoid bleeding.
|
|
* This is not really noticeable so leaving it as is for now. */
|
|
|
|
# if 1 /* 9-tap bilinear upsampler (tent filter) */
|
|
vec4 d = texelSize.xyxy * vec4(1, 1, -1, 0);
|
|
|
|
vec4 s;
|
|
s = textureLod(tex, uv - d.xy, 0.0);
|
|
s += textureLod(tex, uv - d.wy, 0.0) * 2;
|
|
s += textureLod(tex, uv - d.zy, 0.0);
|
|
|
|
s += textureLod(tex, uv + d.zw, 0.0) * 2;
|
|
s += textureLod(tex, uv, 0.0) * 4;
|
|
s += textureLod(tex, uv + d.xw, 0.0) * 2;
|
|
|
|
s += textureLod(tex, uv + d.zy, 0.0);
|
|
s += textureLod(tex, uv + d.wy, 0.0) * 2;
|
|
s += textureLod(tex, uv + d.xy, 0.0);
|
|
|
|
return s * (1.0 / 16.0);
|
|
# else
|
|
/* 4-tap bilinear upsampler */
|
|
vec4 d = texelSize.xyxy * vec4(-1, -1, +1, +1) * 0.5;
|
|
|
|
vec4 s;
|
|
s = textureLod(tex, uv + d.xy, 0.0);
|
|
s += textureLod(tex, uv + d.zy, 0.0);
|
|
s += textureLod(tex, uv + d.xw, 0.0);
|
|
s += textureLod(tex, uv + d.zw, 0.0);
|
|
|
|
return s * (1.0 / 4.0);
|
|
# endif
|
|
}
|
|
|
|
/* Combine the Far and Near color buffers */
|
|
void main(void)
|
|
{
|
|
vec2 uv = uvcoordsvar.xy;
|
|
/* Recompute Near / Far CoC per pixel */
|
|
float depth = textureLod(depthBuffer, uv, 0.0).r;
|
|
float zdepth = linear_depth(depth);
|
|
float coc_signed = calculate_coc(zdepth);
|
|
float coc_far = max(-coc_signed, 0.0);
|
|
float coc_near = max(coc_signed, 0.0);
|
|
|
|
vec4 focus_col = textureLod(colorBuffer, uv, 0.0);
|
|
|
|
vec2 texelSize = vec2(0.5, 1.0) / vec2(textureSize(scatterBuffer, 0));
|
|
vec2 near_uv = uv * vec2(0.5, 1.0);
|
|
vec2 far_uv = near_uv + vec2(0.5, 0.0);
|
|
vec4 near_col = upsample_filter(scatterBuffer, near_uv, texelSize);
|
|
vec4 far_col = upsample_filter(scatterBuffer, far_uv, texelSize);
|
|
|
|
float far_w = far_col.a;
|
|
float near_w = near_col.a;
|
|
float focus_w = 1.0 - smoothstep(1.0, MERGE_THRESHOLD, abs(coc_signed));
|
|
float inv_weight_sum = 1.0 / (near_w + focus_w + far_w);
|
|
|
|
focus_col *= focus_w; /* Premul */
|
|
|
|
# ifdef USE_ALPHA_DOF
|
|
near_col.a = upsample_filter(scatterAlphaBuffer, near_uv, texelSize).r;
|
|
far_col.a = upsample_filter(scatterAlphaBuffer, far_uv, texelSize).r;
|
|
# endif
|
|
|
|
fragColor = (far_col + near_col + focus_col) * inv_weight_sum;
|
|
|
|
# ifdef USE_ALPHA_DOF
|
|
/* Sigh... viewport expect premult output but
|
|
* the final render output needs to be with
|
|
* associated alpha. */
|
|
if (unpremult) {
|
|
fragColor.rgb /= (fragColor.a > 0.0) ? fragColor.a : 1.0;
|
|
}
|
|
# endif
|
|
}
|
|
|
|
#endif
|