UNPKG

pex-renderer

Version:

Physically Based Renderer for Pex

110 lines (93 loc) 3.91 kB
const SHADERS = require('../chunks/index.js') module.exports = /* glsl */ ` // based on Bokeh depth of field in a single pass // http://blog.tuxedolabs.com/2018/05/04/bokeh-depth-of-field-in-single-pass.html precision highp float; varying vec2 vTexCoord0; uniform sampler2D image; //Image to be processed uniform vec2 imageSize; uniform sampler2D depthMap; //Linear depth, where 1.0 == far plane uniform vec2 uPixelSize; //The size of a pixel: vec2(1.0/width, 1.0/height) uniform float uFar; // Far plane uniform float uNear; uniform float uFocusDistance; uniform float uFStop; uniform float uFocalLength; uniform bool uDOFDebug; uniform float uSensorHeight; const float GOLDEN_ANGLE = 2.39996323; // rad const float MAX_BLUR_SIZE = 30.0; const float RAD_SCALE = 1.0; // Smaller = nicer blur, larger = faster const float NUM_ITERATIONS = 50.0; ${SHADERS.depthRead} float getCoCSize(float depth, float focusDistance, float maxCoC) { float coc = clamp((1.0 - focusDistance / depth) * maxCoC, -1.0, 1.0); // (1 - mm/mm) * mm = mm return abs(coc) * MAX_BLUR_SIZE; } vec3 depthOfField(vec2 texCoord, float focusDistance, float maxCoC) { float resolutionScale = imageSize.y / 1080.0; float centerDepth = readDepth(depthMap, texCoord, uNear, uFar) * 1000.0; //m -> mm float centerSize = getCoCSize(centerDepth, focusDistance, maxCoC); if (uDOFDebug && texCoord.x > 0.5) { float coc = (1.0 - focusDistance / centerDepth) * maxCoC; if (texCoord.x > 0.90) { float depth = texCoord.y * 1000.0 * 100.0; //100m if (texCoord.x <= 0.95) { float t = (texCoord.x - 0.9) * 20.0; float coc = (1.0 - focusDistance / depth) * maxCoC * 10.0; coc = abs(coc); if (coc > t) return vec3(1.0); return vec3(0.0); } if (texCoord.x > 0.97) { if (depth > focusDistance - 250.0 && depth < focusDistance + 250.0) { return vec3(1.0, 1.0, 0.0); } return vec3(floor(texCoord.y * 10.0)) / 10.0; } float c = 0.03; //0.03mm for 35mm format float H = uFocalLength * uFocalLength / (uFStop * c); //mm float Dn = H * focusDistance / (H + focusDistance); float Df = H * focusDistance / (H - focusDistance); if (depth > H - 250.0 && depth < H + 250.0) return vec3(1.0, 1.0, 0.0); if (depth < Dn) return vec3(1.0, 0.0, 0.0); if (depth > Df) return vec3(1.0, 0.0, 0.0); return vec3(0.0, 1.0, 0.0); } return vec3(floor(abs(coc) / 0.1 * 100.0) / 100.0, 0.0, 0.0); float c = abs(coc); c = c / (1.0 + c); // tonemapping to avoid burning the color c = pow(c, 2.2); // gamma to linear if (coc > 0.0) return vec3(c, 0.0, 0.0); else return vec3(0.0, 0.0, c); } vec3 color = texture2D(image, vTexCoord0).rgb; float tot = 1.0; float radius = RAD_SCALE; for (float ang = 0.0; ang < GOLDEN_ANGLE * NUM_ITERATIONS; ang += GOLDEN_ANGLE){ vec2 tc = texCoord + vec2(cos(ang), sin(ang)) * uPixelSize * radius * resolutionScale; vec3 sampleColor = texture2D(image, tc).rgb; float sampleDepth = readDepth(depthMap, tc, uNear, uFar) * 1000.0; //m -> mm; float sampleSize = getCoCSize(sampleDepth, focusDistance, maxCoC); if (sampleDepth > centerDepth) sampleSize = clamp(sampleSize, 0.0, centerSize * 2.0); float m = smoothstep(radius - 0.5, radius + 0.5, sampleSize); color += mix(color/tot, sampleColor, m); tot += 1.0; radius += RAD_SCALE / radius; // Not sure if this ever happens as we exit after 50 iterations anyway if (radius > MAX_BLUR_SIZE) { break; } } return color /= tot; } void main () { float F = uFocalLength; float A = F / uFStop; float focusDistance = uFocusDistance * 1000.0; // m -> mm float maxCoC = A * F / (focusDistance - F); //mm * mm / mm = mm vec3 color = depthOfField(vTexCoord0, focusDistance, maxCoC); gl_FragColor = vec4(color, 1.0); } `