// DoF with bokeh GLSL shader by Martins Upitis (martinsh) (devlog-martinsh.blogspot.com) // Creative Commons Attribution 3.0 Unported License #include "compiled.inc" #include "std/math.glsl" // const float compoDOFDistance = 10.0; // Focal distance value in meters // const float compoDOFLength = 160.0; // Focal length in mm 18-200 // const float compoDOFFstop = 128.0; // F-stop value const int samples = 6; // Samples on the first ring const int rings = 6; // Ring count const vec2 focus = vec2(0.5, 0.5); const float coc = 0.11; // Circle of confusion size in mm (35mm film = 0.03mm) const float maxblur = 1.0; const float threshold = 0.5; // Highlight threshold const float gain = 2.0; // Highlight gain const float bias = 0.5; // Bokeh edge bias const float fringe = 0.7; // Bokeh chromatic aberration/fringing const float namount = 0.0001; // Dither amount vec3 color(vec2 coords, const float blur, const sampler2D tex, const vec2 texStep) { vec3 col = vec3(0.0); col.r = textureLod(tex, coords + vec2(0.0, 1.0) * texStep * fringe * blur, 0.0).r; col.g = textureLod(tex, coords + vec2(-0.866, -0.5) * texStep * fringe * blur, 0.0).g; col.b = textureLod(tex, coords + vec2(0.866, -0.5) * texStep * fringe * blur, 0.0).b; const vec3 lumcoeff = vec3(0.299, 0.587, 0.114); float lum = dot(col.rgb, lumcoeff); float thresh = max((lum - threshold) * gain, 0.0); return col + mix(vec3(0.0), col, thresh * blur); } vec3 dof( const vec2 texCoord, const float gdepth, const sampler2D tex, const sampler2D gbufferD, const vec2 texStep, const vec2 cameraProj, const bool autoFocus, const float DOFDistance, const float DOFLength, const float DOFFStop) { float depth = linearize(gdepth, cameraProj); float fDepth = 0.0; if(autoFocus) { fDepth = linearize(textureLod(gbufferD, focus, 0.0).r * 2.0 - 1.0, cameraProj); } else { fDepth = DOFDistance; } float f = DOFLength; // Focal length in mm float d = fDepth * 1000.0; // Focal plane in mm float o = depth * 1000.0; // Depth in mm float a = (o * f) / (o - f); float b = (d * f) / (d - f); float c = (d - f) / (d * DOFFStop * coc); float blur = abs(a - b) * c; blur = clamp(blur, 0.0, 1.0); vec2 noise = rand2(texCoord) * namount * blur; float w = (texStep.x) * blur * maxblur + noise.x; float h = (texStep.y) * blur * maxblur + noise.y; vec3 col = vec3(0.0); if (blur < 0.05) { col = textureLod(tex, texCoord, 0.0).rgb; } else { col = textureLod(tex, texCoord, 0.0).rgb; float s = 1.0; int ringsamples; for (int i = 1; i <= rings; ++i) { ringsamples = i * samples; for (int j = 0 ; j < ringsamples; ++j) { float step = PI2 / float(ringsamples); float pw = (cos(float(j) * step) * float(i)); float ph = (sin(float(j) * step) * float(i)); float p = 1.0; // if (pentagon) p = penta(vec2(pw, ph)); col += color(texCoord + vec2(pw * w, ph * h), blur, tex, texStep) * mix(1.0, (float(i)) / (float(rings)), bias) * p; s += 1.0 * mix(1.0, (float(i)) / (float(rings)), bias) * p; } } col /= s; } return col; }