It now works correctly, and will output a "proper" depth of field effect. There's still work to be done to make it look smoother, but it's already pretty convincing.
67 lines
2.3 KiB
GLSL
Executable file
67 lines
2.3 KiB
GLSL
Executable file
#version 460 core
|
|
|
|
layout(location = 0) out vec2 outUV;
|
|
layout(location = 1) out vec2 outLoc;
|
|
layout(location = 2) out float cocRadius;
|
|
|
|
layout(binding = 2) uniform sampler2D depthSampler;
|
|
|
|
layout(push_constant) uniform PushConstants {
|
|
vec4 dpack;
|
|
vec4 dpack2;
|
|
int reverse;
|
|
} pushConstants;
|
|
|
|
// we calculate a circle of confusion based off of a bias and scale
|
|
// we basically do aperture * difference based off of surrounding depth
|
|
// the bias and scale calculations are based off of Bart Wronski's work:
|
|
// https://bartwronski.com/2014/04/07/bokeh-depth-of-field-going-insane-part-1/
|
|
float calculate_coc(vec2 inUV) {
|
|
const float bias = pushConstants.dpack[0] * (1.0 - pushConstants.dpack2[0] / pushConstants.dpack2[1]);
|
|
const float scale = pushConstants.dpack[0] * pushConstants.dpack2[0] * (pushConstants.dpack2[2] - pushConstants.dpack2[1]) / (pushConstants.dpack2[2] * pushConstants.dpack2[1]);
|
|
|
|
const vec4 depth = textureGather(depthSampler, inUV);
|
|
const float maxDepth = max(max(depth.x, depth.y), max(depth.z, depth.w));
|
|
|
|
return scale * maxDepth + bias;
|
|
}
|
|
|
|
void main() {
|
|
const vec2 res = vec2(pushConstants.dpack[2], pushConstants.dpack[3]);
|
|
|
|
const vec2 loc = vec2((gl_InstanceIndex % int(res.x)), ((gl_InstanceIndex / int(res.x)) % int(res.y)));
|
|
outLoc = loc;
|
|
|
|
const float coc = calculate_coc(vec2(loc.x / res.x, loc.y / res.y));
|
|
|
|
// this dof implementation relies on two separate fields, so we want to cull near objects when rendering the far field, and vice versa
|
|
const bool near = coc < 0.0f;
|
|
float cocScale = abs(coc);
|
|
if(pushConstants.reverse == 1) {
|
|
if(!near) {
|
|
cocScale = 0.0;
|
|
}
|
|
} else {
|
|
if(near) {
|
|
cocScale = 0.0;
|
|
}
|
|
}
|
|
|
|
// we limit the radius of every bokeh sample to 32, any higher risks heavy overdraw
|
|
const float size = min(cocScale, 32.0);
|
|
cocRadius = size;
|
|
|
|
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
|
|
|
vec2 pos = outUV * 2.0 + -1.0;
|
|
pos *= size;
|
|
pos *= vec2(1.0 / res.x, 1.0 / res.y);
|
|
pos.x -= 1;
|
|
pos.y -= 1;
|
|
pos.x += loc.x / (res.x / 2.0);
|
|
pos.y += loc.y / (res.y / 2.0);
|
|
|
|
// invalid bokeh is culled out of viewport
|
|
gl_Position = vec4(pos, 0.0, (cocScale < 1.0) ? -1.0 : 1.0);
|
|
}
|
|
|