UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

3 lines (2 loc) 4.03 kB
declare const _default: "\n// bilateral filter, based on https://www.shadertoy.com/view/4dfGDH# and\n// http://people.csail.mit.edu/sparis/bf_course/course_notes.pdf\n\n// A bilateral filter is a non-linear, edge-preserving, and noise-reducing smoothing filter for images.\n// It replaces the intensity of each pixel with a weighted average of intensity values from nearby pixels.\n// This weight can be based on a Gaussian distribution. Crucially, the weights depend not only on\n// Euclidean distance of pixels, but also on the radiometric differences (e.g., range differences, such\n// as color intensity, depth distance, etc.). This preserves sharp edges.\n\nfn normpdf3(v: vec3f, sigma: f32) -> f32 {\n return 0.39894 * exp(-0.5 * dot(v, v) / (sigma * sigma)) / sigma;\n}\n\nfn decodeRGBM(rgbm: vec4f) -> vec3f {\n let color = (8.0 * rgbm.a) * rgbm.rgb;\n return color * color;\n}\n\nfn saturate(x: f32) -> f32 {\n return clamp(x, 0.0, 1.0);\n}\n\nfn encodeRGBM(color: vec3f) -> vec4f {\n var encoded: vec4f;\n let rgb_processed = pow(color.rgb, vec3f(0.5)) * (1.0 / 8.0);\n encoded = vec4f(rgb_processed, 0.0);\n\n let max_g_b = max( encoded.g, max( encoded.b, 1.0 / 255.0 ) );\n let max_rgb = max( encoded.r, max_g_b );\n encoded.a = clamp(max_rgb, 0.0, 1.0);\n encoded.a = ceil(encoded.a * 255.0) / 255.0;\n\n encoded = vec4f(encoded.rgb / encoded.a, encoded.a);\n return encoded;\n}\n\nfn decode(pixel: vec4f) -> vec3f {\n #if HDR\n return pixel.rgb;\n #else\n return decodeRGBM(pixel);\n #endif\n}\n\nfn isUsed(pixel: vec4f) -> bool {\n #if HDR\n return any(pixel.rgb > vec3f(0.0));\n #else\n return pixel.a > 0.0;\n #endif\n}\n\nvarying vUv0: vec2f;\nvar source: texture_2d<f32>;\nvar sourceSampler: sampler;\nuniform kernel: array<f32, {MSIZE}>;\nuniform pixelOffset: vec2f;\nuniform sigmas: vec2f;\nuniform bZnorm: f32;\n\n@fragment\nfn fragmentMain(input: FragmentInput) -> FragmentOutput {\n var output: FragmentOutput;\n\n let pixel = textureSampleLevel(source, sourceSampler, input.vUv0, 0.0);\n\n // lightmap specific optimization - skip pixels that were not baked\n // this also allows dilate filter that work on the output of this to work correctly, as it depends on .a being zero\n // to dilate, which the following blur filter would otherwise modify\n if (!isUsed(pixel)) {\n output.color = pixel;\n return output;\n }\n\n // range sigma - controls blurriness based on a pixel distance\n let sigma = uniform.sigmas.x;\n\n // domain sigma - controls blurriness based on a pixel similarity (to preserve edges)\n let bSigma = uniform.sigmas.y;\n\n let pixelHdr = decode(pixel);\n var accumulatedHdr = vec3f(0.0);\n var accumulatedFactor = 0.000001; // avoid division by zero\n\n // read out the texels\n const kSize = ({MSIZE} - 1) / 2;\n for (var i: i32 = -kSize; i <= kSize; i = i + 1) {\n for (var j: i32 = -kSize; j <= kSize; j = j + 1) {\n\n // sample the pixel with offset\n let coord = input.vUv0 + vec2f(f32(i), f32(j)) * uniform.pixelOffset;\n let pix = textureSampleLevel(source, sourceSampler, coord, 0.0);\n\n // lightmap - only use baked pixels\n if (isUsed(pix)) {\n let hdr = decode(pix);\n\n // bilateral factors\n var factor = uniform.kernel[u32(kSize + j)].element * uniform.kernel[u32(kSize + i)].element;\n factor = factor * normpdf3(hdr - pixelHdr, bSigma) * uniform.bZnorm;\n\n // accumulate\n accumulatedHdr = accumulatedHdr + factor * hdr;\n accumulatedFactor = accumulatedFactor + factor;\n }\n }\n }\n\n let finalHDR = accumulatedHdr / accumulatedFactor;\n\n #if HDR\n output.color = vec4f(finalHDR, 1.0);\n #else\n output.color = encodeRGBM(finalHDR);\n #endif\n\n return output;\n}\n"; export default _default;